...

Source file src/net/addrselect.go

Documentation: net

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

View as plain text