github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "errors" 8 "fmt" 9 "net" 10 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/network" 15 "github.com/juju/juju/testing" 16 ) 17 18 type AddressSuite struct { 19 testing.BaseSuite 20 } 21 22 var _ = gc.Suite(&AddressSuite{}) 23 24 func (s *AddressSuite) TestNewScopedAddressIPv4(c *gc.C) { 25 type test struct { 26 value string 27 scope network.Scope 28 expectedScope network.Scope 29 } 30 31 tests := []test{{ 32 value: "127.0.0.1", 33 scope: network.ScopeUnknown, 34 expectedScope: network.ScopeMachineLocal, 35 }, { 36 value: "127.0.0.1", 37 scope: network.ScopePublic, 38 expectedScope: network.ScopePublic, // don't second guess != Unknown 39 }, { 40 value: "10.0.3.1", 41 scope: network.ScopeUnknown, 42 expectedScope: network.ScopeCloudLocal, 43 }, { 44 value: "172.16.15.14", 45 scope: network.ScopeUnknown, 46 expectedScope: network.ScopeCloudLocal, 47 }, { 48 value: "192.168.0.1", 49 scope: network.ScopeUnknown, 50 expectedScope: network.ScopeCloudLocal, 51 }, { 52 value: "169.254.1.1", 53 scope: network.ScopeUnknown, 54 expectedScope: network.ScopeLinkLocal, 55 }, { 56 value: "8.8.8.8", 57 scope: network.ScopeUnknown, 58 expectedScope: network.ScopePublic, 59 }} 60 61 for i, t := range tests { 62 c.Logf("test %d: %s %s", i, t.value, t.scope) 63 addr := network.NewScopedAddress(t.value, t.scope) 64 c.Check(addr.Value, gc.Equals, t.value) 65 c.Check(addr.Type, gc.Equals, network.IPv4Address) 66 c.Check(addr.Scope, gc.Equals, t.expectedScope) 67 } 68 } 69 70 func (s *AddressSuite) TestNewScopedAddressIPv6(c *gc.C) { 71 // Examples below taken from 72 // http://en.wikipedia.org/wiki/IPv6_address 73 testAddresses := []struct { 74 value string 75 scope network.Scope 76 }{ 77 // IPv6 loopback address 78 {"::1", network.ScopeMachineLocal}, 79 // used documentation examples 80 {"2001:db8::1", network.ScopePublic}, 81 // link-local 82 {"fe80::1", network.ScopeLinkLocal}, 83 // unique local address (ULA) - first group 84 {"fc00::1", network.ScopeCloudLocal}, 85 // unique local address (ULA) - second group 86 {"fd00::1", network.ScopeCloudLocal}, 87 // IPv4-mapped IPv6 address 88 {"::ffff:0:0:1", network.ScopePublic}, 89 // IPv4-translated IPv6 address (SIIT) 90 {"::ffff:0:0:0:1", network.ScopePublic}, 91 // "well-known" prefix for IPv4/IPv6 auto translation 92 {"64:ff9b::1", network.ScopePublic}, 93 // used for 6to4 addressing 94 {"2002::1", network.ScopePublic}, 95 // used for Teredo tunneling 96 {"2001::1", network.ScopePublic}, 97 // used for IPv6 benchmarking 98 {"2001:2::1", network.ScopePublic}, 99 // used for cryptographic hash identifiers 100 {"2001:10::1", network.ScopePublic}, 101 // interface-local multicast (all nodes) 102 {"ff01::1", network.ScopeLinkLocal}, 103 // link-local multicast (all nodes) 104 {"ff02::1", network.ScopeLinkLocal}, 105 // interface-local multicast (all routers) 106 {"ff01::2", network.ScopeLinkLocal}, 107 // link-local multicast (all routers) 108 {"ff02::2", network.ScopeLinkLocal}, 109 } 110 for i, test := range testAddresses { 111 c.Logf("test %d: %q -> %q", i, test.value, test.scope) 112 addr := network.NewScopedAddress(test.value, network.ScopeUnknown) 113 c.Check(addr.Value, gc.Equals, test.value) 114 c.Check(addr.Type, gc.Equals, network.IPv6Address) 115 c.Check(addr.Scope, gc.Equals, test.scope) 116 } 117 } 118 119 func (s *AddressSuite) TestNewAddressOnSpace(c *gc.C) { 120 addr1 := network.NewAddressOnSpace("foo", "0.1.2.3") 121 addr2 := network.NewAddressOnSpace("", "2001:db8::123") 122 c.Check(addr1, jc.DeepEquals, network.Address{ 123 Value: "0.1.2.3", 124 Type: "ipv4", 125 Scope: "public", 126 SpaceName: "foo", 127 }) 128 c.Check(addr2, jc.DeepEquals, network.Address{ 129 Value: "2001:db8::123", 130 Type: "ipv6", 131 Scope: "public", 132 SpaceName: "", 133 }) 134 } 135 136 func (s *AddressSuite) TestNewAddressesOnSpace(c *gc.C) { 137 addrs := network.NewAddressesOnSpace("bar", "0.2.3.4", "fc00::1") 138 c.Check(addrs, jc.DeepEquals, []network.Address{{ 139 Value: "0.2.3.4", 140 Type: "ipv4", 141 Scope: "public", 142 SpaceName: "bar", 143 SpaceProviderId: network.Id(""), 144 }, { 145 Value: "fc00::1", 146 Type: "ipv6", 147 Scope: "local-cloud", 148 SpaceName: "bar", 149 SpaceProviderId: network.Id(""), 150 }}) 151 } 152 153 func (s *AddressSuite) TestNewAddressIPv4(c *gc.C) { 154 value := "0.1.2.3" 155 addr1 := network.NewScopedAddress(value, network.ScopeUnknown) 156 addr2 := network.NewAddress(value) 157 addr3 := network.NewScopedAddress(value, network.ScopeLinkLocal) 158 // NewAddress behaves exactly like NewScopedAddress with ScopeUnknown 159 c.Assert(addr1, jc.DeepEquals, addr2) 160 c.Assert(addr2.Scope, gc.Equals, network.ScopePublic) // derived from value 161 c.Assert(addr2.Value, gc.Equals, value) 162 c.Assert(addr2.Type, gc.Equals, network.IPv4Address) 163 c.Assert(addr2.Scope, gc.Not(gc.Equals), addr3.Scope) // different scope 164 c.Assert(addr3.Scope, gc.Equals, network.ScopeLinkLocal) 165 } 166 167 func (s *AddressSuite) TestNewAddressIPv6(c *gc.C) { 168 value := "2001:db8::1" 169 addr1 := network.NewScopedAddress(value, network.ScopeUnknown) 170 addr2 := network.NewAddress(value) 171 addr3 := network.NewScopedAddress(value, network.ScopeLinkLocal) 172 // NewAddress behaves exactly like NewScopedAddress with ScopeUnknown 173 c.Assert(addr1, jc.DeepEquals, addr2) 174 c.Assert(addr2.Scope, gc.Equals, network.ScopePublic) // derived from value 175 c.Assert(addr2.Value, gc.Equals, value) 176 c.Assert(addr2.Type, gc.Equals, network.IPv6Address) 177 c.Assert(addr2.Scope, gc.Not(gc.Equals), addr3.Scope) // different scope 178 c.Assert(addr3.Scope, gc.Equals, network.ScopeLinkLocal) 179 } 180 181 func (s *AddressSuite) TestNewAddresses(c *gc.C) { 182 testAddresses := []struct { 183 values []string 184 addrType network.AddressType 185 scope network.Scope 186 }{{ 187 []string{"127.0.0.1", "127.0.1.2"}, 188 network.IPv4Address, 189 network.ScopeMachineLocal, 190 }, { 191 []string{"::1"}, 192 network.IPv6Address, 193 network.ScopeMachineLocal, 194 }, { 195 []string{"192.168.1.1", "192.168.178.255", "10.5.1.1", "172.16.1.1"}, 196 network.IPv4Address, 197 network.ScopeCloudLocal, 198 }, { 199 []string{"fc00::1", "fd00::2"}, 200 network.IPv6Address, 201 network.ScopeCloudLocal, 202 }, { 203 []string{"8.8.8.8", "8.8.4.4"}, 204 network.IPv4Address, 205 network.ScopePublic, 206 }, { 207 []string{"2001:db8::1", "64:ff9b::1", "2002::1"}, 208 network.IPv6Address, 209 network.ScopePublic, 210 }, { 211 []string{"169.254.1.23", "169.254.1.1"}, 212 network.IPv4Address, 213 network.ScopeLinkLocal, 214 }, { 215 []string{"ff01::2", "ff01::1"}, 216 network.IPv6Address, 217 network.ScopeLinkLocal, 218 }, { 219 []string{"example.com", "example.org"}, 220 network.HostName, 221 network.ScopeUnknown, 222 }} 223 224 for i, test := range testAddresses { 225 c.Logf("test %d: %v -> %q", i, test.values, test.scope) 226 addresses := network.NewAddresses(test.values...) 227 c.Check(addresses, gc.HasLen, len(test.values)) 228 for j, addr := range addresses { 229 c.Check(addr.Value, gc.Equals, test.values[j]) 230 c.Check(addr.Type, gc.Equals, test.addrType) 231 c.Check(addr.Scope, gc.Equals, test.scope) 232 } 233 } 234 } 235 236 func (s *AddressSuite) TestNewScopedAddressHostname(c *gc.C) { 237 addr := network.NewScopedAddress("localhost", network.ScopeUnknown) 238 c.Check(addr.Value, gc.Equals, "localhost") 239 c.Check(addr.Type, gc.Equals, network.HostName) 240 c.Check(addr.Scope, gc.Equals, network.ScopeUnknown) 241 addr = network.NewScopedAddress("example.com", network.ScopeUnknown) 242 c.Check(addr.Value, gc.Equals, "example.com") 243 c.Check(addr.Type, gc.Equals, network.HostName) 244 c.Check(addr.Scope, gc.Equals, network.ScopeUnknown) 245 } 246 247 type selectTest struct { 248 about string 249 addresses []network.Address 250 expectedIndex int 251 preferIPv6 bool 252 } 253 254 // expected returns the expected address for the test. 255 func (t selectTest) expected() (network.Address, bool) { 256 if t.expectedIndex == -1 { 257 return network.Address{}, false 258 } 259 return t.addresses[t.expectedIndex], true 260 } 261 262 var selectPublicTests = []selectTest{{ 263 "no addresses gives empty string result", 264 []network.Address{}, 265 -1, 266 false, 267 }, { 268 "a public IPv4 address is selected", 269 []network.Address{ 270 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 271 }, 272 0, 273 false, 274 }, { 275 "a public IPv6 address is selected", 276 []network.Address{ 277 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 278 }, 279 0, 280 false, 281 }, { 282 "first public address is selected", 283 []network.Address{ 284 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 285 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 286 }, 287 0, 288 false, 289 }, { 290 "the first public address is selected when cloud local fallbacks exist", 291 []network.Address{ 292 network.NewScopedAddress("172.16.1.1", network.ScopeCloudLocal), 293 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 294 network.NewScopedAddress("fc00:1", network.ScopeCloudLocal), 295 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 296 }, 297 1, 298 false, 299 }, { 300 "IPv6 public address is preferred to a cloud local one when preferIPv6 is true", 301 []network.Address{ 302 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 303 network.NewScopedAddress("172.16.1.1", network.ScopeCloudLocal), 304 network.NewScopedAddress("fc00:1", network.ScopeCloudLocal), 305 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 306 }, 307 3, 308 true, 309 }, { 310 "a machine IPv4 local address is not selected", 311 []network.Address{ 312 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 313 }, 314 -1, 315 false, 316 }, { 317 "a machine IPv6 local address is not selected", 318 []network.Address{ 319 network.NewScopedAddress("::1", network.ScopeMachineLocal), 320 }, 321 -1, 322 false, 323 }, { 324 "a link-local IPv4 address is not selected", 325 []network.Address{ 326 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 327 }, 328 -1, 329 false, 330 }, { 331 "a link-local (multicast or not) IPv6 address is not selected", 332 []network.Address{ 333 network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 334 network.NewScopedAddress("ff01::2", network.ScopeLinkLocal), 335 network.NewScopedAddress("ff02::1:1", network.ScopeLinkLocal), 336 }, 337 -1, 338 false, 339 }, { 340 "a public name is preferred to an unknown or cloud local address", 341 []network.Address{ 342 network.NewScopedAddress("127.0.0.1", network.ScopeUnknown), 343 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 344 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 345 network.NewScopedAddress("public.invalid.testing", network.ScopePublic), 346 }, 347 3, 348 false, 349 }, { 350 "first unknown address selected", 351 // NOTE(dimitern): Not using NewScopedAddress() below as it derives the 352 // scope internally from the value when given ScopeUnknown. 353 []network.Address{ 354 {Value: "10.0.0.1", Scope: network.ScopeUnknown}, 355 {Value: "8.8.8.8", Scope: network.ScopeUnknown}, 356 }, 357 0, 358 false, 359 }, { 360 "first public address is picked when both public IPs and public hostnames exist", 361 []network.Address{ 362 network.NewScopedAddress("10.0.0.1", network.ScopeUnknown), 363 network.NewScopedAddress("example.com", network.ScopePublic), 364 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 365 }, 366 1, 367 false, 368 }, { 369 "first public IPv6 address is picked when both public IPs and public hostnames exist when preferIPv6 is true", 370 []network.Address{ 371 network.NewScopedAddress("10.0.0.1", network.ScopeUnknown), 372 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 373 network.NewScopedAddress("example.com", network.ScopePublic), 374 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 375 }, 376 3, 377 true, 378 }} 379 380 func (s *AddressSuite) TestSelectPublicAddress(c *gc.C) { 381 oldValue := network.PreferIPv6() 382 defer func() { 383 network.SetPreferIPv6(oldValue) 384 }() 385 for i, t := range selectPublicTests { 386 c.Logf("test %d: %s", i, t.about) 387 network.SetPreferIPv6(t.preferIPv6) 388 expectAddr, expectOK := t.expected() 389 actualAddr, actualOK := network.SelectPublicAddress(t.addresses) 390 c.Check(actualOK, gc.Equals, expectOK) 391 c.Check(actualAddr, gc.Equals, expectAddr) 392 } 393 } 394 395 var selectInternalTests = []selectTest{{ 396 "no addresses gives empty string result", 397 []network.Address{}, 398 -1, 399 false, 400 }, { 401 "a public IPv4 address is selected", 402 []network.Address{ 403 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 404 }, 405 0, 406 false, 407 }, { 408 "a public IPv6 address is selected", 409 []network.Address{ 410 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 411 }, 412 0, 413 false, 414 }, { 415 "a public IPv6 address is selected when both IPv4 and IPv6 addresses exist and preferIPv6 is true", 416 []network.Address{ 417 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 418 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 419 }, 420 1, 421 true, 422 }, { 423 "the first public IPv4 address is selected when preferIPv6 is true and no IPv6 addresses", 424 []network.Address{ 425 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 426 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 427 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 428 network.NewScopedAddress("8.8.4.4", network.ScopePublic), 429 }, 430 1, 431 true, 432 }, { 433 "a cloud local IPv4 address is selected", 434 []network.Address{ 435 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 436 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 437 }, 438 1, 439 false, 440 }, { 441 "a cloud local IPv6 address is selected", 442 []network.Address{ 443 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 444 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 445 }, 446 0, 447 false, 448 }, { 449 "a machine local or link-local address is not selected", 450 []network.Address{ 451 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 452 network.NewScopedAddress("::1", network.ScopeMachineLocal), 453 network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 454 }, 455 -1, 456 false, 457 }, { 458 "a cloud local address is preferred to a public address", 459 []network.Address{ 460 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 461 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 462 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 463 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 464 }, 465 1, 466 false, 467 }, { 468 "an IPv6 cloud local address is preferred to a public address when preferIPv6 is true", 469 []network.Address{ 470 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 471 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 472 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 473 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 474 }, 475 2, 476 false, 477 }} 478 479 func (s *AddressSuite) TestSelectInternalAddress(c *gc.C) { 480 oldValue := network.PreferIPv6() 481 defer func() { 482 network.SetPreferIPv6(oldValue) 483 }() 484 for i, t := range selectInternalTests { 485 c.Logf("test %d: %s", i, t.about) 486 network.SetPreferIPv6(t.preferIPv6) 487 expectAddr, expectOK := t.expected() 488 actualAddr, actualOK := network.SelectInternalAddress(t.addresses, false) 489 c.Check(actualOK, gc.Equals, expectOK) 490 c.Check(actualAddr, gc.Equals, expectAddr) 491 } 492 } 493 494 var selectInternalMachineTests = []selectTest{{ 495 "first cloud local address is selected", 496 []network.Address{ 497 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 498 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 499 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 500 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 501 }, 502 0, 503 false, 504 }, { 505 "first cloud local hostname is selected when preferIPv6 is false", 506 []network.Address{ 507 network.NewScopedAddress("example.com", network.ScopePublic), 508 network.NewScopedAddress("cloud1.internal", network.ScopeCloudLocal), 509 network.NewScopedAddress("cloud2.internal", network.ScopeCloudLocal), 510 network.NewScopedAddress("example.org", network.ScopePublic), 511 }, 512 1, 513 false, 514 }, { 515 "first cloud local hostname is selected when preferIPv6 is true (public first)", 516 []network.Address{ 517 network.NewScopedAddress("example.org", network.ScopePublic), 518 network.NewScopedAddress("example.com", network.ScopePublic), 519 network.NewScopedAddress("cloud1.internal", network.ScopeCloudLocal), 520 network.NewScopedAddress("cloud2.internal", network.ScopeCloudLocal), 521 }, 522 2, 523 true, 524 }, { 525 "first cloud local hostname is selected when preferIPv6 is true (public last)", 526 []network.Address{ 527 network.NewScopedAddress("cloud1.internal", network.ScopeCloudLocal), 528 network.NewScopedAddress("cloud2.internal", network.ScopeCloudLocal), 529 network.NewScopedAddress("example.org", network.ScopePublic), 530 network.NewScopedAddress("example.com", network.ScopePublic), 531 }, 532 0, 533 true, 534 }, { 535 "first IPv6 cloud local address is selected when preferIPv6 is true", 536 []network.Address{ 537 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 538 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 539 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 540 network.NewScopedAddress("2001:db8::1", network.ScopePublic), 541 }, 542 2, 543 true, 544 }, { 545 "first IPv4 cloud local address is selected when preferIPv6 is true and no IPv6 addresses", 546 []network.Address{ 547 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 548 network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 549 network.NewScopedAddress("172.16.1.1", network.ScopeCloudLocal), 550 }, 551 1, 552 true, 553 }, { 554 "first machine local address is selected", 555 []network.Address{ 556 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 557 network.NewScopedAddress("::1", network.ScopeMachineLocal), 558 }, 559 0, 560 false, 561 }, { 562 "first IPv6 machine local address is selected when preferIPv6 is true", 563 []network.Address{ 564 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 565 network.NewScopedAddress("::1", network.ScopeMachineLocal), 566 network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 567 }, 568 1, 569 true, 570 }, { 571 "first IPv4 machine local address is selected when preferIPv6 is true and no IPv6 addresses", 572 []network.Address{ 573 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 574 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 575 network.NewScopedAddress("127.0.0.2", network.ScopeMachineLocal), 576 }, 577 1, 578 true, 579 }, { 580 "first machine local address is selected when preferIPv6 is false even with public/cloud hostnames", 581 []network.Address{ 582 network.NewScopedAddress("public.example.com", network.ScopePublic), 583 network.NewScopedAddress("::1", network.ScopeMachineLocal), 584 network.NewScopedAddress("unknown.example.com", network.ScopeUnknown), 585 network.NewScopedAddress("cloud.internal", network.ScopeCloudLocal), 586 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 587 network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 588 network.NewScopedAddress("127.0.0.2", network.ScopeMachineLocal), 589 }, 590 1, 591 false, 592 }, { 593 "first cloud local hostname is selected when preferIPv6 is false even with other machine/cloud addresses", 594 []network.Address{ 595 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 596 network.NewScopedAddress("cloud-unknown.internal", network.ScopeUnknown), 597 network.NewScopedAddress("cloud-local.internal", network.ScopeCloudLocal), 598 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 599 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 600 network.NewScopedAddress("127.0.0.2", network.ScopeMachineLocal), 601 }, 602 2, 603 false, 604 }, { 605 "first IPv6 machine local address is selected when preferIPv6 is true even with public/cloud hostnames", 606 []network.Address{ 607 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 608 network.NewScopedAddress("public.example.com", network.ScopePublic), 609 network.NewScopedAddress("unknown.example.com", network.ScopeUnknown), 610 network.NewScopedAddress("cloud.internal", network.ScopeCloudLocal), 611 network.NewScopedAddress("::1", network.ScopeMachineLocal), 612 network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 613 }, 614 4, 615 true, 616 }, { 617 "first IPv6 cloud local address is selected when preferIPv6 is true even with cloud local hostnames", 618 []network.Address{ 619 network.NewScopedAddress("169.254.1.1", network.ScopeLinkLocal), 620 network.NewScopedAddress("cloud-unknown.internal", network.ScopeUnknown), 621 network.NewScopedAddress("cloud-local.internal", network.ScopeCloudLocal), 622 network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 623 network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 624 network.NewScopedAddress("fc00::2", network.ScopeCloudLocal), 625 network.NewScopedAddress("127.0.0.2", network.ScopeMachineLocal), 626 }, 627 3, 628 true, 629 }} 630 631 func (s *AddressSuite) TestSelectInternalMachineAddress(c *gc.C) { 632 oldValue := network.PreferIPv6() 633 defer func() { 634 network.SetPreferIPv6(oldValue) 635 }() 636 for i, t := range selectInternalMachineTests { 637 c.Logf("test %d: %s", i, t.about) 638 network.SetPreferIPv6(t.preferIPv6) 639 expectAddr, expectOK := t.expected() 640 actualAddr, actualOK := network.SelectInternalAddress(t.addresses, true) 641 c.Check(actualOK, gc.Equals, expectOK) 642 c.Check(actualAddr, gc.Equals, expectAddr) 643 } 644 } 645 646 type selectInternalHostPortsTest struct { 647 about string 648 addresses []network.HostPort 649 expected []string 650 preferIPv6 bool 651 } 652 653 var selectInternalHostPortsTests = []selectInternalHostPortsTest{{ 654 "no addresses gives empty string result", 655 []network.HostPort{}, 656 []string{}, 657 false, 658 }, { 659 "a public IPv4 address is selected", 660 []network.HostPort{ 661 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 9999}, 662 }, 663 []string{"8.8.8.8:9999"}, 664 false, 665 }, { 666 "public IPv6 addresses selected when both IPv4 and IPv6 addresses exist and preferIPv6 is true", 667 []network.HostPort{ 668 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 9999}, 669 {network.NewScopedAddress("2001:db8::1", network.ScopePublic), 8888}, 670 {network.NewScopedAddress("2002:db8::1", network.ScopePublic), 9999}, 671 }, 672 []string{"[2001:db8::1]:8888", "[2002:db8::1]:9999"}, 673 true, 674 }, { 675 "a cloud local IPv4 addresses are selected", 676 []network.HostPort{ 677 {network.NewScopedAddress("10.1.0.1", network.ScopeCloudLocal), 8888}, 678 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 679 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 1234}, 680 }, 681 []string{"10.1.0.1:8888", "10.0.0.1:1234"}, 682 false, 683 }, { 684 "a machine local or link-local address is not selected", 685 []network.HostPort{ 686 {network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 111}, 687 {network.NewScopedAddress("::1", network.ScopeMachineLocal), 222}, 688 {network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 333}, 689 }, 690 []string{}, 691 false, 692 }, { 693 "cloud local addresses are preferred to a public addresses", 694 []network.HostPort{ 695 {network.NewScopedAddress("2001:db8::1", network.ScopePublic), 123}, 696 {network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 123}, 697 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 698 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 4444}, 699 }, 700 []string{"[fc00::1]:123", "10.0.0.1:4444"}, 701 false, 702 }, { 703 "IPv4 addresses are used when prefer-IPv6 is set but no IPv6 addresses are available", 704 []network.HostPort{ 705 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 706 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 4444}, 707 }, 708 []string{"10.0.0.1:4444"}, 709 true, 710 }} 711 712 func (s *AddressSuite) TestSelectInternalHostPorts(c *gc.C) { 713 oldValue := network.PreferIPv6() 714 defer func() { 715 network.SetPreferIPv6(oldValue) 716 }() 717 for i, t := range selectInternalHostPortsTests { 718 c.Logf("test %d: %s", i, t.about) 719 network.SetPreferIPv6(t.preferIPv6) 720 c.Check(network.SelectInternalHostPorts(t.addresses, false), gc.DeepEquals, t.expected) 721 } 722 } 723 724 var prioritizeInternalHostPortsTests = []selectInternalHostPortsTest{{ 725 "no addresses gives empty string result", 726 []network.HostPort{}, 727 []string{}, 728 false, 729 }, { 730 "a public IPv4 address is selected", 731 []network.HostPort{ 732 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 9999}, 733 }, 734 []string{"8.8.8.8:9999"}, 735 false, 736 }, { 737 "public IPv6 addresses selected when both IPv4 and IPv6 addresses exist and preferIPv6 is true", 738 []network.HostPort{ 739 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 9999}, 740 {network.NewScopedAddress("2001:db8::1", network.ScopePublic), 8888}, 741 {network.NewScopedAddress("2002:db8::1", network.ScopePublic), 9999}, 742 }, 743 []string{"[2001:db8::1]:8888", "[2002:db8::1]:9999", "8.8.8.8:9999"}, 744 true, 745 }, { 746 "a cloud local IPv4 addresses are selected", 747 []network.HostPort{ 748 {network.NewScopedAddress("10.1.0.1", network.ScopeCloudLocal), 8888}, 749 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 750 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 1234}, 751 }, 752 []string{"10.1.0.1:8888", "10.0.0.1:1234", "8.8.8.8:123"}, 753 false, 754 }, { 755 "a machine local or link-local address is not selected", 756 []network.HostPort{ 757 {network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal), 111}, 758 {network.NewScopedAddress("::1", network.ScopeMachineLocal), 222}, 759 {network.NewScopedAddress("fe80::1", network.ScopeLinkLocal), 333}, 760 }, 761 []string{}, 762 false, 763 }, { 764 "cloud local addresses are preferred to a public addresses", 765 []network.HostPort{ 766 {network.NewScopedAddress("2001:db8::1", network.ScopePublic), 123}, 767 {network.NewScopedAddress("fc00::1", network.ScopeCloudLocal), 123}, 768 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 769 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 4444}, 770 }, 771 []string{"[fc00::1]:123", "10.0.0.1:4444", "[2001:db8::1]:123", "8.8.8.8:123"}, 772 false, 773 }, { 774 "IPv4 addresses are used when prefer-IPv6 is set but no IPv6 addresses are available", 775 []network.HostPort{ 776 {network.NewScopedAddress("8.8.8.8", network.ScopePublic), 123}, 777 {network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal), 4444}, 778 }, 779 []string{"10.0.0.1:4444", "8.8.8.8:123"}, 780 true, 781 }} 782 783 func (s *AddressSuite) TestPrioritizeInternalHostPorts(c *gc.C) { 784 oldValue := network.PreferIPv6() 785 defer func() { 786 network.SetPreferIPv6(oldValue) 787 }() 788 for i, t := range prioritizeInternalHostPortsTests { 789 c.Logf("test %d: %s", i, t.about) 790 network.SetPreferIPv6(t.preferIPv6) 791 prioritized := network.PrioritizeInternalHostPorts(t.addresses, false) 792 c.Check(prioritized, gc.DeepEquals, t.expected) 793 } 794 } 795 796 var stringTests = []struct { 797 addr network.Address 798 str string 799 }{{ 800 addr: network.Address{ 801 Type: network.IPv4Address, 802 Value: "127.0.0.1", 803 }, 804 str: "127.0.0.1", 805 }, { 806 addr: network.Address{ 807 Type: network.IPv4Address, 808 Value: "127.0.0.1", 809 SpaceName: "storage-data", 810 }, 811 str: "127.0.0.1@storage-data", 812 }, { 813 addr: network.Address{ 814 Type: network.IPv6Address, 815 Value: "2001:db8::1", 816 Scope: network.ScopePublic, 817 }, 818 str: "public:2001:db8::1", 819 }, { 820 addr: network.Address{ 821 Type: network.HostName, 822 Value: "foo.com", 823 }, 824 str: "foo.com", 825 }, { 826 addr: network.Address{ 827 Type: network.HostName, 828 Value: "foo.com", 829 Scope: network.ScopeUnknown, 830 }, 831 str: "foo.com", 832 }, { 833 addr: network.Address{ 834 Type: network.HostName, 835 Value: "foo.com", 836 Scope: network.ScopePublic, 837 SpaceProviderId: network.Id("3"), 838 }, 839 str: "public:foo.com@(id:3)", 840 }, { 841 addr: network.Address{ 842 Type: network.HostName, 843 Value: "foo.com", 844 Scope: network.ScopePublic, 845 SpaceName: "default", 846 }, 847 str: "public:foo.com@default", 848 }, { 849 addr: network.Address{ 850 Type: network.HostName, 851 Value: "foo.com", 852 Scope: network.ScopePublic, 853 SpaceName: "badlands", 854 SpaceProviderId: network.Id("3"), 855 }, 856 str: "public:foo.com@badlands(id:3)", 857 }} 858 859 func (s *AddressSuite) TestString(c *gc.C) { 860 for i, test := range stringTests { 861 c.Logf("test %d: %#v", i, test.addr) 862 c.Check(test.addr.String(), gc.Equals, test.str) 863 c.Check(test.addr.GoString(), gc.Equals, test.str) 864 } 865 } 866 867 func (*AddressSuite) TestSortAddresses(c *gc.C) { 868 addrs := network.NewAddresses( 869 "127.0.0.1", 870 "::1", 871 "fc00::1", 872 "169.254.1.2", 873 "localhost", 874 "2001:db8::1", 875 "fe80::2", 876 "7.8.8.8", 877 "172.16.0.1", 878 "example.com", 879 "8.8.8.8", 880 ) 881 // Simulate prefer-ipv6: false first. 882 network.SortAddresses(addrs, false) 883 c.Assert(addrs, jc.DeepEquals, network.NewAddresses( 884 // Public IPv4 addresses on top. 885 "7.8.8.8", 886 "8.8.8.8", 887 // After that public IPv6 addresses. 888 "2001:db8::1", 889 // Then hostnames. 890 "example.com", 891 "localhost", 892 // Then IPv4 cloud-local addresses. 893 "172.16.0.1", 894 // Then IPv6 cloud-local addresses. 895 "fc00::1", 896 // Then machine-local IPv4 addresses. 897 "127.0.0.1", 898 // Then machine-local IPv6 addresses. 899 "::1", 900 // Then link-local IPv4 addresses. 901 "169.254.1.2", 902 // Finally, link-local IPv6 addresses. 903 "fe80::2", 904 )) 905 906 // Now, simulate prefer-ipv6: true. 907 network.SortAddresses(addrs, true) 908 c.Assert(addrs, jc.DeepEquals, network.NewAddresses( 909 // Public IPv6 addresses on top. 910 "2001:db8::1", 911 // After that public IPv4 addresses. 912 "7.8.8.8", 913 "8.8.8.8", 914 // Then hostnames. 915 "example.com", 916 "localhost", 917 // Then IPv6 cloud-local addresses. 918 "fc00::1", 919 // Then IPv4 cloud-local addresses. 920 "172.16.0.1", 921 // Then machine-local IPv6 addresses. 922 "::1", 923 // Then machine-local IPv4 addresses. 924 "127.0.0.1", 925 // Then link-local IPv6 addresses. 926 "fe80::2", 927 // Finally, link-local IPv4 addresses. 928 "169.254.1.2", 929 )) 930 } 931 932 func (*AddressSuite) TestIPv4ToDecimal(c *gc.C) { 933 zeroIP, err := network.IPv4ToDecimal(net.ParseIP("0.0.0.0")) 934 c.Assert(err, jc.ErrorIsNil) 935 c.Assert(zeroIP, gc.Equals, uint32(0)) 936 937 nilIP := net.ParseIP("bad format") 938 _, err = network.IPv4ToDecimal(nilIP) 939 c.Assert(err, gc.ErrorMatches, `"<nil>" is not a valid IPv4 address`) 940 941 _, err = network.IPv4ToDecimal(net.ParseIP("2001:db8::1")) 942 c.Assert(err, gc.ErrorMatches, `"2001:db8::1" is not a valid IPv4 address`) 943 944 nonZeroIP, err := network.IPv4ToDecimal(net.ParseIP("192.168.1.1")) 945 c.Assert(err, jc.ErrorIsNil) 946 c.Assert(nonZeroIP, gc.Equals, uint32(3232235777)) 947 } 948 949 func (*AddressSuite) TestDecimalToIPv4(c *gc.C) { 950 addr := network.DecimalToIPv4(uint32(0)) 951 c.Assert(addr.String(), gc.Equals, "0.0.0.0") 952 953 addr = network.DecimalToIPv4(uint32(3232235777)) 954 c.Assert(addr.String(), gc.Equals, "192.168.1.1") 955 } 956 957 func (*AddressSuite) TestExactScopeMatch(c *gc.C) { 958 network.SetPreferIPv6(false) 959 addr := network.NewScopedAddress("10.0.0.2", network.ScopeCloudLocal) 960 match := network.ExactScopeMatch(addr, network.ScopeCloudLocal) 961 c.Assert(match, jc.IsTrue) 962 match = network.ExactScopeMatch(addr, network.ScopePublic) 963 c.Assert(match, jc.IsFalse) 964 965 addr = network.NewScopedAddress("8.8.8.8", network.ScopePublic) 966 match = network.ExactScopeMatch(addr, network.ScopeCloudLocal) 967 c.Assert(match, jc.IsFalse) 968 match = network.ExactScopeMatch(addr, network.ScopePublic) 969 c.Assert(match, jc.IsTrue) 970 } 971 972 func (*AddressSuite) TestExactScopeMatchHonoursPreferIPv6(c *gc.C) { 973 network.SetPreferIPv6(true) 974 addr := network.NewScopedAddress("10.0.0.2", network.ScopeCloudLocal) 975 match := network.ExactScopeMatch(addr, network.ScopeCloudLocal) 976 c.Assert(match, jc.IsFalse) 977 match = network.ExactScopeMatch(addr, network.ScopePublic) 978 c.Assert(match, jc.IsFalse) 979 980 addr = network.NewScopedAddress("8.8.8.8", network.ScopePublic) 981 match = network.ExactScopeMatch(addr, network.ScopeCloudLocal) 982 c.Assert(match, jc.IsFalse) 983 match = network.ExactScopeMatch(addr, network.ScopePublic) 984 c.Assert(match, jc.IsFalse) 985 986 addr = network.NewScopedAddress("2001:db8::ff00:42:8329", network.ScopePublic) 987 match = network.ExactScopeMatch(addr, network.ScopeCloudLocal) 988 c.Assert(match, jc.IsFalse) 989 match = network.ExactScopeMatch(addr, network.ScopePublic) 990 c.Assert(match, jc.IsTrue) 991 992 addr = network.NewScopedAddress("fc00::1", network.ScopeCloudLocal) 993 match = network.ExactScopeMatch(addr, network.ScopeCloudLocal) 994 c.Assert(match, jc.IsTrue) 995 match = network.ExactScopeMatch(addr, network.ScopePublic) 996 c.Assert(match, jc.IsFalse) 997 } 998 999 func (s *AddressSuite) TestResolvableHostnames(c *gc.C) { 1000 seq := 0 1001 1002 s.PatchValue(network.NetLookupIP, func(host string) ([]net.IP, error) { 1003 if host == "not-resolvable.com" { 1004 return nil, errors.New("no such host") 1005 } 1006 seq++ 1007 return []net.IP{net.ParseIP(fmt.Sprintf("1.1.1.%d", seq))}, nil 1008 }) 1009 1010 // Test empty input yields empty output. 1011 empty := []network.Address{} 1012 c.Assert(empty, jc.DeepEquals, network.ResolvableHostnames(empty)) 1013 1014 // Test unresolvable inputs yields empty output. 1015 unresolvable := []network.Address{{Value: "not-resolvable.com", Type: network.HostName}} 1016 c.Assert(empty, jc.DeepEquals, network.ResolvableHostnames(unresolvable)) 1017 1018 // Test resolvable inputs yields identical outputs. 1019 resolvable := []network.Address{{Value: "localhost", Type: network.HostName}} 1020 c.Assert(resolvable, jc.DeepEquals, network.ResolvableHostnames(resolvable)) 1021 1022 unscopedAddrs := []network.Address{ 1023 network.NewAddress("localhost"), 1024 network.NewAddress("127.0.0.1"), 1025 network.NewAddress("fe80::d806:dbff:fe23:1199"), 1026 network.NewAddress("not-resolvable.com"), 1027 network.NewAddress("not-resolvable.com"), 1028 network.NewAddress("fe80::1"), 1029 network.NewAddress("resolvable.com"), 1030 network.NewAddress("localhost"), 1031 network.NewAddress("resolvable.com"), 1032 network.NewAddress("ubuntu.com"), 1033 } 1034 1035 unscopedAddrsExpected := []network.Address{ 1036 unscopedAddrs[0], unscopedAddrs[1], 1037 unscopedAddrs[2], unscopedAddrs[5], 1038 unscopedAddrs[6], unscopedAddrs[7], 1039 unscopedAddrs[8], unscopedAddrs[9], 1040 } 1041 1042 c.Assert(unscopedAddrsExpected, jc.DeepEquals, network.ResolvableHostnames(unscopedAddrs)) 1043 1044 // Test multiple inputs have their order preserved, that 1045 // duplicates are preserved but unresolvable hostnames (except 1046 // 'localhost') are removed. 1047 scopedAddrs := []network.Address{ 1048 network.NewScopedAddress("172.16.1.1", network.ScopeCloudLocal), 1049 network.NewScopedAddress("not-resolvable.com", network.ScopePublic), 1050 network.NewScopedAddress("8.8.8.8", network.ScopePublic), 1051 network.NewScopedAddress("resolvable.com", network.ScopePublic), 1052 network.NewScopedAddress("fc00:1", network.ScopeCloudLocal), 1053 network.NewScopedAddress("localhost", network.ScopePublic), 1054 network.NewScopedAddress("192.168.1.1", network.ScopeCloudLocal), 1055 network.NewScopedAddress("localhost", network.ScopeCloudLocal), 1056 network.NewScopedAddress("not-resolvable.com", network.ScopePublic), 1057 network.NewScopedAddress("resolvable.com", network.ScopePublic), 1058 } 1059 1060 scopedAddrsExpected := []network.Address{ 1061 scopedAddrs[0], scopedAddrs[2], scopedAddrs[3], scopedAddrs[4], 1062 scopedAddrs[5], scopedAddrs[6], scopedAddrs[7], scopedAddrs[9], 1063 } 1064 1065 c.Assert(scopedAddrsExpected, jc.DeepEquals, network.ResolvableHostnames(scopedAddrs)) 1066 }