github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/net/addrselect.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd linux netbsd openbsd solaris
     6  
     7  // Minimal RFC 6724 address selection.
     8  
     9  package net
    10  
    11  import "sort"
    12  
    13  func sortByRFC6724(addrs []IPAddr) {
    14  	if len(addrs) < 2 {
    15  		return
    16  	}
    17  	sortByRFC6724withSrcs(addrs, srcAddrs(addrs))
    18  }
    19  
    20  func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
    21  	if len(addrs) != len(srcs) {
    22  		panic("internal error")
    23  	}
    24  	addrAttr := make([]ipAttr, len(addrs))
    25  	srcAttr := make([]ipAttr, len(srcs))
    26  	for i, v := range addrs {
    27  		addrAttr[i] = ipAttrOf(v.IP)
    28  		srcAttr[i] = ipAttrOf(srcs[i])
    29  	}
    30  	sort.Stable(&byRFC6724{
    31  		addrs:    addrs,
    32  		addrAttr: addrAttr,
    33  		srcs:     srcs,
    34  		srcAttr:  srcAttr,
    35  	})
    36  }
    37  
    38  // srcsAddrs tries to UDP-connect to each address to see if it has a
    39  // route. (This doesn't send any packets). The destination port
    40  // number is irrelevant.
    41  func srcAddrs(addrs []IPAddr) []IP {
    42  	srcs := make([]IP, len(addrs))
    43  	dst := UDPAddr{Port: 9}
    44  	for i := range addrs {
    45  		dst.IP = addrs[i].IP
    46  		dst.Zone = addrs[i].Zone
    47  		c, err := DialUDP("udp", nil, &dst)
    48  		if err == nil {
    49  			if src, ok := c.LocalAddr().(*UDPAddr); ok {
    50  				srcs[i] = src.IP
    51  			}
    52  			c.Close()
    53  		}
    54  	}
    55  	return srcs
    56  }
    57  
    58  type ipAttr struct {
    59  	Scope      scope
    60  	Precedence uint8
    61  	Label      uint8
    62  }
    63  
    64  func ipAttrOf(ip IP) ipAttr {
    65  	if ip == nil {
    66  		return ipAttr{}
    67  	}
    68  	match := rfc6724policyTable.Classify(ip)
    69  	return ipAttr{
    70  		Scope:      classifyScope(ip),
    71  		Precedence: match.Precedence,
    72  		Label:      match.Label,
    73  	}
    74  }
    75  
    76  type byRFC6724 struct {
    77  	addrs    []IPAddr // addrs to sort
    78  	addrAttr []ipAttr
    79  	srcs     []IP // or nil if unreachable
    80  	srcAttr  []ipAttr
    81  }
    82  
    83  func (s *byRFC6724) Len() int { return len(s.addrs) }
    84  
    85  func (s *byRFC6724) Swap(i, j int) {
    86  	s.addrs[i], s.addrs[j] = s.addrs[j], s.addrs[i]
    87  	s.srcs[i], s.srcs[j] = s.srcs[j], s.srcs[i]
    88  	s.addrAttr[i], s.addrAttr[j] = s.addrAttr[j], s.addrAttr[i]
    89  	s.srcAttr[i], s.srcAttr[j] = s.srcAttr[j], s.srcAttr[i]
    90  }
    91  
    92  // Less reports whether i is a better destination address for this
    93  // host than j.
    94  //
    95  // The algorithm and variable names comes from RFC 6724 section 6.
    96  func (s *byRFC6724) Less(i, j int) bool {
    97  	DA := s.addrs[i].IP
    98  	DB := s.addrs[j].IP
    99  	SourceDA := s.srcs[i]
   100  	SourceDB := s.srcs[j]
   101  	attrDA := &s.addrAttr[i]
   102  	attrDB := &s.addrAttr[j]
   103  	attrSourceDA := &s.srcAttr[i]
   104  	attrSourceDB := &s.srcAttr[j]
   105  
   106  	const preferDA = true
   107  	const preferDB = false
   108  
   109  	// Rule 1: Avoid unusable destinations.
   110  	// If DB is known to be unreachable or if Source(DB) is undefined, then
   111  	// prefer DA.  Similarly, if DA is known to be unreachable or if
   112  	// Source(DA) is undefined, then prefer DB.
   113  	if SourceDA == nil && SourceDB == nil {
   114  		return false // "equal"
   115  	}
   116  	if SourceDB == nil {
   117  		return preferDA
   118  	}
   119  	if SourceDA == nil {
   120  		return preferDB
   121  	}
   122  
   123  	// Rule 2: Prefer matching scope.
   124  	// If Scope(DA) = Scope(Source(DA)) and Scope(DB) <> Scope(Source(DB)),
   125  	// then prefer DA.  Similarly, if Scope(DA) <> Scope(Source(DA)) and
   126  	// Scope(DB) = Scope(Source(DB)), then prefer DB.
   127  	if attrDA.Scope == attrSourceDA.Scope && attrDB.Scope != attrSourceDB.Scope {
   128  		return preferDA
   129  	}
   130  	if attrDA.Scope != attrSourceDA.Scope && attrDB.Scope == attrSourceDB.Scope {
   131  		return preferDB
   132  	}
   133  
   134  	// Rule 3: Avoid deprecated addresses.
   135  	// If Source(DA) is deprecated and Source(DB) is not, then prefer DB.
   136  	// Similarly, if Source(DA) is not deprecated and Source(DB) is
   137  	// deprecated, then prefer DA.
   138  
   139  	// TODO(bradfitz): implement? low priority for now.
   140  
   141  	// Rule 4: Prefer home addresses.
   142  	// If Source(DA) is simultaneously a home address and care-of address
   143  	// and Source(DB) is not, then prefer DA.  Similarly, if Source(DB) is
   144  	// simultaneously a home address and care-of address and Source(DA) is
   145  	// not, then prefer DB.
   146  
   147  	// TODO(bradfitz): implement? low priority for now.
   148  
   149  	// Rule 5: Prefer matching label.
   150  	// If Label(Source(DA)) = Label(DA) and Label(Source(DB)) <> Label(DB),
   151  	// then prefer DA.  Similarly, if Label(Source(DA)) <> Label(DA) and
   152  	// Label(Source(DB)) = Label(DB), then prefer DB.
   153  	if attrSourceDA.Label == attrDA.Label &&
   154  		attrSourceDB.Label != attrDB.Label {
   155  		return preferDA
   156  	}
   157  	if attrSourceDA.Label != attrDA.Label &&
   158  		attrSourceDB.Label == attrDB.Label {
   159  		return preferDB
   160  	}
   161  
   162  	// Rule 6: Prefer higher precedence.
   163  	// If Precedence(DA) > Precedence(DB), then prefer DA.  Similarly, if
   164  	// Precedence(DA) < Precedence(DB), then prefer DB.
   165  	if attrDA.Precedence > attrDB.Precedence {
   166  		return preferDA
   167  	}
   168  	if attrDA.Precedence < attrDB.Precedence {
   169  		return preferDB
   170  	}
   171  
   172  	// Rule 7: Prefer native transport.
   173  	// If DA is reached via an encapsulating transition mechanism (e.g.,
   174  	// IPv6 in IPv4) and DB is not, then prefer DB.  Similarly, if DB is
   175  	// reached via encapsulation and DA is not, then prefer DA.
   176  
   177  	// TODO(bradfitz): implement? low priority for now.
   178  
   179  	// Rule 8: Prefer smaller scope.
   180  	// If Scope(DA) < Scope(DB), then prefer DA.  Similarly, if Scope(DA) >
   181  	// Scope(DB), then prefer DB.
   182  	if attrDA.Scope < attrDB.Scope {
   183  		return preferDA
   184  	}
   185  	if attrDA.Scope > attrDB.Scope {
   186  		return preferDB
   187  	}
   188  
   189  	// Rule 9: Use longest matching prefix.
   190  	// When DA and DB belong to the same address family (both are IPv6 or
   191  	// both are IPv4): If CommonPrefixLen(Source(DA), DA) >
   192  	// CommonPrefixLen(Source(DB), DB), then prefer DA.  Similarly, if
   193  	// CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
   194  	// then prefer DB.
   195  	da4 := DA.To4() != nil
   196  	db4 := DB.To4() != nil
   197  	if da4 == db4 {
   198  		commonA := commonPrefixLen(SourceDA, DA)
   199  		commonB := commonPrefixLen(SourceDB, DB)
   200  
   201  		// CommonPrefixLen doesn't really make sense for IPv4, and even
   202  		// causes problems for common load balancing practices
   203  		// (e.g., https://golang.org/issue/13283).  Glibc instead only
   204  		// uses CommonPrefixLen for IPv4 when the source and destination
   205  		// addresses are on the same subnet, but that requires extra
   206  		// work to find the netmask for our source addresses. As a
   207  		// simpler heuristic, we limit its use to when the source and
   208  		// destination belong to the same special purpose block.
   209  		if da4 {
   210  			if !sameIPv4SpecialPurposeBlock(SourceDA, DA) {
   211  				commonA = 0
   212  			}
   213  			if !sameIPv4SpecialPurposeBlock(SourceDB, DB) {
   214  				commonB = 0
   215  			}
   216  		}
   217  
   218  		if commonA > commonB {
   219  			return preferDA
   220  		}
   221  		if commonA < commonB {
   222  			return preferDB
   223  		}
   224  	}
   225  
   226  	// Rule 10: Otherwise, leave the order unchanged.
   227  	// If DA preceded DB in the original list, prefer DA.
   228  	// Otherwise, prefer DB.
   229  	return false // "equal"
   230  }
   231  
   232  type policyTableEntry struct {
   233  	Prefix     *IPNet
   234  	Precedence uint8
   235  	Label      uint8
   236  }
   237  
   238  type policyTable []policyTableEntry
   239  
   240  // RFC 6724 section 2.1.
   241  var rfc6724policyTable = policyTable{
   242  	{
   243  		Prefix:     mustCIDR("::1/128"),
   244  		Precedence: 50,
   245  		Label:      0,
   246  	},
   247  	{
   248  		Prefix:     mustCIDR("::/0"),
   249  		Precedence: 40,
   250  		Label:      1,
   251  	},
   252  	{
   253  		// IPv4-compatible, etc.
   254  		Prefix:     mustCIDR("::ffff:0:0/96"),
   255  		Precedence: 35,
   256  		Label:      4,
   257  	},
   258  	{
   259  		// 6to4
   260  		Prefix:     mustCIDR("2002::/16"),
   261  		Precedence: 30,
   262  		Label:      2,
   263  	},
   264  	{
   265  		// Teredo
   266  		Prefix:     mustCIDR("2001::/32"),
   267  		Precedence: 5,
   268  		Label:      5,
   269  	},
   270  	{
   271  		Prefix:     mustCIDR("fc00::/7"),
   272  		Precedence: 3,
   273  		Label:      13,
   274  	},
   275  	{
   276  		Prefix:     mustCIDR("::/96"),
   277  		Precedence: 1,
   278  		Label:      3,
   279  	},
   280  	{
   281  		Prefix:     mustCIDR("fec0::/10"),
   282  		Precedence: 1,
   283  		Label:      11,
   284  	},
   285  	{
   286  		Prefix:     mustCIDR("3ffe::/16"),
   287  		Precedence: 1,
   288  		Label:      12,
   289  	},
   290  }
   291  
   292  func init() {
   293  	sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable)))
   294  }
   295  
   296  // byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size,
   297  // from smallest mask, to largest.
   298  type byMaskLength []policyTableEntry
   299  
   300  func (s byMaskLength) Len() int      { return len(s) }
   301  func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   302  func (s byMaskLength) Less(i, j int) bool {
   303  	isize, _ := s[i].Prefix.Mask.Size()
   304  	jsize, _ := s[j].Prefix.Mask.Size()
   305  	return isize < jsize
   306  }
   307  
   308  // mustCIDR calls ParseCIDR and panics on any error, or if the network
   309  // is not IPv6.
   310  func mustCIDR(s string) *IPNet {
   311  	ip, ipNet, err := ParseCIDR(s)
   312  	if err != nil {
   313  		panic(err.Error())
   314  	}
   315  	if len(ip) != IPv6len {
   316  		panic("unexpected IP length")
   317  	}
   318  	return ipNet
   319  }
   320  
   321  // Classify returns the policyTableEntry of the entry with the longest
   322  // matching prefix that contains ip.
   323  // The table t must be sorted from largest mask size to smallest.
   324  func (t policyTable) Classify(ip IP) policyTableEntry {
   325  	for _, ent := range t {
   326  		if ent.Prefix.Contains(ip) {
   327  			return ent
   328  		}
   329  	}
   330  	return policyTableEntry{}
   331  }
   332  
   333  // RFC 6724 section 3.1.
   334  type scope uint8
   335  
   336  const (
   337  	scopeInterfaceLocal scope = 0x1
   338  	scopeLinkLocal      scope = 0x2
   339  	scopeAdminLocal     scope = 0x4
   340  	scopeSiteLocal      scope = 0x5
   341  	scopeOrgLocal       scope = 0x8
   342  	scopeGlobal         scope = 0xe
   343  )
   344  
   345  func classifyScope(ip IP) scope {
   346  	if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
   347  		return scopeLinkLocal
   348  	}
   349  	ipv6 := len(ip) == IPv6len && ip.To4() == nil
   350  	if ipv6 && ip.IsMulticast() {
   351  		return scope(ip[1] & 0xf)
   352  	}
   353  	// Site-local addresses are defined in RFC 3513 section 2.5.6
   354  	// (and deprecated in RFC 3879).
   355  	if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
   356  		return scopeSiteLocal
   357  	}
   358  	return scopeGlobal
   359  }
   360  
   361  // commonPrefixLen reports the length of the longest prefix (looking
   362  // at the most significant, or leftmost, bits) that the
   363  // two addresses have in common, up to the length of a's prefix (i.e.,
   364  // the portion of the address not including the interface ID).
   365  //
   366  // If a or b is an IPv4 address as an IPv6 address, the IPv4 addresses
   367  // are compared (with max common prefix length of 32).
   368  // If a and b are different IP versions, 0 is returned.
   369  //
   370  // See https://tools.ietf.org/html/rfc6724#section-2.2
   371  func commonPrefixLen(a, b IP) (cpl int) {
   372  	if a4 := a.To4(); a4 != nil {
   373  		a = a4
   374  	}
   375  	if b4 := b.To4(); b4 != nil {
   376  		b = b4
   377  	}
   378  	if len(a) != len(b) {
   379  		return 0
   380  	}
   381  	// If IPv6, only up to the prefix (first 64 bits)
   382  	if len(a) > 8 {
   383  		a = a[:8]
   384  		b = b[:8]
   385  	}
   386  	for len(a) > 0 {
   387  		if a[0] == b[0] {
   388  			cpl += 8
   389  			a = a[1:]
   390  			b = b[1:]
   391  			continue
   392  		}
   393  		bits := 8
   394  		ab, bb := a[0], b[0]
   395  		for {
   396  			ab >>= 1
   397  			bb >>= 1
   398  			bits--
   399  			if ab == bb {
   400  				cpl += bits
   401  				return
   402  			}
   403  		}
   404  	}
   405  	return
   406  }
   407  
   408  // sameIPv4SpecialPurposeBlock reports whether a and b belong to the same
   409  // address block reserved by the IANA IPv4 Special-Purpose Address Registry:
   410  // http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
   411  func sameIPv4SpecialPurposeBlock(a, b IP) bool {
   412  	a, b = a.To4(), b.To4()
   413  	if a == nil || b == nil || a[0] != b[0] {
   414  		return false
   415  	}
   416  	// IANA defines more special-purpose blocks, but these are the only
   417  	// ones likely to be relevant to typical Go systems.
   418  	switch a[0] {
   419  	case 10: // 10.0.0.0/8: Private-Use
   420  		return true
   421  	case 127: // 127.0.0.0/8: Loopback
   422  		return true
   423  	case 169: // 169.254.0.0/16: Link Local
   424  		return a[1] == 254 && b[1] == 254
   425  	case 172: // 172.16.0.0/12: Private-Use
   426  		return a[1]&0xf0 == 16 && b[1]&0xf0 == 16
   427  	case 192: // 192.168.0.0/16: Private-Use
   428  		return a[1] == 168 && b[1] == 168
   429  	}
   430  	return false
   431  }