github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/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 // +build !js 6 7 package net 8 9 import ( 10 "bytes" 11 "context" 12 "fmt" 13 "internal/testenv" 14 "reflect" 15 "runtime" 16 "sort" 17 "strings" 18 "sync" 19 "testing" 20 "time" 21 ) 22 23 func lookupLocalhost(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 24 switch host { 25 case "localhost": 26 return []IPAddr{ 27 {IP: IPv4(127, 0, 0, 1)}, 28 {IP: IPv6loopback}, 29 }, nil 30 default: 31 return fn(ctx, network, host) 32 } 33 } 34 35 // The Lookup APIs use various sources such as local database, DNS or 36 // mDNS, and may use platform-dependent DNS stub resolver if possible. 37 // The APIs accept any of forms for a query; host name in various 38 // encodings, UTF-8 encoded net name, domain name, FQDN or absolute 39 // FQDN, but the result would be one of the forms and it depends on 40 // the circumstances. 41 42 var lookupGoogleSRVTests = []struct { 43 service, proto, name string 44 cname, target string 45 }{ 46 { 47 "xmpp-server", "tcp", "google.com", 48 "google.com.", "google.com.", 49 }, 50 { 51 "xmpp-server", "tcp", "google.com.", 52 "google.com.", "google.com.", 53 }, 54 55 // non-standard back door 56 { 57 "", "", "_xmpp-server._tcp.google.com", 58 "google.com.", "google.com.", 59 }, 60 { 61 "", "", "_xmpp-server._tcp.google.com.", 62 "google.com.", "google.com.", 63 }, 64 } 65 66 var backoffDuration = [...]time.Duration{time.Second, 5 * time.Second, 30 * time.Second} 67 68 func TestLookupGoogleSRV(t *testing.T) { 69 t.Parallel() 70 mustHaveExternalNetwork(t) 71 72 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 73 t.Skip("no resolv.conf on iOS") 74 } 75 76 if !supportsIPv4() || !*testIPv4 { 77 t.Skip("IPv4 is required") 78 } 79 80 attempts := 0 81 for i := 0; i < len(lookupGoogleSRVTests); i++ { 82 tt := lookupGoogleSRVTests[i] 83 cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name) 84 if err != nil { 85 testenv.SkipFlakyNet(t) 86 if attempts < len(backoffDuration) { 87 dur := backoffDuration[attempts] 88 t.Logf("backoff %v after failure %v\n", dur, err) 89 time.Sleep(dur) 90 attempts++ 91 i-- 92 continue 93 } 94 t.Fatal(err) 95 } 96 if len(srvs) == 0 { 97 t.Error("got no record") 98 } 99 if !strings.HasSuffix(cname, tt.cname) { 100 t.Errorf("got %s; want %s", cname, tt.cname) 101 } 102 for _, srv := range srvs { 103 if !strings.HasSuffix(srv.Target, tt.target) { 104 t.Errorf("got %v; want a record containing %s", srv, tt.target) 105 } 106 } 107 } 108 } 109 110 var lookupGmailMXTests = []struct { 111 name, host string 112 }{ 113 {"gmail.com", "google.com."}, 114 {"gmail.com.", "google.com."}, 115 } 116 117 func TestLookupGmailMX(t *testing.T) { 118 t.Parallel() 119 mustHaveExternalNetwork(t) 120 121 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 122 t.Skip("no resolv.conf on iOS") 123 } 124 125 if !supportsIPv4() || !*testIPv4 { 126 t.Skip("IPv4 is required") 127 } 128 129 attempts := 0 130 for i := 0; i < len(lookupGmailMXTests); i++ { 131 tt := lookupGmailMXTests[i] 132 mxs, err := LookupMX(tt.name) 133 if err != nil { 134 testenv.SkipFlakyNet(t) 135 if attempts < len(backoffDuration) { 136 dur := backoffDuration[attempts] 137 t.Logf("backoff %v after failure %v\n", dur, err) 138 time.Sleep(dur) 139 attempts++ 140 i-- 141 continue 142 } 143 t.Fatal(err) 144 } 145 if len(mxs) == 0 { 146 t.Error("got no record") 147 } 148 for _, mx := range mxs { 149 if !strings.HasSuffix(mx.Host, tt.host) { 150 t.Errorf("got %v; want a record containing %s", mx, tt.host) 151 } 152 } 153 } 154 } 155 156 var lookupGmailNSTests = []struct { 157 name, host string 158 }{ 159 {"gmail.com", "google.com."}, 160 {"gmail.com.", "google.com."}, 161 } 162 163 func TestLookupGmailNS(t *testing.T) { 164 t.Parallel() 165 mustHaveExternalNetwork(t) 166 167 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 168 t.Skip("no resolv.conf on iOS") 169 } 170 171 if !supportsIPv4() || !*testIPv4 { 172 t.Skip("IPv4 is required") 173 } 174 175 attempts := 0 176 for i := 0; i < len(lookupGmailNSTests); i++ { 177 tt := lookupGmailNSTests[i] 178 nss, err := LookupNS(tt.name) 179 if err != nil { 180 testenv.SkipFlakyNet(t) 181 if attempts < len(backoffDuration) { 182 dur := backoffDuration[attempts] 183 t.Logf("backoff %v after failure %v\n", dur, err) 184 time.Sleep(dur) 185 attempts++ 186 i-- 187 continue 188 } 189 t.Fatal(err) 190 } 191 if len(nss) == 0 { 192 t.Error("got no record") 193 } 194 for _, ns := range nss { 195 if !strings.HasSuffix(ns.Host, tt.host) { 196 t.Errorf("got %v; want a record containing %s", ns, tt.host) 197 } 198 } 199 } 200 } 201 202 var lookupGmailTXTTests = []struct { 203 name, txt, host string 204 }{ 205 {"gmail.com", "spf", "google.com"}, 206 {"gmail.com.", "spf", "google.com"}, 207 } 208 209 func TestLookupGmailTXT(t *testing.T) { 210 t.Parallel() 211 mustHaveExternalNetwork(t) 212 213 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 214 t.Skip("no resolv.conf on iOS") 215 } 216 217 if !supportsIPv4() || !*testIPv4 { 218 t.Skip("IPv4 is required") 219 } 220 221 attempts := 0 222 for i := 0; i < len(lookupGmailTXTTests); i++ { 223 tt := lookupGmailTXTTests[i] 224 txts, err := LookupTXT(tt.name) 225 if err != nil { 226 testenv.SkipFlakyNet(t) 227 if attempts < len(backoffDuration) { 228 dur := backoffDuration[attempts] 229 t.Logf("backoff %v after failure %v\n", dur, err) 230 time.Sleep(dur) 231 attempts++ 232 i-- 233 continue 234 } 235 t.Fatal(err) 236 } 237 if len(txts) == 0 { 238 t.Error("got no record") 239 } 240 for _, txt := range txts { 241 if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) { 242 t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host) 243 } 244 } 245 } 246 } 247 248 var lookupGooglePublicDNSAddrTests = []struct { 249 addr, name string 250 }{ 251 {"8.8.8.8", ".google.com."}, 252 {"8.8.4.4", ".google.com."}, 253 254 {"2001:4860:4860::8888", ".google.com."}, 255 {"2001:4860:4860::8844", ".google.com."}, 256 } 257 258 func TestLookupGooglePublicDNSAddr(t *testing.T) { 259 mustHaveExternalNetwork(t) 260 261 if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 { 262 t.Skip("both IPv4 and IPv6 are required") 263 } 264 265 defer dnsWaitGroup.Wait() 266 267 for _, tt := range lookupGooglePublicDNSAddrTests { 268 names, err := LookupAddr(tt.addr) 269 if err != nil { 270 t.Fatal(err) 271 } 272 if len(names) == 0 { 273 t.Error("got no record") 274 } 275 for _, name := range names { 276 if !strings.HasSuffix(name, tt.name) { 277 t.Errorf("got %s; want a record containing %s", name, tt.name) 278 } 279 } 280 } 281 } 282 283 func TestLookupIPv6LinkLocalAddr(t *testing.T) { 284 if !supportsIPv6() || !*testIPv6 { 285 t.Skip("IPv6 is required") 286 } 287 288 defer dnsWaitGroup.Wait() 289 290 addrs, err := LookupHost("localhost") 291 if err != nil { 292 t.Fatal(err) 293 } 294 found := false 295 for _, addr := range addrs { 296 if addr == "fe80::1%lo0" { 297 found = true 298 break 299 } 300 } 301 if !found { 302 t.Skipf("not supported on %s", runtime.GOOS) 303 } 304 if _, err := LookupAddr("fe80::1%lo0"); err != nil { 305 t.Error(err) 306 } 307 } 308 309 func TestLookupIPv6LinkLocalAddrWithZone(t *testing.T) { 310 if !supportsIPv6() || !*testIPv6 { 311 t.Skip("IPv6 is required") 312 } 313 314 ipaddrs, err := DefaultResolver.LookupIPAddr(context.Background(), "fe80::1%lo0") 315 if err != nil { 316 t.Error(err) 317 } 318 for _, addr := range ipaddrs { 319 if e, a := "lo0", addr.Zone; e != a { 320 t.Errorf("wrong zone: want %q, got %q", e, a) 321 } 322 } 323 324 addrs, err := DefaultResolver.LookupHost(context.Background(), "fe80::1%lo0") 325 if err != nil { 326 t.Error(err) 327 } 328 for _, addr := range addrs { 329 if e, a := "fe80::1%lo0", addr; e != a { 330 t.Errorf("wrong host: want %q got %q", e, a) 331 } 332 } 333 } 334 335 var lookupCNAMETests = []struct { 336 name, cname string 337 }{ 338 {"www.iana.org", "icann.org."}, 339 {"www.iana.org.", "icann.org."}, 340 {"www.google.com", "google.com."}, 341 } 342 343 func TestLookupCNAME(t *testing.T) { 344 mustHaveExternalNetwork(t) 345 346 if !supportsIPv4() || !*testIPv4 { 347 t.Skip("IPv4 is required") 348 } 349 350 defer dnsWaitGroup.Wait() 351 352 attempts := 0 353 for i := 0; i < len(lookupCNAMETests); i++ { 354 tt := lookupCNAMETests[i] 355 cname, err := LookupCNAME(tt.name) 356 if err != nil { 357 testenv.SkipFlakyNet(t) 358 if attempts < len(backoffDuration) { 359 dur := backoffDuration[attempts] 360 t.Logf("backoff %v after failure %v\n", dur, err) 361 time.Sleep(dur) 362 attempts++ 363 i-- 364 continue 365 } 366 t.Fatal(err) 367 } 368 if !strings.HasSuffix(cname, tt.cname) { 369 t.Errorf("got %s; want a record containing %s", cname, tt.cname) 370 } 371 } 372 } 373 374 var lookupGoogleHostTests = []struct { 375 name string 376 }{ 377 {"google.com"}, 378 {"google.com."}, 379 } 380 381 func TestLookupGoogleHost(t *testing.T) { 382 mustHaveExternalNetwork(t) 383 384 if !supportsIPv4() || !*testIPv4 { 385 t.Skip("IPv4 is required") 386 } 387 388 defer dnsWaitGroup.Wait() 389 390 for _, tt := range lookupGoogleHostTests { 391 addrs, err := LookupHost(tt.name) 392 if err != nil { 393 t.Fatal(err) 394 } 395 if len(addrs) == 0 { 396 t.Error("got no record") 397 } 398 for _, addr := range addrs { 399 if ParseIP(addr) == nil { 400 t.Errorf("got %q; want a literal IP address", addr) 401 } 402 } 403 } 404 } 405 406 func TestLookupLongTXT(t *testing.T) { 407 testenv.SkipFlaky(t, 22857) 408 mustHaveExternalNetwork(t) 409 410 defer dnsWaitGroup.Wait() 411 412 txts, err := LookupTXT("golang.rsc.io") 413 if err != nil { 414 t.Fatal(err) 415 } 416 sort.Strings(txts) 417 want := []string{ 418 strings.Repeat("abcdefghijklmnopqrstuvwxyABCDEFGHJIKLMNOPQRSTUVWXY", 10), 419 "gophers rule", 420 } 421 if !reflect.DeepEqual(txts, want) { 422 t.Fatalf("LookupTXT golang.rsc.io incorrect\nhave %q\nwant %q", txts, want) 423 } 424 } 425 426 var lookupGoogleIPTests = []struct { 427 name string 428 }{ 429 {"google.com"}, 430 {"google.com."}, 431 } 432 433 func TestLookupGoogleIP(t *testing.T) { 434 mustHaveExternalNetwork(t) 435 436 if !supportsIPv4() || !*testIPv4 { 437 t.Skip("IPv4 is required") 438 } 439 440 defer dnsWaitGroup.Wait() 441 442 for _, tt := range lookupGoogleIPTests { 443 ips, err := LookupIP(tt.name) 444 if err != nil { 445 t.Fatal(err) 446 } 447 if len(ips) == 0 { 448 t.Error("got no record") 449 } 450 for _, ip := range ips { 451 if ip.To4() == nil && ip.To16() == nil { 452 t.Errorf("got %v; want an IP address", ip) 453 } 454 } 455 } 456 } 457 458 var revAddrTests = []struct { 459 Addr string 460 Reverse string 461 ErrPrefix string 462 }{ 463 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, 464 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, 465 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, 466 {"::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.", ""}, 467 {"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.", ""}, 468 {"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.", ""}, 469 {"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.", ""}, 470 {"1.2.3", "", "unrecognized address"}, 471 {"1.2.3.4.5", "", "unrecognized address"}, 472 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, 473 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, 474 } 475 476 func TestReverseAddress(t *testing.T) { 477 defer dnsWaitGroup.Wait() 478 for i, tt := range revAddrTests { 479 a, err := reverseaddr(tt.Addr) 480 if len(tt.ErrPrefix) > 0 && err == nil { 481 t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) 482 continue 483 } 484 if len(tt.ErrPrefix) == 0 && err != nil { 485 t.Errorf("#%d: expected <nil>, got %q (error)", i, err) 486 } 487 if err != nil && err.(*DNSError).Err != tt.ErrPrefix { 488 t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err) 489 } 490 if a != tt.Reverse { 491 t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) 492 } 493 } 494 } 495 496 func TestDNSFlood(t *testing.T) { 497 if !*testDNSFlood { 498 t.Skip("test disabled; use -dnsflood to enable") 499 } 500 501 defer dnsWaitGroup.Wait() 502 503 var N = 5000 504 if runtime.GOOS == "darwin" { 505 // On Darwin this test consumes kernel threads much 506 // than other platforms for some reason. 507 // When we monitor the number of allocated Ms by 508 // observing on runtime.newm calls, we can see that it 509 // easily reaches the per process ceiling 510 // kern.num_threads when CGO_ENABLED=1 and 511 // GODEBUG=netdns=go. 512 N = 500 513 } 514 515 const timeout = 3 * time.Second 516 ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2) 517 defer cancel() 518 ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout) 519 defer cancel() 520 521 c := make(chan error, 2*N) 522 for i := 0; i < N; i++ { 523 name := fmt.Sprintf("%d.net-test.golang.org", i) 524 go func() { 525 _, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name) 526 c <- err 527 }() 528 go func() { 529 _, err := DefaultResolver.LookupIPAddr(ctxTimeout, name) 530 c <- err 531 }() 532 } 533 qstats := struct { 534 succeeded, failed int 535 timeout, temporary, other int 536 unknown int 537 }{} 538 deadline := time.After(timeout + time.Second) 539 for i := 0; i < 2*N; i++ { 540 select { 541 case <-deadline: 542 t.Fatal("deadline exceeded") 543 case err := <-c: 544 switch err := err.(type) { 545 case nil: 546 qstats.succeeded++ 547 case Error: 548 qstats.failed++ 549 if err.Timeout() { 550 qstats.timeout++ 551 } 552 if err.Temporary() { 553 qstats.temporary++ 554 } 555 if !err.Timeout() && !err.Temporary() { 556 qstats.other++ 557 } 558 default: 559 qstats.failed++ 560 qstats.unknown++ 561 } 562 } 563 } 564 565 // A high volume of DNS queries for sub-domain of golang.org 566 // would be coordinated by authoritative or recursive server, 567 // or stub resolver which implements query-response rate 568 // limitation, so we can expect some query successes and more 569 // failures including timeout, temporary and other here. 570 // As a rule, unknown must not be shown but it might possibly 571 // happen due to issue 4856 for now. 572 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) 573 } 574 575 func TestLookupDotsWithLocalSource(t *testing.T) { 576 if !supportsIPv4() || !*testIPv4 { 577 t.Skip("IPv4 is required") 578 } 579 580 mustHaveExternalNetwork(t) 581 582 defer dnsWaitGroup.Wait() 583 584 for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} { 585 fixup := fn() 586 if fixup == nil { 587 continue 588 } 589 names, err := LookupAddr("127.0.0.1") 590 fixup() 591 if err != nil { 592 t.Logf("#%d: %v", i, err) 593 continue 594 } 595 mode := "netgo" 596 if i == 1 { 597 mode = "netcgo" 598 } 599 loop: 600 for i, name := range names { 601 if strings.Index(name, ".") == len(name)-1 { // "localhost" not "localhost." 602 for j := range names { 603 if j == i { 604 continue 605 } 606 if names[j] == name[:len(name)-1] { 607 // It's OK if we find the name without the dot, 608 // as some systems say 127.0.0.1 localhost localhost. 609 continue loop 610 } 611 } 612 t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1]) 613 } else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") { // "localhost.localdomain." not "localhost.localdomain" 614 t.Errorf("%s: got %s; want name ending with trailing dot", mode, name) 615 } 616 } 617 } 618 } 619 620 func TestLookupDotsWithRemoteSource(t *testing.T) { 621 mustHaveExternalNetwork(t) 622 623 if !supportsIPv4() || !*testIPv4 { 624 t.Skip("IPv4 is required") 625 } 626 627 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 628 t.Skip("no resolv.conf on iOS") 629 } 630 631 defer dnsWaitGroup.Wait() 632 633 if fixup := forceGoDNS(); fixup != nil { 634 testDots(t, "go") 635 fixup() 636 } 637 if fixup := forceCgoDNS(); fixup != nil { 638 testDots(t, "cgo") 639 fixup() 640 } 641 } 642 643 func testDots(t *testing.T, mode string) { 644 names, err := LookupAddr("8.8.8.8") // Google dns server 645 if err != nil { 646 testenv.SkipFlakyNet(t) 647 t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) 648 } else { 649 for _, name := range names { 650 if !strings.HasSuffix(name, ".google.com.") { 651 t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode) 652 break 653 } 654 } 655 } 656 657 cname, err := LookupCNAME("www.mit.edu") 658 if err != nil { 659 testenv.SkipFlakyNet(t) 660 t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err) 661 } else if !strings.HasSuffix(cname, ".") { 662 t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode) 663 } 664 665 mxs, err := LookupMX("google.com") 666 if err != nil { 667 testenv.SkipFlakyNet(t) 668 t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode) 669 } else { 670 for _, mx := range mxs { 671 if !strings.HasSuffix(mx.Host, ".google.com.") { 672 t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode) 673 break 674 } 675 } 676 } 677 678 nss, err := LookupNS("google.com") 679 if err != nil { 680 testenv.SkipFlakyNet(t) 681 t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode) 682 } else { 683 for _, ns := range nss { 684 if !strings.HasSuffix(ns.Host, ".google.com.") { 685 t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode) 686 break 687 } 688 } 689 } 690 691 cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com") 692 if err != nil { 693 testenv.SkipFlakyNet(t) 694 t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode) 695 } else { 696 if !strings.HasSuffix(cname, ".google.com.") { 697 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode) 698 } 699 for _, srv := range srvs { 700 if !strings.HasSuffix(srv.Target, ".google.com.") { 701 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) 702 break 703 } 704 } 705 } 706 } 707 708 func mxString(mxs []*MX) string { 709 var buf bytes.Buffer 710 sep := "" 711 fmt.Fprintf(&buf, "[") 712 for _, mx := range mxs { 713 fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref) 714 sep = " " 715 } 716 fmt.Fprintf(&buf, "]") 717 return buf.String() 718 } 719 720 func nsString(nss []*NS) string { 721 var buf bytes.Buffer 722 sep := "" 723 fmt.Fprintf(&buf, "[") 724 for _, ns := range nss { 725 fmt.Fprintf(&buf, "%s%s", sep, ns.Host) 726 sep = " " 727 } 728 fmt.Fprintf(&buf, "]") 729 return buf.String() 730 } 731 732 func srvString(srvs []*SRV) string { 733 var buf bytes.Buffer 734 sep := "" 735 fmt.Fprintf(&buf, "[") 736 for _, srv := range srvs { 737 fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight) 738 sep = " " 739 } 740 fmt.Fprintf(&buf, "]") 741 return buf.String() 742 } 743 744 func TestLookupPort(t *testing.T) { 745 // See https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml 746 // 747 // Please be careful about adding new test cases. 748 // There are platforms which have incomplete mappings for 749 // restricted resource access and security reasons. 750 type test struct { 751 network string 752 name string 753 port int 754 ok bool 755 } 756 var tests = []test{ 757 {"tcp", "0", 0, true}, 758 {"udp", "0", 0, true}, 759 {"udp", "domain", 53, true}, 760 761 {"--badnet--", "zzz", 0, false}, 762 {"tcp", "--badport--", 0, false}, 763 {"tcp", "-1", 0, false}, 764 {"tcp", "65536", 0, false}, 765 {"udp", "-1", 0, false}, 766 {"udp", "65536", 0, false}, 767 {"tcp", "123456789", 0, false}, 768 769 // Issue 13610: LookupPort("tcp", "") 770 {"tcp", "", 0, true}, 771 {"tcp4", "", 0, true}, 772 {"tcp6", "", 0, true}, 773 {"udp", "", 0, true}, 774 {"udp4", "", 0, true}, 775 {"udp6", "", 0, true}, 776 } 777 778 switch runtime.GOOS { 779 case "android": 780 if netGo { 781 t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS) 782 } 783 default: 784 tests = append(tests, test{"tcp", "http", 80, true}) 785 } 786 787 for _, tt := range tests { 788 port, err := LookupPort(tt.network, tt.name) 789 if port != tt.port || (err == nil) != tt.ok { 790 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok) 791 } 792 if err != nil { 793 if perr := parseLookupPortError(err); perr != nil { 794 t.Error(perr) 795 } 796 } 797 } 798 } 799 800 // Like TestLookupPort but with minimal tests that should always pass 801 // because the answers are baked-in to the net package. 802 func TestLookupPort_Minimal(t *testing.T) { 803 type test struct { 804 network string 805 name string 806 port int 807 } 808 var tests = []test{ 809 {"tcp", "http", 80}, 810 {"tcp", "HTTP", 80}, // case shouldn't matter 811 {"tcp", "https", 443}, 812 {"tcp", "ssh", 22}, 813 {"tcp", "gopher", 70}, 814 {"tcp4", "http", 80}, 815 {"tcp6", "http", 80}, 816 } 817 818 for _, tt := range tests { 819 port, err := LookupPort(tt.network, tt.name) 820 if port != tt.port || err != nil { 821 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port) 822 } 823 } 824 } 825 826 func TestLookupProtocol_Minimal(t *testing.T) { 827 type test struct { 828 name string 829 want int 830 } 831 var tests = []test{ 832 {"tcp", 6}, 833 {"TcP", 6}, // case shouldn't matter 834 {"icmp", 1}, 835 {"igmp", 2}, 836 {"udp", 17}, 837 {"ipv6-icmp", 58}, 838 } 839 840 for _, tt := range tests { 841 got, err := lookupProtocol(context.Background(), tt.name) 842 if got != tt.want || err != nil { 843 t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want) 844 } 845 } 846 847 } 848 849 func TestLookupNonLDH(t *testing.T) { 850 if runtime.GOOS == "nacl" { 851 t.Skip("skip on nacl") 852 } 853 854 defer dnsWaitGroup.Wait() 855 856 if fixup := forceGoDNS(); fixup != nil { 857 defer fixup() 858 } 859 860 // "LDH" stands for letters, digits, and hyphens and is the usual 861 // description of standard DNS names. 862 // This test is checking that other kinds of names are reported 863 // as not found, not reported as invalid names. 864 addrs, err := LookupHost("!!!.###.bogus..domain.") 865 if err == nil { 866 t.Fatalf("lookup succeeded: %v", addrs) 867 } 868 if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) { 869 t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost) 870 } 871 } 872 873 func TestLookupContextCancel(t *testing.T) { 874 mustHaveExternalNetwork(t) 875 if runtime.GOOS == "nacl" { 876 t.Skip("skip on nacl") 877 } 878 879 defer dnsWaitGroup.Wait() 880 881 ctx, ctxCancel := context.WithCancel(context.Background()) 882 ctxCancel() 883 _, err := DefaultResolver.LookupIPAddr(ctx, "google.com") 884 if err != errCanceled { 885 testenv.SkipFlakyNet(t) 886 t.Fatal(err) 887 } 888 ctx = context.Background() 889 _, err = DefaultResolver.LookupIPAddr(ctx, "google.com") 890 if err != nil { 891 testenv.SkipFlakyNet(t) 892 t.Fatal(err) 893 } 894 } 895 896 // Issue 24330: treat the nil *Resolver like a zero value. Verify nothing 897 // crashes if nil is used. 898 func TestNilResolverLookup(t *testing.T) { 899 mustHaveExternalNetwork(t) 900 if runtime.GOOS == "nacl" { 901 t.Skip("skip on nacl") 902 } 903 var r *Resolver = nil 904 ctx := context.Background() 905 906 // Don't care about the results, just that nothing panics: 907 r.LookupAddr(ctx, "8.8.8.8") 908 r.LookupCNAME(ctx, "google.com") 909 r.LookupHost(ctx, "google.com") 910 r.LookupIPAddr(ctx, "google.com") 911 r.LookupMX(ctx, "gmail.com") 912 r.LookupNS(ctx, "google.com") 913 r.LookupPort(ctx, "tcp", "smtp") 914 r.LookupSRV(ctx, "service", "proto", "name") 915 r.LookupTXT(ctx, "gmail.com") 916 } 917 918 // TestLookupHostCancel verifies that lookup works even after many 919 // canceled lookups (see golang.org/issue/24178 for details). 920 func TestLookupHostCancel(t *testing.T) { 921 mustHaveExternalNetwork(t) 922 if runtime.GOOS == "nacl" { 923 t.Skip("skip on nacl") 924 } 925 926 const ( 927 google = "www.google.com" 928 invalidDomain = "nonexistentdomain.golang.org" 929 n = 600 // this needs to be larger than threadLimit size 930 ) 931 932 _, err := LookupHost(google) 933 if err != nil { 934 t.Fatal(err) 935 } 936 937 ctx, cancel := context.WithCancel(context.Background()) 938 cancel() 939 for i := 0; i < n; i++ { 940 addr, err := DefaultResolver.LookupHost(ctx, invalidDomain) 941 if err == nil { 942 t.Fatalf("LookupHost(%q): returns %v, but should fail", invalidDomain, addr) 943 } 944 if !strings.Contains(err.Error(), "canceled") { 945 t.Fatalf("LookupHost(%q): failed with unexpected error: %v", invalidDomain, err) 946 } 947 time.Sleep(time.Millisecond * 1) 948 } 949 950 _, err = LookupHost(google) 951 if err != nil { 952 t.Fatal(err) 953 } 954 } 955 956 type lookupCustomResolver struct { 957 *Resolver 958 mu sync.RWMutex 959 dialed bool 960 } 961 962 func (lcr *lookupCustomResolver) dial() func(ctx context.Context, network, address string) (Conn, error) { 963 return func(ctx context.Context, network, address string) (Conn, error) { 964 lcr.mu.Lock() 965 lcr.dialed = true 966 lcr.mu.Unlock() 967 return Dial(network, address) 968 } 969 } 970 971 // TestConcurrentPreferGoResolversDial tests that multiple resolvers with the 972 // PreferGo option used concurrently are all dialed properly. 973 func TestConcurrentPreferGoResolversDial(t *testing.T) { 974 // The windows implementation of the resolver does not use the Dial 975 // function. 976 if runtime.GOOS == "windows" { 977 t.Skip("skip on windows") 978 } 979 980 testenv.MustHaveExternalNetwork(t) 981 testenv.SkipFlakyNet(t) 982 983 defer dnsWaitGroup.Wait() 984 985 resolvers := make([]*lookupCustomResolver, 2) 986 for i := range resolvers { 987 cs := lookupCustomResolver{Resolver: &Resolver{PreferGo: true}} 988 cs.Dial = cs.dial() 989 resolvers[i] = &cs 990 } 991 992 var wg sync.WaitGroup 993 wg.Add(len(resolvers)) 994 for i, resolver := range resolvers { 995 go func(r *Resolver, index int) { 996 defer wg.Done() 997 _, err := r.LookupIPAddr(context.Background(), "google.com") 998 if err != nil { 999 t.Fatalf("lookup failed for resolver %d: %q", index, err) 1000 } 1001 }(resolver.Resolver, i) 1002 } 1003 wg.Wait() 1004 1005 for i, resolver := range resolvers { 1006 if !resolver.dialed { 1007 t.Errorf("custom resolver %d not dialed during lookup", i) 1008 } 1009 } 1010 } 1011 1012 var ipVersionTests = []struct { 1013 network string 1014 version byte 1015 }{ 1016 {"tcp", 0}, 1017 {"tcp4", '4'}, 1018 {"tcp6", '6'}, 1019 {"udp", 0}, 1020 {"udp4", '4'}, 1021 {"udp6", '6'}, 1022 {"ip", 0}, 1023 {"ip4", '4'}, 1024 {"ip6", '6'}, 1025 {"ip7", 0}, 1026 {"", 0}, 1027 } 1028 1029 func TestIPVersion(t *testing.T) { 1030 for _, tt := range ipVersionTests { 1031 if version := ipVersion(tt.network); version != tt.version { 1032 t.Errorf("Family for: %s. Expected: %s, Got: %s", tt.network, 1033 string(tt.version), string(version)) 1034 } 1035 } 1036 }