Source file
src/net/addrselect.go
Documentation: net
1
2
3
4
5
6
7
8
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
40
41
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
79 addrAttr []ipAttr
80 srcs []IP
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
94
95
96
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
111
112
113
114 if SourceDA == nil && SourceDB == nil {
115 return false
116 }
117 if SourceDB == nil {
118 return preferDA
119 }
120 if SourceDA == nil {
121 return preferDB
122 }
123
124
125
126
127
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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
164
165
166 if attrDA.Precedence > attrDB.Precedence {
167 return preferDA
168 }
169 if attrDA.Precedence < attrDB.Precedence {
170 return preferDB
171 }
172
173
174
175
176
177
178
179
180
181
182
183 if attrDA.Scope < attrDB.Scope {
184 return preferDA
185 }
186 if attrDA.Scope > attrDB.Scope {
187 return preferDB
188 }
189
190
191
192
193
194
195
196
197
198
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
212
213
214 return false
215 }
216
217 type policyTableEntry struct {
218 Prefix *IPNet
219 Precedence uint8
220 Label uint8
221 }
222
223 type policyTable []policyTableEntry
224
225
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
239 Prefix: mustCIDR("::ffff:0:0/96"),
240 Precedence: 35,
241 Label: 4,
242 },
243 {
244
245 Prefix: mustCIDR("2002::/16"),
246 Precedence: 30,
247 Label: 2,
248 },
249 {
250
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
282
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
294
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
307
308
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
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
339
340 if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
341 return scopeSiteLocal
342 }
343 return scopeGlobal
344 }
345
346
347
348
349
350
351
352
353
354
355
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
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