github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/proxy/dial.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package proxy 18 19 import ( 20 "context" 21 "crypto/tls" 22 "fmt" 23 "net" 24 "net/http" 25 "net/url" 26 27 utilnet "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/net" 28 "github.com/spotmaxtech/k8s-apimachinery-v0260/third_party/forked/golang/netutil" 29 "k8s.io/klog/v2" 30 ) 31 32 // dialURL will dial the specified URL using the underlying dialer held by the passed 33 // RoundTripper. The primary use of this method is to support proxying upgradable connections. 34 // For this reason this method will prefer to negotiate http/1.1 if the URL scheme is https. 35 // If you wish to ensure ALPN negotiates http2 then set NextProto=[]string{"http2"} in the 36 // TLSConfig of the http.Transport 37 func dialURL(ctx context.Context, url *url.URL, transport http.RoundTripper) (net.Conn, error) { 38 dialAddr := netutil.CanonicalAddr(url) 39 40 dialer, err := utilnet.DialerFor(transport) 41 if err != nil { 42 klog.V(5).Infof("Unable to unwrap transport %T to get dialer: %v", transport, err) 43 } 44 45 switch url.Scheme { 46 case "http": 47 if dialer != nil { 48 return dialer(ctx, "tcp", dialAddr) 49 } 50 var d net.Dialer 51 return d.DialContext(ctx, "tcp", dialAddr) 52 case "https": 53 // Get the tls config from the transport if we recognize it 54 tlsConfig, err := utilnet.TLSClientConfig(transport) 55 if err != nil { 56 klog.V(5).Infof("Unable to unwrap transport %T to get at TLS config: %v", transport, err) 57 } 58 59 if dialer != nil { 60 // We have a dialer; use it to open the connection, then 61 // create a tls client using the connection. 62 netConn, err := dialer(ctx, "tcp", dialAddr) 63 if err != nil { 64 return nil, err 65 } 66 if tlsConfig == nil { 67 // tls.Client requires non-nil config 68 klog.Warning("using custom dialer with no TLSClientConfig. Defaulting to InsecureSkipVerify") 69 // tls.Handshake() requires ServerName or InsecureSkipVerify 70 tlsConfig = &tls.Config{ 71 InsecureSkipVerify: true, 72 } 73 } else if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify { 74 // tls.HandshakeContext() requires ServerName or InsecureSkipVerify 75 // infer the ServerName from the hostname we're connecting to. 76 inferredHost := dialAddr 77 if host, _, err := net.SplitHostPort(dialAddr); err == nil { 78 inferredHost = host 79 } 80 // Make a copy to avoid polluting the provided config 81 tlsConfigCopy := tlsConfig.Clone() 82 tlsConfigCopy.ServerName = inferredHost 83 tlsConfig = tlsConfigCopy 84 } 85 86 // Since this method is primarily used within a "Connection: Upgrade" call we assume the caller is 87 // going to write HTTP/1.1 request to the wire. http2 should not be allowed in the TLSConfig.NextProtos, 88 // so we explicitly set that here. We only do this check if the TLSConfig support http/1.1. 89 if supportsHTTP11(tlsConfig.NextProtos) { 90 tlsConfig = tlsConfig.Clone() 91 tlsConfig.NextProtos = []string{"http/1.1"} 92 } 93 94 tlsConn := tls.Client(netConn, tlsConfig) 95 if err := tlsConn.HandshakeContext(ctx); err != nil { 96 netConn.Close() 97 return nil, err 98 } 99 return tlsConn, nil 100 } else { 101 // Dial. 102 tlsDialer := tls.Dialer{ 103 Config: tlsConfig, 104 } 105 return tlsDialer.DialContext(ctx, "tcp", dialAddr) 106 } 107 default: 108 return nil, fmt.Errorf("unknown scheme: %s", url.Scheme) 109 } 110 } 111 112 func supportsHTTP11(nextProtos []string) bool { 113 if len(nextProtos) == 0 { 114 return true 115 } 116 for _, proto := range nextProtos { 117 if proto == "http/1.1" { 118 return true 119 } 120 } 121 return false 122 }