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  `)