Change:
Is this a BUG REPORT or FEATURE REQUEST?: /kind bug What happened: When setting an HTTPPROXY with an IPv6 address, the is no HTTPProxy warning. What you expected to happen: There should be a warning that a proxy is being used. How to reproduce it (as minimally and precisely as possible): Use Kubeadm with IPv6 addresses, and IPv6 proxy in the environment. Such as: NOPROXY=2001:420:2c50:2021::/64 Anything else we need to know?: Environment: Kubernetes version (use ): 9 Cloud provider or hardware configuration: OS (e.g. from /etc/os-release): Kernel (e.g. ): Install tools: Others:
/assign rpothier
/sig cluster-lifecycle
/area ipv6

Discussion:
// Check validates http connectivity type, direct or via proxy. func (hst HTTPProxyCheck) Check() (warnings, errors []error) { <del> url := fmt.Sprintf("%s://%s", hst.Proto, hst.Host) </del> <ins> u := (&url.URL{Scheme: hst.Proto, Host: hst.Host}).String() </ins> <del> req, err := http.NewRequest("GET", url, nil) </del> <ins> req, err := http.NewRequest("GET", u, nil) </ins> if err != nil { return nil, []error{err} }

return nil, []error{err} } if proxy != nil { <del> return []error{fmt.Errorf("Connection to %q uses proxy %q. If that is not intended, adjust your proxy settings", url, proxy)}, nil </del> <ins> return []error{fmt.Errorf("Connection to %q uses proxy %q. If that is not intended, adjust your proxy settings", u, proxy)}, nil </ins> } return nil, nil }

} // Save current content of *_proxy and *_PROXY variables. <del> savedEnv := resetProxyEnv() </del> <ins> savedEnv := resetProxyEnv(t) </ins> defer restoreEnv(savedEnv) <del> t.Log("Saved environment: ", savedEnv) os.Setenv("HTTP_PROXY", "http://proxy.example.com:3128") os.Setenv("NO_PROXY", "example.com,10.0.0.0/8,2001:db8::/48") // Check if we can reliably execute tests: // ProxyFromEnvironment caches the *_proxy environment variables and // if ProxyFromEnvironment already executed before our test with empty // HTTP_PROXY it will make these tests return false positive failures req, err := http.NewRequest("GET", "http://host.fake.tld/", nil) if err != nil { t.Fatalf("unexpected err: %v", err) } proxy, err := http.ProxyFromEnvironment(req) if err != nil { t.Fatalf("unexpected err: %v", err) </del> <ins> for _, rt := range tests { warning, _ := rt.check.Check() if (warning != nil) != rt.expectWarnings { t.Errorf( "failed HTTPProxyCIDRCheck:ntexpected: %tnt  actual: %t (CIDR:%s). Warnings: %v", rt.expectWarnings, (warning != nil), rt.check.CIDR, warning, ) } </ins> } <del> if proxy == nil { t.Skip("test skipped as ProxyFromEnvironment already initialized in environment without defined HTTP proxy") </del> <ins> } func TestHTTPProxyCheck(t *testing.T) { var tests = []struct { name           string check          HTTPProxyCheck expectWarnings bool }{ { name: "Loopback address", check: HTTPProxyCheck{ Proto: "https", Host:  "127.0.0.1", }, // Loopback addresses never should produce proxy warnings expectWarnings: false, }, { name: "IPv4 direct access", check: HTTPProxyCheck{ Proto: "https", Host:  "10.96.0.1", }, // Expected to be accessed directly, we set NO_PROXY to 10.0.0.0/8 expectWarnings: false, }, { name: "IPv4 via proxy", check: HTTPProxyCheck{ Proto: "https", Host:  "192.168.0.1", }, // Expected to go via proxy as this range is not listed in NO_PROXY expectWarnings: true, }, { name: "IPv6 direct access", check: HTTPProxyCheck{ Proto: "https", Host:  "[2001:db8::1:15]", }, // Expected to be accessed directly, part of 2001:db8::/48 in NO_PROXY expectWarnings: false, }, { name: "IPv6 via proxy", check: HTTPProxyCheck{ Proto: "https", Host:  "[2001:db8:1::1:15]", }, // Expected to go via proxy, range is not in 2001:db8::/48 expectWarnings: true, }, </ins> } <del> t.Log("http.ProxyFromEnvironment is usable, continue executing test") </del> <ins> // Save current content of *_proxy and *_PROXY variables. savedEnv := resetProxyEnv(t) defer restoreEnv(savedEnv) </ins> for _, rt := range tests { warning, _ := rt.check.Check() if (warning != nil) != rt.expectWarnings { t.Errorf( <del> "failed HTTPProxyCIDRCheck:ntexpected: %tnt  actual: %t (CIDR:%s). Warnings: %v", </del> <ins> "%s failed HTTPProxyCheck:ntexpected: %tnt  actual: %t (Host:%s). Warnings: %v", rt.name, </ins> rt.expectWarnings, (warning != nil), <del> rt.check.CIDR, </del> <ins> rt.check.Host, </ins> warning, ) }

// resetProxyEnv is helper function that unsets all *_proxy variables // and return previously set values as map. This can be used to restore // original state of the environment. <del> func resetProxyEnv() map[string]string { </del> <ins> func resetProxyEnv(t *testing.T) map[string]string { </ins> savedEnv := make(map[string]string) for _, e := range os.Environ() { pair := strings.Split(e, "=")

os.Unsetenv(pair[0]) } } <ins> t.Log("Saved environment: ", savedEnv) os.Setenv("HTTP_PROXY", "http://proxy.example.com:3128") os.Setenv("NO_PROXY", "example.com,10.0.0.0/8,2001:db8::/48") // Check if we can reliably execute tests: // ProxyFromEnvironment caches the *_proxy environment variables and // if ProxyFromEnvironment already executed before our test with empty // HTTP_PROXY it will make these tests return false positive failures req, err := http.NewRequest("GET", "http://host.fake.tld/", nil) if err != nil { t.Fatalf("unexpected err: %v", err) } proxy, err := http.ProxyFromEnvironment(req) if err != nil { t.Fatalf("unexpected err: %v", err) } if proxy == nil { t.Skip("test skipped as ProxyFromEnvironment already initialized in environment without defined HTTP proxy") } t.Log("http.ProxyFromEnvironment is usable, continue executing test") </ins> return savedEnv }