blob: 80aa4eb195b535ffb1811b2c60660221def9429c [file] [log] [blame]
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -07001// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build darwin dragonfly freebsd linux netbsd openbsd solaris
6
7package net
8
9import (
10 "reflect"
11 "testing"
12)
13
14func TestSortByRFC6724(t *testing.T) {
15 tests := []struct {
16 in []IPAddr
17 srcs []IP
18 want []IPAddr
19 reverse bool // also test it starting backwards
20 }{
21 // Examples from RFC 6724 section 10.2:
22
23 // Prefer matching scope.
24 {
25 in: []IPAddr{
26 {IP: ParseIP("2001:db8:1::1")},
27 {IP: ParseIP("198.51.100.121")},
28 },
29 srcs: []IP{
30 ParseIP("2001:db8:1::2"),
31 ParseIP("169.254.13.78"),
32 },
33 want: []IPAddr{
34 {IP: ParseIP("2001:db8:1::1")},
35 {IP: ParseIP("198.51.100.121")},
36 },
37 reverse: true,
38 },
39
40 // Prefer matching scope.
41 {
42 in: []IPAddr{
43 {IP: ParseIP("2001:db8:1::1")},
44 {IP: ParseIP("198.51.100.121")},
45 },
46 srcs: []IP{
47 ParseIP("fe80::1"),
48 ParseIP("198.51.100.117"),
49 },
50 want: []IPAddr{
51 {IP: ParseIP("198.51.100.121")},
52 {IP: ParseIP("2001:db8:1::1")},
53 },
54 reverse: true,
55 },
56
57 // Prefer higher precedence.
58 {
59 in: []IPAddr{
60 {IP: ParseIP("2001:db8:1::1")},
61 {IP: ParseIP("10.1.2.3")},
62 },
63 srcs: []IP{
64 ParseIP("2001:db8:1::2"),
65 ParseIP("10.1.2.4"),
66 },
67 want: []IPAddr{
68 {IP: ParseIP("2001:db8:1::1")},
69 {IP: ParseIP("10.1.2.3")},
70 },
71 reverse: true,
72 },
73
74 // Prefer smaller scope.
75 {
76 in: []IPAddr{
77 {IP: ParseIP("2001:db8:1::1")},
78 {IP: ParseIP("fe80::1")},
79 },
80 srcs: []IP{
81 ParseIP("2001:db8:1::2"),
82 ParseIP("fe80::2"),
83 },
84 want: []IPAddr{
85 {IP: ParseIP("fe80::1")},
86 {IP: ParseIP("2001:db8:1::1")},
87 },
88 reverse: true,
89 },
Matthew Dempsky4d4a2662015-11-16 20:26:24 -080090
91 // Issue 13283. Having a 10/8 source address does not
92 // mean we should prefer 23/8 destination addresses.
93 {
94 in: []IPAddr{
95 {IP: ParseIP("54.83.193.112")},
96 {IP: ParseIP("184.72.238.214")},
97 {IP: ParseIP("23.23.172.185")},
98 {IP: ParseIP("75.101.148.21")},
99 {IP: ParseIP("23.23.134.56")},
100 {IP: ParseIP("23.21.50.150")},
101 },
102 srcs: []IP{
103 ParseIP("10.2.3.4"),
104 ParseIP("10.2.3.4"),
105 ParseIP("10.2.3.4"),
106 ParseIP("10.2.3.4"),
107 ParseIP("10.2.3.4"),
108 ParseIP("10.2.3.4"),
109 },
110 want: []IPAddr{
111 {IP: ParseIP("54.83.193.112")},
112 {IP: ParseIP("184.72.238.214")},
113 {IP: ParseIP("23.23.172.185")},
114 {IP: ParseIP("75.101.148.21")},
115 {IP: ParseIP("23.23.134.56")},
116 {IP: ParseIP("23.21.50.150")},
117 },
118 reverse: false,
119 },
120
121 // Prefer longer common prefixes, but only for IPv4 address
122 // pairs in the same special-purpose block.
123 {
124 in: []IPAddr{
125 {IP: ParseIP("1.2.3.4")},
126 {IP: ParseIP("10.55.0.1")},
127 {IP: ParseIP("10.66.0.1")},
128 },
129 srcs: []IP{
130 ParseIP("1.2.3.5"),
131 ParseIP("10.66.1.2"),
132 ParseIP("10.66.1.2"),
133 },
134 want: []IPAddr{
135 {IP: ParseIP("10.66.0.1")},
136 {IP: ParseIP("10.55.0.1")},
137 {IP: ParseIP("1.2.3.4")},
138 },
139 reverse: true,
140 },
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -0700141 }
142 for i, tt := range tests {
143 inCopy := make([]IPAddr, len(tt.in))
144 copy(inCopy, tt.in)
145 srcCopy := make([]IP, len(tt.in))
146 copy(srcCopy, tt.srcs)
147 sortByRFC6724withSrcs(inCopy, srcCopy)
148 if !reflect.DeepEqual(inCopy, tt.want) {
149 t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
150 }
151 if tt.reverse {
152 copy(inCopy, tt.in)
153 copy(srcCopy, tt.srcs)
154 for j := 0; j < len(inCopy)/2; j++ {
155 k := len(inCopy) - j - 1
156 inCopy[j], inCopy[k] = inCopy[k], inCopy[j]
157 srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j]
158 }
159 sortByRFC6724withSrcs(inCopy, srcCopy)
160 if !reflect.DeepEqual(inCopy, tt.want) {
161 t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
162 }
163 }
164
165 }
166
167}
168
169func TestRFC6724PolicyTableClassify(t *testing.T) {
170 tests := []struct {
171 ip IP
172 want policyTableEntry
173 }{
174 {
175 ip: ParseIP("127.0.0.1"),
176 want: policyTableEntry{
177 Prefix: &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)},
178 Precedence: 35,
179 Label: 4,
180 },
181 },
182 {
183 ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"),
184 want: policyTableEntry{
185 Prefix: &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)},
186 Precedence: 40,
187 Label: 1,
188 },
189 },
190 {
191 ip: ParseIP("::1"),
192 want: policyTableEntry{
193 Prefix: &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)},
194 Precedence: 50,
195 Label: 0,
196 },
197 },
198 {
199 ip: ParseIP("2002::ab12"),
200 want: policyTableEntry{
201 Prefix: &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)},
202 Precedence: 30,
203 Label: 2,
204 },
205 },
206 }
207 for i, tt := range tests {
208 got := rfc6724policyTable.Classify(tt.ip)
209 if !reflect.DeepEqual(got, tt.want) {
210 t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want)
211 }
212 }
213}
214
215func TestRFC6724ClassifyScope(t *testing.T) {
216 tests := []struct {
217 ip IP
218 want scope
219 }{
220 {ParseIP("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2
221 {ParseIP("::1"), scopeLinkLocal}, // rfc4007#section-4
222 {ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
Mikio Haraaadd84e2015-07-17 17:31:49 +0900223 {ParseIP("fec0::1"), scopeSiteLocal},
Brad Fitzpatrickadb1e032015-07-15 17:02:06 -0700224 {ParseIP("8.8.8.8"), scopeGlobal},
225
226 {ParseIP("ff02::"), scopeLinkLocal}, // IPv6 multicast
227 {ParseIP("ff05::"), scopeSiteLocal}, // IPv6 multicast
228 {ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast
229 {ParseIP("ff0e::"), scopeGlobal}, // IPv6 multicast
230
231 {IPv4(0xe0, 0, 0, 0), scopeGlobal}, // IPv4 link-local multicast as 16 bytes
232 {IPv4(0xe0, 2, 2, 2), scopeGlobal}, // IPv4 global multicast as 16 bytes
233 {IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes
234 {IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes
235 }
236 for i, tt := range tests {
237 got := classifyScope(tt.ip)
238 if got != tt.want {
239 t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want)
240 }
241 }
242}
243
244func TestRFC6724CommonPrefixLength(t *testing.T) {
245 tests := []struct {
246 a, b IP
247 want int
248 }{
249 {ParseIP("fe80::1"), ParseIP("fe80::2"), 64},
250 {ParseIP("fe81::1"), ParseIP("fe80::2"), 15},
251 {ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
252 {IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32},
253 {IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16},
254 {IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17},
255 {IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18},
256 {IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19},
257 {IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20},
258 {IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21},
259 {IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22},
260 {IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23},
261 {IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24},
262 }
263 for i, tt := range tests {
264 got := commonPrefixLen(tt.a, tt.b)
265 if got != tt.want {
266 t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want)
267 }
268 }
269
270}
Matthew Dempsky4d4a2662015-11-16 20:26:24 -0800271
272func mustParseCIDRs(t *testing.T, blocks ...string) []*IPNet {
273 res := make([]*IPNet, len(blocks))
274 for i, block := range blocks {
275 var err error
276 _, res[i], err = ParseCIDR(block)
277 if err != nil {
278 t.Fatalf("ParseCIDR(%s) failed: %v", block, err)
279 }
280 }
281 return res
282}
283
284func TestSameIPv4SpecialPurposeBlock(t *testing.T) {
285 blocks := mustParseCIDRs(t,
286 "10.0.0.0/8",
287 "127.0.0.0/8",
288 "169.254.0.0/16",
289 "172.16.0.0/12",
290 "192.168.0.0/16",
291 )
292
293 addrs := []struct {
294 ip IP
295 block int // index or -1
296 }{
297 {IP{1, 2, 3, 4}, -1},
298 {IP{2, 3, 4, 5}, -1},
299 {IP{10, 2, 3, 4}, 0},
300 {IP{10, 6, 7, 8}, 0},
301 {IP{127, 0, 0, 1}, 1},
302 {IP{127, 255, 255, 255}, 1},
303 {IP{169, 254, 77, 99}, 2},
304 {IP{169, 254, 44, 22}, 2},
305 {IP{169, 255, 0, 1}, -1},
306 {IP{172, 15, 5, 6}, -1},
307 {IP{172, 16, 32, 41}, 3},
308 {IP{172, 31, 128, 9}, 3},
309 {IP{172, 32, 88, 100}, -1},
310 {IP{192, 168, 1, 1}, 4},
311 {IP{192, 168, 128, 42}, 4},
312 {IP{192, 169, 1, 1}, -1},
313 }
314
315 for i, addr := range addrs {
316 for j, block := range blocks {
317 got := block.Contains(addr.ip)
318 want := addr.block == j
319 if got != want {
320 t.Errorf("%d/%d. %s.Contains(%s): got %v, want %v", i, j, block, addr.ip, got, want)
321 }
322 }
323 }
324
325 for i, addr1 := range addrs {
326 for j, addr2 := range addrs {
327 got := sameIPv4SpecialPurposeBlock(addr1.ip, addr2.ip)
328 want := addr1.block >= 0 && addr1.block == addr2.block
329 if got != want {
330 t.Errorf("%d/%d. sameIPv4SpecialPurposeBlock(%s, %s): got %v, want %v", i, j, addr1.ip, addr2.ip, got, want)
331 }
332 }
333 }
334}