6
6
7
7
package net
8
8
9
- import "sort"
9
+ import (
10
+ "net/netip"
11
+ "sort"
12
+ )
10
13
11
14
func sortByRFC6724 (addrs []IPAddr ) {
12
15
if len (addrs ) < 2 {
@@ -15,14 +18,15 @@ func sortByRFC6724(addrs []IPAddr) {
15
18
sortByRFC6724withSrcs (addrs , srcAddrs (addrs ))
16
19
}
17
20
18
- func sortByRFC6724withSrcs (addrs []IPAddr , srcs []IP ) {
21
+ func sortByRFC6724withSrcs (addrs []IPAddr , srcs []netip. Addr ) {
19
22
if len (addrs ) != len (srcs ) {
20
23
panic ("internal error" )
21
24
}
22
25
addrAttr := make ([]ipAttr , len (addrs ))
23
26
srcAttr := make ([]ipAttr , len (srcs ))
24
27
for i , v := range addrs {
25
- addrAttr [i ] = ipAttrOf (v .IP )
28
+ addrAttrIP , _ := netip .AddrFromSlice (v .IP )
29
+ addrAttr [i ] = ipAttrOf (addrAttrIP )
26
30
srcAttr [i ] = ipAttrOf (srcs [i ])
27
31
}
28
32
sort .Stable (& byRFC6724 {
@@ -36,16 +40,16 @@ func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
36
40
// srcsAddrs tries to UDP-connect to each address to see if it has a
37
41
// route. (This doesn't send any packets). The destination port
38
42
// number is irrelevant.
39
- func srcAddrs (addrs []IPAddr ) []IP {
40
- srcs := make ([]IP , len (addrs ))
43
+ func srcAddrs (addrs []IPAddr ) []netip. Addr {
44
+ srcs := make ([]netip. Addr , len (addrs ))
41
45
dst := UDPAddr {Port : 9 }
42
46
for i := range addrs {
43
47
dst .IP = addrs [i ].IP
44
48
dst .Zone = addrs [i ].Zone
45
49
c , err := DialUDP ("udp" , nil , & dst )
46
50
if err == nil {
47
51
if src , ok := c .LocalAddr ().(* UDPAddr ); ok {
48
- srcs [i ] = src .IP
52
+ srcs [i ], _ = netip . AddrFromSlice ( src .IP )
49
53
}
50
54
c .Close ()
51
55
}
@@ -59,8 +63,8 @@ type ipAttr struct {
59
63
Label uint8
60
64
}
61
65
62
- func ipAttrOf (ip IP ) ipAttr {
63
- if ip == nil {
66
+ func ipAttrOf (ip netip. Addr ) ipAttr {
67
+ if ! ip . IsValid () {
64
68
return ipAttr {}
65
69
}
66
70
match := rfc6724policyTable .Classify (ip )
@@ -74,7 +78,7 @@ func ipAttrOf(ip IP) ipAttr {
74
78
type byRFC6724 struct {
75
79
addrs []IPAddr // addrs to sort
76
80
addrAttr []ipAttr
77
- srcs []IP // or nil if unreachable
81
+ srcs []netip. Addr // or not valid addr if unreachable
78
82
srcAttr []ipAttr
79
83
}
80
84
@@ -108,13 +112,13 @@ func (s *byRFC6724) Less(i, j int) bool {
108
112
// If DB is known to be unreachable or if Source(DB) is undefined, then
109
113
// prefer DA. Similarly, if DA is known to be unreachable or if
110
114
// Source(DA) is undefined, then prefer DB.
111
- if SourceDA == nil && SourceDB == nil {
115
+ if ! SourceDA . IsValid () && ! SourceDB . IsValid () {
112
116
return false // "equal"
113
117
}
114
- if SourceDB == nil {
118
+ if ! SourceDB . IsValid () {
115
119
return preferDA
116
120
}
117
- if SourceDA == nil {
121
+ if ! SourceDA . IsValid () {
118
122
return preferDB
119
123
}
120
124
@@ -184,7 +188,7 @@ func (s *byRFC6724) Less(i, j int) bool {
184
188
return preferDB
185
189
}
186
190
187
- // Rule 9: Use longest matching prefix.
191
+ // Rule 9: Use the longest matching prefix.
188
192
// When DA and DB belong to the same address family (both are IPv6 or
189
193
// both are IPv4 [but see below]): If CommonPrefixLen(Source(DA), DA) >
190
194
// CommonPrefixLen(Source(DB), DB), then prefer DA. Similarly, if
@@ -212,98 +216,83 @@ func (s *byRFC6724) Less(i, j int) bool {
212
216
}
213
217
214
218
type policyTableEntry struct {
215
- Prefix * IPNet
219
+ Prefix netip. Prefix
216
220
Precedence uint8
217
221
Label uint8
218
222
}
219
223
220
224
type policyTable []policyTableEntry
221
225
222
226
// RFC 6724 section 2.1.
227
+ // Items are sorted by the size of their Prefix.Mask.Size,
223
228
var rfc6724policyTable = policyTable {
224
229
{
225
- Prefix : mustCIDR ("::1/128" ),
230
+ // "::1/128"
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 ),
226
232
Precedence : 50 ,
227
233
Label : 0 ,
228
234
},
229
235
{
230
- Prefix : mustCIDR ("::/0" ),
231
- Precedence : 40 ,
232
- Label : 1 ,
233
- },
234
- {
236
+ // "::ffff:0:0/96"
235
237
// IPv4-compatible, etc.
236
- Prefix : mustCIDR ( "::ffff:0:0/96" ),
238
+ Prefix : netip . PrefixFrom ( netip . AddrFrom16 ([ 16 ] byte { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0xff }), 96 ),
237
239
Precedence : 35 ,
238
240
Label : 4 ,
239
241
},
240
242
{
241
- // 6to4
242
- Prefix : mustCIDR ( "2002::/16" ),
243
- Precedence : 30 ,
244
- Label : 2 ,
243
+ // "::/96"
244
+ Prefix : netip . PrefixFrom ( netip . AddrFrom16 ([ 16 ] byte {}), 96 ),
245
+ Precedence : 1 ,
246
+ Label : 3 ,
245
247
},
246
248
{
249
+ // "2001::/32"
247
250
// Teredo
248
- Prefix : mustCIDR ( "2001::/32" ),
251
+ Prefix : netip . PrefixFrom ( netip . AddrFrom16 ([ 16 ] byte { 0x20 , 0x01 }), 32 ),
249
252
Precedence : 5 ,
250
253
Label : 5 ,
251
254
},
252
255
{
253
- Prefix : mustCIDR ("fc00::/7" ),
254
- Precedence : 3 ,
255
- Label : 13 ,
256
+ // "2002::/16"
257
+ // 6to4
258
+ Prefix : netip .PrefixFrom (netip .AddrFrom16 ([16 ]byte {0x20 , 0x02 }), 16 ),
259
+ Precedence : 30 ,
260
+ Label : 2 ,
256
261
},
257
262
{
258
- Prefix : mustCIDR ("::/96" ),
263
+ // "3ffe::/16"
264
+ Prefix : netip .PrefixFrom (netip .AddrFrom16 ([16 ]byte {0x3f , 0xfe }), 16 ),
259
265
Precedence : 1 ,
260
- Label : 3 ,
266
+ Label : 12 ,
261
267
},
262
268
{
263
- Prefix : mustCIDR ("fec0::/10" ),
269
+ // "fec0::/10"
270
+ Prefix : netip .PrefixFrom (netip .AddrFrom16 ([16 ]byte {0xfe , 0xc0 }), 10 ),
264
271
Precedence : 1 ,
265
272
Label : 11 ,
266
273
},
267
274
{
268
- Prefix : mustCIDR ("3ffe::/16" ),
269
- Precedence : 1 ,
270
- Label : 12 ,
275
+ // "fc00::/7"
276
+ Prefix : netip .PrefixFrom (netip .AddrFrom16 ([16 ]byte {0xfc }), 7 ),
277
+ Precedence : 3 ,
278
+ Label : 13 ,
279
+ },
280
+ {
281
+ // "::/0"
282
+ Prefix : netip .PrefixFrom (netip .AddrFrom16 ([16 ]byte {}), 0 ),
283
+ Precedence : 40 ,
284
+ Label : 1 ,
271
285
},
272
- }
273
-
274
- func 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.
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
- // mustCIDR calls ParseCIDR and panics on any error, or if the network
291
- // is not IPv6.
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
286
}
302
287
303
288
// Classify returns the policyTableEntry of the entry with the longest
304
289
// matching prefix that contains ip.
305
290
// The table t must be sorted from largest mask size to smallest.
306
- func (t policyTable ) Classify (ip IP ) policyTableEntry {
291
+ func (t policyTable ) Classify (ip netip.Addr ) policyTableEntry {
292
+ // Prefix.Contains() will not match an IPv6 prefix for an IPv4 address.
293
+ if ip .Is4 () {
294
+ ip = netip .AddrFrom16 (ip .As16 ())
295
+ }
307
296
for _ , ent := range t {
308
297
if ent .Prefix .Contains (ip ) {
309
298
return ent
@@ -324,17 +313,18 @@ const (
324
313
scopeGlobal scope = 0xe
325
314
)
326
315
327
- func classifyScope (ip IP ) scope {
316
+ func classifyScope (ip netip. Addr ) scope {
328
317
if ip .IsLoopback () || ip .IsLinkLocalUnicast () {
329
318
return scopeLinkLocal
330
319
}
331
- ipv6 := len (ip ) == IPv6len && ip .To4 () == nil
320
+ ipv6 := ip .Is6 () && ! ip .Is4In6 ()
321
+ ipv6AsBytes := ip .As16 ()
332
322
if ipv6 && ip .IsMulticast () {
333
- return scope (ip [1 ] & 0xf )
323
+ return scope (ipv6AsBytes [1 ] & 0xf )
334
324
}
335
325
// Site-local addresses are defined in RFC 3513 section 2.5.6
336
326
// (and deprecated in RFC 3879).
337
- if ipv6 && ip [0 ] == 0xfe && ip [1 ]& 0xc0 == 0xc0 {
327
+ if ipv6 && ipv6AsBytes [0 ] == 0xfe && ipv6AsBytes [1 ]& 0xc0 == 0xc0 {
338
328
return scopeSiteLocal
339
329
}
340
330
return scopeGlobal
@@ -350,30 +340,28 @@ func classifyScope(ip IP) scope {
350
340
// If a and b are different IP versions, 0 is returned.
351
341
//
352
342
// See https://tools.ietf.org/html/rfc6724#section-2.2
353
- func commonPrefixLen (a , b IP ) (cpl int ) {
354
- if a4 := a .To4 (); a4 != nil {
355
- a = a4
356
- }
343
+ func commonPrefixLen (a netip.Addr , b IP ) (cpl int ) {
357
344
if b4 := b .To4 (); b4 != nil {
358
345
b = b4
359
346
}
360
- if len (a ) != len (b ) {
347
+ aAsSlice := a .AsSlice ()
348
+ if len (aAsSlice ) != len (b ) {
361
349
return 0
362
350
}
363
351
// If IPv6, only up to the prefix (first 64 bits)
364
- if len (a ) > 8 {
365
- a = a [:8 ]
352
+ if len (aAsSlice ) > 8 {
353
+ aAsSlice = aAsSlice [:8 ]
366
354
b = b [:8 ]
367
355
}
368
- for len (a ) > 0 {
369
- if a [0 ] == b [0 ] {
356
+ for len (aAsSlice ) > 0 {
357
+ if aAsSlice [0 ] == b [0 ] {
370
358
cpl += 8
371
- a = a [1 :]
359
+ aAsSlice = aAsSlice [1 :]
372
360
b = b [1 :]
373
361
continue
374
362
}
375
363
bits := 8
376
- ab , bb := a [0 ], b [0 ]
364
+ ab , bb := aAsSlice [0 ], b [0 ]
377
365
for {
378
366
ab >>= 1
379
367
bb >>= 1
0 commit comments