Source file
src/net/ip_test.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "bytes"
11 "math/rand"
12 "reflect"
13 "runtime"
14 "testing"
15 )
16
17 var parseIPTests = []struct {
18 in string
19 out IP
20 }{
21 {"127.0.1.2", IPv4(127, 0, 1, 2)},
22 {"127.0.0.1", IPv4(127, 0, 0, 1)},
23 {"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
24 {"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
25 {"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
26 {"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
27 {"0:0:0:0::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
28
29 {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
30 {"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
31
32 {"-0.0.0.0", nil},
33 {"0.-1.0.0", nil},
34 {"0.0.-2.0", nil},
35 {"0.0.0.-3", nil},
36 {"127.0.0.256", nil},
37 {"abc", nil},
38 {"123:", nil},
39 {"fe80::1%lo0", nil},
40 {"fe80::1%911", nil},
41 {"", nil},
42 {"a1:a2:a3:a4::b1:b2:b3:b4", nil},
43 {"127.001.002.003", nil},
44 {"::ffff:127.001.002.003", nil},
45 {"123.000.000.000", nil},
46 {"1.2..4", nil},
47 {"0123.0.0.1", nil},
48 }
49
50 func TestParseIP(t *testing.T) {
51 for _, tt := range parseIPTests {
52 if out := ParseIP(tt.in); !reflect.DeepEqual(out, tt.out) {
53 t.Errorf("ParseIP(%q) = %v, want %v", tt.in, out, tt.out)
54 }
55 if tt.in == "" {
56
57 continue
58 }
59 var out IP
60 if err := out.UnmarshalText([]byte(tt.in)); !reflect.DeepEqual(out, tt.out) || (tt.out == nil) != (err != nil) {
61 t.Errorf("IP.UnmarshalText(%q) = %v, %v, want %v", tt.in, out, err, tt.out)
62 }
63 }
64 }
65
66 func TestLookupWithIP(t *testing.T) {
67 _, err := LookupIP("")
68 if err == nil {
69 t.Errorf(`LookupIP("") succeeded, should fail`)
70 }
71 _, err = LookupHost("")
72 if err == nil {
73 t.Errorf(`LookupIP("") succeeded, should fail`)
74 }
75
76
77
78 for _, tt := range parseIPTests {
79 if tt.out != nil {
80 addrs, err := LookupHost(tt.in)
81 if len(addrs) != 1 || addrs[0] != tt.in || err != nil {
82 t.Errorf("LookupHost(%q) = %v, %v, want %v, nil", tt.in, addrs, err, []string{tt.in})
83 }
84 } else if !testing.Short() {
85
86
87
88 addrs, err := LookupHost(tt.in)
89 if err == nil {
90 t.Logf("warning: LookupHost(%q) = %v, want error", tt.in, addrs)
91 }
92 }
93
94 if tt.out != nil {
95 ips, err := LookupIP(tt.in)
96 if len(ips) != 1 || !reflect.DeepEqual(ips[0], tt.out) || err != nil {
97 t.Errorf("LookupIP(%q) = %v, %v, want %v, nil", tt.in, ips, err, []IP{tt.out})
98 }
99 } else if !testing.Short() {
100 ips, err := LookupIP(tt.in)
101
102 if err == nil {
103 t.Logf("warning: LookupIP(%q) = %v, want error", tt.in, ips)
104 }
105 }
106 }
107 }
108
109 func BenchmarkParseIP(b *testing.B) {
110 testHookUninstaller.Do(uninstallTestHooks)
111
112 for i := 0; i < b.N; i++ {
113 for _, tt := range parseIPTests {
114 ParseIP(tt.in)
115 }
116 }
117 }
118
119 func BenchmarkParseIPValidIPv4(b *testing.B) {
120 testHookUninstaller.Do(uninstallTestHooks)
121
122 for i := 0; i < b.N; i++ {
123 ParseIP("192.0.2.1")
124 }
125 }
126
127 func BenchmarkParseIPValidIPv6(b *testing.B) {
128 testHookUninstaller.Do(uninstallTestHooks)
129
130 for i := 0; i < b.N; i++ {
131 ParseIP("2001:DB8::1")
132 }
133 }
134
135
136 func TestMarshalEmptyIP(t *testing.T) {
137 for _, in := range [][]byte{nil, []byte("")} {
138 var out = IP{1, 2, 3, 4}
139 if err := out.UnmarshalText(in); err != nil || out != nil {
140 t.Errorf("UnmarshalText(%v) = %v, %v; want nil, nil", in, out, err)
141 }
142 }
143 var ip IP
144 got, err := ip.MarshalText()
145 if err != nil {
146 t.Fatal(err)
147 }
148 if !reflect.DeepEqual(got, []byte("")) {
149 t.Errorf(`got %#v, want []byte("")`, got)
150 }
151 }
152
153 var ipStringTests = []*struct {
154 in IP
155 str string
156 byt []byte
157 error
158 }{
159
160 {
161 IP{192, 0, 2, 1},
162 "192.0.2.1",
163 []byte("192.0.2.1"),
164 nil,
165 },
166 {
167 IP{0, 0, 0, 0},
168 "0.0.0.0",
169 []byte("0.0.0.0"),
170 nil,
171 },
172
173
174 {
175 IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 0, 2, 1},
176 "192.0.2.1",
177 []byte("192.0.2.1"),
178 nil,
179 },
180 {
181 IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0},
182 "0.0.0.0",
183 []byte("0.0.0.0"),
184 nil,
185 },
186
187
188 {
189 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
190 "2001:db8::123:12:1",
191 []byte("2001:db8::123:12:1"),
192 nil,
193 },
194 {
195 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
196 "2001:db8::1",
197 []byte("2001:db8::1"),
198 nil,
199 },
200 {
201 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
202 "2001:db8:0:1:0:1:0:1",
203 []byte("2001:db8:0:1:0:1:0:1"),
204 nil,
205 },
206 {
207 IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
208 "2001:db8:1:0:1:0:1:0",
209 []byte("2001:db8:1:0:1:0:1:0"),
210 nil,
211 },
212 {
213 IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
214 "2001::1:0:0:1",
215 []byte("2001::1:0:0:1"),
216 nil,
217 },
218 {
219 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
220 "2001:db8:0:0:1::",
221 []byte("2001:db8:0:0:1::"),
222 nil,
223 },
224 {
225 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
226 "2001:db8::1:0:0:1",
227 []byte("2001:db8::1:0:0:1"),
228 nil,
229 },
230 {
231 IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd},
232 "2001:db8::a:b:c:d",
233 []byte("2001:db8::a:b:c:d"),
234 nil,
235 },
236 {
237 IPv6unspecified,
238 "::",
239 []byte("::"),
240 nil,
241 },
242
243
244 {
245 nil,
246 "<nil>",
247 nil,
248 nil,
249 },
250
251
252 {
253 IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
254 "?0123456789abcdef",
255 nil,
256 &AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"},
257 },
258 }
259
260 func TestIPString(t *testing.T) {
261 for _, tt := range ipStringTests {
262 if out := tt.in.String(); out != tt.str {
263 t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.str)
264 }
265 if out, err := tt.in.MarshalText(); !bytes.Equal(out, tt.byt) || !reflect.DeepEqual(err, tt.error) {
266 t.Errorf("IP.MarshalText(%v) = %v, %v, want %v, %v", tt.in, out, err, tt.byt, tt.error)
267 }
268 }
269 }
270
271 var sink string
272
273 func BenchmarkIPString(b *testing.B) {
274 testHookUninstaller.Do(uninstallTestHooks)
275
276 b.Run("IPv4", func(b *testing.B) {
277 benchmarkIPString(b, IPv4len)
278 })
279
280 b.Run("IPv6", func(b *testing.B) {
281 benchmarkIPString(b, IPv6len)
282 })
283 }
284
285 func benchmarkIPString(b *testing.B, size int) {
286 b.ReportAllocs()
287 b.ResetTimer()
288 for i := 0; i < b.N; i++ {
289 for _, tt := range ipStringTests {
290 if tt.in != nil && len(tt.in) == size {
291 sink = tt.in.String()
292 }
293 }
294 }
295 }
296
297 var ipMaskTests = []struct {
298 in IP
299 mask IPMask
300 out IP
301 }{
302 {IPv4(192, 168, 1, 127), IPv4Mask(255, 255, 255, 128), IPv4(192, 168, 1, 0)},
303 {IPv4(192, 168, 1, 127), IPMask(ParseIP("255.255.255.192")), IPv4(192, 168, 1, 64)},
304 {IPv4(192, 168, 1, 127), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0")), IPv4(192, 168, 1, 96)},
305 {IPv4(192, 168, 1, 127), IPv4Mask(255, 0, 255, 0), IPv4(192, 0, 1, 0)},
306 {ParseIP("2001:db8::1"), IPMask(ParseIP("ffff:ff80::")), ParseIP("2001:d80::")},
307 {ParseIP("2001:db8::1"), IPMask(ParseIP("f0f0:0f0f::")), ParseIP("2000:d08::")},
308 }
309
310 func TestIPMask(t *testing.T) {
311 for _, tt := range ipMaskTests {
312 if out := tt.in.Mask(tt.mask); out == nil || !tt.out.Equal(out) {
313 t.Errorf("IP(%v).Mask(%v) = %v, want %v", tt.in, tt.mask, out, tt.out)
314 }
315 }
316 }
317
318 var ipMaskStringTests = []struct {
319 in IPMask
320 out string
321 }{
322 {IPv4Mask(255, 255, 255, 240), "fffffff0"},
323 {IPv4Mask(255, 0, 128, 0), "ff008000"},
324 {IPMask(ParseIP("ffff:ff80::")), "ffffff80000000000000000000000000"},
325 {IPMask(ParseIP("ef00:ff80::cafe:0")), "ef00ff800000000000000000cafe0000"},
326 {nil, "<nil>"},
327 }
328
329 func TestIPMaskString(t *testing.T) {
330 for _, tt := range ipMaskStringTests {
331 if out := tt.in.String(); out != tt.out {
332 t.Errorf("IPMask.String(%v) = %q, want %q", tt.in, out, tt.out)
333 }
334 }
335 }
336
337 func BenchmarkIPMaskString(b *testing.B) {
338 testHookUninstaller.Do(uninstallTestHooks)
339
340 for i := 0; i < b.N; i++ {
341 for _, tt := range ipMaskStringTests {
342 sink = tt.in.String()
343 }
344 }
345 }
346
347 var parseCIDRTests = []struct {
348 in string
349 ip IP
350 net *IPNet
351 err error
352 }{
353 {"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
354 {"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IP: IPv4(0, 0, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
355 {"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
356 {"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 1), Mask: IPv4Mask(255, 255, 255, 255)}, nil},
357 {"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IP: IPv4(135, 104, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)}, nil},
358 {"::1/128", ParseIP("::1"), &IPNet{IP: ParseIP("::1"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
359 {"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
360 {"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
361 {"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
362 {"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
363 {"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
364 {"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2345::"), Mask: IPMask(ParseIP("ffff:ffff::"))}, nil},
365 {"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{IP: ParseIP("abcd:2344::"), Mask: IPMask(ParseIP("ffff:fffe::"))}, nil},
366 {"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
367 {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
368 {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
369 {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
370 {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
371 {"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
372 {"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
373 {"2001:db8::1/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-0"}},
374 {"-0.0.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "-0.0.0.0/32"}},
375 {"0.-1.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.-1.0.0/32"}},
376 {"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
377 {"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
378 {"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
379 {"127.000.000.001/32", nil, nil, &ParseError{Type: "CIDR address", Text: "127.000.000.001/32"}},
380 {"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
381 }
382
383 func TestParseCIDR(t *testing.T) {
384 for _, tt := range parseCIDRTests {
385 ip, net, err := ParseCIDR(tt.in)
386 if !reflect.DeepEqual(err, tt.err) {
387 t.Errorf("ParseCIDR(%q) = %v, %v; want %v, %v", tt.in, ip, net, tt.ip, tt.net)
388 }
389 if err == nil && (!tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !reflect.DeepEqual(net.Mask, tt.net.Mask)) {
390 t.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v, {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
391 }
392 }
393 }
394
395 var ipNetContainsTests = []struct {
396 ip IP
397 net *IPNet
398 ok bool
399 }{
400 {IPv4(172, 16, 1, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(12, 32)}, true},
401 {IPv4(172, 24, 0, 1), &IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(13, 32)}, false},
402 {IPv4(192, 168, 0, 3), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 0, 255, 252)}, true},
403 {IPv4(192, 168, 0, 4), &IPNet{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(0, 255, 0, 252)}, false},
404 {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: CIDRMask(47, 128)}, true},
405 {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:2::"), Mask: CIDRMask(47, 128)}, false},
406 {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:0:ffff::"))}, true},
407 {ParseIP("2001:db8:1:2::1"), &IPNet{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("0:0:0:ffff::"))}, false},
408 }
409
410 func TestIPNetContains(t *testing.T) {
411 for _, tt := range ipNetContainsTests {
412 if ok := tt.net.Contains(tt.ip); ok != tt.ok {
413 t.Errorf("IPNet(%v).Contains(%v) = %v, want %v", tt.net, tt.ip, ok, tt.ok)
414 }
415 }
416 }
417
418 var ipNetStringTests = []struct {
419 in *IPNet
420 out string
421 }{
422 {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"},
423 {&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
424 {&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
425 {&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
426 {nil, "<nil>"},
427 }
428
429 func TestIPNetString(t *testing.T) {
430 for _, tt := range ipNetStringTests {
431 if out := tt.in.String(); out != tt.out {
432 t.Errorf("IPNet.String(%v) = %q, want %q", tt.in, out, tt.out)
433 }
434 }
435 }
436
437 var cidrMaskTests = []struct {
438 ones int
439 bits int
440 out IPMask
441 }{
442 {0, 32, IPv4Mask(0, 0, 0, 0)},
443 {12, 32, IPv4Mask(255, 240, 0, 0)},
444 {24, 32, IPv4Mask(255, 255, 255, 0)},
445 {32, 32, IPv4Mask(255, 255, 255, 255)},
446 {0, 128, IPMask{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
447 {4, 128, IPMask{0xf0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
448 {48, 128, IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
449 {128, 128, IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
450 {33, 32, nil},
451 {32, 33, nil},
452 {-1, 128, nil},
453 {128, -1, nil},
454 }
455
456 func TestCIDRMask(t *testing.T) {
457 for _, tt := range cidrMaskTests {
458 if out := CIDRMask(tt.ones, tt.bits); !reflect.DeepEqual(out, tt.out) {
459 t.Errorf("CIDRMask(%v, %v) = %v, want %v", tt.ones, tt.bits, out, tt.out)
460 }
461 }
462 }
463
464 var (
465 v4addr = IP{192, 168, 0, 1}
466 v4mappedv6addr = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 0, 1}
467 v6addr = IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}
468 v4mask = IPMask{255, 255, 255, 0}
469 v4mappedv6mask = IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 255, 255, 255, 0}
470 v6mask = IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}
471 badaddr = IP{192, 168, 0}
472 badmask = IPMask{255, 255, 0}
473 v4maskzero = IPMask{0, 0, 0, 0}
474 )
475
476 var networkNumberAndMaskTests = []struct {
477 in IPNet
478 out IPNet
479 }{
480 {IPNet{IP: v4addr, Mask: v4mask}, IPNet{IP: v4addr, Mask: v4mask}},
481 {IPNet{IP: v4addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
482 {IPNet{IP: v4mappedv6addr, Mask: v4mappedv6mask}, IPNet{IP: v4addr, Mask: v4mask}},
483 {IPNet{IP: v4mappedv6addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
484 {IPNet{IP: v4addr, Mask: v6mask}, IPNet{IP: v4addr, Mask: v4maskzero}},
485 {IPNet{IP: v6addr, Mask: v6mask}, IPNet{IP: v6addr, Mask: v6mask}},
486 {IPNet{IP: v6addr, Mask: v4mappedv6mask}, IPNet{IP: v6addr, Mask: v4mappedv6mask}},
487 {in: IPNet{IP: v6addr, Mask: v4mask}},
488 {in: IPNet{IP: v4addr, Mask: badmask}},
489 {in: IPNet{IP: v4mappedv6addr, Mask: badmask}},
490 {in: IPNet{IP: v6addr, Mask: badmask}},
491 {in: IPNet{IP: badaddr, Mask: v4mask}},
492 {in: IPNet{IP: badaddr, Mask: v4mappedv6mask}},
493 {in: IPNet{IP: badaddr, Mask: v6mask}},
494 {in: IPNet{IP: badaddr, Mask: badmask}},
495 }
496
497 func TestNetworkNumberAndMask(t *testing.T) {
498 for _, tt := range networkNumberAndMaskTests {
499 ip, m := networkNumberAndMask(&tt.in)
500 out := &IPNet{IP: ip, Mask: m}
501 if !reflect.DeepEqual(&tt.out, out) {
502 t.Errorf("networkNumberAndMask(%v) = %v, want %v", tt.in, out, &tt.out)
503 }
504 }
505 }
506
507 func TestSplitHostPort(t *testing.T) {
508 for _, tt := range []struct {
509 hostPort string
510 host string
511 port string
512 }{
513
514 {"localhost:http", "localhost", "http"},
515 {"localhost:80", "localhost", "80"},
516
517
518 {"localhost%lo0:http", "localhost%lo0", "http"},
519 {"localhost%lo0:80", "localhost%lo0", "80"},
520 {"[localhost%lo0]:http", "localhost%lo0", "http"},
521 {"[localhost%lo0]:80", "localhost%lo0", "80"},
522
523
524 {"127.0.0.1:http", "127.0.0.1", "http"},
525 {"127.0.0.1:80", "127.0.0.1", "80"},
526 {"[::1]:http", "::1", "http"},
527 {"[::1]:80", "::1", "80"},
528
529
530 {"[::1%lo0]:http", "::1%lo0", "http"},
531 {"[::1%lo0]:80", "::1%lo0", "80"},
532
533
534 {":http", "", "http"},
535 {":80", "", "80"},
536
537
538 {"golang.org:", "golang.org", ""},
539 {"127.0.0.1:", "127.0.0.1", ""},
540 {"[::1]:", "::1", ""},
541
542
543 {"golang.org:https%foo", "golang.org", "https%foo"},
544 } {
545 if host, port, err := SplitHostPort(tt.hostPort); host != tt.host || port != tt.port || err != nil {
546 t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.hostPort, host, port, err, tt.host, tt.port)
547 }
548 }
549
550 for _, tt := range []struct {
551 hostPort string
552 err string
553 }{
554 {"golang.org", "missing port in address"},
555 {"127.0.0.1", "missing port in address"},
556 {"[::1]", "missing port in address"},
557 {"[fe80::1%lo0]", "missing port in address"},
558 {"[localhost%lo0]", "missing port in address"},
559 {"localhost%lo0", "missing port in address"},
560
561 {"::1", "too many colons in address"},
562 {"fe80::1%lo0", "too many colons in address"},
563 {"fe80::1%lo0:80", "too many colons in address"},
564
565
566
567 {"[foo:bar]", "missing port in address"},
568 {"[foo:bar]baz", "missing port in address"},
569 {"[foo]bar:baz", "missing port in address"},
570
571 {"[foo]:[bar]:baz", "too many colons in address"},
572
573 {"[foo]:[bar]baz", "unexpected '[' in address"},
574 {"foo[bar]:baz", "unexpected '[' in address"},
575
576 {"foo]bar:baz", "unexpected ']' in address"},
577 } {
578 if host, port, err := SplitHostPort(tt.hostPort); err == nil {
579 t.Errorf("SplitHostPort(%q) should have failed", tt.hostPort)
580 } else {
581 e := err.(*AddrError)
582 if e.Err != tt.err {
583 t.Errorf("SplitHostPort(%q) = _, _, %q; want %q", tt.hostPort, e.Err, tt.err)
584 }
585 if host != "" || port != "" {
586 t.Errorf("SplitHostPort(%q) = %q, %q, err; want %q, %q, err on failure", tt.hostPort, host, port, "", "")
587 }
588 }
589 }
590 }
591
592 func TestJoinHostPort(t *testing.T) {
593 for _, tt := range []struct {
594 host string
595 port string
596 hostPort string
597 }{
598
599 {"localhost", "http", "localhost:http"},
600 {"localhost", "80", "localhost:80"},
601
602
603 {"localhost%lo0", "http", "localhost%lo0:http"},
604 {"localhost%lo0", "80", "localhost%lo0:80"},
605
606
607 {"127.0.0.1", "http", "127.0.0.1:http"},
608 {"127.0.0.1", "80", "127.0.0.1:80"},
609 {"::1", "http", "[::1]:http"},
610 {"::1", "80", "[::1]:80"},
611
612
613 {"::1%lo0", "http", "[::1%lo0]:http"},
614 {"::1%lo0", "80", "[::1%lo0]:80"},
615
616
617 {"", "http", ":http"},
618 {"", "80", ":80"},
619
620
621 {"golang.org", "", "golang.org:"},
622 {"127.0.0.1", "", "127.0.0.1:"},
623 {"::1", "", "[::1]:"},
624
625
626 {"golang.org", "https%foo", "golang.org:https%foo"},
627 } {
628 if hostPort := JoinHostPort(tt.host, tt.port); hostPort != tt.hostPort {
629 t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.host, tt.port, hostPort, tt.hostPort)
630 }
631 }
632 }
633
634 var ipAddrFamilyTests = []struct {
635 in IP
636 af4 bool
637 af6 bool
638 }{
639 {IPv4bcast, true, false},
640 {IPv4allsys, true, false},
641 {IPv4allrouter, true, false},
642 {IPv4zero, true, false},
643 {IPv4(224, 0, 0, 1), true, false},
644 {IPv4(127, 0, 0, 1), true, false},
645 {IPv4(240, 0, 0, 1), true, false},
646 {IPv6unspecified, false, true},
647 {IPv6loopback, false, true},
648 {IPv6interfacelocalallnodes, false, true},
649 {IPv6linklocalallnodes, false, true},
650 {IPv6linklocalallrouters, false, true},
651 {ParseIP("ff05::a:b:c:d"), false, true},
652 {ParseIP("fe80::1:2:3:4"), false, true},
653 {ParseIP("2001:db8::123:12:1"), false, true},
654 }
655
656 func TestIPAddrFamily(t *testing.T) {
657 for _, tt := range ipAddrFamilyTests {
658 if af := tt.in.To4() != nil; af != tt.af4 {
659 t.Errorf("verifying IPv4 address family for %q = %v, want %v", tt.in, af, tt.af4)
660 }
661 if af := len(tt.in) == IPv6len && tt.in.To4() == nil; af != tt.af6 {
662 t.Errorf("verifying IPv6 address family for %q = %v, want %v", tt.in, af, tt.af6)
663 }
664 }
665 }
666
667 var ipAddrScopeTests = []struct {
668 scope func(IP) bool
669 in IP
670 ok bool
671 }{
672 {IP.IsUnspecified, IPv4zero, true},
673 {IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
674 {IP.IsUnspecified, IPv6unspecified, true},
675 {IP.IsUnspecified, IPv6interfacelocalallnodes, false},
676 {IP.IsUnspecified, nil, false},
677 {IP.IsLoopback, IPv4(127, 0, 0, 1), true},
678 {IP.IsLoopback, IPv4(127, 255, 255, 254), true},
679 {IP.IsLoopback, IPv4(128, 1, 2, 3), false},
680 {IP.IsLoopback, IPv6loopback, true},
681 {IP.IsLoopback, IPv6linklocalallrouters, false},
682 {IP.IsLoopback, nil, false},
683 {IP.IsMulticast, IPv4(224, 0, 0, 0), true},
684 {IP.IsMulticast, IPv4(239, 0, 0, 0), true},
685 {IP.IsMulticast, IPv4(240, 0, 0, 0), false},
686 {IP.IsMulticast, IPv6linklocalallnodes, true},
687 {IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
688 {IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
689 {IP.IsMulticast, nil, false},
690 {IP.IsInterfaceLocalMulticast, IPv4(224, 0, 0, 0), false},
691 {IP.IsInterfaceLocalMulticast, IPv4(0xff, 0x01, 0, 0), false},
692 {IP.IsInterfaceLocalMulticast, IPv6interfacelocalallnodes, true},
693 {IP.IsInterfaceLocalMulticast, nil, false},
694 {IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
695 {IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
696 {IP.IsLinkLocalMulticast, IPv4(0xff, 0x02, 0, 0), false},
697 {IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
698 {IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
699 {IP.IsLinkLocalMulticast, nil, false},
700 {IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
701 {IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
702 {IP.IsLinkLocalUnicast, IPv4(0xfe, 0x80, 0, 0), false},
703 {IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
704 {IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
705 {IP.IsLinkLocalUnicast, nil, false},
706 {IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
707 {IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
708 {IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
709 {IP.IsGlobalUnicast, IPv4bcast, false},
710 {IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
711 {IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
712 {IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
713 {IP.IsGlobalUnicast, nil, false},
714 {IP.IsPrivate, nil, false},
715 {IP.IsPrivate, IPv4(1, 1, 1, 1), false},
716 {IP.IsPrivate, IPv4(9, 255, 255, 255), false},
717 {IP.IsPrivate, IPv4(10, 0, 0, 0), true},
718 {IP.IsPrivate, IPv4(10, 255, 255, 255), true},
719 {IP.IsPrivate, IPv4(11, 0, 0, 0), false},
720 {IP.IsPrivate, IPv4(172, 15, 255, 255), false},
721 {IP.IsPrivate, IPv4(172, 16, 0, 0), true},
722 {IP.IsPrivate, IPv4(172, 16, 255, 255), true},
723 {IP.IsPrivate, IPv4(172, 23, 18, 255), true},
724 {IP.IsPrivate, IPv4(172, 31, 255, 255), true},
725 {IP.IsPrivate, IPv4(172, 31, 0, 0), true},
726 {IP.IsPrivate, IPv4(172, 32, 0, 0), false},
727 {IP.IsPrivate, IPv4(192, 167, 255, 255), false},
728 {IP.IsPrivate, IPv4(192, 168, 0, 0), true},
729 {IP.IsPrivate, IPv4(192, 168, 255, 255), true},
730 {IP.IsPrivate, IPv4(192, 169, 0, 0), false},
731 {IP.IsPrivate, IP{0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, false},
732 {IP.IsPrivate, IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
733 {IP.IsPrivate, IP{0xfc, 0xff, 0x12, 0, 0, 0, 0, 0x44, 0, 0, 0, 0, 0, 0, 0, 0}, true},
734 {IP.IsPrivate, IP{0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true},
735 {IP.IsPrivate, IP{0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
736 }
737
738 func name(f any) string {
739 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
740 }
741
742 func TestIPAddrScope(t *testing.T) {
743 for _, tt := range ipAddrScopeTests {
744 if ok := tt.scope(tt.in); ok != tt.ok {
745 t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
746 }
747 ip := tt.in.To4()
748 if ip == nil {
749 continue
750 }
751 if ok := tt.scope(ip); ok != tt.ok {
752 t.Errorf("%s(%q) = %v, want %v", name(tt.scope), ip, ok, tt.ok)
753 }
754 }
755 }
756
757 func BenchmarkIPEqual(b *testing.B) {
758 b.Run("IPv4", func(b *testing.B) {
759 benchmarkIPEqual(b, IPv4len)
760 })
761 b.Run("IPv6", func(b *testing.B) {
762 benchmarkIPEqual(b, IPv6len)
763 })
764 }
765
766 func benchmarkIPEqual(b *testing.B, size int) {
767 ips := make([]IP, 1000)
768 for i := range ips {
769 ips[i] = make(IP, size)
770 rand.Read(ips[i])
771 }
772
773 for i := 0; i < b.N/2; i++ {
774 x := ips[i%len(ips)]
775 y := ips[i%len(ips)]
776 x.Equal(y)
777 }
778
779 for i := 0; i < b.N/2; i++ {
780 x := ips[i%len(ips)]
781 y := ips[(i+1)%len(ips)]
782 x.Equal(y)
783 }
784 }
785
View as plain text