blob: e22fbac5cee1a99ac0ae7fa7ff31e6e4036a15a0 [file] [log] [blame]
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -07001// 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
9package net
10
11import "sort"
12
13func sortByRFC6724(addrs []IPAddr) {
14 if len(addrs) < 2 {
15 return
16 }
17 sortByRFC6724withSrcs(addrs, srcAddrs(addrs))
18}
19
20func 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.
41func srcAddrs(addrs []IPAddr) []IP {
42 srcs := make([]IP, len(addrs))
Mikio Hara2899be82015-07-17 10:16:45 +090043 dst := UDPAddr{Port: 9}
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -070044 for i := range addrs {
Mikio Hara2899be82015-07-17 10:16:45 +090045 dst.IP = addrs[i].IP
46 dst.Zone = addrs[i].Zone
47 c, err := DialUDP("udp", nil, &dst)
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -070048 if err == nil {
Mikio Hara2899be82015-07-17 10:16:45 +090049 if src, ok := c.LocalAddr().(*UDPAddr); ok {
50 srcs[i] = src.IP
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -070051 }
Mikio Hara2899be82015-07-17 10:16:45 +090052 c.Close()
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -070053 }
54 }
55 return srcs
56}
57
58type ipAttr struct {
59 Scope scope
60 Precedence uint8
61 Label uint8
62}
63
64func 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
76type byRFC6724 struct {
77 addrs []IPAddr // addrs to sort
78 addrAttr []ipAttr
79 srcs []IP // or nil if unreachable
80 srcAttr []ipAttr
81}
82
83func (s *byRFC6724) Len() int { return len(s.addrs) }
84
85func (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.
96func (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
214type policyTableEntry struct {
215 Prefix *IPNet
216 Precedence uint8
217 Label uint8
218}
219
220type policyTable []policyTableEntry
221
222// RFC 6724 section 2.1.
223var 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
274func 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.
280type byMaskLength []policyTableEntry
281
282func (s byMaskLength) Len() int { return len(s) }
283func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
284func (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.
292func 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.
306func (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.
316type scope uint8
317
318const (
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
327func classifyScope(ip IP) scope {
328 if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
329 return scopeLinkLocal
330 }
Mikio Haraaadd84e2015-07-17 17:31:49 +0900331 ipv6 := len(ip) == IPv6len && ip.To4() == nil
332 if ipv6 && ip.IsMulticast() {
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -0700333 return scope(ip[1] & 0xf)
334 }
Mikio Haraaadd84e2015-07-17 17:31:49 +0900335 // 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 Fitzpatrickadb1e032015-07-15 17:02:06 -0700340 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
353func 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}