github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/proxy/dial_test.go (about) 1 /* 2 Copyright 2016 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 "crypto/x509" 23 "fmt" 24 "net" 25 "net/http" 26 "net/http/httptest" 27 "net/url" 28 "reflect" 29 "regexp" 30 "testing" 31 32 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/diff" 33 utilnet "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/net" 34 ) 35 36 func TestDialURL(t *testing.T) { 37 roots := x509.NewCertPool() 38 if !roots.AppendCertsFromPEM(localhostCert) { 39 t.Fatal("error setting up localhostCert pool") 40 } 41 42 cert, err := tls.X509KeyPair(localhostCert, localhostKey) 43 if err != nil { 44 t.Fatal(err) 45 } 46 var d net.Dialer 47 48 testcases := map[string]struct { 49 TLSConfig *tls.Config 50 Dial utilnet.DialFunc 51 ExpectError string 52 ExpectProto string 53 }{ 54 "insecure": { 55 TLSConfig: &tls.Config{InsecureSkipVerify: true}, 56 }, 57 "secure, no roots": { 58 TLSConfig: &tls.Config{InsecureSkipVerify: false}, 59 ExpectError: "unknown authority|not trusted", 60 }, 61 "secure with roots": { 62 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots}, 63 }, 64 "secure with mismatched server": { 65 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "bogus.com"}, 66 ExpectError: "not bogus.com", 67 }, 68 "secure with matched server": { 69 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "example.com"}, 70 }, 71 72 "insecure, custom dial": { 73 TLSConfig: &tls.Config{InsecureSkipVerify: true}, 74 Dial: d.DialContext, 75 }, 76 "secure, no roots, custom dial": { 77 TLSConfig: &tls.Config{InsecureSkipVerify: false}, 78 Dial: d.DialContext, 79 ExpectError: "unknown authority|not trusted", 80 }, 81 "secure with roots, custom dial": { 82 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots}, 83 Dial: d.DialContext, 84 }, 85 "secure with mismatched server, custom dial": { 86 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "bogus.com"}, 87 Dial: d.DialContext, 88 ExpectError: "not bogus.com", 89 }, 90 "secure with matched server, custom dial": { 91 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "example.com"}, 92 Dial: d.DialContext, 93 }, 94 "ensure we use http2 if specified": { 95 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "example.com", NextProtos: []string{"http2"}}, 96 Dial: d.DialContext, 97 ExpectProto: "http2", 98 }, 99 "ensure we use http/1.1 if unspecified": { 100 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "example.com"}, 101 Dial: d.DialContext, 102 ExpectProto: "http/1.1", 103 }, 104 "ensure we use http/1.1 if available": { 105 TLSConfig: &tls.Config{InsecureSkipVerify: false, RootCAs: roots, ServerName: "example.com", NextProtos: []string{"http2", "http/1.1"}}, 106 Dial: d.DialContext, 107 ExpectProto: "http/1.1", 108 }, 109 } 110 111 for k, tc := range testcases { 112 func() { 113 ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {})) 114 defer ts.Close() 115 ts.TLS = &tls.Config{Certificates: []tls.Certificate{cert}, NextProtos: []string{"http2", "http/1.1"}} 116 ts.StartTLS() 117 118 // Make a copy of the config 119 tlsConfigCopy := tc.TLSConfig.Clone() 120 // Clone() mutates the receiver (!), so also call it on the copy 121 tlsConfigCopy.Clone() 122 transport := &http.Transport{ 123 DialContext: tc.Dial, 124 TLSClientConfig: tlsConfigCopy, 125 } 126 127 extractedDial, err := utilnet.DialerFor(transport) 128 if err != nil { 129 t.Fatal(err) 130 } 131 if fmt.Sprintf("%p", extractedDial) != fmt.Sprintf("%p", tc.Dial) { 132 t.Fatalf("%s: Unexpected dial", k) 133 } 134 135 extractedTLSConfig, err := utilnet.TLSClientConfig(transport) 136 if err != nil { 137 t.Fatal(err) 138 } 139 if extractedTLSConfig == nil { 140 t.Fatalf("%s: Expected tlsConfig", k) 141 } 142 143 u, _ := url.Parse(ts.URL) 144 _, p, _ := net.SplitHostPort(u.Host) 145 u.Host = net.JoinHostPort("127.0.0.1", p) 146 conn, err := dialURL(context.Background(), u, transport) 147 148 // Make sure dialing doesn't mutate the transport's TLSConfig 149 if !reflect.DeepEqual(tc.TLSConfig, tlsConfigCopy) { 150 t.Errorf("%s: transport's copy of TLSConfig was mutated\n%s", k, diff.ObjectReflectDiff(tc.TLSConfig, tlsConfigCopy)) 151 } 152 153 if err != nil { 154 if tc.ExpectError == "" { 155 t.Errorf("%s: expected no error, got %q", k, err.Error()) 156 } 157 if tc.ExpectError != "" && !regexp.MustCompile(tc.ExpectError).MatchString(err.Error()) { 158 t.Errorf("%s: expected error containing %q, got %q", k, tc.ExpectError, err.Error()) 159 } 160 return 161 } 162 163 tlsConn := conn.(*tls.Conn) 164 if tc.ExpectProto != "" { 165 if tlsConn.ConnectionState().NegotiatedProtocol != tc.ExpectProto { 166 t.Errorf("%s: expected proto %s, got %s", k, tc.ExpectProto, tlsConn.ConnectionState().NegotiatedProtocol) 167 } 168 } 169 170 conn.Close() 171 if tc.ExpectError != "" { 172 t.Errorf("%s: expected error %q, got none", k, tc.ExpectError) 173 } 174 }() 175 } 176 177 } 178 179 // localhostCert was generated from crypto/tls/generate_cert.go with the following command: 180 // 181 // go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h 182 var localhostCert = []byte(`-----BEGIN CERTIFICATE----- 183 MIIDGTCCAgGgAwIBAgIRAKfNl1LEAt7nFPYvHBnpv2swDQYJKoZIhvcNAQELBQAw 184 EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2 185 MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP 186 ADCCAQoCggEBAKww39FwmV5lDIbAUIAuSYYVtZke6bca1oyq19ZrRL0uavwPXSJm 187 +Qxt4RKUQhzYhZ/alJp8iRfu/Z+Yv9Beez89dQB9V8YnHj/AX4Jph9lJ2aawWMI6 188 AqPLdIzKLQVVvPw+UVKH9x8yy08H/23AIFGyK4Dbht+KZJeUbJQFiGlRFJim8atx 189 KA3C9NzCHw6hyhP46jguLl65rcxLMSzcTz97ToG0MP66YEUbsA/YzFTKDwht7ESH 190 nRMBnQ4wZfWpvAiXMr3XJGOa3NYJy1A+WkWyrfZO7guwsZ4L6dGqnlPpzA5QkKYx 191 H9Z5K1bUaYEi0Yi2ug7Jkvd1HE179nkF7t0CAwEAAaNoMGYwDgYDVR0PAQH/BAQD 192 AgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0R 193 BCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI 194 hvcNAQELBQADggEBAAKSQToD1iLujFhQwaLnPVRV6r4nEFVXCxXYtQNEX1DVSKSj 195 JYbBGJnL50oc0N4Ar+Spqofm+THkiTQJUzptPtnYIzNpKYdE6+bPwqURWzFEI2OF 196 ks3fYZ4ZdbMbmJRo1qPJO34emm4KrOl9aoV0qwp2QyTvHgLroU3icKoe4e7+p4KK 197 02Rt3qczHvCKoUnw6m07Ql0n9e7Ncpujcs2A8PaQ1iPX+BVOmvjTVT8y5NSRDzwL 198 a2wur8BSZ5E8SVzzvNZJlLSi6BbObQUjALHkjVYm11dWv/BY8jHdt+iFhbNBRASx 199 ENuih3pX1Poki1qRYOtB/vAS99E1ORj9zJlUlzo= 200 -----END CERTIFICATE-----`) 201 202 // localhostKey is the private key for localhostCert. 203 var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- 204 MIIEogIBAAKCAQEArDDf0XCZXmUMhsBQgC5JhhW1mR7ptxrWjKrX1mtEvS5q/A9d 205 Imb5DG3hEpRCHNiFn9qUmnyJF+79n5i/0F57Pz11AH1XxiceP8BfgmmH2UnZprBY 206 wjoCo8t0jMotBVW8/D5RUof3HzLLTwf/bcAgUbIrgNuG34pkl5RslAWIaVEUmKbx 207 q3EoDcL03MIfDqHKE/jqOC4uXrmtzEsxLNxPP3tOgbQw/rpgRRuwD9jMVMoPCG3s 208 RIedEwGdDjBl9am8CJcyvdckY5rc1gnLUD5aRbKt9k7uC7Cxngvp0aqeU+nMDlCQ 209 pjEf1nkrVtRpgSLRiLa6DsmS93UcTXv2eQXu3QIDAQABAoIBACAYnB+2FWB7BXK4 210 tkiuWBYeRdNc58OxxPxDfCgDprR8yoRheMLI3vNqJ+IGsKwf0AiT/c8uF3/WlIAD 211 QP3eHqsTEZQdyRaug/zuJt9wPFpMYb2ocWMC3Ssa6Ya0yN+Ns8Rw+UehAHdYSH1a 212 yEn03hFcXK+QO/u/GDEJAZQ108+NdznT4ql59tt791d97meNlMVJwkwVf/NqtDqi 213 UNx6BvSj5+6MoWjU8hqrYv9pkzP386QRsl70tVH+0LZd5XUZsSyof/IdV1EmfGUR 214 5les8tsd+fuo3LaPObksJu+GBwvEStmQPjZjiBUzw0Sx8VYTJfZr7gl2h4mmk/AJ 215 F5P+fSECgYEAzwDcJCuYPA8nzVB+ZOM+Wl+3uUKG/Xn8Yx8uWtWU7o9qsJmasLqO 216 sLtz1zadPtYOBXsb4H5PisNPuosVEqnthjRwmPhIA3tK/X3UzhnriACCrKpg3Ix0 217 uJG2vqpdaPXYxmyTQfI8YSp5X0gTg3R4xQqmbGMyAQg+1NzcGAf+qQ8CgYEA1PKX 218 vkxzJuSPsfQYr34fnZRuogANNGUaWCTYMhH6sK8qrJu5RXmEemaraqT/esUUu1fl 219 cTAxRqUb8ysexA+RKR848hFkrvAR5M1t6xK2hPuSec1Lm9HNfHoFB7Pa5t7APoJ9 220 8NkjNzI0mL9YqYcfJpzfFrxtzfLwlm6B3irS8VMCgYBg3skmUBRcvsbkiO+tLL7I 221 MhTbKGvdgNGAXV4m+d5JSWonHKrMW3Fc+Uv7gb5SYn+LRxJDmziD+mR8KowBAO57 222 qFys6TtiDbeJKvKERJL5QSvlu5G6hCw3F1GKplUyQiJgsPy0lrR00BieYy9mjAHc 223 S+CXxk/nNcGZgYWp5UviNwKBgC7t46kpmfsJRe222LXcOsV0j8kd78sLOPoR7J9k 224 PPYxNFtj2jnIZPzAoahYAoGg60e6QDNopoNmIbm+WAJnV9tTKS6XzLOM7rSY3U+A 225 CT9XXdl/99i4LOvwzCj9ZxGYJ4/fHDg28j7YzqSXDsgVojTVP4j4L87CamkMo4w9 226 rc1HAoGARE2WActS2PF75jRXCjj4SjB/3vOJVGKxrJdoo2HPzY0psTmdJJULOGYZ 227 MU1KC4EDzhSfM3juBbEhaZx9NFZOHVp2hxZpg77B5cQXGH6HIiZ20jCNjdcioHl9 228 HeVeFG/9rJG0NcQe3pIm9f0EY5JCbzr0fa2tTPV3N9jGHc0sFtI= 229 -----END RSA PRIVATE KEY----- 230 `)