mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 12:18:16 +00:00 
			
		
		
		
	Move GetNodeAddresses() and ContainsIPv4Loopback() into a new file
Both sound slightly generic, but implement semantics specific to the handling of NodePort addresses. (No changes other than moving code.)
This commit is contained in:
		
							
								
								
									
										120
									
								
								pkg/proxy/util/nodeport_addresses.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								pkg/proxy/util/nodeport_addresses.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2022 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package util
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	netutils "k8s.io/utils/net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetNodeAddresses return all matched node IP addresses based on given cidr slice.
 | 
			
		||||
// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
 | 
			
		||||
// NetworkInterfacer is injected for test purpose.
 | 
			
		||||
// We expect the cidrs passed in is already validated.
 | 
			
		||||
// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
 | 
			
		||||
// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
 | 
			
		||||
// only return `0.0.0.0/0`.
 | 
			
		||||
// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
 | 
			
		||||
func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
 | 
			
		||||
	uniqueAddressList := sets.NewString()
 | 
			
		||||
	if len(cidrs) == 0 {
 | 
			
		||||
		uniqueAddressList.Insert(IPv4ZeroCIDR)
 | 
			
		||||
		uniqueAddressList.Insert(IPv6ZeroCIDR)
 | 
			
		||||
		return uniqueAddressList, nil
 | 
			
		||||
	}
 | 
			
		||||
	// First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
 | 
			
		||||
	for _, cidr := range cidrs {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			uniqueAddressList.Insert(cidr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrs, err := nw.InterfaceAddrs()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Second round of iteration to parse IPs based on cidr.
 | 
			
		||||
	for _, cidr := range cidrs {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_, ipNet, _ := netutils.ParseCIDRSloppy(cidr)
 | 
			
		||||
		for _, addr := range addrs {
 | 
			
		||||
			var ip net.IP
 | 
			
		||||
			// nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux.
 | 
			
		||||
			switch v := addr.(type) {
 | 
			
		||||
			case *net.IPAddr:
 | 
			
		||||
				ip = v.IP
 | 
			
		||||
			case *net.IPNet:
 | 
			
		||||
				ip = v.IP
 | 
			
		||||
			default:
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ipNet.Contains(ip) {
 | 
			
		||||
				if netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
 | 
			
		||||
					uniqueAddressList.Insert(ip.String())
 | 
			
		||||
				}
 | 
			
		||||
				if !netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
 | 
			
		||||
					uniqueAddressList.Insert(ip.String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uniqueAddressList.Len() == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("no addresses found for cidrs %v", cidrs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return uniqueAddressList, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsIPv4Loopback returns true if the input is empty or one of the CIDR contains an IPv4 loopback address.
 | 
			
		||||
func ContainsIPv4Loopback(cidrStrings []string) bool {
 | 
			
		||||
	if len(cidrStrings) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	// RFC 5735 127.0.0.0/8 - This block is assigned for use as the Internet host loopback address
 | 
			
		||||
	ipv4LoopbackStart := netutils.ParseIPSloppy("127.0.0.0")
 | 
			
		||||
	for _, cidr := range cidrStrings {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ip, ipnet, err := netutils.ParseCIDRSloppy(cidr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if netutils.IsIPv6CIDR(ipnet) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ip.IsLoopback() {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if ipnet.Contains(ipv4LoopbackStart) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										311
									
								
								pkg/proxy/util/nodeport_addresses_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								pkg/proxy/util/nodeport_addresses_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,311 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2022 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package util
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	fake "k8s.io/kubernetes/pkg/proxy/util/testing"
 | 
			
		||||
	netutils "k8s.io/utils/net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type InterfaceAddrsPair struct {
 | 
			
		||||
	itf   net.Interface
 | 
			
		||||
	addrs []net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetNodeAddresses(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		cidrs         []string
 | 
			
		||||
		nw            *fake.FakeNetwork
 | 
			
		||||
		itfAddrsPairs []InterfaceAddrsPair
 | 
			
		||||
		expected      sets.String
 | 
			
		||||
		expectedErr   error
 | 
			
		||||
	}{
 | 
			
		||||
		{ // case 0
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.200.201.1"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("10.20.30.51"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 1
 | 
			
		||||
			cidrs: []string{"0.0.0.0/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 2
 | 
			
		||||
			cidrs: []string{"2001:db8::/32", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("2001:db8::1", "::1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 3
 | 
			
		||||
			cidrs: []string{"::/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 4
 | 
			
		||||
			cidrs: []string{"127.0.0.1/32"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("127.0.0.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 5
 | 
			
		||||
			cidrs: []string{"127.0.0.0/8"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.1.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("127.0.1.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 6
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.200.201.1"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("10.20.30.51", "100.200.201.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 7
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("192.168.1.2"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected:    nil,
 | 
			
		||||
			expectedErr: fmt.Errorf("no addresses found for cidrs %v", []string{"10.20.30.0/24", "100.200.201.0/24"}),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 8
 | 
			
		||||
			cidrs: []string{},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("192.168.1.2"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 9
 | 
			
		||||
			cidrs: []string{},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 9
 | 
			
		||||
			cidrs: []string{"1.2.3.0/24", "0.0.0.0/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 10
 | 
			
		||||
			cidrs: []string{"0.0.0.0/0", "1.2.3.0/24", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 11
 | 
			
		||||
			cidrs: []string{"::/0", "1.2.3.0/24", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("::/0", "1.2.3.4"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range testCases {
 | 
			
		||||
		for _, pair := range testCases[i].itfAddrsPairs {
 | 
			
		||||
			testCases[i].nw.AddInterfaceAddr(&pair.itf, pair.addrs)
 | 
			
		||||
		}
 | 
			
		||||
		addrList, err := GetNodeAddresses(testCases[i].cidrs, testCases[i].nw)
 | 
			
		||||
		if !reflect.DeepEqual(err, testCases[i].expectedErr) {
 | 
			
		||||
			t.Errorf("case [%d], unexpected error: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !addrList.Equal(testCases[i].expected) {
 | 
			
		||||
			t.Errorf("case [%d], unexpected mismatch, expected: %v, got: %v", i, testCases[i].expected, addrList)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestContainsIPv4Loopback(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		cidrStrings []string
 | 
			
		||||
		want        bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "empty",
 | 
			
		||||
			want: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv4",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "0.0.0.0/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv4 and invalid cidr",
 | 
			
		||||
			cidrStrings: []string{"invalid.cidr", "192.168.0.0/16", "fd00:1:d::/64", "0.0.0.0/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv6", // interpret all zeros equal for IPv4 and IPv6 as Golang stdlib
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "::/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "127.0.0.0/8"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv6 loopback",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "::1/128"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback smaller range",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "127.0.2.0/28"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback within larger range",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "64.0.0.0/2"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "non loop loopback",
 | 
			
		||||
			cidrStrings: []string{"128.0.2.0/28", "224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "invalid cidr",
 | 
			
		||||
			cidrStrings: []string{"invalid.ip/invalid.mask"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if got := ContainsIPv4Loopback(tt.cidrStrings); got != tt.want {
 | 
			
		||||
				t.Errorf("ContainLoopback() = %v, want %v", got, tt.want)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -78,37 +78,6 @@ func BuildPortsToEndpointsMap(endpoints *v1.Endpoints) map[string][]string {
 | 
			
		||||
	return portsToEndpoints
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsIPv4Loopback returns true if the input is empty or one of the CIDR contains an IPv4 loopback address.
 | 
			
		||||
func ContainsIPv4Loopback(cidrStrings []string) bool {
 | 
			
		||||
	if len(cidrStrings) == 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	// RFC 5735 127.0.0.0/8 - This block is assigned for use as the Internet host loopback address
 | 
			
		||||
	ipv4LoopbackStart := netutils.ParseIPSloppy("127.0.0.0")
 | 
			
		||||
	for _, cidr := range cidrStrings {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ip, ipnet, err := netutils.ParseCIDRSloppy(cidr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if netutils.IsIPv6CIDR(ipnet) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ip.IsLoopback() {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		if ipnet.Contains(ipv4LoopbackStart) {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsZeroCIDR checks whether the input CIDR string is either
 | 
			
		||||
// the IPv4 or IPv6 zero CIDR
 | 
			
		||||
func IsZeroCIDR(cidr string) bool {
 | 
			
		||||
@@ -228,70 +197,6 @@ func ShouldSkipService(service *v1.Service) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetNodeAddresses return all matched node IP addresses based on given cidr slice.
 | 
			
		||||
// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
 | 
			
		||||
// NetworkInterfacer is injected for test purpose.
 | 
			
		||||
// We expect the cidrs passed in is already validated.
 | 
			
		||||
// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
 | 
			
		||||
// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
 | 
			
		||||
// only return `0.0.0.0/0`.
 | 
			
		||||
// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
 | 
			
		||||
func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
 | 
			
		||||
	uniqueAddressList := sets.NewString()
 | 
			
		||||
	if len(cidrs) == 0 {
 | 
			
		||||
		uniqueAddressList.Insert(IPv4ZeroCIDR)
 | 
			
		||||
		uniqueAddressList.Insert(IPv6ZeroCIDR)
 | 
			
		||||
		return uniqueAddressList, nil
 | 
			
		||||
	}
 | 
			
		||||
	// First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
 | 
			
		||||
	for _, cidr := range cidrs {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			uniqueAddressList.Insert(cidr)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrs, err := nw.InterfaceAddrs()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Second round of iteration to parse IPs based on cidr.
 | 
			
		||||
	for _, cidr := range cidrs {
 | 
			
		||||
		if IsZeroCIDR(cidr) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_, ipNet, _ := netutils.ParseCIDRSloppy(cidr)
 | 
			
		||||
		for _, addr := range addrs {
 | 
			
		||||
			var ip net.IP
 | 
			
		||||
			// nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux.
 | 
			
		||||
			switch v := addr.(type) {
 | 
			
		||||
			case *net.IPAddr:
 | 
			
		||||
				ip = v.IP
 | 
			
		||||
			case *net.IPNet:
 | 
			
		||||
				ip = v.IP
 | 
			
		||||
			default:
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ipNet.Contains(ip) {
 | 
			
		||||
				if netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
 | 
			
		||||
					uniqueAddressList.Insert(ip.String())
 | 
			
		||||
				}
 | 
			
		||||
				if !netutils.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
 | 
			
		||||
					uniqueAddressList.Insert(ip.String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uniqueAddressList.Len() == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("no addresses found for cidrs %v", cidrs)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return uniqueAddressList, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddressSet validates the addresses in the slice using the "isValid" function.
 | 
			
		||||
// Addresses that pass the validation are returned as a string Set.
 | 
			
		||||
func AddressSet(isValid func(ip net.IP) bool, addrs []net.Addr) sets.String {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@ package util
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net"
 | 
			
		||||
	"reflect"
 | 
			
		||||
@@ -28,7 +27,6 @@ import (
 | 
			
		||||
	v1 "k8s.io/api/core/v1"
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	fake "k8s.io/kubernetes/pkg/proxy/util/testing"
 | 
			
		||||
	netutils "k8s.io/utils/net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -399,224 +397,6 @@ func (t *testResolver) LookupIPAddr(_ context.Context, address string) ([]net.IP
 | 
			
		||||
	return t.addrs, t.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type InterfaceAddrsPair struct {
 | 
			
		||||
	itf   net.Interface
 | 
			
		||||
	addrs []net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetNodeAddresses(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		cidrs         []string
 | 
			
		||||
		nw            *fake.FakeNetwork
 | 
			
		||||
		itfAddrsPairs []InterfaceAddrsPair
 | 
			
		||||
		expected      sets.String
 | 
			
		||||
		expectedErr   error
 | 
			
		||||
	}{
 | 
			
		||||
		{ // case 0
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.200.201.1"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("10.20.30.51"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 1
 | 
			
		||||
			cidrs: []string{"0.0.0.0/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 2
 | 
			
		||||
			cidrs: []string{"2001:db8::/32", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("2001:db8::1", "::1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 3
 | 
			
		||||
			cidrs: []string{"::/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 4
 | 
			
		||||
			cidrs: []string{"127.0.0.1/32"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("127.0.0.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 5
 | 
			
		||||
			cidrs: []string{"127.0.0.0/8"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.1.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("127.0.1.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 6
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("10.20.30.51"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("100.200.201.1"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("10.20.30.51", "100.200.201.1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 7
 | 
			
		||||
			cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("192.168.1.2"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected:    nil,
 | 
			
		||||
			expectedErr: fmt.Errorf("no addresses found for cidrs %v", []string{"10.20.30.0/24", "100.200.201.0/24"}),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 8
 | 
			
		||||
			cidrs: []string{},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("192.168.1.2"), Mask: net.CIDRMask(24, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("127.0.0.1"), Mask: net.CIDRMask(8, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 9
 | 
			
		||||
			cidrs: []string{},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(32, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 9
 | 
			
		||||
			cidrs: []string{"1.2.3.0/24", "0.0.0.0/0"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 10
 | 
			
		||||
			cidrs: []string{"0.0.0.0/0", "1.2.3.0/24", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("0.0.0.0/0", "::1"),
 | 
			
		||||
		},
 | 
			
		||||
		{ // case 11
 | 
			
		||||
			cidrs: []string{"::/0", "1.2.3.0/24", "::1/128"},
 | 
			
		||||
			nw:    fake.NewFakeNetwork(),
 | 
			
		||||
			itfAddrsPairs: []InterfaceAddrsPair{
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("1.2.3.4"), Mask: net.CIDRMask(30, 32)}},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					itf:   net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
 | 
			
		||||
					addrs: []net.Addr{&net.IPNet{IP: netutils.ParseIPSloppy("::1"), Mask: net.CIDRMask(128, 128)}},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expected: sets.NewString("::/0", "1.2.3.4"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range testCases {
 | 
			
		||||
		for _, pair := range testCases[i].itfAddrsPairs {
 | 
			
		||||
			testCases[i].nw.AddInterfaceAddr(&pair.itf, pair.addrs)
 | 
			
		||||
		}
 | 
			
		||||
		addrList, err := GetNodeAddresses(testCases[i].cidrs, testCases[i].nw)
 | 
			
		||||
		if !reflect.DeepEqual(err, testCases[i].expectedErr) {
 | 
			
		||||
			t.Errorf("case [%d], unexpected error: %v", i, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !addrList.Equal(testCases[i].expected) {
 | 
			
		||||
			t.Errorf("case [%d], unexpected mismatch, expected: %v, got: %v", i, testCases[i].expected, addrList)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAppendPortIfNeeded(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name   string
 | 
			
		||||
@@ -1405,71 +1185,6 @@ func TestAddressSet(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestContainsIPv4Loopback(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		cidrStrings []string
 | 
			
		||||
		want        bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "empty",
 | 
			
		||||
			want: true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv4",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "0.0.0.0/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv4 and invalid cidr",
 | 
			
		||||
			cidrStrings: []string{"invalid.cidr", "192.168.0.0/16", "fd00:1:d::/64", "0.0.0.0/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "all zeros ipv6", // interpret all zeros equal for IPv4 and IPv6 as Golang stdlib
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "::/0"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "127.0.0.0/8"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv6 loopback",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "::1/128"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback smaller range",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "127.0.2.0/28"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "ipv4 loopback within larger range",
 | 
			
		||||
			cidrStrings: []string{"224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64", "64.0.0.0/2"},
 | 
			
		||||
			want:        true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "non loop loopback",
 | 
			
		||||
			cidrStrings: []string{"128.0.2.0/28", "224.0.0.0/24", "192.168.0.0/16", "fd00:1:d::/64"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:        "invalid cidr",
 | 
			
		||||
			cidrStrings: []string{"invalid.ip/invalid.mask"},
 | 
			
		||||
			want:        false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			if got := ContainsIPv4Loopback(tt.cidrStrings); got != tt.want {
 | 
			
		||||
				t.Errorf("ContainLoopback() = %v, want %v", got, tt.want)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsZeroCIDR(t *testing.T) {
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user