github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/network/address_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package network_test 5 6 import ( 7 "fmt" 8 "net" 9 "sort" 10 11 "github.com/juju/errors" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/core/network" 16 "github.com/juju/juju/testing" 17 ) 18 19 type AddressSuite struct { 20 testing.BaseSuite 21 } 22 23 var _ = gc.Suite(&AddressSuite{}) 24 25 func (s *AddressSuite) TestNewScopedAddressIPv4(c *gc.C) { 26 type test struct { 27 value string 28 scope network.Scope 29 expectedScope network.Scope 30 } 31 32 tests := []test{{ 33 value: "127.0.0.1", 34 scope: network.ScopeUnknown, 35 expectedScope: network.ScopeMachineLocal, 36 }, { 37 value: "127.0.0.1", 38 scope: network.ScopePublic, 39 expectedScope: network.ScopePublic, // don't second guess != Unknown 40 }, { 41 value: "10.0.3.1", 42 scope: network.ScopeUnknown, 43 expectedScope: network.ScopeCloudLocal, 44 }, { 45 value: "172.16.15.14", 46 scope: network.ScopeUnknown, 47 expectedScope: network.ScopeCloudLocal, 48 }, { 49 value: "192.168.0.1", 50 scope: network.ScopeUnknown, 51 expectedScope: network.ScopeCloudLocal, 52 }, { 53 value: "169.254.1.1", 54 scope: network.ScopeUnknown, 55 expectedScope: network.ScopeLinkLocal, 56 }, { 57 value: "8.8.8.8", 58 scope: network.ScopeUnknown, 59 expectedScope: network.ScopePublic, 60 }, { 61 value: "241.1.2.3", 62 scope: network.ScopeUnknown, 63 expectedScope: network.ScopeFanLocal, 64 }} 65 66 for i, t := range tests { 67 c.Logf("test %d: %s %s", i, t.value, t.scope) 68 addr := network.NewSpaceAddress(t.value, network.WithScope(t.scope)) 69 c.Check(addr.Value, gc.Equals, t.value) 70 c.Check(addr.Type, gc.Equals, network.IPv4Address) 71 c.Check(addr.Scope, gc.Equals, t.expectedScope) 72 } 73 } 74 75 func (s *AddressSuite) TestNewScopedAddressIPv6(c *gc.C) { 76 // Examples below taken from 77 // http://en.wikipedia.org/wiki/IPv6_address 78 testAddresses := []struct { 79 value string 80 scope network.Scope 81 }{ 82 // IPv6 loopback address 83 {"::1", network.ScopeMachineLocal}, 84 // used documentation examples 85 {"2001:db8::1", network.ScopePublic}, 86 // link-local 87 {"fe80::1", network.ScopeLinkLocal}, 88 // unique local address (ULA) - first group 89 {"fc00::1", network.ScopeCloudLocal}, 90 // unique local address (ULA) - second group 91 {"fd00::1", network.ScopeCloudLocal}, 92 // IPv4-mapped IPv6 address 93 {"::ffff:0:0:1", network.ScopePublic}, 94 // IPv4-translated IPv6 address (SIIT) 95 {"::ffff:0:0:0:1", network.ScopePublic}, 96 // "well-known" prefix for IPv4/IPv6 auto translation 97 {"64:ff9b::1", network.ScopePublic}, 98 // used for 6to4 addressing 99 {"2002::1", network.ScopePublic}, 100 // used for Teredo tunneling 101 {"2001::1", network.ScopePublic}, 102 // used for IPv6 benchmarking 103 {"2001:2::1", network.ScopePublic}, 104 // used for cryptographic hash identifiers 105 {"2001:10::1", network.ScopePublic}, 106 // interface-local multicast (all nodes) 107 {"ff01::1", network.ScopeLinkLocal}, 108 // link-local multicast (all nodes) 109 {"ff02::1", network.ScopeLinkLocal}, 110 // interface-local multicast (all routers) 111 {"ff01::2", network.ScopeLinkLocal}, 112 // link-local multicast (all routers) 113 {"ff02::2", network.ScopeLinkLocal}, 114 } 115 for i, test := range testAddresses { 116 c.Logf("test %d: %q -> %q", i, test.value, test.scope) 117 addr := network.NewSpaceAddress(test.value) 118 c.Check(addr.Value, gc.Equals, test.value) 119 c.Check(addr.Type, gc.Equals, network.IPv6Address) 120 c.Check(addr.Scope, gc.Equals, test.scope) 121 } 122 } 123 124 func (s *AddressSuite) TestAsProviderAddress(c *gc.C) { 125 addr1 := network.NewMachineAddress("0.1.2.3").AsProviderAddress( 126 network.WithSpaceName("foo"), 127 network.WithProviderSpaceID("3"), 128 network.WithProviderID("523"), 129 network.WithProviderSubnetID("5"), 130 network.WithProviderVLANID("5001"), 131 network.WithVLANTag(50), 132 ) 133 addr2 := network.NewMachineAddress("2001:db8::123").AsProviderAddress( 134 network.WithSpaceName(""), 135 ) 136 c.Check(addr1, jc.DeepEquals, network.ProviderAddress{ 137 MachineAddress: network.MachineAddress{ 138 Value: "0.1.2.3", 139 Type: "ipv4", 140 Scope: "public", 141 }, 142 SpaceName: "foo", 143 ProviderSpaceID: "3", 144 ProviderID: "523", 145 ProviderSubnetID: "5", 146 ProviderVLANID: "5001", 147 VLANTag: 50, 148 }) 149 c.Check(addr2, jc.DeepEquals, network.ProviderAddress{ 150 MachineAddress: network.MachineAddress{ 151 Value: "2001:db8::123", 152 Type: "ipv6", 153 Scope: "public", 154 }, 155 SpaceName: "", 156 }) 157 } 158 159 func (s *AddressSuite) TestAsProviderAddresses(c *gc.C) { 160 addrs := network.NewMachineAddresses([]string{"0.2.3.4", "fc00::1"}).AsProviderAddresses( 161 network.WithSpaceName("bar"), 162 network.WithProviderSpaceID("4"), 163 network.WithProviderSubnetID("6"), 164 network.WithProviderVLANID("5002"), 165 network.WithVLANTag(100), 166 ) 167 c.Check(addrs, jc.DeepEquals, network.ProviderAddresses{{ 168 MachineAddress: network.MachineAddress{ 169 Value: "0.2.3.4", 170 Type: "ipv4", 171 Scope: "public", 172 }, 173 SpaceName: "bar", 174 ProviderSpaceID: "4", 175 ProviderSubnetID: "6", 176 ProviderVLANID: "5002", 177 VLANTag: 100, 178 }, { 179 MachineAddress: network.MachineAddress{ 180 Value: "fc00::1", 181 Type: "ipv6", 182 Scope: "local-cloud", 183 }, 184 SpaceName: "bar", 185 ProviderSpaceID: "4", 186 ProviderSubnetID: "6", 187 ProviderVLANID: "5002", 188 VLANTag: 100, 189 }}) 190 } 191 192 func (s *AddressSuite) TestNewAddressIPv4(c *gc.C) { 193 value := "0.1.2.3" 194 addr1 := network.NewSpaceAddress(value) 195 addr2 := network.NewSpaceAddress(value, network.WithScope(network.ScopeLinkLocal)) 196 c.Assert(addr1.Scope, gc.Equals, network.ScopePublic) // derived from value 197 c.Assert(addr1.Value, gc.Equals, value) 198 c.Assert(addr1.Type, gc.Equals, network.IPv4Address) 199 c.Assert(addr2.Scope, gc.Equals, network.ScopeLinkLocal) 200 } 201 202 func (s *AddressSuite) TestNewAddressIPv6(c *gc.C) { 203 value := "2001:db8::1" 204 addr1 := network.NewSpaceAddress(value) 205 addr2 := network.NewSpaceAddress(value, network.WithScope(network.ScopeLinkLocal)) 206 c.Assert(addr1.Scope, gc.Equals, network.ScopePublic) // derived from value 207 c.Assert(addr1.Value, gc.Equals, value) 208 c.Assert(addr1.Type, gc.Equals, network.IPv6Address) 209 c.Assert(addr2.Scope, gc.Equals, network.ScopeLinkLocal) 210 } 211 212 func (s *AddressSuite) TestNewAddresses(c *gc.C) { 213 testAddresses := []struct { 214 values []string 215 addrType network.AddressType 216 scope network.Scope 217 }{{ 218 []string{"127.0.0.1", "127.0.1.2"}, 219 network.IPv4Address, 220 network.ScopeMachineLocal, 221 }, { 222 []string{"::1"}, 223 network.IPv6Address, 224 network.ScopeMachineLocal, 225 }, { 226 []string{"192.168.1.1", "192.168.178.255", "10.5.1.1", "172.16.1.1"}, 227 network.IPv4Address, 228 network.ScopeCloudLocal, 229 }, { 230 []string{"fc00::1", "fd00::2"}, 231 network.IPv6Address, 232 network.ScopeCloudLocal, 233 }, { 234 []string{"8.8.8.8", "8.8.4.4"}, 235 network.IPv4Address, 236 network.ScopePublic, 237 }, { 238 []string{"2001:db8::1", "64:ff9b::1", "2002::1"}, 239 network.IPv6Address, 240 network.ScopePublic, 241 }, { 242 []string{"169.254.1.23", "169.254.1.1"}, 243 network.IPv4Address, 244 network.ScopeLinkLocal, 245 }, { 246 []string{"243.1.5.7", "245.3.1.2"}, 247 network.IPv4Address, 248 network.ScopeFanLocal, 249 }, { 250 []string{"ff01::2", "ff01::1"}, 251 network.IPv6Address, 252 network.ScopeLinkLocal, 253 }, { 254 []string{"example.com", "example.org"}, 255 network.HostName, 256 network.ScopeUnknown, 257 }} 258 259 for i, test := range testAddresses { 260 c.Logf("test %d: %v -> %q", i, test.values, test.scope) 261 addresses := network.NewSpaceAddresses(test.values...) 262 c.Check(addresses, gc.HasLen, len(test.values)) 263 for j, addr := range addresses { 264 c.Check(addr.Value, gc.Equals, test.values[j]) 265 c.Check(addr.Type, gc.Equals, test.addrType) 266 c.Check(addr.Scope, gc.Equals, test.scope) 267 } 268 } 269 } 270 271 func (s *AddressSuite) TestNewScopedAddressHostname(c *gc.C) { 272 addr := network.NewSpaceAddress("localhost") 273 c.Check(addr.Value, gc.Equals, "localhost") 274 c.Check(addr.Type, gc.Equals, network.HostName) 275 c.Check(addr.Scope, gc.Equals, network.ScopeUnknown) 276 addr = network.NewSpaceAddress("example.com") 277 c.Check(addr.Value, gc.Equals, "example.com") 278 c.Check(addr.Type, gc.Equals, network.HostName) 279 c.Check(addr.Scope, gc.Equals, network.ScopeUnknown) 280 } 281 282 type selectTest struct { 283 about string 284 addresses network.SpaceAddresses 285 expectedIndex int 286 } 287 288 // expected returns the expected address for the test. 289 func (t selectTest) expected() (network.SpaceAddress, bool) { 290 if t.expectedIndex == -1 { 291 return network.SpaceAddress{}, false 292 } 293 return t.addresses[t.expectedIndex], true 294 } 295 296 var selectPublicTests = []selectTest{{ 297 "no addresses gives empty string result", 298 []network.SpaceAddress{}, 299 -1, 300 }, { 301 "a public IPv4 address is selected", 302 []network.SpaceAddress{ 303 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 304 }, 305 0, 306 }, { 307 "a public IPv6 address is selected", 308 []network.SpaceAddress{ 309 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 310 }, 311 0, 312 }, { 313 "first public address is selected", 314 []network.SpaceAddress{ 315 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 316 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 317 }, 318 0, 319 }, { 320 "the first public address is selected when cloud local fallbacks exist", 321 []network.SpaceAddress{ 322 network.NewSpaceAddress("172.16.1.1", network.WithScope(network.ScopeCloudLocal)), 323 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 324 network.NewSpaceAddress("fc00:1", network.WithScope(network.ScopeCloudLocal)), 325 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 326 }, 327 1, 328 }, { 329 "the cloud local address is selected when a fan-local fallback exists", 330 []network.SpaceAddress{ 331 network.NewSpaceAddress("243.1.1.1", network.WithScope(network.ScopeFanLocal)), 332 network.NewSpaceAddress("172.16.1.1", network.WithScope(network.ScopeCloudLocal)), 333 }, 334 1, 335 }, 336 { 337 "a machine IPv4 local address is not selected", 338 []network.SpaceAddress{ 339 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 340 }, 341 -1, 342 }, { 343 "a machine IPv6 local address is not selected", 344 []network.SpaceAddress{ 345 network.NewSpaceAddress("::1", network.WithScope(network.ScopeMachineLocal)), 346 }, 347 -1, 348 }, { 349 "a link-local IPv4 address is not selected", 350 []network.SpaceAddress{ 351 network.NewSpaceAddress("169.254.1.1", network.WithScope(network.ScopeLinkLocal)), 352 }, 353 -1, 354 }, { 355 "a link-local (multicast or not) IPv6 address is not selected", 356 []network.SpaceAddress{ 357 network.NewSpaceAddress("fe80::1", network.WithScope(network.ScopeLinkLocal)), 358 network.NewSpaceAddress("ff01::2", network.WithScope(network.ScopeLinkLocal)), 359 network.NewSpaceAddress("ff02::1:1", network.WithScope(network.ScopeLinkLocal)), 360 }, 361 -1, 362 }, { 363 "a public name is preferred to an unknown or cloud local address", 364 []network.SpaceAddress{ 365 network.NewSpaceAddress("127.0.0.1"), 366 network.NewSpaceAddress("10.0.0.1", network.WithScope(network.ScopeCloudLocal)), 367 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 368 network.NewSpaceAddress("public.invalid.testing", network.WithScope(network.ScopePublic)), 369 }, 370 3, 371 }, { 372 "first unknown address selected", 373 // NOTE(dimitern): Not using NewSpaceAddress() below as it derives the 374 // scope internally from the value when given ScopeUnknown. 375 []network.SpaceAddress{ 376 { 377 MachineAddress: network.MachineAddress{ 378 Value: "10.0.0.1", 379 Scope: network.ScopeUnknown, 380 }, 381 }, 382 { 383 MachineAddress: network.MachineAddress{ 384 Value: "8.8.8.8", 385 Scope: network.ScopeUnknown, 386 }, 387 }, 388 }, 389 0, 390 }, { 391 "public IP address is picked when both public IPs and public hostnames exist", 392 []network.SpaceAddress{ 393 network.NewSpaceAddress("10.0.0.1"), 394 network.NewSpaceAddress("example.com", network.WithScope(network.ScopePublic)), 395 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 396 }, 397 2, 398 }, { 399 "hostname is picked over cloud local address", 400 []network.SpaceAddress{ 401 network.NewSpaceAddress("10.0.0.1"), 402 network.NewSpaceAddress("example.com", network.WithScope(network.ScopePublic)), 403 }, 404 1, 405 }, { 406 "IPv4 preferred over IPv6", 407 []network.SpaceAddress{ 408 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 409 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 410 }, 411 1, 412 }} 413 414 func (s *AddressSuite) TestSelectPublicAddress(c *gc.C) { 415 for i, t := range selectPublicTests { 416 c.Logf("test %d: %s", i, t.about) 417 expectAddr, expectOK := t.expected() 418 actualAddr, actualOK := t.addresses.OneMatchingScope(network.ScopeMatchPublic) 419 c.Check(actualOK, gc.Equals, expectOK) 420 c.Check(actualAddr, gc.Equals, expectAddr) 421 } 422 } 423 424 var selectInternalTests = []selectTest{{ 425 "no addresses gives empty string result", 426 []network.SpaceAddress{}, 427 -1, 428 }, { 429 "a public IPv4 address is selected", 430 []network.SpaceAddress{ 431 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 432 }, 433 0, 434 }, { 435 "a public IPv6 address is selected", 436 []network.SpaceAddress{ 437 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 438 }, 439 0, 440 }, { 441 "a cloud local IPv4 address is selected", 442 []network.SpaceAddress{ 443 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 444 network.NewSpaceAddress("10.0.0.1", network.WithScope(network.ScopeCloudLocal)), 445 }, 446 1, 447 }, { 448 "a cloud local IPv6 address is selected", 449 []network.SpaceAddress{ 450 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 451 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 452 }, 453 0, 454 }, { 455 "a machine local or link-local address is not selected", 456 []network.SpaceAddress{ 457 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 458 network.NewSpaceAddress("::1", network.WithScope(network.ScopeMachineLocal)), 459 network.NewSpaceAddress("fe80::1", network.WithScope(network.ScopeLinkLocal)), 460 }, 461 -1, 462 }, { 463 "a cloud local address is preferred to a public address", 464 []network.SpaceAddress{ 465 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 466 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 467 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 468 }, 469 1, 470 }, { 471 "an IPv6 cloud local address is preferred to a public address if the former appears first", 472 []network.SpaceAddress{ 473 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 474 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 475 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 476 }, 477 2, 478 }} 479 480 func (s *AddressSuite) TestSelectInternalAddress(c *gc.C) { 481 for i, t := range selectInternalTests { 482 c.Logf("test %d: %s", i, t.about) 483 expectAddr, expectOK := t.expected() 484 actualAddr, actualOK := t.addresses.OneMatchingScope(network.ScopeMatchCloudLocal) 485 c.Check(actualOK, gc.Equals, expectOK) 486 c.Check(actualAddr, gc.Equals, expectAddr) 487 } 488 } 489 490 var selectInternalMachineTests = []selectTest{{ 491 "first cloud local IPv4 address is selected", 492 []network.SpaceAddress{ 493 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopePublic)), 494 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 495 network.NewSpaceAddress("10.0.0.1", network.WithScope(network.ScopeCloudLocal)), 496 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 497 }, 498 2, 499 }, { 500 "first cloud local address is selected", 501 []network.SpaceAddress{ 502 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 503 network.NewSpaceAddress("2001:db8::1", network.WithScope(network.ScopePublic)), 504 network.NewSpaceAddress("8.8.8.8", network.WithScope(network.ScopePublic)), 505 }, 506 0, 507 }, { 508 "first cloud local hostname is selected", 509 []network.SpaceAddress{ 510 network.NewSpaceAddress("example.com", network.WithScope(network.ScopePublic)), 511 network.NewSpaceAddress("cloud1.internal", network.WithScope(network.ScopeCloudLocal)), 512 network.NewSpaceAddress("cloud2.internal", network.WithScope(network.ScopeCloudLocal)), 513 network.NewSpaceAddress("example.org", network.WithScope(network.ScopePublic)), 514 }, 515 1, 516 }, { 517 "first machine local address is selected", 518 []network.SpaceAddress{ 519 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 520 network.NewSpaceAddress("::1", network.WithScope(network.ScopeMachineLocal)), 521 }, 522 0, 523 }, { 524 "first machine local IPv4 address is selected even with public/cloud hostnames", 525 []network.SpaceAddress{ 526 network.NewSpaceAddress("public.example.com", network.WithScope(network.ScopePublic)), 527 network.NewSpaceAddress("::1", network.WithScope(network.ScopeMachineLocal)), 528 network.NewSpaceAddress("unknown.example.com"), 529 network.NewSpaceAddress("cloud.internal", network.WithScope(network.ScopeCloudLocal)), 530 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 531 network.NewSpaceAddress("fe80::1", network.WithScope(network.ScopeLinkLocal)), 532 network.NewSpaceAddress("127.0.0.2", network.WithScope(network.ScopeMachineLocal)), 533 }, 534 4, 535 }, { 536 "first machine local non-IPv4 address is selected even with public/cloud hostnames", 537 []network.SpaceAddress{ 538 network.NewSpaceAddress("public.example.com", network.WithScope(network.ScopePublic)), 539 network.NewSpaceAddress("::1", network.WithScope(network.ScopeMachineLocal)), 540 network.NewSpaceAddress("unknown.example.com"), 541 network.NewSpaceAddress("cloud.internal", network.WithScope(network.ScopeCloudLocal)), 542 network.NewSpaceAddress("fe80::1", network.WithScope(network.ScopeLinkLocal)), 543 }, 544 1, 545 }, { 546 "cloud local IPv4 is selected even with other machine/cloud addresses", 547 []network.SpaceAddress{ 548 network.NewSpaceAddress("169.254.1.1", network.WithScope(network.ScopeLinkLocal)), 549 network.NewSpaceAddress("cloud-unknown.internal"), 550 network.NewSpaceAddress("cloud-local.internal", network.WithScope(network.ScopeCloudLocal)), 551 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 552 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 553 network.NewSpaceAddress("127.0.0.2", network.WithScope(network.ScopeMachineLocal)), 554 }, 555 4, 556 }, { 557 "first cloud local hostname is selected even with other machine/cloud addresses", 558 []network.SpaceAddress{ 559 network.NewSpaceAddress("169.254.1.1", network.WithScope(network.ScopeLinkLocal)), 560 network.NewSpaceAddress("cloud-unknown.internal"), 561 network.NewSpaceAddress("cloud-local.internal", network.WithScope(network.ScopeCloudLocal)), 562 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopeCloudLocal)), 563 }, 564 2, 565 }} 566 567 func (s *AddressSuite) TestSelectInternalMachineAddress(c *gc.C) { 568 for i, t := range selectInternalMachineTests { 569 c.Logf("test %d: %s", i, t.about) 570 expectAddr, expectOK := t.expected() 571 actualAddr, actualOK := t.addresses.OneMatchingScope(network.ScopeMatchMachineOrCloudLocal) 572 c.Check(actualOK, gc.Equals, expectOK) 573 c.Check(actualAddr, gc.Equals, expectAddr) 574 } 575 } 576 577 type selectInternalAddressesTest struct { 578 about string 579 addresses network.SpaceAddresses 580 matcher network.ScopeMatchFunc 581 expected network.SpaceAddresses 582 } 583 584 var selectInternalAddressesTests = []selectInternalAddressesTest{ 585 { 586 about: "machine/cloud-local addresses are selected when machineLocal is true", 587 addresses: []network.SpaceAddress{ 588 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 589 network.NewSpaceAddress("10.0.0.9", network.WithScope(network.ScopeCloudLocal)), 590 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopePublic)), 591 }, 592 matcher: network.ScopeMatchMachineOrCloudLocal, 593 expected: []network.SpaceAddress{ 594 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 595 network.NewSpaceAddress("10.0.0.9", network.WithScope(network.ScopeCloudLocal)), 596 }, 597 }, 598 { 599 about: "cloud-local addresses are selected when machineLocal is false", 600 addresses: []network.SpaceAddress{ 601 network.NewSpaceAddress("169.254.1.1", network.WithScope(network.ScopeLinkLocal)), 602 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 603 network.NewSpaceAddress("cloud-local.internal", network.WithScope(network.ScopeCloudLocal)), 604 network.NewSpaceAddress("cloud-local2.internal", network.WithScope(network.ScopeCloudLocal)), 605 network.NewSpaceAddress("fc00::1", network.WithScope(network.ScopePublic)), 606 }, 607 matcher: network.ScopeMatchCloudLocal, 608 expected: []network.SpaceAddress{ 609 network.NewSpaceAddress("cloud-local.internal", network.WithScope(network.ScopeCloudLocal)), 610 network.NewSpaceAddress("cloud-local2.internal", network.WithScope(network.ScopeCloudLocal)), 611 }, 612 }, 613 { 614 about: "nil is returned when no cloud-local addresses are found", 615 addresses: []network.SpaceAddress{ 616 network.NewSpaceAddress("169.254.1.1", network.WithScope(network.ScopeLinkLocal)), 617 network.NewSpaceAddress("127.0.0.1", network.WithScope(network.ScopeMachineLocal)), 618 }, 619 matcher: network.ScopeMatchCloudLocal, 620 expected: nil, 621 }, 622 } 623 624 func (s *AddressSuite) TestSelectInternalAddresses(c *gc.C) { 625 for i, t := range selectInternalAddressesTests { 626 c.Logf("test %d: %s", i, t.about) 627 actualAddr := t.addresses.AllMatchingScope(t.matcher) 628 c.Check(actualAddr, gc.DeepEquals, t.expected) 629 } 630 } 631 632 // stringer wraps Stringer and GoStringer for convenience. 633 type stringer interface { 634 fmt.Stringer 635 fmt.GoStringer 636 } 637 638 var stringTests = []struct { 639 addr stringer 640 str string 641 }{{ 642 addr: network.MachineAddress{ 643 Type: network.IPv4Address, 644 Value: "127.0.0.1", 645 }, 646 str: "127.0.0.1", 647 }, { 648 addr: network.ProviderAddress{ 649 MachineAddress: network.MachineAddress{ 650 Type: network.IPv4Address, 651 Value: "127.0.0.1", 652 }, 653 SpaceName: "storage-data", 654 }, 655 str: "127.0.0.1@storage-data", 656 }, { 657 addr: network.MachineAddress{ 658 Type: network.IPv6Address, 659 Value: "2001:db8::1", 660 Scope: network.ScopePublic, 661 }, 662 str: "public:2001:db8::1", 663 }, { 664 addr: network.MachineAddress{ 665 Type: network.HostName, 666 Value: "foo.com", 667 }, 668 str: "foo.com", 669 }, { 670 addr: network.MachineAddress{ 671 Type: network.HostName, 672 Value: "foo.com", 673 Scope: network.ScopeUnknown, 674 }, 675 str: "foo.com", 676 }, { 677 addr: network.ProviderAddress{ 678 MachineAddress: network.MachineAddress{ 679 Type: network.HostName, 680 Value: "foo.com", 681 Scope: network.ScopePublic, 682 }, 683 ProviderSpaceID: network.Id("3"), 684 }, 685 str: "public:foo.com@(id:3)", 686 }, { 687 addr: network.ProviderAddress{ 688 MachineAddress: network.MachineAddress{ 689 Type: network.HostName, 690 Value: "foo.com", 691 Scope: network.ScopePublic, 692 }, 693 SpaceName: "default", 694 }, 695 str: "public:foo.com@default", 696 }, { 697 addr: network.ProviderAddress{ 698 MachineAddress: network.MachineAddress{ 699 Type: network.HostName, 700 Value: "foo.com", 701 Scope: network.ScopePublic, 702 }, 703 SpaceName: "badlands", 704 ProviderSpaceID: network.Id("3"), 705 }, 706 str: "public:foo.com@badlands(id:3)", 707 }, { 708 addr: network.ProviderAddress{ 709 MachineAddress: network.MachineAddress{ 710 Type: network.HostName, 711 Value: "foo.com", 712 Scope: network.ScopePublic, 713 }, 714 SpaceName: "badlands", 715 ProviderSpaceID: network.Id("3"), 716 ProviderID: "523", 717 }, 718 str: "public:foo.com@badlands(id:3)", 719 }, { 720 addr: network.ProviderAddress{ 721 MachineAddress: network.MachineAddress{ 722 Type: network.HostName, 723 Value: "foo.com", 724 Scope: network.ScopePublic, 725 }, 726 SpaceName: "badlands", 727 ProviderSpaceID: network.Id("3"), 728 ProviderSubnetID: "5", 729 }, 730 str: "public:foo.com@badlands(id:3)", 731 }, { 732 addr: network.ProviderAddress{ 733 MachineAddress: network.MachineAddress{ 734 Type: network.HostName, 735 Value: "foo.com", 736 Scope: network.ScopePublic, 737 }, 738 SpaceName: "badlands", 739 ProviderSpaceID: network.Id("3"), 740 ProviderVLANID: "5001", 741 }, 742 str: "public:foo.com@badlands(id:3)", 743 }, { 744 addr: network.ProviderAddress{ 745 MachineAddress: network.MachineAddress{ 746 Type: network.HostName, 747 Value: "foo.com", 748 Scope: network.ScopePublic, 749 }, 750 SpaceName: "badlands", 751 ProviderSpaceID: network.Id("3"), 752 VLANTag: 50, 753 }, 754 str: "public:foo.com@badlands(id:3)", 755 }} 756 757 func (s *AddressSuite) TestString(c *gc.C) { 758 for i, test := range stringTests { 759 c.Logf("test %d: %#v", i, test.addr) 760 c.Check(test.addr.String(), gc.Equals, test.str) 761 c.Check(test.addr.GoString(), gc.Equals, test.str) 762 } 763 } 764 765 func (*AddressSuite) TestSortAddresses(c *gc.C) { 766 addrs := network.NewSpaceAddresses( 767 "127.0.0.1", 768 "::1", 769 "fc00::1", 770 "169.254.1.2", 771 "localhost", 772 "243.5.1.2", 773 "2001:db8::1", 774 "fe80::2", 775 "7.8.8.8", 776 "172.16.0.2", 777 "example.com", 778 "8.8.8.8", 779 ) 780 781 // Public and local-cloud secondary addresses. 782 addrs = append(addrs, network.NewSpaceAddress("6.8.8.8", network.WithSecondary(true))) 783 addrs = append(addrs, network.NewSpaceAddress("172.16.0.1", network.WithSecondary(true))) 784 785 sort.Sort(addrs) 786 c.Assert(addrs.Values(), jc.DeepEquals, []string{ 787 // Public IPv4 addresses on top. 788 "7.8.8.8", 789 "8.8.8.8", 790 // After that public IPv6 addresses. 791 "2001:db8::1", 792 // Then hostname. 793 "example.com", 794 // Secondary public address follows the others. 795 "6.8.8.8", 796 // With localhost last. 797 "localhost", 798 // Then IPv4 cloud-local addresses. 799 "172.16.0.2", 800 // Then IPv6 cloud-local addresses. 801 "fc00::1", 802 // Then secondary cloud-local addresses. 803 "172.16.0.1", 804 // Then fan-local addresses. 805 "243.5.1.2", 806 // Then machine-local IPv4 addresses. 807 "127.0.0.1", 808 // Then machine-local IPv6 addresses. 809 "::1", 810 // Then link-local IPv4 addresses. 811 "169.254.1.2", 812 // Finally, link-local IPv6 addresses. 813 "fe80::2", 814 }) 815 } 816 817 func (*AddressSuite) TestExactScopeMatch(c *gc.C) { 818 var addr network.Address 819 820 addr = network.NewMachineAddress("10.0.0.2", network.WithScope(network.ScopeCloudLocal)) 821 match := network.ExactScopeMatch(addr, network.ScopeCloudLocal) 822 c.Assert(match, jc.IsTrue) 823 match = network.ExactScopeMatch(addr, network.ScopePublic) 824 c.Assert(match, jc.IsFalse) 825 826 addr = network.NewMachineAddress("8.8.8.8", network.WithScope(network.ScopePublic)).AsProviderAddress() 827 match = network.ExactScopeMatch(addr, network.ScopeCloudLocal) 828 c.Assert(match, jc.IsFalse) 829 match = network.ExactScopeMatch(addr, network.ScopePublic) 830 c.Assert(match, jc.IsTrue) 831 } 832 833 func (s *AddressSuite) TestSelectAddressesBySpaceNamesFiltered(c *gc.C) { 834 sp := network.SpaceInfo{ 835 ID: "666", 836 Name: "thaSpace", 837 ProviderId: "", 838 Subnets: nil, 839 } 840 841 // Only the first address has a space. 842 addr := network.NewSpaceAddress("192.168.5.5") 843 addr.SpaceID = sp.ID 844 addrs := network.SpaceAddresses{ 845 addr, 846 network.NewSpaceAddress("127.0.0.1"), 847 } 848 849 filtered, ok := addrs.InSpaces(sp) 850 c.Check(ok, jc.IsTrue) 851 c.Check(filtered, jc.DeepEquals, network.SpaceAddresses{addr}) 852 } 853 854 func (s *AddressSuite) TestSelectAddressesBySpaceNoSpaceFalse(c *gc.C) { 855 addrs := network.SpaceAddresses{network.NewSpaceAddress("127.0.0.1")} 856 filtered, ok := addrs.InSpaces() 857 c.Check(ok, jc.IsFalse) 858 c.Check(filtered, jc.DeepEquals, addrs) 859 } 860 861 func (s *AddressSuite) TestSelectAddressesBySpaceNoneFound(c *gc.C) { 862 sp := network.SpaceInfo{ 863 ID: "666", 864 Name: "noneSpace", 865 ProviderId: "", 866 Subnets: nil, 867 } 868 869 addrs := network.SpaceAddresses{network.NewSpaceAddress("127.0.0.1")} 870 filtered, ok := addrs.InSpaces(sp) 871 c.Check(ok, jc.IsFalse) 872 c.Check(filtered, jc.DeepEquals, addrs) 873 } 874 875 type stubLookup struct{} 876 877 var _ network.SpaceLookup = stubLookup{} 878 879 func (s stubLookup) AllSpaceInfos() (network.SpaceInfos, error) { 880 return network.SpaceInfos{ 881 {ID: "1", Name: "space-one", ProviderId: "p1"}, 882 {ID: "2", Name: "space-two"}, 883 { 884 ID: "6", 885 Name: "space-six", 886 Subnets: network.SubnetInfos{ 887 { 888 ID: "666", 889 CIDR: "10.0.0.0/24", 890 ProviderId: "61", 891 }, 892 }, 893 }, 894 }, nil 895 } 896 897 func (s *AddressSuite) TestProviderAddressesToSpaceAddressesByName(c *gc.C) { 898 // Check success. 899 addrs := network.ProviderAddresses{ 900 network.NewMachineAddress("1.2.3.4").AsProviderAddress(network.WithSpaceName("space-one")), 901 network.NewMachineAddress("2.3.4.5").AsProviderAddress(network.WithSpaceName("space-two")), 902 network.NewMachineAddress("3.4.5.6").AsProviderAddress(), 903 } 904 905 exp := network.NewSpaceAddresses("1.2.3.4", "2.3.4.5", "3.4.5.6") 906 exp[0].SpaceID = "1" 907 exp[1].SpaceID = "2" 908 909 res, err := addrs.ToSpaceAddresses(stubLookup{}) 910 c.Assert(err, jc.ErrorIsNil) 911 c.Check(res, jc.SameContents, exp) 912 913 // Add an address in a space that the lookup will not resolve. 914 addrs = append(addrs, network.NewMachineAddress("4.5.6.7").AsProviderAddress(network.WithSpaceName("space-denied"))) 915 _, err = addrs.ToSpaceAddresses(stubLookup{}) 916 c.Assert(err, jc.Satisfies, errors.IsNotFound) 917 } 918 919 func (s *AddressSuite) TestProviderAddressesToSpaceAddressesBySubnet(c *gc.C) { 920 // Check success. 921 addrs := network.ProviderAddresses{ 922 network.NewMachineAddress( 923 "10.0.0.6", 924 network.WithCIDR("10.0.0.0/24"), 925 ).AsProviderAddress(network.WithProviderSubnetID("61")), 926 } 927 928 res, err := addrs.ToSpaceAddresses(stubLookup{}) 929 c.Assert(err, jc.ErrorIsNil) 930 c.Assert(res, gc.HasLen, 1) 931 c.Check(res[0].SpaceID, gc.Equals, "6") 932 } 933 934 func (s *AddressSuite) TestSpaceAddressesToProviderAddresses(c *gc.C) { 935 // Check success. 936 addrs := network.NewSpaceAddresses("1.2.3.4", "2.3.4.5", "3.4.5.6") 937 addrs[0].SpaceID = "1" 938 addrs[1].SpaceID = "2" 939 940 exp := network.ProviderAddresses{ 941 network.NewMachineAddress("1.2.3.4").AsProviderAddress(network.WithSpaceName("space-one")), 942 network.NewMachineAddress("2.3.4.5").AsProviderAddress(network.WithSpaceName("space-two")), 943 network.NewMachineAddress("3.4.5.6").AsProviderAddress(), 944 } 945 // Only the first address in the lookup has a provider ID. 946 exp[0].ProviderSpaceID = "p1" 947 948 res, err := addrs.ToProviderAddresses(stubLookup{}) 949 c.Assert(err, jc.ErrorIsNil) 950 c.Check(res, jc.SameContents, exp) 951 952 // Add an address in a space that the lookup will not resolve. 953 addrs = append(addrs, network.NewSpaceAddress("4.5.6.7")) 954 addrs[3].SpaceID = "3" 955 _, err = addrs.ToProviderAddresses(stubLookup{}) 956 c.Assert(err, jc.Satisfies, errors.IsNotFound) 957 } 958 959 func (s *AddressSuite) TestSpaceAddressesValues(c *gc.C) { 960 values := []string{"1.2.3.4", "2.3.4.5", "3.4.5.6"} 961 addrs := network.NewSpaceAddresses(values...) 962 c.Check(addrs.Values(), gc.DeepEquals, values) 963 } 964 965 func (s *AddressSuite) TestAddressValueForCIDR(c *gc.C) { 966 _, err := network.NewMachineAddress("172.31.37.53").ValueWithMask() 967 c.Assert(err, jc.Satisfies, errors.IsNotFound) 968 969 _, err = network.NewMachineAddress("", network.WithCIDR("172.31.37.0/20")).ValueWithMask() 970 c.Assert(err, jc.Satisfies, errors.IsNotFound) 971 972 val, err := network.NewMachineAddress("172.31.37.53", network.WithCIDR("172.31.37.0/20")).ValueWithMask() 973 c.Assert(err, jc.ErrorIsNil) 974 c.Check(val, gc.Equals, "172.31.37.53/20") 975 } 976 977 func (s *AddressSuite) TestCIDRAddressType(c *gc.C) { 978 tests := []struct { 979 descr string 980 CIDR string 981 exp network.AddressType 982 expErr string 983 }{ 984 { 985 descr: "IPV4 CIDR", 986 CIDR: "10.0.0.0/24", 987 exp: network.IPv4Address, 988 }, 989 { 990 descr: "IPV6 CIDR", 991 CIDR: "2002::1234:abcd:ffff:c0a8:101/64", 992 exp: network.IPv6Address, 993 }, 994 { 995 descr: "IPV6 with 4in6 prefix", 996 CIDR: "0:0:0:0:0:ffff:c0a8:2a00/120", 997 // The Go stdlib interprets this as an IPV4 998 exp: network.IPv4Address, 999 }, 1000 { 1001 descr: "bogus CIDR", 1002 CIDR: "catastrophe", 1003 expErr: ".*invalid CIDR address.*", 1004 }, 1005 } 1006 1007 for i, t := range tests { 1008 c.Logf("test %d: %s", i, t.descr) 1009 got, err := network.CIDRAddressType(t.CIDR) 1010 if t.expErr != "" { 1011 c.Check(got, gc.Equals, network.AddressType("")) 1012 c.Check(err, gc.ErrorMatches, t.expErr) 1013 } else { 1014 c.Check(err, jc.ErrorIsNil) 1015 c.Check(got, gc.Equals, t.exp) 1016 } 1017 } 1018 } 1019 1020 func (s *AddressSuite) TestNoAddressError(c *gc.C) { 1021 err := network.NoAddressError("fake") 1022 c.Assert(err, gc.ErrorMatches, `no fake address\(es\)`) 1023 c.Assert(network.IsNoAddressError(err), jc.IsTrue) 1024 c.Assert(network.IsNoAddressError(errors.New("address found")), jc.IsFalse) 1025 } 1026 1027 func (s *AddressSuite) TestNetworkCIDRFromIPAndMask(c *gc.C) { 1028 specs := []struct { 1029 descr string 1030 ip net.IP 1031 mask net.IPMask 1032 expCIDR string 1033 }{ 1034 { 1035 descr: "nil ip", 1036 mask: net.IPv4Mask(0, 0, 0, 255), 1037 expCIDR: "", 1038 }, 1039 { 1040 descr: "nil mask", 1041 ip: net.ParseIP("10.1.2.42"), 1042 expCIDR: "", 1043 }, 1044 { 1045 descr: "network IP", 1046 ip: net.ParseIP("10.1.0.0"), 1047 mask: net.IPv4Mask(255, 255, 0, 0), 1048 expCIDR: "10.1.0.0/16", 1049 }, 1050 { 1051 descr: "host IP", 1052 ip: net.ParseIP("10.1.2.42"), 1053 mask: net.IPv4Mask(255, 255, 255, 0), 1054 expCIDR: "10.1.2.0/24", 1055 }, 1056 } 1057 1058 for i, spec := range specs { 1059 c.Logf("%d: %s", i, spec.descr) 1060 gotCIDR := network.NetworkCIDRFromIPAndMask(spec.ip, spec.mask) 1061 c.Assert(gotCIDR, gc.Equals, spec.expCIDR) 1062 } 1063 } 1064 1065 func (s *AddressSuite) TestIsValidAddressConfigTypeWithValidValues(c *gc.C) { 1066 validTypes := []network.AddressConfigType{ 1067 network.ConfigLoopback, 1068 network.ConfigStatic, 1069 network.ConfigDHCP, 1070 network.ConfigManual, 1071 } 1072 1073 for _, value := range validTypes { 1074 result := network.IsValidAddressConfigType(string(value)) 1075 c.Check(result, jc.IsTrue) 1076 } 1077 } 1078 1079 func (s *AddressSuite) TestIsValidAddressConfigTypeWithInvalidValues(c *gc.C) { 1080 result := network.IsValidAddressConfigType("") 1081 c.Check(result, jc.IsFalse) 1082 1083 result = network.IsValidAddressConfigType("anything") 1084 c.Check(result, jc.IsFalse) 1085 1086 result = network.IsValidAddressConfigType(" ") 1087 c.Check(result, jc.IsFalse) 1088 } 1089 1090 // spaceAddressCandidate implements the SpaceAddressCandidate 1091 // interface from the core/network package. 1092 type spaceAddressCandidate struct { 1093 value string 1094 configMethod network.AddressConfigType 1095 subnetCIDR string 1096 isSecondary bool 1097 } 1098 1099 func (s spaceAddressCandidate) Value() string { 1100 return s.value 1101 } 1102 1103 func (s spaceAddressCandidate) ConfigMethod() network.AddressConfigType { 1104 return s.configMethod 1105 } 1106 1107 func (s spaceAddressCandidate) SubnetCIDR() string { 1108 return s.subnetCIDR 1109 } 1110 1111 func (s spaceAddressCandidate) IsSecondary() bool { 1112 return s.isSecondary 1113 } 1114 1115 func (s *AddressSuite) TestConvertToSpaceAddresses(c *gc.C) { 1116 subs := network.SubnetInfos{ 1117 {ID: "1", CIDR: "192.168.0.0/24", SpaceID: "666"}, 1118 {ID: "2", CIDR: "252.80.0.0/12", SpaceID: "999"}, 1119 {ID: "3", CIDR: "10.0.0.10/32", SpaceID: "333"}, 1120 } 1121 1122 candidates := []network.SpaceAddressCandidate{ 1123 spaceAddressCandidate{ 1124 value: "252.80.0.100", 1125 configMethod: network.ConfigStatic, 1126 subnetCIDR: "252.80.0.0/12", 1127 isSecondary: true, 1128 }, 1129 spaceAddressCandidate{ 1130 value: "192.168.0.66", 1131 configMethod: network.ConfigDHCP, 1132 subnetCIDR: "192.168.0.0/24", 1133 }, 1134 // This simulates an address added to the loopback device, 1135 // such as done by BGP. 1136 spaceAddressCandidate{ 1137 value: "10.0.0.10", 1138 configMethod: network.ConfigLoopback, 1139 subnetCIDR: "10.0.0.10/32", 1140 }, 1141 } 1142 1143 addrs := make(network.SpaceAddresses, len(candidates)) 1144 for i, ca := range candidates { 1145 var err error 1146 addrs[i], err = network.ConvertToSpaceAddress(ca, subs) 1147 c.Assert(err, jc.ErrorIsNil) 1148 } 1149 1150 sort.Sort(addrs) 1151 c.Check(addrs, gc.DeepEquals, network.SpaceAddresses{ 1152 { 1153 MachineAddress: network.MachineAddress{ 1154 Value: "10.0.0.10", 1155 Type: network.IPv4Address, 1156 Scope: network.ScopeCloudLocal, 1157 ConfigType: network.ConfigLoopback, 1158 CIDR: "10.0.0.10/32", 1159 }, 1160 SpaceID: "333", 1161 }, 1162 { 1163 MachineAddress: network.MachineAddress{ 1164 Value: "192.168.0.66", 1165 Type: network.IPv4Address, 1166 Scope: network.ScopeCloudLocal, 1167 ConfigType: network.ConfigDHCP, 1168 CIDR: "192.168.0.0/24", 1169 }, 1170 SpaceID: "666", 1171 }, 1172 { 1173 MachineAddress: network.MachineAddress{ 1174 Value: "252.80.0.100", 1175 Type: network.IPv4Address, 1176 Scope: network.ScopeFanLocal, 1177 ConfigType: network.ConfigStatic, 1178 CIDR: "252.80.0.0/12", 1179 IsSecondary: true, 1180 }, 1181 SpaceID: "999", 1182 }, 1183 }) 1184 } 1185 1186 type testFindSubnetAddr struct { 1187 val string 1188 } 1189 1190 func (a testFindSubnetAddr) Network() string { 1191 return "ip+net" 1192 } 1193 1194 func (a testFindSubnetAddr) String() string { 1195 return a.val 1196 } 1197 1198 func testAddresses(c *gc.C, networks ...string) ([]net.Addr, error) { 1199 addrs := make([]net.Addr, 0) 1200 for _, n := range networks { 1201 _, _, err := net.ParseCIDR(n) 1202 if err != nil { 1203 return nil, err 1204 } 1205 c.Assert(err, gc.IsNil) 1206 addrs = append(addrs, testFindSubnetAddr{n}) 1207 } 1208 return addrs, nil 1209 } 1210 1211 func (s *AddressSuite) TestIsLocalAddress(c *gc.C) { 1212 1213 tests := []struct { 1214 descr string 1215 ip net.IP 1216 ifaceAddrsResult []string 1217 ifaceAddrsErr error 1218 expected bool 1219 expectedErr string 1220 }{ 1221 { 1222 descr: "error returned from net.InterfaceAddrs()", 1223 ifaceAddrsErr: errors.New("interface addrs - some error"), 1224 expectedErr: "interface addrs - some error", 1225 expected: false, 1226 }, 1227 { 1228 descr: "IPv4 is local", 1229 ifaceAddrsResult: []string{"192.168.0.0/16"}, 1230 ip: net.IPv4(192, 168, 0, 0), 1231 expected: true, 1232 }, 1233 { 1234 descr: "IPv4 is not local", 1235 ifaceAddrsResult: []string{"192.168.0.0/16"}, 1236 ip: net.IPv4(8, 8, 8, 8), 1237 expected: false, 1238 }, 1239 { 1240 descr: "IPv6 is local", 1241 ifaceAddrsResult: []string{"fc00::/7"}, 1242 ip: net.ParseIP("fc00::0"), 1243 expected: true, 1244 }, 1245 { 1246 descr: "IPv6 is not local", 1247 ifaceAddrsResult: []string{"fc00::/7"}, 1248 ip: net.ParseIP("2606::1"), 1249 expected: false, 1250 }, 1251 } 1252 1253 for i, tt := range tests { 1254 c.Logf("Test %d: %s", i, tt.descr) 1255 1256 s.PatchValue(&network.InterfaceAddrs, func() ([]net.Addr, error) { 1257 if tt.ifaceAddrsErr != nil { 1258 return []net.Addr{}, tt.ifaceAddrsErr 1259 } 1260 return testAddresses(c, tt.ifaceAddrsResult...) 1261 }) 1262 isLocal, err := network.IsLocalAddress(tt.ip) 1263 if err != nil { 1264 c.Check(err, gc.ErrorMatches, tt.expectedErr) 1265 // when err is returned, isLocal is false 1266 c.Check(isLocal, gc.Equals, false) 1267 continue 1268 } 1269 c.Check(err, jc.ErrorIsNil) 1270 c.Check("", gc.Equals, tt.expectedErr) 1271 1272 c.Check(isLocal, gc.Equals, tt.expected) 1273 } 1274 }