diff options
Diffstat (limited to 'src/net/addrselect.go')
| -rw-r--r-- | src/net/addrselect.go | 148 |
1 files changed, 68 insertions, 80 deletions
diff --git a/src/net/addrselect.go b/src/net/addrselect.go index 59380b9486..b76183a34c 100644 --- a/src/net/addrselect.go +++ b/src/net/addrselect.go @@ -6,7 +6,10 @@ package net -import "sort" +import ( + "net/netip" + "sort" +) func sortByRFC6724(addrs []IPAddr) { if len(addrs) < 2 { @@ -15,14 +18,15 @@ func sortByRFC6724(addrs []IPAddr) { sortByRFC6724withSrcs(addrs, srcAddrs(addrs)) } -func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) { +func sortByRFC6724withSrcs(addrs []IPAddr, srcs []netip.Addr) { if len(addrs) != len(srcs) { panic("internal error") } addrAttr := make([]ipAttr, len(addrs)) srcAttr := make([]ipAttr, len(srcs)) for i, v := range addrs { - addrAttr[i] = ipAttrOf(v.IP) + addrAttrIP, _ := netip.AddrFromSlice(v.IP) + addrAttr[i] = ipAttrOf(addrAttrIP) srcAttr[i] = ipAttrOf(srcs[i]) } sort.Stable(&byRFC6724{ @@ -36,8 +40,8 @@ func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) { // srcsAddrs tries to UDP-connect to each address to see if it has a // route. (This doesn't send any packets). The destination port // number is irrelevant. -func srcAddrs(addrs []IPAddr) []IP { - srcs := make([]IP, len(addrs)) +func srcAddrs(addrs []IPAddr) []netip.Addr { + srcs := make([]netip.Addr, len(addrs)) dst := UDPAddr{Port: 9} for i := range addrs { dst.IP = addrs[i].IP @@ -45,7 +49,7 @@ func srcAddrs(addrs []IPAddr) []IP { c, err := DialUDP("udp", nil, &dst) if err == nil { if src, ok := c.LocalAddr().(*UDPAddr); ok { - srcs[i] = src.IP + srcs[i], _ = netip.AddrFromSlice(src.IP) } c.Close() } @@ -59,8 +63,8 @@ type ipAttr struct { Label uint8 } -func ipAttrOf(ip IP) ipAttr { - if ip == nil { +func ipAttrOf(ip netip.Addr) ipAttr { + if !ip.IsValid() { return ipAttr{} } match := rfc6724policyTable.Classify(ip) @@ -74,7 +78,7 @@ func ipAttrOf(ip IP) ipAttr { type byRFC6724 struct { addrs []IPAddr // addrs to sort addrAttr []ipAttr - srcs []IP // or nil if unreachable + srcs []netip.Addr // or not valid addr if unreachable srcAttr []ipAttr } @@ -108,13 +112,13 @@ func (s *byRFC6724) Less(i, j int) bool { // If DB is known to be unreachable or if Source(DB) is undefined, then // prefer DA. Similarly, if DA is known to be unreachable or if // Source(DA) is undefined, then prefer DB. - if SourceDA == nil && SourceDB == nil { + if !SourceDA.IsValid() && !SourceDB.IsValid() { return false // "equal" } - if SourceDB == nil { + if !SourceDB.IsValid() { return preferDA } - if SourceDA == nil { + if !SourceDA.IsValid() { return preferDB } @@ -184,7 +188,7 @@ func (s *byRFC6724) Less(i, j int) bool { return preferDB } - // Rule 9: Use longest matching prefix. + // Rule 9: Use the longest matching prefix. // When DA and DB belong to the same address family (both are IPv6 or // both are IPv4 [but see below]): If CommonPrefixLen(Source(DA), DA) > // CommonPrefixLen(Source(DB), DB), then prefer DA. Similarly, if @@ -212,7 +216,7 @@ func (s *byRFC6724) Less(i, j int) bool { } type policyTableEntry struct { - Prefix *IPNet + Prefix netip.Prefix Precedence uint8 Label uint8 } @@ -220,90 +224,75 @@ type policyTableEntry struct { type policyTable []policyTableEntry // RFC 6724 section 2.1. +// Items are sorted by the size of their Prefix.Mask.Size, var rfc6724policyTable = policyTable{ { - Prefix: mustCIDR("::1/128"), + // "::1/128" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}), 128), Precedence: 50, Label: 0, }, { - Prefix: mustCIDR("::/0"), - Precedence: 40, - Label: 1, - }, - { + // "::ffff:0:0/96" // IPv4-compatible, etc. - Prefix: mustCIDR("::ffff:0:0/96"), + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}), 96), Precedence: 35, Label: 4, }, { - // 6to4 - Prefix: mustCIDR("2002::/16"), - Precedence: 30, - Label: 2, + // "::/96" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 96), + Precedence: 1, + Label: 3, }, { + // "2001::/32" // Teredo - Prefix: mustCIDR("2001::/32"), + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x01}), 32), Precedence: 5, Label: 5, }, { - Prefix: mustCIDR("fc00::/7"), - Precedence: 3, - Label: 13, + // "2002::/16" + // 6to4 + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x02}), 16), + Precedence: 30, + Label: 2, }, { - Prefix: mustCIDR("::/96"), + // "3ffe::/16" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x3f, 0xfe}), 16), Precedence: 1, - Label: 3, + Label: 12, }, { - Prefix: mustCIDR("fec0::/10"), + // "fec0::/10" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfe, 0xc0}), 10), Precedence: 1, Label: 11, }, { - Prefix: mustCIDR("3ffe::/16"), - Precedence: 1, - Label: 12, + // "fc00::/7" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfc}), 7), + Precedence: 3, + Label: 13, + }, + { + // "::/0" + Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0), + Precedence: 40, + Label: 1, }, -} - -func init() { - sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable))) -} - -// byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size, -// from smallest mask, to largest. -type byMaskLength []policyTableEntry - -func (s byMaskLength) Len() int { return len(s) } -func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s byMaskLength) Less(i, j int) bool { - isize, _ := s[i].Prefix.Mask.Size() - jsize, _ := s[j].Prefix.Mask.Size() - return isize < jsize -} - -// mustCIDR calls ParseCIDR and panics on any error, or if the network -// is not IPv6. -func mustCIDR(s string) *IPNet { - ip, ipNet, err := ParseCIDR(s) - if err != nil { - panic(err.Error()) - } - if len(ip) != IPv6len { - panic("unexpected IP length") - } - return ipNet } // Classify returns the policyTableEntry of the entry with the longest // matching prefix that contains ip. // The table t must be sorted from largest mask size to smallest. -func (t policyTable) Classify(ip IP) policyTableEntry { +func (t policyTable) Classify(ip netip.Addr) policyTableEntry { + // Prefix.Contains() will not match an IPv6 prefix for an IPv4 address. + if ip.Is4() { + ip = netip.AddrFrom16(ip.As16()) + } for _, ent := range t { if ent.Prefix.Contains(ip) { return ent @@ -324,17 +313,18 @@ const ( scopeGlobal scope = 0xe ) -func classifyScope(ip IP) scope { +func classifyScope(ip netip.Addr) scope { if ip.IsLoopback() || ip.IsLinkLocalUnicast() { return scopeLinkLocal } - ipv6 := len(ip) == IPv6len && ip.To4() == nil + ipv6 := ip.Is6() && !ip.Is4In6() + ipv6AsBytes := ip.As16() if ipv6 && ip.IsMulticast() { - return scope(ip[1] & 0xf) + return scope(ipv6AsBytes[1] & 0xf) } // Site-local addresses are defined in RFC 3513 section 2.5.6 // (and deprecated in RFC 3879). - if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 { + if ipv6 && ipv6AsBytes[0] == 0xfe && ipv6AsBytes[1]&0xc0 == 0xc0 { return scopeSiteLocal } return scopeGlobal @@ -350,30 +340,28 @@ func classifyScope(ip IP) scope { // If a and b are different IP versions, 0 is returned. // // See https://tools.ietf.org/html/rfc6724#section-2.2 -func commonPrefixLen(a, b IP) (cpl int) { - if a4 := a.To4(); a4 != nil { - a = a4 - } +func commonPrefixLen(a netip.Addr, b IP) (cpl int) { if b4 := b.To4(); b4 != nil { b = b4 } - if len(a) != len(b) { + aAsSlice := a.AsSlice() + if len(aAsSlice) != len(b) { return 0 } // If IPv6, only up to the prefix (first 64 bits) - if len(a) > 8 { - a = a[:8] + if len(aAsSlice) > 8 { + aAsSlice = aAsSlice[:8] b = b[:8] } - for len(a) > 0 { - if a[0] == b[0] { + for len(aAsSlice) > 0 { + if aAsSlice[0] == b[0] { cpl += 8 - a = a[1:] + aAsSlice = aAsSlice[1:] b = b[1:] continue } bits := 8 - ab, bb := a[0], b[0] + ab, bb := aAsSlice[0], b[0] for { ab >>= 1 bb >>= 1 |
