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  }