github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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  	"net"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/network"
    13  	"github.com/juju/juju/testing"
    14  )
    15  
    16  type AddressSuite struct {
    17  	testing.BaseSuite
    18  }
    19  
    20  var _ = gc.Suite(&AddressSuite{})
    21  
    22  func (s *AddressSuite) TestNewScopedAddressIPv4(c *gc.C) {
    23  	type test struct {
    24  		value         string
    25  		scope         network.Scope
    26  		expectedScope network.Scope
    27  	}
    28  
    29  	tests := []test{{
    30  		value:         "127.0.0.1",
    31  		scope:         network.ScopeUnknown,
    32  		expectedScope: network.ScopeMachineLocal,
    33  	}, {
    34  		value:         "127.0.0.1",
    35  		scope:         network.ScopePublic,
    36  		expectedScope: network.ScopePublic, // don't second guess != Unknown
    37  	}, {
    38  		value:         "10.0.3.1",
    39  		scope:         network.ScopeUnknown,
    40  		expectedScope: network.ScopeCloudLocal,
    41  	}, {
    42  		value:         "172.16.15.14",
    43  		scope:         network.ScopeUnknown,
    44  		expectedScope: network.ScopeCloudLocal,
    45  	}, {
    46  		value:         "192.168.0.1",
    47  		scope:         network.ScopeUnknown,
    48  		expectedScope: network.ScopeCloudLocal,
    49  	}, {
    50  		value:         "169.254.1.1",
    51  		scope:         network.ScopeUnknown,
    52  		expectedScope: network.ScopeLinkLocal,
    53  	}, {
    54  		value:         "8.8.8.8",
    55  		scope:         network.ScopeUnknown,
    56  		expectedScope: network.ScopePublic,
    57  	}}
    58  
    59  	for i, t := range tests {
    60  		c.Logf("test %d: %s %s", i, t.value, t.scope)
    61  		addr := network.NewScopedAddress(t.value, t.scope)
    62  		c.Check(addr.Value, gc.Equals, t.value)
    63  		c.Check(addr.Type, gc.Equals, network.IPv4Address)
    64  		c.Check(addr.Scope, gc.Equals, t.expectedScope)
    65  	}
    66  }
    67  
    68  func (s *AddressSuite) TestNewScopedAddressIPv6(c *gc.C) {
    69  	// Examples below taken from
    70  	// http://en.wikipedia.org/wiki/IPv6_address
    71  	testAddresses := []struct {
    72  		value string
    73  		scope network.Scope
    74  	}{
    75  		// IPv6 loopback address
    76  		{"::1", network.ScopeMachineLocal},
    77  		// used documentation examples
    78  		{"2001:db8::1", network.ScopePublic},
    79  		// link-local
    80  		{"fe80::1", network.ScopeLinkLocal},
    81  		// unique local address (ULA) - first group
    82  		{"fc00::1", network.ScopeCloudLocal},
    83  		// unique local address (ULA) - second group
    84  		{"fd00::1", network.ScopeCloudLocal},
    85  		// IPv4-mapped IPv6 address
    86  		{"::ffff:0:0:1", network.ScopePublic},
    87  		// IPv4-translated IPv6 address (SIIT)
    88  		{"::ffff:0:0:0:1", network.ScopePublic},
    89  		// "well-known" prefix for IPv4/IPv6 auto translation
    90  		{"64:ff9b::1", network.ScopePublic},
    91  		// used for 6to4 addressing
    92  		{"2002::1", network.ScopePublic},
    93  		// used for Teredo tunneling
    94  		{"2001::1", network.ScopePublic},
    95  		// used for IPv6 benchmarking
    96  		{"2001:2::1", network.ScopePublic},
    97  		// used for cryptographic hash identifiers
    98  		{"2001:10::1", network.ScopePublic},
    99  		// interface-local multicast (all nodes)
   100  		{"ff01::1", network.ScopeLinkLocal},
   101  		// link-local multicast (all nodes)
   102  		{"ff02::1", network.ScopeLinkLocal},
   103  		// interface-local multicast (all routers)
   104  		{"ff01::2", network.ScopeLinkLocal},
   105  		// link-local multicast (all routers)
   106  		{"ff02::2", network.ScopeLinkLocal},
   107  	}
   108  	for i, test := range testAddresses {
   109  		c.Logf("test %d: %q -> %q", i, test.value, test.scope)
   110  		addr := network.NewScopedAddress(test.value, network.ScopeUnknown)
   111  		c.Check(addr.Value, gc.Equals, test.value)
   112  		c.Check(addr.Type, gc.Equals, network.IPv6Address)
   113  		c.Check(addr.Scope, gc.Equals, test.scope)
   114  	}
   115  }
   116  
   117  func (s *AddressSuite) TestNewAddressIPv4(c *gc.C) {
   118  	value := "0.1.2.3"
   119  	addr1 := network.NewScopedAddress(value, network.ScopeUnknown)
   120  	addr2 := network.NewAddress(value)
   121  	addr3 := network.NewScopedAddress(value, network.ScopeLinkLocal)
   122  	// NewAddress behaves exactly like NewScopedAddress with ScopeUnknown
   123  	c.Assert(addr1, jc.DeepEquals, addr2)
   124  	c.Assert(addr2.Scope, gc.Equals, network.ScopePublic) // derived from value
   125  	c.Assert(addr2.Value, gc.Equals, value)
   126  	c.Assert(addr2.Type, gc.Equals, network.IPv4Address)
   127  	c.Assert(addr2.Scope, gc.Not(gc.Equals), addr3.Scope) // different scope
   128  	c.Assert(addr3.Scope, gc.Equals, network.ScopeLinkLocal)
   129  }
   130  
   131  func (s *AddressSuite) TestNewAddressIPv6(c *gc.C) {
   132  	value := "2001:db8::1"
   133  	addr1 := network.NewScopedAddress(value, network.ScopeUnknown)
   134  	addr2 := network.NewAddress(value)
   135  	addr3 := network.NewScopedAddress(value, network.ScopeLinkLocal)
   136  	// NewAddress behaves exactly like NewScopedAddress with ScopeUnknown
   137  	c.Assert(addr1, jc.DeepEquals, addr2)
   138  	c.Assert(addr2.Scope, gc.Equals, network.ScopePublic) // derived from value
   139  	c.Assert(addr2.Value, gc.Equals, value)
   140  	c.Assert(addr2.Type, gc.Equals, network.IPv6Address)
   141  	c.Assert(addr2.Scope, gc.Not(gc.Equals), addr3.Scope) // different scope
   142  	c.Assert(addr3.Scope, gc.Equals, network.ScopeLinkLocal)
   143  }
   144  
   145  func (s *AddressSuite) TestNewAddresses(c *gc.C) {
   146  	testAddresses := []struct {
   147  		values   []string
   148  		addrType network.AddressType
   149  		scope    network.Scope
   150  	}{{
   151  		[]string{"127.0.0.1", "127.0.1.2"},
   152  		network.IPv4Address,
   153  		network.ScopeMachineLocal,
   154  	}, {
   155  		[]string{"::1"},
   156  		network.IPv6Address,
   157  		network.ScopeMachineLocal,
   158  	}, {
   159  		[]string{"192.168.1.1", "192.168.178.255", "10.5.1.1", "172.16.1.1"},
   160  		network.IPv4Address,
   161  		network.ScopeCloudLocal,
   162  	}, {
   163  		[]string{"fc00::1", "fd00::2"},
   164  		network.IPv6Address,
   165  		network.ScopeCloudLocal,
   166  	}, {
   167  		[]string{"8.8.8.8", "8.8.4.4"},
   168  		network.IPv4Address,
   169  		network.ScopePublic,
   170  	}, {
   171  		[]string{"2001:db8::1", "64:ff9b::1", "2002::1"},
   172  		network.IPv6Address,
   173  		network.ScopePublic,
   174  	}, {
   175  		[]string{"169.254.1.23", "169.254.1.1"},
   176  		network.IPv4Address,
   177  		network.ScopeLinkLocal,
   178  	}, {
   179  		[]string{"ff01::2", "ff01::1"},
   180  		network.IPv6Address,
   181  		network.ScopeLinkLocal,
   182  	}, {
   183  		[]string{"example.com", "example.org"},
   184  		network.HostName,
   185  		network.ScopeUnknown,
   186  	}}
   187  
   188  	for i, test := range testAddresses {
   189  		c.Logf("test %d: %v -> %q", i, test.values, test.scope)
   190  		addresses := network.NewAddresses(test.values...)
   191  		c.Check(addresses, gc.HasLen, len(test.values))
   192  		for j, addr := range addresses {
   193  			c.Check(addr.Value, gc.Equals, test.values[j])
   194  			c.Check(addr.Type, gc.Equals, test.addrType)
   195  			c.Check(addr.Scope, gc.Equals, test.scope)
   196  		}
   197  	}
   198  }
   199  
   200  func (s *AddressSuite) TestNewScopedAddressHostname(c *gc.C) {
   201  	addr := network.NewScopedAddress("localhost", network.ScopeUnknown)
   202  	c.Check(addr.Value, gc.Equals, "localhost")
   203  	c.Check(addr.Type, gc.Equals, network.HostName)
   204  	c.Check(addr.Scope, gc.Equals, network.ScopeUnknown)
   205  	addr = network.NewScopedAddress("example.com", network.ScopeUnknown)
   206  	c.Check(addr.Value, gc.Equals, "example.com")
   207  	c.Check(addr.Type, gc.Equals, network.HostName)
   208  	c.Check(addr.Scope, gc.Equals, network.ScopeUnknown)
   209  }
   210  
   211  type selectTest struct {
   212  	about         string
   213  	addresses     []network.Address
   214  	expectedIndex int
   215  	preferIPv6    bool
   216  }
   217  
   218  // expected returns the expected address for the test.
   219  func (t selectTest) expected() (network.Address, bool) {
   220  	if t.expectedIndex == -1 {
   221  		return network.Address{}, false
   222  	}
   223  	return t.addresses[t.expectedIndex], true
   224  }
   225  
   226  var selectPublicTests = []selectTest{{
   227  	"no addresses gives empty string result",
   228  	[]network.Address{},
   229  	-1,
   230  	false,
   231  }, {
   232  	"a public IPv4 address is selected",
   233  	[]network.Address{
   234  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   235  	},
   236  	0,
   237  	false,
   238  }, {
   239  	"a public IPv6 address is selected",
   240  	[]network.Address{
   241  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   242  	},
   243  	0,
   244  	false,
   245  }, {
   246  	"first public address is selected",
   247  	[]network.Address{
   248  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   249  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   250  	},
   251  	0,
   252  	false,
   253  }, {
   254  	"the first public address is selected when cloud local fallbacks exist",
   255  	[]network.Address{
   256  		{"172.16.1.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   257  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   258  		{"fc00:1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   259  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   260  	},
   261  	1,
   262  	false,
   263  }, {
   264  	"IPv6 public address is preferred to a cloud local one when preferIPv6 is true",
   265  	[]network.Address{
   266  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   267  		{"172.16.1.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   268  		{"fc00:1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   269  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   270  	},
   271  	3,
   272  	true,
   273  }, {
   274  	"a machine IPv4 local address is not selected",
   275  	[]network.Address{
   276  		{"127.0.0.1", network.IPv4Address, "machine", network.ScopeMachineLocal},
   277  	},
   278  	-1,
   279  	false,
   280  }, {
   281  	"a machine IPv6 local address is not selected",
   282  	[]network.Address{
   283  		{"::1", network.IPv6Address, "machine", network.ScopeMachineLocal},
   284  	},
   285  	-1,
   286  	false,
   287  }, {
   288  	"a link-local IPv4 address is not selected",
   289  	[]network.Address{
   290  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   291  	},
   292  	-1,
   293  	false,
   294  }, {
   295  	"a link-local (multicast or not) IPv6 address is not selected",
   296  	[]network.Address{
   297  		{"fe80::1", network.IPv6Address, "link", network.ScopeLinkLocal},
   298  		{"ff01::2", network.IPv6Address, "link", network.ScopeLinkLocal},
   299  		{"ff02::1:1", network.IPv6Address, "link", network.ScopeLinkLocal},
   300  	},
   301  	-1,
   302  	false,
   303  }, {
   304  	"a public name is preferred to an unknown or cloud local address",
   305  	[]network.Address{
   306  		{"127.0.0.1", network.IPv4Address, "local", network.ScopeUnknown},
   307  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   308  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   309  		{"public.invalid.testing", network.HostName, "public", network.ScopePublic},
   310  	},
   311  	3,
   312  	false,
   313  }, {
   314  	"first unknown address selected",
   315  	[]network.Address{
   316  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeUnknown},
   317  		{"8.8.8.8", network.IPv4Address, "floating", network.ScopeUnknown},
   318  	},
   319  	0,
   320  	false,
   321  }, {
   322  	"first public address is picked when both public IPs and public hostnames exist",
   323  	[]network.Address{
   324  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeUnknown},
   325  		{"example.com", network.HostName, "public", network.ScopePublic},
   326  		{"8.8.8.8", network.IPv4Address, "floating", network.ScopePublic},
   327  	},
   328  	1,
   329  	false,
   330  }, {
   331  	"first public IPv6 address is picked when both public IPs and public hostnames exist when preferIPv6 is true",
   332  	[]network.Address{
   333  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeUnknown},
   334  		{"8.8.8.8", network.IPv4Address, "floating", network.ScopePublic},
   335  		{"example.com", network.HostName, "public", network.ScopePublic},
   336  		{"2001:db8::1", network.IPv6Address, "other", network.ScopePublic},
   337  	},
   338  	3,
   339  	true,
   340  }}
   341  
   342  func (s *AddressSuite) TestSelectPublicAddress(c *gc.C) {
   343  	oldValue := network.GetPreferIPv6()
   344  	defer func() {
   345  		network.SetPreferIPv6(oldValue)
   346  	}()
   347  	for i, t := range selectPublicTests {
   348  		c.Logf("test %d: %s", i, t.about)
   349  		network.SetPreferIPv6(t.preferIPv6)
   350  		expectAddr, expectOK := t.expected()
   351  		actualAddr, actualOK := network.SelectPublicAddress(t.addresses)
   352  		c.Check(actualOK, gc.Equals, expectOK)
   353  		c.Check(actualAddr, gc.Equals, expectAddr)
   354  	}
   355  }
   356  
   357  var selectInternalTests = []selectTest{{
   358  	"no addresses gives empty string result",
   359  	[]network.Address{},
   360  	-1,
   361  	false,
   362  }, {
   363  	"a public IPv4 address is selected",
   364  	[]network.Address{
   365  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   366  	},
   367  	0,
   368  	false,
   369  }, {
   370  	"a public IPv6 address is selected",
   371  	[]network.Address{
   372  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   373  	},
   374  	0,
   375  	false,
   376  }, {
   377  	"a public IPv6 address is selected when both IPv4 and IPv6 addresses exist and preferIPv6 is true",
   378  	[]network.Address{
   379  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   380  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   381  	},
   382  	1,
   383  	true,
   384  }, {
   385  	"the first public IPv4 address is selected when preferIPv6 is true and no IPv6 addresses",
   386  	[]network.Address{
   387  		{"127.0.0.1", network.IPv4Address, "machine", network.ScopeMachineLocal},
   388  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   389  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   390  		{"8.8.4.4", network.IPv4Address, "public", network.ScopePublic},
   391  	},
   392  	1,
   393  	true,
   394  }, {
   395  	"a cloud local IPv4 address is selected",
   396  	[]network.Address{
   397  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   398  		{"10.0.0.1", network.IPv4Address, "private", network.ScopeCloudLocal},
   399  	},
   400  	1,
   401  	false,
   402  }, {
   403  	"a cloud local IPv6 address is selected",
   404  	[]network.Address{
   405  		{"fc00::1", network.IPv6Address, "private", network.ScopeCloudLocal},
   406  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   407  	},
   408  	0,
   409  	false,
   410  }, {
   411  	"a machine local or link-local address is not selected",
   412  	[]network.Address{
   413  		{"127.0.0.1", network.IPv4Address, "machine", network.ScopeMachineLocal},
   414  		{"::1", network.IPv6Address, "machine", network.ScopeMachineLocal},
   415  		{"fe80::1", network.IPv6Address, "machine", network.ScopeLinkLocal},
   416  	},
   417  	-1,
   418  	false,
   419  }, {
   420  	"a cloud local address is preferred to a public address",
   421  	[]network.Address{
   422  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   423  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   424  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   425  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   426  	},
   427  	1,
   428  	false,
   429  }, {
   430  	"an IPv6 cloud local address is preferred to a public address when preferIPv6 is true",
   431  	[]network.Address{
   432  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   433  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   434  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   435  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   436  	},
   437  	2,
   438  	false,
   439  }}
   440  
   441  func (s *AddressSuite) TestSelectInternalAddress(c *gc.C) {
   442  	oldValue := network.GetPreferIPv6()
   443  	defer func() {
   444  		network.SetPreferIPv6(oldValue)
   445  	}()
   446  	for i, t := range selectInternalTests {
   447  		c.Logf("test %d: %s", i, t.about)
   448  		network.SetPreferIPv6(t.preferIPv6)
   449  		expectAddr, expectOK := t.expected()
   450  		actualAddr, actualOK := network.SelectInternalAddress(t.addresses, false)
   451  		c.Check(actualOK, gc.Equals, expectOK)
   452  		c.Check(actualAddr, gc.Equals, expectAddr)
   453  	}
   454  }
   455  
   456  var selectInternalMachineTests = []selectTest{{
   457  	"first cloud local address is selected",
   458  	[]network.Address{
   459  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   460  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   461  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   462  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   463  	},
   464  	0,
   465  	false,
   466  }, {
   467  	"first cloud local hostname is selected when preferIPv6 is false",
   468  	[]network.Address{
   469  		{"example.com", network.HostName, "public", network.ScopePublic},
   470  		{"cloud1.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   471  		{"cloud2.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   472  		{"example.org", network.HostName, "public", network.ScopePublic},
   473  	},
   474  	1,
   475  	false,
   476  }, {
   477  	"first cloud local hostname is selected when preferIPv6 is true (public first)",
   478  	[]network.Address{
   479  		{"example.org", network.HostName, "public", network.ScopePublic},
   480  		{"example.com", network.HostName, "public", network.ScopePublic},
   481  		{"cloud1.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   482  		{"cloud2.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   483  	},
   484  	2,
   485  	true,
   486  }, {
   487  	"first cloud local hostname is selected when preferIPv6 is true (public last)",
   488  	[]network.Address{
   489  		{"cloud1.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   490  		{"cloud2.internal", network.HostName, "cloud", network.ScopeCloudLocal},
   491  		{"example.org", network.HostName, "public", network.ScopePublic},
   492  		{"example.com", network.HostName, "public", network.ScopePublic},
   493  	},
   494  	0,
   495  	true,
   496  }, {
   497  	"first IPv6 cloud local address is selected when preferIPv6 is true",
   498  	[]network.Address{
   499  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   500  		{"8.8.8.8", network.IPv4Address, "public", network.ScopePublic},
   501  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   502  		{"2001:db8::1", network.IPv6Address, "public", network.ScopePublic},
   503  	},
   504  	2,
   505  	true,
   506  }, {
   507  	"first IPv4 cloud local address is selected when preferIPv6 is true and no IPv6 addresses",
   508  	[]network.Address{
   509  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   510  		{"10.0.0.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   511  		{"172.16.1.1", network.IPv4Address, "cloud", network.ScopeCloudLocal},
   512  	},
   513  	1,
   514  	true,
   515  }, {
   516  	"first machine local address is selected",
   517  	[]network.Address{
   518  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   519  		{"::1", network.IPv6Address, "container", network.ScopeMachineLocal},
   520  	},
   521  	0,
   522  	false,
   523  }, {
   524  	"first IPv6 machine local address is selected when preferIPv6 is true",
   525  	[]network.Address{
   526  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   527  		{"::1", network.IPv6Address, "container", network.ScopeMachineLocal},
   528  		{"fe80::1", network.IPv6Address, "container", network.ScopeLinkLocal},
   529  	},
   530  	1,
   531  	true,
   532  }, {
   533  	"first IPv4 machine local address is selected when preferIPv6 is true and no IPv6 addresses",
   534  	[]network.Address{
   535  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   536  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   537  		{"127.0.0.2", network.IPv4Address, "container", network.ScopeMachineLocal},
   538  	},
   539  	1,
   540  	true,
   541  }, {
   542  	"first machine local address is selected when preferIPv6 is false even with public/cloud hostnames",
   543  	[]network.Address{
   544  		{"public.example.com", network.HostName, "public", network.ScopePublic},
   545  		{"::1", network.IPv6Address, "container", network.ScopeMachineLocal},
   546  		{"unknown.example.com", network.HostName, "public", network.ScopeUnknown},
   547  		{"cloud.internal", network.HostName, "public", network.ScopeCloudLocal},
   548  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   549  		{"fe80::1", network.IPv6Address, "container", network.ScopeLinkLocal},
   550  		{"127.0.0.2", network.IPv4Address, "container", network.ScopeMachineLocal},
   551  	},
   552  	1,
   553  	false,
   554  }, {
   555  	"first cloud local hostname is selected when preferIPv6 is false even with other machine/cloud addresses",
   556  	[]network.Address{
   557  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   558  		{"cloud-unknown.internal", network.HostName, "container", network.ScopeUnknown},
   559  		{"cloud-local.internal", network.HostName, "container", network.ScopeCloudLocal},
   560  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   561  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   562  		{"127.0.0.2", network.IPv4Address, "container", network.ScopeMachineLocal},
   563  	},
   564  	2,
   565  	false,
   566  }, {
   567  	"first IPv6 machine local address is selected when preferIPv6 is true even with public/cloud hostnames",
   568  	[]network.Address{
   569  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   570  		{"public.example.com", network.HostName, "public", network.ScopePublic},
   571  		{"unknown.example.com", network.HostName, "public", network.ScopeUnknown},
   572  		{"cloud.internal", network.HostName, "public", network.ScopeCloudLocal},
   573  		{"::1", network.IPv6Address, "container", network.ScopeMachineLocal},
   574  		{"fe80::1", network.IPv6Address, "container", network.ScopeLinkLocal},
   575  	},
   576  	4,
   577  	true,
   578  }, {
   579  	"first IPv6 cloud local address is selected when preferIPv6 is true even with cloud local hostnames",
   580  	[]network.Address{
   581  		{"169.254.1.1", network.IPv4Address, "link", network.ScopeLinkLocal},
   582  		{"cloud-unknown.internal", network.HostName, "container", network.ScopeUnknown},
   583  		{"cloud-local.internal", network.HostName, "container", network.ScopeCloudLocal},
   584  		{"fc00::1", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   585  		{"127.0.0.1", network.IPv4Address, "container", network.ScopeMachineLocal},
   586  		{"fc00::2", network.IPv6Address, "cloud", network.ScopeCloudLocal},
   587  		{"127.0.0.2", network.IPv4Address, "container", network.ScopeMachineLocal},
   588  	},
   589  	3,
   590  	true,
   591  }}
   592  
   593  func (s *AddressSuite) TestSelectInternalMachineAddress(c *gc.C) {
   594  	oldValue := network.GetPreferIPv6()
   595  	defer func() {
   596  		network.SetPreferIPv6(oldValue)
   597  	}()
   598  	for i, t := range selectInternalMachineTests {
   599  		c.Logf("test %d: %s", i, t.about)
   600  		network.SetPreferIPv6(t.preferIPv6)
   601  		expectAddr, expectOK := t.expected()
   602  		actualAddr, actualOK := network.SelectInternalAddress(t.addresses, true)
   603  		c.Check(actualOK, gc.Equals, expectOK)
   604  		c.Check(actualAddr, gc.Equals, expectAddr)
   605  	}
   606  }
   607  
   608  var stringTests = []struct {
   609  	addr network.Address
   610  	str  string
   611  }{{
   612  	addr: network.Address{
   613  		Type:  network.IPv4Address,
   614  		Value: "127.0.0.1",
   615  	},
   616  	str: "127.0.0.1",
   617  }, {
   618  	addr: network.Address{
   619  		Type:  network.IPv6Address,
   620  		Value: "2001:db8::1",
   621  		Scope: network.ScopePublic,
   622  	},
   623  	str: "public:2001:db8::1",
   624  }, {
   625  	addr: network.Address{
   626  		Type:  network.HostName,
   627  		Value: "foo.com",
   628  	},
   629  	str: "foo.com",
   630  }, {
   631  	addr: network.Address{
   632  		Type:  network.HostName,
   633  		Value: "foo.com",
   634  		Scope: network.ScopeUnknown,
   635  	},
   636  	str: "foo.com",
   637  }, {
   638  	addr: network.Address{
   639  		Type:  network.HostName,
   640  		Value: "foo.com",
   641  		Scope: network.ScopePublic,
   642  	},
   643  	str: "public:foo.com",
   644  }, {
   645  	addr: network.Address{
   646  		Type:        network.HostName,
   647  		Value:       "foo.com",
   648  		Scope:       network.ScopePublic,
   649  		NetworkName: "netname",
   650  	},
   651  	str: "public:foo.com(netname)",
   652  }}
   653  
   654  func (s *AddressSuite) TestString(c *gc.C) {
   655  	for i, test := range stringTests {
   656  		c.Logf("test %d: %#v", i, test.addr)
   657  		c.Check(test.addr.String(), gc.Equals, test.str)
   658  		c.Check(test.addr.GoString(), gc.Equals, test.str)
   659  	}
   660  }
   661  
   662  func (*AddressSuite) TestSortAddresses(c *gc.C) {
   663  	addrs := network.NewAddresses(
   664  		"127.0.0.1",
   665  		"::1",
   666  		"fc00::1",
   667  		"169.254.1.2",
   668  		"localhost",
   669  		"2001:db8::1",
   670  		"fe80::2",
   671  		"7.8.8.8",
   672  		"172.16.0.1",
   673  		"example.com",
   674  		"8.8.8.8",
   675  	)
   676  	// Simulate prefer-ipv6: false first.
   677  	network.SortAddresses(addrs, false)
   678  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses(
   679  		// Public IPv4 addresses on top.
   680  		"7.8.8.8",
   681  		"8.8.8.8",
   682  		// After that public IPv6 addresses.
   683  		"2001:db8::1",
   684  		// Then hostnames.
   685  		"example.com",
   686  		"localhost",
   687  		// Then IPv4 cloud-local addresses.
   688  		"172.16.0.1",
   689  		// Then IPv6 cloud-local addresses.
   690  		"fc00::1",
   691  		// Then machine-local IPv4 addresses.
   692  		"127.0.0.1",
   693  		// Then machine-local IPv6 addresses.
   694  		"::1",
   695  		// Then link-local IPv4 addresses.
   696  		"169.254.1.2",
   697  		// Finally, link-local IPv6 addresses.
   698  		"fe80::2",
   699  	))
   700  
   701  	// Now, simulate prefer-ipv6: true.
   702  	network.SortAddresses(addrs, true)
   703  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses(
   704  		// Public IPv6 addresses on top.
   705  		"2001:db8::1",
   706  		// After that public IPv4 addresses.
   707  		"7.8.8.8",
   708  		"8.8.8.8",
   709  		// Then hostnames.
   710  		"example.com",
   711  		"localhost",
   712  		// Then IPv6 cloud-local addresses.
   713  		"fc00::1",
   714  		// Then IPv4 cloud-local addresses.
   715  		"172.16.0.1",
   716  		// Then machine-local IPv6 addresses.
   717  		"::1",
   718  		// Then machine-local IPv4 addresses.
   719  		"127.0.0.1",
   720  		// Then link-local IPv6 addresses.
   721  		"fe80::2",
   722  		// Finally, link-local IPv4 addresses.
   723  		"169.254.1.2",
   724  	))
   725  }
   726  
   727  func (*AddressSuite) TestIPv4ToDecimal(c *gc.C) {
   728  	zeroIP, err := network.IPv4ToDecimal(net.ParseIP("0.0.0.0"))
   729  	c.Assert(err, jc.ErrorIsNil)
   730  	c.Assert(zeroIP, gc.Equals, uint32(0))
   731  
   732  	nilIP := net.ParseIP("bad format")
   733  	_, err = network.IPv4ToDecimal(nilIP)
   734  	c.Assert(err, gc.ErrorMatches, `"<nil>" is not a valid IPv4 address`)
   735  
   736  	_, err = network.IPv4ToDecimal(net.ParseIP("2001:db8::1"))
   737  	c.Assert(err, gc.ErrorMatches, `"2001:db8::1" is not a valid IPv4 address`)
   738  
   739  	nonZeroIP, err := network.IPv4ToDecimal(net.ParseIP("192.168.1.1"))
   740  	c.Assert(err, jc.ErrorIsNil)
   741  	c.Assert(nonZeroIP, gc.Equals, uint32(3232235777))
   742  }
   743  
   744  func (*AddressSuite) TestDecimalToIPv4(c *gc.C) {
   745  	addr := network.DecimalToIPv4(uint32(0))
   746  	c.Assert(addr.String(), gc.Equals, "0.0.0.0")
   747  
   748  	addr = network.DecimalToIPv4(uint32(3232235777))
   749  	c.Assert(addr.String(), gc.Equals, "192.168.1.1")
   750  }
   751  
   752  func (*AddressSuite) TestExactScopeMatch(c *gc.C) {
   753  	network.SetPreferIPv6(false)
   754  	addr := network.NewScopedAddress("10.0.0.2", network.ScopeCloudLocal)
   755  	match := network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   756  	c.Assert(match, jc.IsTrue)
   757  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   758  	c.Assert(match, jc.IsFalse)
   759  
   760  	addr = network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   761  	match = network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   762  	c.Assert(match, jc.IsFalse)
   763  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   764  	c.Assert(match, jc.IsTrue)
   765  }
   766  
   767  func (*AddressSuite) TestExactScopeMatchHonoursPreferIPv6(c *gc.C) {
   768  	network.SetPreferIPv6(true)
   769  	addr := network.NewScopedAddress("10.0.0.2", network.ScopeCloudLocal)
   770  	match := network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   771  	c.Assert(match, jc.IsFalse)
   772  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   773  	c.Assert(match, jc.IsFalse)
   774  
   775  	addr = network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   776  	match = network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   777  	c.Assert(match, jc.IsFalse)
   778  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   779  	c.Assert(match, jc.IsFalse)
   780  
   781  	addr = network.NewScopedAddress("2001:db8::ff00:42:8329", network.ScopePublic)
   782  	match = network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   783  	c.Assert(match, jc.IsFalse)
   784  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   785  	c.Assert(match, jc.IsTrue)
   786  
   787  	addr = network.NewScopedAddress("fc00::1", network.ScopeCloudLocal)
   788  	match = network.ExactScopeMatch(addr, network.ScopeCloudLocal)
   789  	c.Assert(match, jc.IsTrue)
   790  	match = network.ExactScopeMatch(addr, network.ScopePublic)
   791  	c.Assert(match, jc.IsFalse)
   792  }