Source file
src/net/addrselect.go
Documentation: net
1
2
3
4
5
6
7 package net
8
9 import "sort"
10
11 func sortByRFC6724(addrs []IPAddr) {
12 if len(addrs) < 2 {
13 return
14 }
15 sortByRFC6724withSrcs(addrs, srcAddrs(addrs))
16 }
17
18 func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
19 if len(addrs) != len(srcs) {
20 panic("internal error")
21 }
22 addrAttr := make([]ipAttr, len(addrs))
23 srcAttr := make([]ipAttr, len(srcs))
24 for i, v := range addrs {
25 addrAttr[i] = ipAttrOf(v.IP)
26 srcAttr[i] = ipAttrOf(srcs[i])
27 }
28 sort.Stable(&byRFC6724{
29 addrs: addrs,
30 addrAttr: addrAttr,
31 srcs: srcs,
32 srcAttr: srcAttr,
33 })
34 }
35
36
37
38
39 func srcAddrs(addrs []IPAddr) []IP {
40 srcs := make([]IP, len(addrs))
41 dst := UDPAddr{Port: 9}
42 for i := range addrs {
43 dst.IP = addrs[i].IP
44 dst.Zone = addrs[i].Zone
45 c, err := DialUDP("udp", nil, &dst)
46 if err == nil {
47 if src, ok := c.LocalAddr().(*UDPAddr); ok {
48 srcs[i] = src.IP
49 }
50 c.Close()
51 }
52 }
53 return srcs
54 }
55
56 type ipAttr struct {
57 Scope scope
58 Precedence uint8
59 Label uint8
60 }
61
62 func ipAttrOf(ip IP) ipAttr {
63 if ip == nil {
64 return ipAttr{}
65 }
66 match := rfc6724policyTable.Classify(ip)
67 return ipAttr{
68 Scope: classifyScope(ip),
69 Precedence: match.Precedence,
70 Label: match.Label,
71 }
72 }
73
74 type byRFC6724 struct {
75 addrs []IPAddr
76 addrAttr []ipAttr
77 srcs []IP
78 srcAttr []ipAttr
79 }
80
81 func (s *byRFC6724) Len() int { return len(s.addrs) }
82
83 func (s *byRFC6724) Swap(i, j int) {
84 s.addrs[i], s.addrs[j] = s.addrs[j], s.addrs[i]
85 s.srcs[i], s.srcs[j] = s.srcs[j], s.srcs[i]
86 s.addrAttr[i], s.addrAttr[j] = s.addrAttr[j], s.addrAttr[i]
87 s.srcAttr[i], s.srcAttr[j] = s.srcAttr[j], s.srcAttr[i]
88 }
89
90
91
92
93
94 func (s *byRFC6724) Less(i, j int) bool {
95 DA := s.addrs[i].IP
96 DB := s.addrs[j].IP
97 SourceDA := s.srcs[i]
98 SourceDB := s.srcs[j]
99 attrDA := &s.addrAttr[i]
100 attrDB := &s.addrAttr[j]
101 attrSourceDA := &s.srcAttr[i]
102 attrSourceDB := &s.srcAttr[j]
103
104 const preferDA = true
105 const preferDB = false
106
107
108
109
110
111 if SourceDA == nil && SourceDB == nil {
112 return false
113 }
114 if SourceDB == nil {
115 return preferDA
116 }
117 if SourceDA == nil {
118 return preferDB
119 }
120
121
122
123
124
125 if attrDA.Scope == attrSourceDA.Scope && attrDB.Scope != attrSourceDB.Scope {
126 return preferDA
127 }
128 if attrDA.Scope != attrSourceDA.Scope && attrDB.Scope == attrSourceDB.Scope {
129 return preferDB
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 if attrSourceDA.Label == attrDA.Label &&
152 attrSourceDB.Label != attrDB.Label {
153 return preferDA
154 }
155 if attrSourceDA.Label != attrDA.Label &&
156 attrSourceDB.Label == attrDB.Label {
157 return preferDB
158 }
159
160
161
162
163 if attrDA.Precedence > attrDB.Precedence {
164 return preferDA
165 }
166 if attrDA.Precedence < attrDB.Precedence {
167 return preferDB
168 }
169
170
171
172
173
174
175
176
177
178
179
180 if attrDA.Scope < attrDB.Scope {
181 return preferDA
182 }
183 if attrDA.Scope > attrDB.Scope {
184 return preferDB
185 }
186
187
188
189
190
191
192
193
194
195
196 if DA.To4() == nil && DB.To4() == nil {
197 commonA := commonPrefixLen(SourceDA, DA)
198 commonB := commonPrefixLen(SourceDB, DB)
199
200 if commonA > commonB {
201 return preferDA
202 }
203 if commonA < commonB {
204 return preferDB
205 }
206 }
207
208
209
210
211 return false
212 }
213
214 type policyTableEntry struct {
215 Prefix *IPNet
216 Precedence uint8
217 Label uint8
218 }
219
220 type policyTable []policyTableEntry
221
222
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
236 Prefix: mustCIDR("::ffff:0:0/96"),
237 Precedence: 35,
238 Label: 4,
239 },
240 {
241
242 Prefix: mustCIDR("2002::/16"),
243 Precedence: 30,
244 Label: 2,
245 },
246 {
247
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
279
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
291
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
304
305
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
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 }
331 ipv6 := len(ip) == IPv6len && ip.To4() == nil
332 if ipv6 && ip.IsMulticast() {
333 return scope(ip[1] & 0xf)
334 }
335
336
337 if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
338 return scopeSiteLocal
339 }
340 return scopeGlobal
341 }
342
343
344
345
346
347
348
349
350
351
352
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
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 }
389
View as plain text