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 }