github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/net/interface_test.go (about)

     1  /*
     2  Copyright 2014 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 net
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net"
    23  	"os"
    24  	"strings"
    25  	"testing"
    26  
    27  	netutils "k8s.io/utils/net"
    28  )
    29  
    30  const gatewayfirst = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                       
    31  eth3	00000000	0100FE0A	0003	0	0	1024	00000000	0	0	0                                                                   
    32  eth3	0000FE0A	00000000	0001	0	0	0	0080FFFF	0	0	0                                                                      
    33  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    34  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0
    35  `
    36  const gatewaylast = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT  
    37  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    38  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0                                                                                                                     
    39  eth3	0000FE0A	00000000	0001	0	0	0	0080FFFF	0	0	0       
    40  eth3	00000000	0100FE0A	0003	0	0	1024	00000000	0	0	0                                                                 
    41  `
    42  const gatewaymiddle = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                                                                                     
    43  eth3	0000FE0A	00000000	0001	0	0	0	0080FFFF	0	0	0                                                                      
    44  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0       
    45  eth3	00000000	0100FE0A	0003	0	0	1024	00000000	0	0	0                                                                         
    46  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0
    47  `
    48  const noInternetConnection = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                       
    49  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    50  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0            
    51  `
    52  const nothing = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                            
    53  `
    54  const badDestination = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT                                                       
    55  eth3	00000000	0100FE0A	0003	0	0	1024	00000000	0	0	0                                                                   
    56  eth3	0000FE0AA1	00000000	0001	0	0	0	0080FFFF	0	0	0                                                                      
    57  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    58  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0
    59  `
    60  const badGateway = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT
    61  eth3	00000000	0100FE0AA1	0003	0	0	1024	00000000	0	0	0                                                                   
    62  eth3	0000FE0A	00000000	0001	0	0	0	0080FFFF	0	0	0                                                                      
    63  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    64  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0
    65  `
    66  const route_Invalidhex = `Iface	Destination	Gateway 	Flags	RefCnt	Use	Metric	Mask		MTU	Window	IRTT
    67  eth3	00000000	0100FE0AA	0003	0	0	1024	00000000	0	0	0                                                                   
    68  eth3	0000FE0A	00000000	0001	0	0	0	0080FFFF	0	0	0                                                                      
    69  docker0	000011AC	00000000	0001	0	0	0	0000FFFF	0	0	0                                                                            
    70  virbr0	007AA8C0	00000000	0001	0	0	0	00FFFFFF	0	0	0
    71  `
    72  
    73  const v6gatewayfirst = `00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3
    74  20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3
    75  00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200       lo
    76  `
    77  const v6gatewaylast = `20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3
    78  00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200       lo
    79  00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3
    80  `
    81  const v6gatewaymiddle = `20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3
    82  00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3
    83  00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200       lo
    84  `
    85  const v6noDefaultRoutes = `00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200       lo
    86  20010001000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00000001  docker0
    87  20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001   eth3
    88  fe800000000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001   eth3
    89  `
    90  const v6nothing = ``
    91  const v6badDestination = `2001000200000000 7a 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200       lo
    92  `
    93  const v6badGateway = `00000000000000000000000000000000 00 00000000000000000000000000000000 00 200100010000000000000000000000000012 00000064 00000000 00000000 00000003 eth3
    94  `
    95  const v6route_Invalidhex = `000000000000000000000000000000000 00 00000000000000000000000000000000 00 fe80000000000000021fcafffea0ec00 00000064 00000000 00000000 00000003 enp1s0f0
    96  
    97  `
    98  
    99  const (
   100  	flagUp       = net.FlagUp | net.FlagBroadcast | net.FlagMulticast
   101  	flagDown     = net.FlagBroadcast | net.FlagMulticast
   102  	flagLoopback = net.FlagUp | net.FlagLoopback
   103  	flagP2P      = net.FlagUp | net.FlagPointToPoint
   104  )
   105  
   106  func makeIntf(index int, name string, flags net.Flags) net.Interface {
   107  	mac := net.HardwareAddr{0, 0x32, 0x7d, 0x69, 0xf7, byte(0x30 + index)}
   108  	return net.Interface{
   109  		Index:        index,
   110  		MTU:          1500,
   111  		Name:         name,
   112  		HardwareAddr: mac,
   113  		Flags:        flags}
   114  }
   115  
   116  var (
   117  	downIntf     = makeIntf(1, "eth3", flagDown)
   118  	loopbackIntf = makeIntf(1, "lo", flagLoopback)
   119  	p2pIntf      = makeIntf(1, "lo", flagP2P)
   120  	upIntf       = makeIntf(1, "eth3", flagUp)
   121  )
   122  
   123  var (
   124  	ipv4Route = Route{Interface: "eth3", Destination: netutils.ParseIPSloppy("0.0.0.0"), Gateway: netutils.ParseIPSloppy("10.254.0.1"), Family: familyIPv4}
   125  	ipv6Route = Route{Interface: "eth3", Destination: netutils.ParseIPSloppy("::"), Gateway: netutils.ParseIPSloppy("2001:1::1"), Family: familyIPv6}
   126  )
   127  
   128  var (
   129  	noRoutes   = []Route{}
   130  	routeV4    = []Route{ipv4Route}
   131  	routeV6    = []Route{ipv6Route}
   132  	bothRoutes = []Route{ipv4Route, ipv6Route}
   133  )
   134  
   135  func TestGetIPv4Routes(t *testing.T) {
   136  	testCases := []struct {
   137  		tcase      string
   138  		route      string
   139  		count      int
   140  		expected   *Route
   141  		errStrFrag string
   142  	}{
   143  		{"gatewayfirst", gatewayfirst, 1, &ipv4Route, ""},
   144  		{"gatewaymiddle", gatewaymiddle, 1, &ipv4Route, ""},
   145  		{"gatewaylast", gatewaylast, 1, &ipv4Route, ""},
   146  		{"no routes", nothing, 0, nil, ""},
   147  		{"badDestination", badDestination, 0, nil, "invalid IPv4"},
   148  		{"badGateway", badGateway, 0, nil, "invalid IPv4"},
   149  		{"route_Invalidhex", route_Invalidhex, 0, nil, "odd length hex string"},
   150  		{"no default routes", noInternetConnection, 0, nil, ""},
   151  	}
   152  	for _, tc := range testCases {
   153  		r := strings.NewReader(tc.route)
   154  		routes, err := getIPv4DefaultRoutes(r)
   155  		if err != nil {
   156  			if !strings.Contains(err.Error(), tc.errStrFrag) {
   157  				t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag)
   158  			}
   159  		} else if tc.errStrFrag != "" {
   160  			t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag)
   161  		} else {
   162  			if tc.count != len(routes) {
   163  				t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes)
   164  			} else if tc.count == 1 {
   165  				if !tc.expected.Gateway.Equal(routes[0].Gateway) {
   166  					t.Errorf("case[%s]: expected %v, got %v .err : %v", tc.tcase, tc.expected, routes, err)
   167  				}
   168  				if !routes[0].Destination.Equal(net.IPv4zero) {
   169  					t.Errorf("case[%s}: destination is not for default route (not zero)", tc.tcase)
   170  				}
   171  
   172  			}
   173  		}
   174  	}
   175  }
   176  
   177  func TestGetIPv6Routes(t *testing.T) {
   178  	testCases := []struct {
   179  		tcase      string
   180  		route      string
   181  		count      int
   182  		expected   *Route
   183  		errStrFrag string
   184  	}{
   185  		{"v6 gatewayfirst", v6gatewayfirst, 1, &ipv6Route, ""},
   186  		{"v6 gatewaymiddle", v6gatewaymiddle, 1, &ipv6Route, ""},
   187  		{"v6 gatewaylast", v6gatewaylast, 1, &ipv6Route, ""},
   188  		{"v6 no routes", v6nothing, 0, nil, ""},
   189  		{"v6 badDestination", v6badDestination, 0, nil, "invalid IPv6"},
   190  		{"v6 badGateway", v6badGateway, 0, nil, "invalid IPv6"},
   191  		{"v6 route_Invalidhex", v6route_Invalidhex, 0, nil, "odd length hex string"},
   192  		{"v6 no default routes", v6noDefaultRoutes, 0, nil, ""},
   193  	}
   194  	for _, tc := range testCases {
   195  		r := strings.NewReader(tc.route)
   196  		routes, err := getIPv6DefaultRoutes(r)
   197  		if err != nil {
   198  			if !strings.Contains(err.Error(), tc.errStrFrag) {
   199  				t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag)
   200  			}
   201  		} else if tc.errStrFrag != "" {
   202  			t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag)
   203  		} else {
   204  			if tc.count != len(routes) {
   205  				t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes)
   206  			} else if tc.count == 1 {
   207  				if !tc.expected.Gateway.Equal(routes[0].Gateway) {
   208  					t.Errorf("case[%s]: expected %v, got %v .err : %v", tc.tcase, tc.expected, routes, err)
   209  				}
   210  				if !routes[0].Destination.Equal(net.IPv6zero) {
   211  					t.Errorf("case[%s}: destination is not for default route (not zero)", tc.tcase)
   212  				}
   213  			}
   214  		}
   215  	}
   216  }
   217  
   218  func TestParseIP(t *testing.T) {
   219  	testCases := []struct {
   220  		tcase    string
   221  		ip       string
   222  		family   AddressFamily
   223  		success  bool
   224  		expected net.IP
   225  	}{
   226  		{"empty", "", familyIPv4, false, nil},
   227  		{"too short", "AA", familyIPv4, false, nil},
   228  		{"too long", "0011223344", familyIPv4, false, nil},
   229  		{"invalid", "invalid!", familyIPv4, false, nil},
   230  		{"zero", "00000000", familyIPv4, true, net.IP{0, 0, 0, 0}},
   231  		{"ffff", "FFFFFFFF", familyIPv4, true, net.IP{0xff, 0xff, 0xff, 0xff}},
   232  		{"valid v4", "12345678", familyIPv4, true, net.IP{120, 86, 52, 18}},
   233  		{"valid v6", "fe800000000000000000000000000000", familyIPv6, true, net.IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
   234  		{"v6 too short", "fe80000000000000021fcafffea0ec0", familyIPv6, false, nil},
   235  		{"v6 too long", "fe80000000000000021fcafffea0ec002", familyIPv6, false, nil},
   236  	}
   237  	for _, tc := range testCases {
   238  		ip, err := parseIP(tc.ip, tc.family)
   239  		if !ip.Equal(tc.expected) {
   240  			t.Errorf("case[%v]: expected %q, got %q . err : %v", tc.tcase, tc.expected, ip, err)
   241  		}
   242  	}
   243  }
   244  
   245  func TestIsInterfaceUp(t *testing.T) {
   246  	testCases := []struct {
   247  		tcase    string
   248  		intf     *net.Interface
   249  		expected bool
   250  	}{
   251  		{"up", &net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp}, true},
   252  		{"down", &net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0}, false},
   253  		{"no interface", nil, false},
   254  	}
   255  	for _, tc := range testCases {
   256  		it := isInterfaceUp(tc.intf)
   257  		if it != tc.expected {
   258  			t.Errorf("case[%v]: expected %v, got %v .", tc.tcase, tc.expected, it)
   259  		}
   260  	}
   261  }
   262  
   263  type addrStruct struct{ val string }
   264  
   265  func (a addrStruct) Network() string {
   266  	return a.val
   267  }
   268  func (a addrStruct) String() string {
   269  	return a.val
   270  }
   271  
   272  func TestFinalIP(t *testing.T) {
   273  	testCases := []struct {
   274  		tcase    string
   275  		addr     []net.Addr
   276  		family   AddressFamily
   277  		expected net.IP
   278  	}{
   279  		{"no ipv4", []net.Addr{addrStruct{val: "2001::5/64"}}, familyIPv4, nil},
   280  		{"no ipv6", []net.Addr{addrStruct{val: "10.128.0.4/32"}}, familyIPv6, nil},
   281  		{"invalidV4CIDR", []net.Addr{addrStruct{val: "10.20.30.40.50/24"}}, familyIPv4, nil},
   282  		{"invalidV6CIDR", []net.Addr{addrStruct{val: "fe80::2f7:67fff:fe6e:2956/64"}}, familyIPv6, nil},
   283  		{"loopback", []net.Addr{addrStruct{val: "127.0.0.1/24"}}, familyIPv4, nil},
   284  		{"loopbackv6", []net.Addr{addrStruct{val: "::1/128"}}, familyIPv6, nil},
   285  		{"link local v4", []net.Addr{addrStruct{val: "169.254.1.10/16"}}, familyIPv4, nil},
   286  		{"link local v6", []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}}, familyIPv6, nil},
   287  		{"ip4", []net.Addr{addrStruct{val: "10.254.12.132/17"}}, familyIPv4, netutils.ParseIPSloppy("10.254.12.132")},
   288  		{"ip6", []net.Addr{addrStruct{val: "2001::5/64"}}, familyIPv6, netutils.ParseIPSloppy("2001::5")},
   289  
   290  		{"no addresses", []net.Addr{}, familyIPv4, nil},
   291  	}
   292  	for _, tc := range testCases {
   293  		ip, err := getMatchingGlobalIP(tc.addr, tc.family)
   294  		if !ip.Equal(tc.expected) {
   295  			t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, ip, err)
   296  		}
   297  	}
   298  }
   299  
   300  func TestAddrs(t *testing.T) {
   301  	var nw networkInterfacer = validNetworkInterface{}
   302  	intf := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0}
   303  	addrs, err := nw.Addrs(&intf)
   304  	if err != nil {
   305  		t.Errorf("expected no error got : %v", err)
   306  	}
   307  	if len(addrs) != 2 {
   308  		t.Errorf("expected addrs: 2 got null")
   309  	}
   310  }
   311  
   312  // Has a valid IPv4 address (IPv6 is LLA)
   313  type validNetworkInterface struct {
   314  }
   315  
   316  func (_ validNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   317  	return &upIntf, nil
   318  }
   319  func (_ validNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   320  	var ifat []net.Addr
   321  	ifat = []net.Addr{
   322  		addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}}
   323  	return ifat, nil
   324  }
   325  func (_ validNetworkInterface) Interfaces() ([]net.Interface, error) {
   326  	return []net.Interface{upIntf}, nil
   327  }
   328  
   329  // Both IPv4 and IPv6 addresses (expecting IPv4 to be used)
   330  type v4v6NetworkInterface struct {
   331  }
   332  
   333  func (_ v4v6NetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   334  	return &upIntf, nil
   335  }
   336  func (_ v4v6NetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   337  	var ifat []net.Addr
   338  	ifat = []net.Addr{
   339  		addrStruct{val: "2001::10/64"}, addrStruct{val: "10.254.71.145/17"}}
   340  	return ifat, nil
   341  }
   342  func (_ v4v6NetworkInterface) Interfaces() ([]net.Interface, error) {
   343  	return []net.Interface{upIntf}, nil
   344  }
   345  
   346  // Interface with only IPv6 address
   347  type ipv6NetworkInterface struct {
   348  }
   349  
   350  func (_ ipv6NetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   351  	return &upIntf, nil
   352  }
   353  func (_ ipv6NetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   354  	var ifat []net.Addr
   355  	ifat = []net.Addr{addrStruct{val: "2001::200/64"}}
   356  	return ifat, nil
   357  }
   358  
   359  func (_ ipv6NetworkInterface) Interfaces() ([]net.Interface, error) {
   360  	return []net.Interface{upIntf}, nil
   361  }
   362  
   363  // Only with link local addresses
   364  type networkInterfaceWithOnlyLinkLocals struct {
   365  }
   366  
   367  func (_ networkInterfaceWithOnlyLinkLocals) InterfaceByName(intfName string) (*net.Interface, error) {
   368  	return &upIntf, nil
   369  }
   370  func (_ networkInterfaceWithOnlyLinkLocals) Addrs(intf *net.Interface) ([]net.Addr, error) {
   371  	var ifat []net.Addr
   372  	ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"}}
   373  	return ifat, nil
   374  }
   375  func (_ networkInterfaceWithOnlyLinkLocals) Interfaces() ([]net.Interface, error) {
   376  	return []net.Interface{upIntf}, nil
   377  }
   378  
   379  // Unable to get interface(s)
   380  type failGettingNetworkInterface struct {
   381  }
   382  
   383  func (_ failGettingNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   384  	return nil, fmt.Errorf("unable get Interface")
   385  }
   386  func (_ failGettingNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   387  	return nil, nil
   388  }
   389  func (_ failGettingNetworkInterface) Interfaces() ([]net.Interface, error) {
   390  	return nil, fmt.Errorf("mock failed getting all interfaces")
   391  }
   392  
   393  // No interfaces
   394  type noNetworkInterface struct {
   395  }
   396  
   397  func (_ noNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   398  	return nil, fmt.Errorf("no such network interface")
   399  }
   400  func (_ noNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   401  	return nil, nil
   402  }
   403  func (_ noNetworkInterface) Interfaces() ([]net.Interface, error) {
   404  	return []net.Interface{}, nil
   405  }
   406  
   407  // Interface is down
   408  type downNetworkInterface struct {
   409  }
   410  
   411  func (_ downNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   412  	return &downIntf, nil
   413  }
   414  func (_ downNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   415  	var ifat []net.Addr
   416  	ifat = []net.Addr{
   417  		addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}}
   418  	return ifat, nil
   419  }
   420  func (_ downNetworkInterface) Interfaces() ([]net.Interface, error) {
   421  	return []net.Interface{downIntf}, nil
   422  }
   423  
   424  // Loopback interface
   425  type loopbackNetworkInterface struct {
   426  }
   427  
   428  func (_ loopbackNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   429  	return &loopbackIntf, nil
   430  }
   431  func (_ loopbackNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   432  	var ifat []net.Addr
   433  	ifat = []net.Addr{
   434  		addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"}}
   435  	return ifat, nil
   436  }
   437  func (_ loopbackNetworkInterface) Interfaces() ([]net.Interface, error) {
   438  	return []net.Interface{loopbackIntf}, nil
   439  }
   440  
   441  // Point to point interface
   442  type p2pNetworkInterface struct {
   443  }
   444  
   445  func (_ p2pNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   446  	return &p2pIntf, nil
   447  }
   448  func (_ p2pNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   449  	var ifat []net.Addr
   450  	ifat = []net.Addr{
   451  		addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"}}
   452  	return ifat, nil
   453  }
   454  func (_ p2pNetworkInterface) Interfaces() ([]net.Interface, error) {
   455  	return []net.Interface{p2pIntf}, nil
   456  }
   457  
   458  // Interface with link locals and loopback interface with global addresses
   459  type linkLocalLoopbackNetworkInterface struct {
   460  }
   461  
   462  func (_ linkLocalLoopbackNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   463  	if intfName == LoopbackInterfaceName {
   464  		return &loopbackIntf, nil
   465  	}
   466  	return &upIntf, nil
   467  }
   468  func (_ linkLocalLoopbackNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   469  	var ifat []net.Addr
   470  	ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"}}
   471  	if intf.Name == LoopbackInterfaceName {
   472  		ifat = []net.Addr{addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"},
   473  			// global addresses on loopback interface
   474  			addrStruct{val: "10.1.1.1/32"}, addrStruct{val: "fd00:1:1::1/128"}}
   475  	}
   476  	return ifat, nil
   477  }
   478  func (_ linkLocalLoopbackNetworkInterface) Interfaces() ([]net.Interface, error) {
   479  	return []net.Interface{upIntf, loopbackIntf}, nil
   480  }
   481  
   482  // Interface and loopback interface with global addresses
   483  type globalsNetworkInterface struct {
   484  }
   485  
   486  func (_ globalsNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
   487  	if intfName == LoopbackInterfaceName {
   488  		return &loopbackIntf, nil
   489  	}
   490  	return &upIntf, nil
   491  }
   492  func (_ globalsNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
   493  	var ifat []net.Addr
   494  	ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"},
   495  		addrStruct{val: "192.168.1.1/31"}, addrStruct{val: "fd00::200/127"}}
   496  	if intf.Name == LoopbackInterfaceName {
   497  		ifat = []net.Addr{addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"},
   498  			// global addresses on loopback interface
   499  			addrStruct{val: "10.1.1.1/32"}, addrStruct{val: "fd00:1:1::1/128"}}
   500  	}
   501  	return ifat, nil
   502  }
   503  func (_ globalsNetworkInterface) Interfaces() ([]net.Interface, error) {
   504  	return []net.Interface{upIntf, loopbackIntf}, nil
   505  }
   506  
   507  // Unable to get IP addresses for interface
   508  type networkInterfaceFailGetAddrs struct {
   509  }
   510  
   511  func (_ networkInterfaceFailGetAddrs) InterfaceByName(intfName string) (*net.Interface, error) {
   512  	return &upIntf, nil
   513  }
   514  func (_ networkInterfaceFailGetAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) {
   515  	return nil, fmt.Errorf("unable to get Addrs")
   516  }
   517  func (_ networkInterfaceFailGetAddrs) Interfaces() ([]net.Interface, error) {
   518  	return []net.Interface{upIntf}, nil
   519  }
   520  
   521  // No addresses for interface
   522  type networkInterfaceWithNoAddrs struct {
   523  }
   524  
   525  func (_ networkInterfaceWithNoAddrs) InterfaceByName(intfName string) (*net.Interface, error) {
   526  	return &upIntf, nil
   527  }
   528  func (_ networkInterfaceWithNoAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) {
   529  	ifat := []net.Addr{}
   530  	return ifat, nil
   531  }
   532  func (_ networkInterfaceWithNoAddrs) Interfaces() ([]net.Interface, error) {
   533  	return []net.Interface{upIntf}, nil
   534  }
   535  
   536  // Invalid addresses for interface
   537  type networkInterfaceWithInvalidAddr struct {
   538  }
   539  
   540  func (_ networkInterfaceWithInvalidAddr) InterfaceByName(intfName string) (*net.Interface, error) {
   541  	return &upIntf, nil
   542  }
   543  func (_ networkInterfaceWithInvalidAddr) Addrs(intf *net.Interface) ([]net.Addr, error) {
   544  	var ifat []net.Addr
   545  	ifat = []net.Addr{addrStruct{val: "10.20.30.40.50/24"}}
   546  	return ifat, nil
   547  }
   548  func (_ networkInterfaceWithInvalidAddr) Interfaces() ([]net.Interface, error) {
   549  	return []net.Interface{upIntf}, nil
   550  }
   551  
   552  func TestGetIPFromInterface(t *testing.T) {
   553  	testCases := []struct {
   554  		tcase      string
   555  		nwname     string
   556  		family     AddressFamily
   557  		nw         networkInterfacer
   558  		expected   net.IP
   559  		errStrFrag string
   560  	}{
   561  		{"ipv4", "eth3", familyIPv4, validNetworkInterface{}, netutils.ParseIPSloppy("10.254.71.145"), ""},
   562  		{"ipv6", "eth3", familyIPv6, ipv6NetworkInterface{}, netutils.ParseIPSloppy("2001::200"), ""},
   563  		{"no ipv4", "eth3", familyIPv4, ipv6NetworkInterface{}, nil, ""},
   564  		{"no ipv6", "eth3", familyIPv6, validNetworkInterface{}, nil, ""},
   565  		{"I/F down", "eth3", familyIPv4, downNetworkInterface{}, nil, ""},
   566  		{"I/F get fail", "eth3", familyIPv4, noNetworkInterface{}, nil, "no such network interface"},
   567  		{"fail get addr", "eth3", familyIPv4, networkInterfaceFailGetAddrs{}, nil, "unable to get Addrs"},
   568  		{"bad addr", "eth3", familyIPv4, networkInterfaceWithInvalidAddr{}, nil, "invalid CIDR"},
   569  	}
   570  	for _, tc := range testCases {
   571  		ip, err := getIPFromInterface(tc.nwname, tc.family, tc.nw)
   572  		if err != nil {
   573  			if !strings.Contains(err.Error(), tc.errStrFrag) {
   574  				t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag)
   575  			}
   576  		} else if tc.errStrFrag != "" {
   577  			t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag)
   578  		} else if !ip.Equal(tc.expected) {
   579  			t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err)
   580  		}
   581  	}
   582  }
   583  
   584  func TestGetIPFromLoopbackInterface(t *testing.T) {
   585  	testCases := []struct {
   586  		tcase      string
   587  		family     AddressFamily
   588  		nw         networkInterfacer
   589  		expected   net.IP
   590  		errStrFrag string
   591  	}{
   592  		{"ipv4", familyIPv4, linkLocalLoopbackNetworkInterface{}, netutils.ParseIPSloppy("10.1.1.1"), ""},
   593  		{"ipv6", familyIPv6, linkLocalLoopbackNetworkInterface{}, netutils.ParseIPSloppy("fd00:1:1::1"), ""},
   594  		{"no global ipv4", familyIPv4, loopbackNetworkInterface{}, nil, ""},
   595  		{"no global ipv6", familyIPv6, loopbackNetworkInterface{}, nil, ""},
   596  	}
   597  	for _, tc := range testCases {
   598  		ip, err := getIPFromLoopbackInterface(tc.family, tc.nw)
   599  		if err != nil {
   600  			if !strings.Contains(err.Error(), tc.errStrFrag) {
   601  				t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag)
   602  			}
   603  		} else if tc.errStrFrag != "" {
   604  			t.Errorf("case[%s]: Error %q expected, but seen %v", tc.tcase, tc.errStrFrag, err)
   605  		} else if !ip.Equal(tc.expected) {
   606  			t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err)
   607  		}
   608  	}
   609  }
   610  
   611  func TestChooseHostInterfaceFromRoute(t *testing.T) {
   612  	testCases := []struct {
   613  		tcase    string
   614  		routes   []Route
   615  		nw       networkInterfacer
   616  		order    AddressFamilyPreference
   617  		expected net.IP
   618  	}{
   619  		{"single-stack ipv4", routeV4, validNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.254.71.145")},
   620  		{"single-stack ipv4, prefer v6", routeV4, validNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("10.254.71.145")},
   621  		{"single-stack ipv6", routeV6, ipv6NetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("2001::200")},
   622  		{"single-stack ipv6, prefer v6", routeV6, ipv6NetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("2001::200")},
   623  		{"dual stack", bothRoutes, v4v6NetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.254.71.145")},
   624  		{"dual stack, prefer v6", bothRoutes, v4v6NetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("2001::10")},
   625  		{"LLA and loopback with global, IPv4", routeV4, linkLocalLoopbackNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.1.1.1")},
   626  		{"LLA and loopback with global, IPv6", routeV6, linkLocalLoopbackNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("fd00:1:1::1")},
   627  		{"LLA and loopback with global, dual stack prefer IPv4", bothRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.1.1.1")},
   628  		{"LLA and loopback with global, dual stack prefer IPv6", bothRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("fd00:1:1::1")},
   629  		{"LLA and loopback with global, no routes", noRoutes, linkLocalLoopbackNetworkInterface{}, preferIPv6, nil},
   630  		{"interface and loopback with global, IPv4", routeV4, globalsNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("192.168.1.1")},
   631  		{"interface and loopback with global, IPv6", routeV6, globalsNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("fd00::200")},
   632  		{"interface and loopback with global, dual stack prefer IPv4", bothRoutes, globalsNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("192.168.1.1")},
   633  		{"interface and loopback with global, dual stack prefer IPv6", bothRoutes, globalsNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("fd00::200")},
   634  		{"interface and loopback with global, no routes", noRoutes, globalsNetworkInterface{}, preferIPv6, nil},
   635  		{"all LLA", routeV4, networkInterfaceWithOnlyLinkLocals{}, preferIPv4, nil},
   636  		{"no routes", noRoutes, validNetworkInterface{}, preferIPv4, nil},
   637  		{"fail get IP", routeV4, networkInterfaceFailGetAddrs{}, preferIPv4, nil},
   638  	}
   639  	for _, tc := range testCases {
   640  		ip, err := chooseHostInterfaceFromRoute(tc.routes, tc.nw, tc.order)
   641  		if !ip.Equal(tc.expected) {
   642  			t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err)
   643  		}
   644  	}
   645  }
   646  
   647  func TestMemberOf(t *testing.T) {
   648  	testCases := []struct {
   649  		tcase    string
   650  		ip       net.IP
   651  		family   AddressFamily
   652  		expected bool
   653  	}{
   654  		{"ipv4 is 4", netutils.ParseIPSloppy("10.20.30.40"), familyIPv4, true},
   655  		{"ipv4 is 6", netutils.ParseIPSloppy("10.10.10.10"), familyIPv6, false},
   656  		{"ipv6 is 4", netutils.ParseIPSloppy("2001::100"), familyIPv4, false},
   657  		{"ipv6 is 6", netutils.ParseIPSloppy("2001::100"), familyIPv6, true},
   658  	}
   659  	for _, tc := range testCases {
   660  		if memberOf(tc.ip, tc.family) != tc.expected {
   661  			t.Errorf("case[%s]: expected %+v", tc.tcase, tc.expected)
   662  		}
   663  	}
   664  }
   665  
   666  func TestGetIPFromHostInterfaces(t *testing.T) {
   667  	testCases := []struct {
   668  		tcase      string
   669  		nw         networkInterfacer
   670  		order      AddressFamilyPreference
   671  		expected   net.IP
   672  		errStrFrag string
   673  	}{
   674  		{"fail get I/Fs", failGettingNetworkInterface{}, preferIPv4, nil, "failed getting all interfaces"},
   675  		{"no interfaces", noNetworkInterface{}, preferIPv4, nil, "no interfaces"},
   676  		{"I/F not up", downNetworkInterface{}, preferIPv4, nil, "no acceptable"},
   677  		{"loopback only", loopbackNetworkInterface{}, preferIPv4, nil, "no acceptable"},
   678  		{"P2P I/F only", p2pNetworkInterface{}, preferIPv4, nil, "no acceptable"},
   679  		{"fail get addrs", networkInterfaceFailGetAddrs{}, preferIPv4, nil, "unable to get Addrs"},
   680  		{"no addresses", networkInterfaceWithNoAddrs{}, preferIPv4, nil, "no acceptable"},
   681  		{"invalid addr", networkInterfaceWithInvalidAddr{}, preferIPv4, nil, "invalid CIDR"},
   682  		{"no matches", networkInterfaceWithOnlyLinkLocals{}, preferIPv4, nil, "no acceptable"},
   683  		{"single-stack ipv4", validNetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.254.71.145"), ""},
   684  		{"single-stack ipv4, prefer ipv6", validNetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("10.254.71.145"), ""},
   685  		{"single-stack ipv6", ipv6NetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("2001::200"), ""},
   686  		{"single-stack ipv6, prefer ipv6", ipv6NetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("2001::200"), ""},
   687  		{"dual stack", v4v6NetworkInterface{}, preferIPv4, netutils.ParseIPSloppy("10.254.71.145"), ""},
   688  		{"dual stack, prefer ipv6", v4v6NetworkInterface{}, preferIPv6, netutils.ParseIPSloppy("2001::10"), ""},
   689  	}
   690  
   691  	for _, tc := range testCases {
   692  		ip, err := chooseIPFromHostInterfaces(tc.nw, tc.order)
   693  		if !ip.Equal(tc.expected) {
   694  			t.Errorf("case[%s]: expected %+v, got %+v with err : %v", tc.tcase, tc.expected, ip, err)
   695  		}
   696  		if err != nil && !strings.Contains(err.Error(), tc.errStrFrag) {
   697  			t.Errorf("case[%s]: unable to find %q in error string %q", tc.tcase, tc.errStrFrag, err.Error())
   698  		}
   699  	}
   700  }
   701  
   702  func makeRouteFile(content string, t *testing.T) (*os.File, error) {
   703  	routeFile, err := ioutil.TempFile("", "route")
   704  	if err != nil {
   705  		return nil, err
   706  	}
   707  
   708  	if _, err := routeFile.Write([]byte(content)); err != nil {
   709  		return routeFile, err
   710  	}
   711  	err = routeFile.Close()
   712  	return routeFile, err
   713  }
   714  
   715  func TestFailGettingIPv4Routes(t *testing.T) {
   716  	defer func() { v4File.name = ipv4RouteFile }()
   717  
   718  	// Try failure to open file (should not occur, as caller ensures we have IPv4 route file, but being thorough)
   719  	v4File.name = "no-such-file"
   720  	errStrFrag := "no such file"
   721  	_, err := v4File.extract()
   722  	if err == nil {
   723  		t.Errorf("Expected error trying to read non-existent v4 route file")
   724  	}
   725  	if !strings.Contains(err.Error(), errStrFrag) {
   726  		t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error())
   727  	}
   728  }
   729  
   730  func TestFailGettingIPv6Routes(t *testing.T) {
   731  	defer func() { v6File.name = ipv6RouteFile }()
   732  
   733  	// Try failure to open file (this would be ignored by caller)
   734  	v6File.name = "no-such-file"
   735  	errStrFrag := "no such file"
   736  	_, err := v6File.extract()
   737  	if err == nil {
   738  		t.Errorf("Expected error trying to read non-existent v6 route file")
   739  	}
   740  	if !strings.Contains(err.Error(), errStrFrag) {
   741  		t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error())
   742  	}
   743  }
   744  
   745  func TestGetAllDefaultRoutesFailNoV4RouteFile(t *testing.T) {
   746  	defer func() { v4File.name = ipv4RouteFile }()
   747  
   748  	// Should not occur, as caller ensures we have IPv4 route file, but being thorough
   749  	v4File.name = "no-such-file"
   750  	errStrFrag := "no such file"
   751  	_, err := getAllDefaultRoutes()
   752  	if err == nil {
   753  		t.Errorf("Expected error trying to read non-existent v4 route file")
   754  	}
   755  	if !strings.Contains(err.Error(), errStrFrag) {
   756  		t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error())
   757  	}
   758  }
   759  
   760  func TestGetAllDefaultRoutes(t *testing.T) {
   761  	testCases := []struct {
   762  		tcase      string
   763  		v4Info     string
   764  		v6Info     string
   765  		count      int
   766  		expected   []Route
   767  		errStrFrag string
   768  	}{
   769  		{"no routes", noInternetConnection, v6noDefaultRoutes, 0, nil, "no default routes"},
   770  		{"only v4 route", gatewayfirst, v6noDefaultRoutes, 1, routeV4, ""},
   771  		{"only v6 route", noInternetConnection, v6gatewayfirst, 1, routeV6, ""},
   772  		{"v4 and v6 routes", gatewayfirst, v6gatewayfirst, 2, bothRoutes, ""},
   773  	}
   774  	defer func() {
   775  		v4File.name = ipv4RouteFile
   776  		v6File.name = ipv6RouteFile
   777  	}()
   778  
   779  	for _, tc := range testCases {
   780  		routeFile, err := makeRouteFile(tc.v4Info, t)
   781  		if routeFile != nil {
   782  			defer os.Remove(routeFile.Name())
   783  		}
   784  		if err != nil {
   785  			t.Errorf("case[%s]: test setup failure for IPv4 route file: %v", tc.tcase, err)
   786  		}
   787  		v4File.name = routeFile.Name()
   788  		v6routeFile, err := makeRouteFile(tc.v6Info, t)
   789  		if v6routeFile != nil {
   790  			defer os.Remove(v6routeFile.Name())
   791  		}
   792  		if err != nil {
   793  			t.Errorf("case[%s]: test setup failure for IPv6 route file: %v", tc.tcase, err)
   794  		}
   795  		v6File.name = v6routeFile.Name()
   796  
   797  		routes, err := getAllDefaultRoutes()
   798  		if err != nil {
   799  			if !strings.Contains(err.Error(), tc.errStrFrag) {
   800  				t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag)
   801  			}
   802  		} else if tc.errStrFrag != "" {
   803  			t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag)
   804  		} else {
   805  			if tc.count != len(routes) {
   806  				t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes)
   807  			}
   808  			for i, expected := range tc.expected {
   809  				if !expected.Gateway.Equal(routes[i].Gateway) {
   810  					t.Errorf("case[%s]: at %d expected %v, got %v .err : %v", tc.tcase, i, tc.expected, routes, err)
   811  				}
   812  				zeroIP := net.IPv4zero
   813  				if expected.Family == familyIPv6 {
   814  					zeroIP = net.IPv6zero
   815  				}
   816  				if !routes[i].Destination.Equal(zeroIP) {
   817  					t.Errorf("case[%s}: at %d destination is not for default route (not %v)", tc.tcase, i, zeroIP)
   818  				}
   819  			}
   820  		}
   821  	}
   822  }