Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 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)) |
Mikio Hara | 2899be8 | 2015-07-17 10:16:45 +0900 | [diff] [blame] | 43 | dst := UDPAddr{Port: 9} |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 44 | for i := range addrs { |
Mikio Hara | 2899be8 | 2015-07-17 10:16:45 +0900 | [diff] [blame] | 45 | dst.IP = addrs[i].IP |
| 46 | dst.Zone = addrs[i].Zone |
| 47 | c, err := DialUDP("udp", nil, &dst) |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 48 | if err == nil { |
Mikio Hara | 2899be8 | 2015-07-17 10:16:45 +0900 | [diff] [blame] | 49 | if src, ok := c.LocalAddr().(*UDPAddr); ok { |
| 50 | srcs[i] = src.IP |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 51 | } |
Mikio Hara | 2899be8 | 2015-07-17 10:16:45 +0900 | [diff] [blame] | 52 | c.Close() |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 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 | if commonA > commonB { |
| 201 | return preferDA |
| 202 | } |
| 203 | if commonA < commonB { |
| 204 | return preferDB |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | // Rule 10: Otherwise, leave the order unchanged. |
| 209 | // If DA preceded DB in the original list, prefer DA. |
| 210 | // Otherwise, prefer DB. |
| 211 | return false // "equal" |
| 212 | } |
| 213 | |
| 214 | type policyTableEntry struct { |
| 215 | Prefix *IPNet |
| 216 | Precedence uint8 |
| 217 | Label uint8 |
| 218 | } |
| 219 | |
| 220 | type policyTable []policyTableEntry |
| 221 | |
| 222 | // RFC 6724 section 2.1. |
| 223 | var rfc6724policyTable = policyTable{ |
| 224 | { |
| 225 | Prefix: mustCIDR("::1/128"), |
| 226 | Precedence: 50, |
| 227 | Label: 0, |
| 228 | }, |
| 229 | { |
| 230 | Prefix: mustCIDR("::/0"), |
| 231 | Precedence: 40, |
| 232 | Label: 1, |
| 233 | }, |
| 234 | { |
| 235 | // IPv4-compatible, etc. |
| 236 | Prefix: mustCIDR("::ffff:0:0/96"), |
| 237 | Precedence: 35, |
| 238 | Label: 4, |
| 239 | }, |
| 240 | { |
| 241 | // 6to4 |
| 242 | Prefix: mustCIDR("2002::/16"), |
| 243 | Precedence: 30, |
| 244 | Label: 2, |
| 245 | }, |
| 246 | { |
| 247 | // Teredo |
| 248 | Prefix: mustCIDR("2001::/32"), |
| 249 | Precedence: 5, |
| 250 | Label: 5, |
| 251 | }, |
| 252 | { |
| 253 | Prefix: mustCIDR("fc00::/7"), |
| 254 | Precedence: 3, |
| 255 | Label: 13, |
| 256 | }, |
| 257 | { |
| 258 | Prefix: mustCIDR("::/96"), |
| 259 | Precedence: 1, |
| 260 | Label: 3, |
| 261 | }, |
| 262 | { |
| 263 | Prefix: mustCIDR("fec0::/10"), |
| 264 | Precedence: 1, |
| 265 | Label: 11, |
| 266 | }, |
| 267 | { |
| 268 | Prefix: mustCIDR("3ffe::/16"), |
| 269 | Precedence: 1, |
| 270 | Label: 12, |
| 271 | }, |
| 272 | } |
| 273 | |
| 274 | func init() { |
| 275 | sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable))) |
| 276 | } |
| 277 | |
| 278 | // byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size, |
| 279 | // from smallest mask, to largest. |
| 280 | type byMaskLength []policyTableEntry |
| 281 | |
| 282 | func (s byMaskLength) Len() int { return len(s) } |
| 283 | func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
| 284 | func (s byMaskLength) Less(i, j int) bool { |
| 285 | isize, _ := s[i].Prefix.Mask.Size() |
| 286 | jsize, _ := s[j].Prefix.Mask.Size() |
| 287 | return isize < jsize |
| 288 | } |
| 289 | |
| 290 | // mustCIDR calls ParseCIDR and panics on any error, or if the network |
| 291 | // is not IPv6. |
| 292 | func mustCIDR(s string) *IPNet { |
| 293 | ip, ipNet, err := ParseCIDR(s) |
| 294 | if err != nil { |
| 295 | panic(err.Error()) |
| 296 | } |
| 297 | if len(ip) != IPv6len { |
| 298 | panic("unexpected IP length") |
| 299 | } |
| 300 | return ipNet |
| 301 | } |
| 302 | |
| 303 | // Classify returns the policyTableEntry of the entry with the longest |
| 304 | // matching prefix that contains ip. |
| 305 | // The table t must be sorted from largest mask size to smallest. |
| 306 | func (t policyTable) Classify(ip IP) policyTableEntry { |
| 307 | for _, ent := range t { |
| 308 | if ent.Prefix.Contains(ip) { |
| 309 | return ent |
| 310 | } |
| 311 | } |
| 312 | return policyTableEntry{} |
| 313 | } |
| 314 | |
| 315 | // RFC 6724 section 3.1. |
| 316 | type scope uint8 |
| 317 | |
| 318 | const ( |
| 319 | scopeInterfaceLocal scope = 0x1 |
| 320 | scopeLinkLocal scope = 0x2 |
| 321 | scopeAdminLocal scope = 0x4 |
| 322 | scopeSiteLocal scope = 0x5 |
| 323 | scopeOrgLocal scope = 0x8 |
| 324 | scopeGlobal scope = 0xe |
| 325 | ) |
| 326 | |
| 327 | func classifyScope(ip IP) scope { |
| 328 | if ip.IsLoopback() || ip.IsLinkLocalUnicast() { |
| 329 | return scopeLinkLocal |
| 330 | } |
Mikio Hara | aadd84e | 2015-07-17 17:31:49 +0900 | [diff] [blame] | 331 | ipv6 := len(ip) == IPv6len && ip.To4() == nil |
| 332 | if ipv6 && ip.IsMulticast() { |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 333 | return scope(ip[1] & 0xf) |
| 334 | } |
Mikio Hara | aadd84e | 2015-07-17 17:31:49 +0900 | [diff] [blame] | 335 | // Site-local addresses are defined in RFC 3513 section 2.5.6 |
| 336 | // (and deprecated in RFC 3879). |
| 337 | if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 { |
| 338 | return scopeSiteLocal |
| 339 | } |
Brad Fitzpatrick | adb1e03 | 2015-07-15 17:02:06 -0700 | [diff] [blame] | 340 | return scopeGlobal |
| 341 | } |
| 342 | |
| 343 | // commonPrefixLen reports the length of the longest prefix (looking |
| 344 | // at the most significant, or leftmost, bits) that the |
| 345 | // two addresses have in common, up to the length of a's prefix (i.e., |
| 346 | // the portion of the address not including the interface ID). |
| 347 | // |
| 348 | // If a or b is an IPv4 address as an IPv6 address, the IPv4 addresses |
| 349 | // are compared (with max common prefix length of 32). |
| 350 | // If a and b are different IP versions, 0 is returned. |
| 351 | // |
| 352 | // See https://tools.ietf.org/html/rfc6724#section-2.2 |
| 353 | func commonPrefixLen(a, b IP) (cpl int) { |
| 354 | if a4 := a.To4(); a4 != nil { |
| 355 | a = a4 |
| 356 | } |
| 357 | if b4 := b.To4(); b4 != nil { |
| 358 | b = b4 |
| 359 | } |
| 360 | if len(a) != len(b) { |
| 361 | return 0 |
| 362 | } |
| 363 | // If IPv6, only up to the prefix (first 64 bits) |
| 364 | if len(a) > 8 { |
| 365 | a = a[:8] |
| 366 | b = b[:8] |
| 367 | } |
| 368 | for len(a) > 0 { |
| 369 | if a[0] == b[0] { |
| 370 | cpl += 8 |
| 371 | a = a[1:] |
| 372 | b = b[1:] |
| 373 | continue |
| 374 | } |
| 375 | bits := 8 |
| 376 | ab, bb := a[0], b[0] |
| 377 | for { |
| 378 | ab >>= 1 |
| 379 | bb >>= 1 |
| 380 | bits-- |
| 381 | if ab == bb { |
| 382 | cpl += bits |
| 383 | return |
| 384 | } |
| 385 | } |
| 386 | } |
| 387 | return |
| 388 | } |