From 6d71eb590bf54d2fd7ff9c1370e4a9b83875470a Mon Sep 17 00:00:00 2001 From: Dane LeBlanc Date: Sun, 17 Sep 2017 13:42:09 -0400 Subject: [PATCH] Add check for IPv6 '::' when calculating kube-proxy's node IP kube-proxy currently checks for a bind address of 0.0.0.0 (IPv4 all-zeros) when calculating kube-proxy's node IP, but it does not check for an address of '::' (IPv6 all-zeros). For either of those all-zeros addresses, the node IP should be determined based on the hostname, rather than using the address directly. Also added a helpful log message when the kube-proxy protocol is determined to be IPv6. fixes #52613 --- cmd/kube-proxy/app/server_others.go | 7 ++-- cmd/kube-proxy/app/server_test.go | 59 +++++++++++++++++++++++++++-- pkg/proxy/userspace/proxier.go | 2 +- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/cmd/kube-proxy/app/server_others.go b/cmd/kube-proxy/app/server_others.go index b0f0eace57..479d2adb4c 100644 --- a/cmd/kube-proxy/app/server_others.go +++ b/cmd/kube-proxy/app/server_others.go @@ -65,6 +65,7 @@ func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndEx protocol := utiliptables.ProtocolIpv4 if net.ParseIP(config.BindAddress).To4() == nil { + glog.V(0).Infof("IPv6 bind address (%s), assume IPv6 operation", config.BindAddress) protocol = utiliptables.ProtocolIpv6 } @@ -115,10 +116,8 @@ func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndEx proxyMode := getProxyMode(string(config.Mode), iptInterface, iptables.LinuxKernelCompatTester{}) if proxyMode == proxyModeIPTables { glog.V(0).Info("Using iptables Proxier.") - var nodeIP net.IP - if config.BindAddress != "0.0.0.0" { - nodeIP = net.ParseIP(config.BindAddress) - } else { + nodeIP := net.ParseIP(config.BindAddress) + if nodeIP.Equal(net.IPv4zero) || nodeIP.Equal(net.IPv6zero) { nodeIP = getNodeIP(client, hostname) } if config.IPTables.MasqueradeBit == nil { diff --git a/cmd/kube-proxy/app/server_test.go b/cmd/kube-proxy/app/server_test.go index cf047b5f2c..e6e0708064 100644 --- a/cmd/kube-proxy/app/server_test.go +++ b/cmd/kube-proxy/app/server_test.go @@ -177,7 +177,7 @@ func TestProxyServerWithCleanupAndExit(t *testing.T) { // Each bind address below is a separate test case bindAddresses := []string{ "0.0.0.0", - "2001:db8::1", + "::", } for _, addr := range bindAddresses { options, err := NewOptions() @@ -308,13 +308,54 @@ udpTimeoutMilliseconds: 123ms metricsBindAddress string }{ { - name: "iptables mode, IPv4 config", + name: "iptables mode, IPv4 all-zeros bind address", + mode: "iptables", + bindAddress: "0.0.0.0", + clusterCIDR: "1.2.3.0/24", + healthzBindAddress: "1.2.3.4:12345", + metricsBindAddress: "2.3.4.5:23456", + }, + { + name: "iptables mode, non-zeros IPv4 config", mode: "iptables", bindAddress: "9.8.7.6", clusterCIDR: "1.2.3.0/24", healthzBindAddress: "1.2.3.4:12345", metricsBindAddress: "2.3.4.5:23456", }, + { + // Test for 'bindAddress: "::"' (IPv6 all-zeros) in kube-proxy + // config file. The user will need to put quotes around '::' since + // 'bindAddress: ::' is invalid yaml syntax. + name: "iptables mode, IPv6 \"::\" bind address", + mode: "iptables", + bindAddress: "\"::\"", + clusterCIDR: "fd00:1::0/64", + healthzBindAddress: "[fd00:1::5]:12345", + metricsBindAddress: "[fd00:2::5]:23456", + }, + { + // Test for 'bindAddress: "[::]"' (IPv6 all-zeros in brackets) + // in kube-proxy config file. The user will need to use + // surrounding quotes here since 'bindAddress: [::]' is invalid + // yaml syntax. + name: "iptables mode, IPv6 \"[::]\" bind address", + mode: "iptables", + bindAddress: "\"[::]\"", + clusterCIDR: "fd00:1::0/64", + healthzBindAddress: "[fd00:1::5]:12345", + metricsBindAddress: "[fd00:2::5]:23456", + }, + { + // Test for 'bindAddress: ::0' (another form of IPv6 all-zeros). + // No surrounding quotes are required around '::0'. + name: "iptables mode, IPv6 ::0 bind address", + mode: "iptables", + bindAddress: "::0", + clusterCIDR: "fd00:1::0/64", + healthzBindAddress: "[fd00:1::5]:12345", + metricsBindAddress: "[fd00:2::5]:23456", + }, { name: "ipvs mode, IPv6 config", mode: "ipvs", @@ -326,8 +367,13 @@ udpTimeoutMilliseconds: 123ms } for _, tc := range testCases { + expBindAddr := tc.bindAddress + if tc.bindAddress[0] == '"' { + // Surrounding double quotes will get stripped by the yaml parser. + expBindAddr = expBindAddr[1 : len(tc.bindAddress)-1] + } expected := &componentconfig.KubeProxyConfiguration{ - BindAddress: tc.bindAddress, + BindAddress: expBindAddr, ClientConnection: componentconfig.ClientConnectionConfiguration{ AcceptContentTypes: "abc", Burst: 100, @@ -374,7 +420,7 @@ udpTimeoutMilliseconds: 123ms config, err := options.loadConfig([]byte(yaml)) assert.NoError(t, err, "unexpected error for %s: %v", tc.name, err) if !reflect.DeepEqual(expected, config) { - t.Fatalf("unexpected config for %s test, diff = %s", tc.name, diff.ObjectDiff(config, expected)) + t.Fatalf("unexpected config for %s, diff = %s", tc.name, diff.ObjectDiff(config, expected)) } } } @@ -396,6 +442,11 @@ func TestLoadConfigFailures(t *testing.T) { config: "kind: KubeSchedulerConfiguration", expErr: "unexpected config type", }, + { + name: "Missing quotes around :: bindAddress", + config: "bindAddress: ::", + expErr: "mapping values are not allowed in this context", + }, } version := "apiVersion: componentconfig/v1alpha1" for _, tc := range testCases { diff --git a/pkg/proxy/userspace/proxier.go b/pkg/proxy/userspace/proxier.go index a6304db35f..8e319c8ba2 100644 --- a/pkg/proxy/userspace/proxier.go +++ b/pkg/proxy/userspace/proxier.go @@ -942,7 +942,7 @@ func iptablesFlush(ipt iptables.Interface) error { var zeroIPv4 = net.ParseIP("0.0.0.0") var localhostIPv4 = net.ParseIP("127.0.0.1") -var zeroIPv6 = net.ParseIP("::0") +var zeroIPv6 = net.ParseIP("::") var localhostIPv6 = net.ParseIP("::1") // Build a slice of iptables args that are common to from-container and from-host portal rules.