github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/net/lookup_test.go (about) 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 "context" 10 "fmt" 11 "internal/testenv" 12 "runtime" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 func lookupLocalhost(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) { 19 switch host { 20 case "localhost": 21 return []IPAddr{ 22 {IP: IPv4(127, 0, 0, 1)}, 23 {IP: IPv6loopback}, 24 }, nil 25 default: 26 return fn(ctx, host) 27 } 28 } 29 30 // The Lookup APIs use various sources such as local database, DNS or 31 // mDNS, and may use platform-dependent DNS stub resolver if possible. 32 // The APIs accept any of forms for a query; host name in various 33 // encodings, UTF-8 encoded net name, domain name, FQDN or absolute 34 // FQDN, but the result would be one of the forms and it depends on 35 // the circumstances. 36 37 var lookupGoogleSRVTests = []struct { 38 service, proto, name string 39 cname, target string 40 }{ 41 { 42 "xmpp-server", "tcp", "google.com", 43 "google.com.", "google.com.", 44 }, 45 { 46 "xmpp-server", "tcp", "google.com.", 47 "google.com.", "google.com.", 48 }, 49 50 // non-standard back door 51 { 52 "", "", "_xmpp-server._tcp.google.com", 53 "google.com.", "google.com.", 54 }, 55 { 56 "", "", "_xmpp-server._tcp.google.com.", 57 "google.com.", "google.com.", 58 }, 59 } 60 61 func TestLookupGoogleSRV(t *testing.T) { 62 if testenv.Builder() == "" { 63 testenv.MustHaveExternalNetwork(t) 64 } 65 66 if !supportsIPv4 || !*testIPv4 { 67 t.Skip("IPv4 is required") 68 } 69 70 for _, tt := range lookupGoogleSRVTests { 71 cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name) 72 if err != nil { 73 testenv.SkipFlakyNet(t) 74 t.Fatal(err) 75 } 76 if len(srvs) == 0 { 77 t.Error("got no record") 78 } 79 if !strings.HasSuffix(cname, tt.cname) { 80 t.Errorf("got %s; want %s", cname, tt.cname) 81 } 82 for _, srv := range srvs { 83 if !strings.HasSuffix(srv.Target, tt.target) { 84 t.Errorf("got %v; want a record containing %s", srv, tt.target) 85 } 86 } 87 } 88 } 89 90 var lookupGmailMXTests = []struct { 91 name, host string 92 }{ 93 {"gmail.com", "google.com."}, 94 {"gmail.com.", "google.com."}, 95 } 96 97 func TestLookupGmailMX(t *testing.T) { 98 if testenv.Builder() == "" { 99 testenv.MustHaveExternalNetwork(t) 100 } 101 102 if !supportsIPv4 || !*testIPv4 { 103 t.Skip("IPv4 is required") 104 } 105 106 for _, tt := range lookupGmailMXTests { 107 mxs, err := LookupMX(tt.name) 108 if err != nil { 109 t.Fatal(err) 110 } 111 if len(mxs) == 0 { 112 t.Error("got no record") 113 } 114 for _, mx := range mxs { 115 if !strings.HasSuffix(mx.Host, tt.host) { 116 t.Errorf("got %v; want a record containing %s", mx, tt.host) 117 } 118 } 119 } 120 } 121 122 var lookupGmailNSTests = []struct { 123 name, host string 124 }{ 125 {"gmail.com", "google.com."}, 126 {"gmail.com.", "google.com."}, 127 } 128 129 func TestLookupGmailNS(t *testing.T) { 130 if testenv.Builder() == "" { 131 testenv.MustHaveExternalNetwork(t) 132 } 133 134 if !supportsIPv4 || !*testIPv4 { 135 t.Skip("IPv4 is required") 136 } 137 138 for _, tt := range lookupGmailNSTests { 139 nss, err := LookupNS(tt.name) 140 if err != nil { 141 testenv.SkipFlakyNet(t) 142 t.Fatal(err) 143 } 144 if len(nss) == 0 { 145 t.Error("got no record") 146 } 147 for _, ns := range nss { 148 if !strings.HasSuffix(ns.Host, tt.host) { 149 t.Errorf("got %v; want a record containing %s", ns, tt.host) 150 } 151 } 152 } 153 } 154 155 var lookupGmailTXTTests = []struct { 156 name, txt, host string 157 }{ 158 {"gmail.com", "spf", "google.com"}, 159 {"gmail.com.", "spf", "google.com"}, 160 } 161 162 func TestLookupGmailTXT(t *testing.T) { 163 if testenv.Builder() == "" { 164 testenv.MustHaveExternalNetwork(t) 165 } 166 167 if !supportsIPv4 || !*testIPv4 { 168 t.Skip("IPv4 is required") 169 } 170 171 for _, tt := range lookupGmailTXTTests { 172 txts, err := LookupTXT(tt.name) 173 if err != nil { 174 t.Fatal(err) 175 } 176 if len(txts) == 0 { 177 t.Error("got no record") 178 } 179 for _, txt := range txts { 180 if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) { 181 t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host) 182 } 183 } 184 } 185 } 186 187 var lookupGooglePublicDNSAddrTests = []struct { 188 addr, name string 189 }{ 190 {"8.8.8.8", ".google.com."}, 191 {"8.8.4.4", ".google.com."}, 192 193 {"2001:4860:4860::8888", ".google.com."}, 194 {"2001:4860:4860::8844", ".google.com."}, 195 } 196 197 func TestLookupGooglePublicDNSAddr(t *testing.T) { 198 if testenv.Builder() == "" { 199 testenv.MustHaveExternalNetwork(t) 200 } 201 202 if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { 203 t.Skip("both IPv4 and IPv6 are required") 204 } 205 206 for _, tt := range lookupGooglePublicDNSAddrTests { 207 names, err := LookupAddr(tt.addr) 208 if err != nil { 209 t.Fatal(err) 210 } 211 if len(names) == 0 { 212 t.Error("got no record") 213 } 214 for _, name := range names { 215 if !strings.HasSuffix(name, tt.name) { 216 t.Errorf("got %s; want a record containing %s", name, tt.name) 217 } 218 } 219 } 220 } 221 222 func TestLookupIPv6LinkLocalAddr(t *testing.T) { 223 if !supportsIPv6 || !*testIPv6 { 224 t.Skip("IPv6 is required") 225 } 226 227 addrs, err := LookupHost("localhost") 228 if err != nil { 229 t.Fatal(err) 230 } 231 found := false 232 for _, addr := range addrs { 233 if addr == "fe80::1%lo0" { 234 found = true 235 break 236 } 237 } 238 if !found { 239 t.Skipf("not supported on %s", runtime.GOOS) 240 } 241 if _, err := LookupAddr("fe80::1%lo0"); err != nil { 242 t.Error(err) 243 } 244 } 245 246 var lookupIANACNAMETests = []struct { 247 name, cname string 248 }{ 249 {"www.iana.org", "icann.org."}, 250 {"www.iana.org.", "icann.org."}, 251 } 252 253 func TestLookupIANACNAME(t *testing.T) { 254 if testenv.Builder() == "" { 255 testenv.MustHaveExternalNetwork(t) 256 } 257 258 if !supportsIPv4 || !*testIPv4 { 259 t.Skip("IPv4 is required") 260 } 261 262 for _, tt := range lookupIANACNAMETests { 263 cname, err := LookupCNAME(tt.name) 264 if err != nil { 265 t.Fatal(err) 266 } 267 if !strings.HasSuffix(cname, tt.cname) { 268 t.Errorf("got %s; want a record containing %s", cname, tt.cname) 269 } 270 } 271 } 272 273 var lookupGoogleHostTests = []struct { 274 name string 275 }{ 276 {"google.com"}, 277 {"google.com."}, 278 } 279 280 func TestLookupGoogleHost(t *testing.T) { 281 if testenv.Builder() == "" { 282 testenv.MustHaveExternalNetwork(t) 283 } 284 285 if !supportsIPv4 || !*testIPv4 { 286 t.Skip("IPv4 is required") 287 } 288 289 for _, tt := range lookupGoogleHostTests { 290 addrs, err := LookupHost(tt.name) 291 if err != nil { 292 t.Fatal(err) 293 } 294 if len(addrs) == 0 { 295 t.Error("got no record") 296 } 297 for _, addr := range addrs { 298 if ParseIP(addr) == nil { 299 t.Errorf("got %q; want a literal IP address", addr) 300 } 301 } 302 } 303 } 304 305 var lookupGoogleIPTests = []struct { 306 name string 307 }{ 308 {"google.com"}, 309 {"google.com."}, 310 } 311 312 func TestLookupGoogleIP(t *testing.T) { 313 if testenv.Builder() == "" { 314 testenv.MustHaveExternalNetwork(t) 315 } 316 317 if !supportsIPv4 || !*testIPv4 { 318 t.Skip("IPv4 is required") 319 } 320 321 for _, tt := range lookupGoogleIPTests { 322 ips, err := LookupIP(tt.name) 323 if err != nil { 324 t.Fatal(err) 325 } 326 if len(ips) == 0 { 327 t.Error("got no record") 328 } 329 for _, ip := range ips { 330 if ip.To4() == nil && ip.To16() == nil { 331 t.Errorf("got %v; want an IP address", ip) 332 } 333 } 334 } 335 } 336 337 var revAddrTests = []struct { 338 Addr string 339 Reverse string 340 ErrPrefix string 341 }{ 342 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, 343 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, 344 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, 345 {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, 346 {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, 347 {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, 348 {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, 349 {"1.2.3", "", "unrecognized address"}, 350 {"1.2.3.4.5", "", "unrecognized address"}, 351 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, 352 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, 353 } 354 355 func TestReverseAddress(t *testing.T) { 356 for i, tt := range revAddrTests { 357 a, err := reverseaddr(tt.Addr) 358 if len(tt.ErrPrefix) > 0 && err == nil { 359 t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) 360 continue 361 } 362 if len(tt.ErrPrefix) == 0 && err != nil { 363 t.Errorf("#%d: expected <nil>, got %q (error)", i, err) 364 } 365 if err != nil && err.(*DNSError).Err != tt.ErrPrefix { 366 t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err) 367 } 368 if a != tt.Reverse { 369 t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) 370 } 371 } 372 } 373 374 func TestDNSFlood(t *testing.T) { 375 if !*testDNSFlood { 376 t.Skip("test disabled; use -dnsflood to enable") 377 } 378 379 var N = 5000 380 if runtime.GOOS == "darwin" { 381 // On Darwin this test consumes kernel threads much 382 // than other platforms for some reason. 383 // When we monitor the number of allocated Ms by 384 // observing on runtime.newm calls, we can see that it 385 // easily reaches the per process ceiling 386 // kern.num_threads when CGO_ENABLED=1 and 387 // GODEBUG=netdns=go. 388 N = 500 389 } 390 391 const timeout = 3 * time.Second 392 ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2) 393 defer cancel() 394 ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout) 395 defer cancel() 396 397 c := make(chan error, 2*N) 398 for i := 0; i < N; i++ { 399 name := fmt.Sprintf("%d.net-test.golang.org", i) 400 go func() { 401 _, err := lookupIPContext(ctxHalfTimeout, name) 402 c <- err 403 }() 404 go func() { 405 _, err := lookupIPContext(ctxTimeout, name) 406 c <- err 407 }() 408 } 409 qstats := struct { 410 succeeded, failed int 411 timeout, temporary, other int 412 unknown int 413 }{} 414 deadline := time.After(timeout + time.Second) 415 for i := 0; i < 2*N; i++ { 416 select { 417 case <-deadline: 418 t.Fatal("deadline exceeded") 419 case err := <-c: 420 switch err := err.(type) { 421 case nil: 422 qstats.succeeded++ 423 case Error: 424 qstats.failed++ 425 if err.Timeout() { 426 qstats.timeout++ 427 } 428 if err.Temporary() { 429 qstats.temporary++ 430 } 431 if !err.Timeout() && !err.Temporary() { 432 qstats.other++ 433 } 434 default: 435 qstats.failed++ 436 qstats.unknown++ 437 } 438 } 439 } 440 441 // A high volume of DNS queries for sub-domain of golang.org 442 // would be coordinated by authoritative or recursive server, 443 // or stub resolver which implements query-response rate 444 // limitation, so we can expect some query successes and more 445 // failures including timeout, temporary and other here. 446 // As a rule, unknown must not be shown but it might possibly 447 // happen due to issue 4856 for now. 448 t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown) 449 } 450 451 func TestLookupDotsWithLocalSource(t *testing.T) { 452 if !supportsIPv4 || !*testIPv4 { 453 t.Skip("IPv4 is required") 454 } 455 456 for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} { 457 fixup := fn() 458 if fixup == nil { 459 continue 460 } 461 names, err := LookupAddr("127.0.0.1") 462 fixup() 463 if err != nil { 464 t.Logf("#%d: %v", i, err) 465 continue 466 } 467 mode := "netgo" 468 if i == 1 { 469 mode = "netcgo" 470 } 471 loop: 472 for i, name := range names { 473 if strings.Index(name, ".") == len(name)-1 { // "localhost" not "localhost." 474 for j := range names { 475 if j == i { 476 continue 477 } 478 if names[j] == name[:len(name)-1] { 479 // It's OK if we find the name without the dot, 480 // as some systems say 127.0.0.1 localhost localhost. 481 continue loop 482 } 483 } 484 t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1]) 485 } else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") { // "localhost.localdomain." not "localhost.localdomain" 486 t.Errorf("%s: got %s; want name ending with trailing dot", mode, name) 487 } 488 } 489 } 490 } 491 492 func TestLookupDotsWithRemoteSource(t *testing.T) { 493 if testenv.Builder() == "" { 494 testenv.MustHaveExternalNetwork(t) 495 } 496 497 if !supportsIPv4 || !*testIPv4 { 498 t.Skip("IPv4 is required") 499 } 500 501 if fixup := forceGoDNS(); fixup != nil { 502 testDots(t, "go") 503 fixup() 504 } 505 if fixup := forceCgoDNS(); fixup != nil { 506 testDots(t, "cgo") 507 fixup() 508 } 509 } 510 511 func testDots(t *testing.T, mode string) { 512 names, err := LookupAddr("8.8.8.8") // Google dns server 513 if err != nil { 514 testenv.SkipFlakyNet(t) 515 t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) 516 } else { 517 for _, name := range names { 518 if !strings.HasSuffix(name, ".google.com.") { 519 t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode) 520 break 521 } 522 } 523 } 524 525 cname, err := LookupCNAME("www.mit.edu") 526 if err != nil { 527 testenv.SkipFlakyNet(t) 528 t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err) 529 } else if !strings.HasSuffix(cname, ".") { 530 t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode) 531 } 532 533 mxs, err := LookupMX("google.com") 534 if err != nil { 535 testenv.SkipFlakyNet(t) 536 t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode) 537 } else { 538 for _, mx := range mxs { 539 if !strings.HasSuffix(mx.Host, ".google.com.") { 540 t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode) 541 break 542 } 543 } 544 } 545 546 nss, err := LookupNS("google.com") 547 if err != nil { 548 testenv.SkipFlakyNet(t) 549 t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode) 550 } else { 551 for _, ns := range nss { 552 if !strings.HasSuffix(ns.Host, ".google.com.") { 553 t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode) 554 break 555 } 556 } 557 } 558 559 cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com") 560 if err != nil { 561 testenv.SkipFlakyNet(t) 562 t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode) 563 } else { 564 if !strings.HasSuffix(cname, ".google.com.") { 565 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode) 566 } 567 for _, srv := range srvs { 568 if !strings.HasSuffix(srv.Target, ".google.com.") { 569 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode) 570 break 571 } 572 } 573 } 574 } 575 576 func mxString(mxs []*MX) string { 577 var buf bytes.Buffer 578 sep := "" 579 fmt.Fprintf(&buf, "[") 580 for _, mx := range mxs { 581 fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref) 582 sep = " " 583 } 584 fmt.Fprintf(&buf, "]") 585 return buf.String() 586 } 587 588 func nsString(nss []*NS) string { 589 var buf bytes.Buffer 590 sep := "" 591 fmt.Fprintf(&buf, "[") 592 for _, ns := range nss { 593 fmt.Fprintf(&buf, "%s%s", sep, ns.Host) 594 sep = " " 595 } 596 fmt.Fprintf(&buf, "]") 597 return buf.String() 598 } 599 600 func srvString(srvs []*SRV) string { 601 var buf bytes.Buffer 602 sep := "" 603 fmt.Fprintf(&buf, "[") 604 for _, srv := range srvs { 605 fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight) 606 sep = " " 607 } 608 fmt.Fprintf(&buf, "]") 609 return buf.String() 610 } 611 612 func TestLookupPort(t *testing.T) { 613 // See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml 614 // 615 // Please be careful about adding new mappings for testings. 616 // There are platforms having incomplete mappings for 617 // restricted resource access and security reasons. 618 type test struct { 619 network string 620 name string 621 port int 622 ok bool 623 } 624 var tests = []test{ 625 {"tcp", "0", 0, true}, 626 {"udp", "0", 0, true}, 627 {"udp", "domain", 53, true}, 628 629 {"--badnet--", "zzz", 0, false}, 630 {"tcp", "--badport--", 0, false}, 631 {"tcp", "-1", 0, false}, 632 {"tcp", "65536", 0, false}, 633 {"udp", "-1", 0, false}, 634 {"udp", "65536", 0, false}, 635 {"tcp", "123456789", 0, false}, 636 637 // Issue 13610: LookupPort("tcp", "") 638 {"tcp", "", 0, true}, 639 {"tcp4", "", 0, true}, 640 {"tcp6", "", 0, true}, 641 {"udp", "", 0, true}, 642 {"udp4", "", 0, true}, 643 {"udp6", "", 0, true}, 644 } 645 646 switch runtime.GOOS { 647 case "nacl": 648 t.Skipf("not supported on %s", runtime.GOOS) 649 case "android": 650 if netGo { 651 t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS) 652 } 653 default: 654 tests = append(tests, test{"tcp", "http", 80, true}) 655 } 656 657 for _, tt := range tests { 658 port, err := LookupPort(tt.network, tt.name) 659 if port != tt.port || (err == nil) != tt.ok { 660 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok) 661 } 662 if err != nil { 663 if perr := parseLookupPortError(err); perr != nil { 664 t.Error(perr) 665 } 666 } 667 } 668 }