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