Source file
src/net/addrselect.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "net/netip"
11 "sort"
12 )
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 []netip.Addr) {
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 addrAttrIP, _ := netip.AddrFromSlice(v.IP)
29 addrAttr[i] = ipAttrOf(addrAttrIP)
30 srcAttr[i] = ipAttrOf(srcs[i])
31 }
32 sort.Stable(&byRFC6724{
33 addrs: addrs,
34 addrAttr: addrAttr,
35 srcs: srcs,
36 srcAttr: srcAttr,
37 })
38 }
39
40
41
42
43 func srcAddrs(addrs []IPAddr) []netip.Addr {
44 srcs := make([]netip.Addr, len(addrs))
45 dst := UDPAddr{Port: 53}
46 for i := range addrs {
47 dst.IP = addrs[i].IP
48 dst.Zone = addrs[i].Zone
49 c, err := DialUDP("udp", nil, &dst)
50 if err == nil {
51 if src, ok := c.LocalAddr().(*UDPAddr); ok {
52 srcs[i], _ = netip.AddrFromSlice(src.IP)
53 }
54 c.Close()
55 }
56 }
57 return srcs
58 }
59
60 type ipAttr struct {
61 Scope scope
62 Precedence uint8
63 Label uint8
64 }
65
66 func ipAttrOf(ip netip.Addr) ipAttr {
67 if !ip.IsValid() {
68 return ipAttr{}
69 }
70 match := rfc6724policyTable.Classify(ip)
71 return ipAttr{
72 Scope: classifyScope(ip),
73 Precedence: match.Precedence,
74 Label: match.Label,
75 }
76 }
77
78 type byRFC6724 struct {
79 addrs []IPAddr
80 addrAttr []ipAttr
81 srcs []netip.Addr
82 srcAttr []ipAttr
83 }
84
85 func (s *byRFC6724) Len() int { return len(s.addrs) }
86
87 func (s *byRFC6724) Swap(i, j int) {
88 s.addrs[i], s.addrs[j] = s.addrs[j], s.addrs[i]
89 s.srcs[i], s.srcs[j] = s.srcs[j], s.srcs[i]
90 s.addrAttr[i], s.addrAttr[j] = s.addrAttr[j], s.addrAttr[i]
91 s.srcAttr[i], s.srcAttr[j] = s.srcAttr[j], s.srcAttr[i]
92 }
93
94
95
96
97
98 func (s *byRFC6724) Less(i, j int) bool {
99 DA := s.addrs[i].IP
100 DB := s.addrs[j].IP
101 SourceDA := s.srcs[i]
102 SourceDB := s.srcs[j]
103 attrDA := &s.addrAttr[i]
104 attrDB := &s.addrAttr[j]
105 attrSourceDA := &s.srcAttr[i]
106 attrSourceDB := &s.srcAttr[j]
107
108 const preferDA = true
109 const preferDB = false
110
111
112
113
114
115 if !SourceDA.IsValid() && !SourceDB.IsValid() {
116 return false
117 }
118 if !SourceDB.IsValid() {
119 return preferDA
120 }
121 if !SourceDA.IsValid() {
122 return preferDB
123 }
124
125
126
127
128
129 if attrDA.Scope == attrSourceDA.Scope && attrDB.Scope != attrSourceDB.Scope {
130 return preferDA
131 }
132 if attrDA.Scope != attrSourceDA.Scope && attrDB.Scope == attrSourceDB.Scope {
133 return preferDB
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 if attrSourceDA.Label == attrDA.Label &&
156 attrSourceDB.Label != attrDB.Label {
157 return preferDA
158 }
159 if attrSourceDA.Label != attrDA.Label &&
160 attrSourceDB.Label == attrDB.Label {
161 return preferDB
162 }
163
164
165
166
167 if attrDA.Precedence > attrDB.Precedence {
168 return preferDA
169 }
170 if attrDA.Precedence < attrDB.Precedence {
171 return preferDB
172 }
173
174
175
176
177
178
179
180
181
182
183
184 if attrDA.Scope < attrDB.Scope {
185 return preferDA
186 }
187 if attrDA.Scope > attrDB.Scope {
188 return preferDB
189 }
190
191
192
193
194
195
196
197
198
199
200 if DA.To4() == nil && DB.To4() == nil {
201 commonA := commonPrefixLen(SourceDA, DA)
202 commonB := commonPrefixLen(SourceDB, DB)
203
204 if commonA > commonB {
205 return preferDA
206 }
207 if commonA < commonB {
208 return preferDB
209 }
210 }
211
212
213
214
215 return false
216 }
217
218 type policyTableEntry struct {
219 Prefix netip.Prefix
220 Precedence uint8
221 Label uint8
222 }
223
224 type policyTable []policyTableEntry
225
226
227
228 var rfc6724policyTable = policyTable{
229 {
230
231 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}), 128),
232 Precedence: 50,
233 Label: 0,
234 },
235 {
236
237
238 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}), 96),
239 Precedence: 35,
240 Label: 4,
241 },
242 {
243
244 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 96),
245 Precedence: 1,
246 Label: 3,
247 },
248 {
249
250
251 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x01}), 32),
252 Precedence: 5,
253 Label: 5,
254 },
255 {
256
257
258 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x02}), 16),
259 Precedence: 30,
260 Label: 2,
261 },
262 {
263
264 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0x3f, 0xfe}), 16),
265 Precedence: 1,
266 Label: 12,
267 },
268 {
269
270 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfe, 0xc0}), 10),
271 Precedence: 1,
272 Label: 11,
273 },
274 {
275
276 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfc}), 7),
277 Precedence: 3,
278 Label: 13,
279 },
280 {
281
282 Prefix: netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0),
283 Precedence: 40,
284 Label: 1,
285 },
286 }
287
288
289
290
291 func (t policyTable) Classify(ip netip.Addr) policyTableEntry {
292
293 if ip.Is4() {
294 ip = netip.AddrFrom16(ip.As16())
295 }
296 for _, ent := range t {
297 if ent.Prefix.Contains(ip) {
298 return ent
299 }
300 }
301 return policyTableEntry{}
302 }
303
304
305 type scope uint8
306
307 const (
308 scopeInterfaceLocal scope = 0x1
309 scopeLinkLocal scope = 0x2
310 scopeAdminLocal scope = 0x4
311 scopeSiteLocal scope = 0x5
312 scopeOrgLocal scope = 0x8
313 scopeGlobal scope = 0xe
314 )
315
316 func classifyScope(ip netip.Addr) scope {
317 if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
318 return scopeLinkLocal
319 }
320 ipv6 := ip.Is6() && !ip.Is4In6()
321 ipv6AsBytes := ip.As16()
322 if ipv6 && ip.IsMulticast() {
323 return scope(ipv6AsBytes[1] & 0xf)
324 }
325
326
327 if ipv6 && ipv6AsBytes[0] == 0xfe && ipv6AsBytes[1]&0xc0 == 0xc0 {
328 return scopeSiteLocal
329 }
330 return scopeGlobal
331 }
332
333
334
335
336
337
338
339
340
341
342
343 func commonPrefixLen(a netip.Addr, b IP) (cpl int) {
344 if b4 := b.To4(); b4 != nil {
345 b = b4
346 }
347 aAsSlice := a.AsSlice()
348 if len(aAsSlice) != len(b) {
349 return 0
350 }
351
352 if len(aAsSlice) > 8 {
353 aAsSlice = aAsSlice[:8]
354 b = b[:8]
355 }
356 for len(aAsSlice) > 0 {
357 if aAsSlice[0] == b[0] {
358 cpl += 8
359 aAsSlice = aAsSlice[1:]
360 b = b[1:]
361 continue
362 }
363 bits := 8
364 ab, bb := aAsSlice[0], b[0]
365 for {
366 ab >>= 1
367 bb >>= 1
368 bits--
369 if ab == bb {
370 cpl += bits
371 return
372 }
373 }
374 }
375 return
376 }
377
View as plain text