Source file
src/net/addrselect.go
1
2
3
4
5
6
7
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
39
40
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
78 addrAttr []ipAttr
79 srcs []IP
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
93
94
95
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
110
111
112
113 if SourceDA == nil && SourceDB == nil {
114 return false
115 }
116 if SourceDB == nil {
117 return preferDA
118 }
119 if SourceDA == nil {
120 return preferDB
121 }
122
123
124
125
126
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
163
164
165 if attrDA.Precedence > attrDB.Precedence {
166 return preferDA
167 }
168 if attrDA.Precedence < attrDB.Precedence {
169 return preferDB
170 }
171
172
173
174
175
176
177
178
179
180
181
182 if attrDA.Scope < attrDB.Scope {
183 return preferDA
184 }
185 if attrDA.Scope > attrDB.Scope {
186 return preferDB
187 }
188
189
190
191
192
193
194
195
196
197
198 if DA.To4() == nil && DB.To4() == nil {
199 commonA := commonPrefixLen(SourceDA, DA)
200 commonB := commonPrefixLen(SourceDB, DB)
201
202 if commonA > commonB {
203 return preferDA
204 }
205 if commonA < commonB {
206 return preferDB
207 }
208 }
209
210
211
212
213 return false
214 }
215
216 type policyTableEntry struct {
217 Prefix *IPNet
218 Precedence uint8
219 Label uint8
220 }
221
222 type policyTable []policyTableEntry
223
224
225 var rfc6724policyTable = policyTable{
226 {
227 Prefix: mustCIDR("::1/128"),
228 Precedence: 50,
229 Label: 0,
230 },
231 {
232 Prefix: mustCIDR("::/0"),
233 Precedence: 40,
234 Label: 1,
235 },
236 {
237
238 Prefix: mustCIDR("::ffff:0:0/96"),
239 Precedence: 35,
240 Label: 4,
241 },
242 {
243
244 Prefix: mustCIDR("2002::/16"),
245 Precedence: 30,
246 Label: 2,
247 },
248 {
249
250 Prefix: mustCIDR("2001::/32"),
251 Precedence: 5,
252 Label: 5,
253 },
254 {
255 Prefix: mustCIDR("fc00::/7"),
256 Precedence: 3,
257 Label: 13,
258 },
259 {
260 Prefix: mustCIDR("::/96"),
261 Precedence: 1,
262 Label: 3,
263 },
264 {
265 Prefix: mustCIDR("fec0::/10"),
266 Precedence: 1,
267 Label: 11,
268 },
269 {
270 Prefix: mustCIDR("3ffe::/16"),
271 Precedence: 1,
272 Label: 12,
273 },
274 }
275
276 func init() {
277 sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable)))
278 }
279
280
281
282 type byMaskLength []policyTableEntry
283
284 func (s byMaskLength) Len() int { return len(s) }
285 func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
286 func (s byMaskLength) Less(i, j int) bool {
287 isize, _ := s[i].Prefix.Mask.Size()
288 jsize, _ := s[j].Prefix.Mask.Size()
289 return isize < jsize
290 }
291
292
293
294 func mustCIDR(s string) *IPNet {
295 ip, ipNet, err := ParseCIDR(s)
296 if err != nil {
297 panic(err.Error())
298 }
299 if len(ip) != IPv6len {
300 panic("unexpected IP length")
301 }
302 return ipNet
303 }
304
305
306
307
308 func (t policyTable) Classify(ip IP) policyTableEntry {
309 for _, ent := range t {
310 if ent.Prefix.Contains(ip) {
311 return ent
312 }
313 }
314 return policyTableEntry{}
315 }
316
317
318 type scope uint8
319
320 const (
321 scopeInterfaceLocal scope = 0x1
322 scopeLinkLocal scope = 0x2
323 scopeAdminLocal scope = 0x4
324 scopeSiteLocal scope = 0x5
325 scopeOrgLocal scope = 0x8
326 scopeGlobal scope = 0xe
327 )
328
329 func classifyScope(ip IP) scope {
330 if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
331 return scopeLinkLocal
332 }
333 ipv6 := len(ip) == IPv6len && ip.To4() == nil
334 if ipv6 && ip.IsMulticast() {
335 return scope(ip[1] & 0xf)
336 }
337
338
339 if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
340 return scopeSiteLocal
341 }
342 return scopeGlobal
343 }
344
345
346
347
348
349
350
351
352
353
354
355 func commonPrefixLen(a, b IP) (cpl int) {
356 if a4 := a.To4(); a4 != nil {
357 a = a4
358 }
359 if b4 := b.To4(); b4 != nil {
360 b = b4
361 }
362 if len(a) != len(b) {
363 return 0
364 }
365
366 if len(a) > 8 {
367 a = a[:8]
368 b = b[:8]
369 }
370 for len(a) > 0 {
371 if a[0] == b[0] {
372 cpl += 8
373 a = a[1:]
374 b = b[1:]
375 continue
376 }
377 bits := 8
378 ab, bb := a[0], b[0]
379 for {
380 ab >>= 1
381 bb >>= 1
382 bits--
383 if ab == bb {
384 cpl += bits
385 return
386 }
387 }
388 }
389 return
390 }
391
View as plain text