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