Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / net / lookup_test.go
blob8a41510daf3ece4d5184482f79554ce9c7ad6670
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.
5 // +build !js
7 package net
9 import (
10 "bytes"
11 "context"
12 "fmt"
13 "internal/testenv"
14 "reflect"
15 "runtime"
16 "sort"
17 "strings"
18 "sync"
19 "sync/atomic"
20 "testing"
21 "time"
24 func hasSuffixFold(s, suffix string) bool {
25 return strings.HasSuffix(strings.ToLower(s), strings.ToLower(suffix))
28 func lookupLocalhost(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
29 switch host {
30 case "localhost":
31 return []IPAddr{
32 {IP: IPv4(127, 0, 0, 1)},
33 {IP: IPv6loopback},
34 }, nil
35 default:
36 return fn(ctx, network, host)
40 // The Lookup APIs use various sources such as local database, DNS or
41 // mDNS, and may use platform-dependent DNS stub resolver if possible.
42 // The APIs accept any of forms for a query; host name in various
43 // encodings, UTF-8 encoded net name, domain name, FQDN or absolute
44 // FQDN, but the result would be one of the forms and it depends on
45 // the circumstances.
47 var lookupGoogleSRVTests = []struct {
48 service, proto, name string
49 cname, target string
52 "xmpp-server", "tcp", "google.com",
53 "google.com.", "google.com.",
56 "xmpp-server", "tcp", "google.com.",
57 "google.com.", "google.com.",
60 // non-standard back door
62 "", "", "_xmpp-server._tcp.google.com",
63 "google.com.", "google.com.",
66 "", "", "_xmpp-server._tcp.google.com.",
67 "google.com.", "google.com.",
71 var backoffDuration = [...]time.Duration{time.Second, 5 * time.Second, 30 * time.Second}
73 func TestLookupGoogleSRV(t *testing.T) {
74 t.Parallel()
75 mustHaveExternalNetwork(t)
77 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
78 t.Skip("no resolv.conf on iOS")
81 if !supportsIPv4() || !*testIPv4 {
82 t.Skip("IPv4 is required")
85 attempts := 0
86 for i := 0; i < len(lookupGoogleSRVTests); i++ {
87 tt := lookupGoogleSRVTests[i]
88 cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
89 if err != nil {
90 testenv.SkipFlakyNet(t)
91 if attempts < len(backoffDuration) {
92 dur := backoffDuration[attempts]
93 t.Logf("backoff %v after failure %v\n", dur, err)
94 time.Sleep(dur)
95 attempts++
96 i--
97 continue
99 t.Fatal(err)
101 if len(srvs) == 0 {
102 t.Error("got no record")
104 if !hasSuffixFold(cname, tt.cname) {
105 t.Errorf("got %s; want %s", cname, tt.cname)
107 for _, srv := range srvs {
108 if !hasSuffixFold(srv.Target, tt.target) {
109 t.Errorf("got %v; want a record containing %s", srv, tt.target)
115 var lookupGmailMXTests = []struct {
116 name, host string
118 {"gmail.com", "google.com."},
119 {"gmail.com.", "google.com."},
122 func TestLookupGmailMX(t *testing.T) {
123 t.Parallel()
124 mustHaveExternalNetwork(t)
126 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
127 t.Skip("no resolv.conf on iOS")
130 if !supportsIPv4() || !*testIPv4 {
131 t.Skip("IPv4 is required")
134 attempts := 0
135 for i := 0; i < len(lookupGmailMXTests); i++ {
136 tt := lookupGmailMXTests[i]
137 mxs, err := LookupMX(tt.name)
138 if err != nil {
139 testenv.SkipFlakyNet(t)
140 if attempts < len(backoffDuration) {
141 dur := backoffDuration[attempts]
142 t.Logf("backoff %v after failure %v\n", dur, err)
143 time.Sleep(dur)
144 attempts++
146 continue
148 t.Fatal(err)
150 if len(mxs) == 0 {
151 t.Error("got no record")
153 for _, mx := range mxs {
154 if !hasSuffixFold(mx.Host, tt.host) {
155 t.Errorf("got %v; want a record containing %s", mx, tt.host)
161 var lookupGmailNSTests = []struct {
162 name, host string
164 {"gmail.com", "google.com."},
165 {"gmail.com.", "google.com."},
168 func TestLookupGmailNS(t *testing.T) {
169 t.Parallel()
170 mustHaveExternalNetwork(t)
172 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
173 t.Skip("no resolv.conf on iOS")
176 if !supportsIPv4() || !*testIPv4 {
177 t.Skip("IPv4 is required")
180 attempts := 0
181 for i := 0; i < len(lookupGmailNSTests); i++ {
182 tt := lookupGmailNSTests[i]
183 nss, err := LookupNS(tt.name)
184 if err != nil {
185 testenv.SkipFlakyNet(t)
186 if attempts < len(backoffDuration) {
187 dur := backoffDuration[attempts]
188 t.Logf("backoff %v after failure %v\n", dur, err)
189 time.Sleep(dur)
190 attempts++
192 continue
194 t.Fatal(err)
196 if len(nss) == 0 {
197 t.Error("got no record")
199 for _, ns := range nss {
200 if !hasSuffixFold(ns.Host, tt.host) {
201 t.Errorf("got %v; want a record containing %s", ns, tt.host)
207 var lookupGmailTXTTests = []struct {
208 name, txt, host string
210 {"gmail.com", "spf", "google.com"},
211 {"gmail.com.", "spf", "google.com"},
214 func TestLookupGmailTXT(t *testing.T) {
215 if runtime.GOOS == "plan9" {
216 t.Skip("skipping on plan9; see https://golang.org/issue/29722")
218 t.Parallel()
219 mustHaveExternalNetwork(t)
221 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
222 t.Skip("no resolv.conf on iOS")
225 if !supportsIPv4() || !*testIPv4 {
226 t.Skip("IPv4 is required")
229 attempts := 0
230 for i := 0; i < len(lookupGmailTXTTests); i++ {
231 tt := lookupGmailTXTTests[i]
232 txts, err := LookupTXT(tt.name)
233 if err != nil {
234 testenv.SkipFlakyNet(t)
235 if attempts < len(backoffDuration) {
236 dur := backoffDuration[attempts]
237 t.Logf("backoff %v after failure %v\n", dur, err)
238 time.Sleep(dur)
239 attempts++
241 continue
243 t.Fatal(err)
245 if len(txts) == 0 {
246 t.Error("got no record")
248 found := false
249 for _, txt := range txts {
250 if strings.Contains(txt, tt.txt) && (strings.HasSuffix(txt, tt.host) || strings.HasSuffix(txt, tt.host+".")) {
251 found = true
252 break
255 if !found {
256 t.Errorf("got %v; want a record containing %s, %s", txts, tt.txt, tt.host)
261 var lookupGooglePublicDNSAddrTests = []string{
262 "8.8.8.8",
263 "8.8.4.4",
264 "2001:4860:4860::8888",
265 "2001:4860:4860::8844",
268 func TestLookupGooglePublicDNSAddr(t *testing.T) {
269 mustHaveExternalNetwork(t)
271 if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 {
272 t.Skip("both IPv4 and IPv6 are required")
275 defer dnsWaitGroup.Wait()
277 for _, ip := range lookupGooglePublicDNSAddrTests {
278 names, err := LookupAddr(ip)
279 if err != nil {
280 t.Fatal(err)
282 if len(names) == 0 {
283 t.Error("got no record")
285 for _, name := range names {
286 if !hasSuffixFold(name, ".google.com.") && !hasSuffixFold(name, ".google.") {
287 t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
293 func TestLookupIPv6LinkLocalAddr(t *testing.T) {
294 if !supportsIPv6() || !*testIPv6 {
295 t.Skip("IPv6 is required")
298 defer dnsWaitGroup.Wait()
300 addrs, err := LookupHost("localhost")
301 if err != nil {
302 t.Fatal(err)
304 found := false
305 for _, addr := range addrs {
306 if addr == "fe80::1%lo0" {
307 found = true
308 break
311 if !found {
312 t.Skipf("not supported on %s", runtime.GOOS)
314 if _, err := LookupAddr("fe80::1%lo0"); err != nil {
315 t.Error(err)
319 func TestLookupIPv6LinkLocalAddrWithZone(t *testing.T) {
320 if !supportsIPv6() || !*testIPv6 {
321 t.Skip("IPv6 is required")
324 ipaddrs, err := DefaultResolver.LookupIPAddr(context.Background(), "fe80::1%lo0")
325 if err != nil {
326 t.Error(err)
328 for _, addr := range ipaddrs {
329 if e, a := "lo0", addr.Zone; e != a {
330 t.Errorf("wrong zone: want %q, got %q", e, a)
334 addrs, err := DefaultResolver.LookupHost(context.Background(), "fe80::1%lo0")
335 if err != nil {
336 t.Error(err)
338 for _, addr := range addrs {
339 if e, a := "fe80::1%lo0", addr; e != a {
340 t.Errorf("wrong host: want %q got %q", e, a)
345 var lookupCNAMETests = []struct {
346 name, cname string
348 {"www.iana.org", "icann.org."},
349 {"www.iana.org.", "icann.org."},
350 {"www.google.com", "google.com."},
353 func TestLookupCNAME(t *testing.T) {
354 mustHaveExternalNetwork(t)
356 if !supportsIPv4() || !*testIPv4 {
357 t.Skip("IPv4 is required")
360 defer dnsWaitGroup.Wait()
362 attempts := 0
363 for i := 0; i < len(lookupCNAMETests); i++ {
364 tt := lookupCNAMETests[i]
365 cname, err := LookupCNAME(tt.name)
366 if err != nil {
367 testenv.SkipFlakyNet(t)
368 if attempts < len(backoffDuration) {
369 dur := backoffDuration[attempts]
370 t.Logf("backoff %v after failure %v\n", dur, err)
371 time.Sleep(dur)
372 attempts++
374 continue
376 t.Fatal(err)
378 if !hasSuffixFold(cname, tt.cname) {
379 t.Errorf("got %s; want a record containing %s", cname, tt.cname)
384 var lookupGoogleHostTests = []struct {
385 name string
387 {"google.com"},
388 {"google.com."},
391 func TestLookupGoogleHost(t *testing.T) {
392 mustHaveExternalNetwork(t)
394 if !supportsIPv4() || !*testIPv4 {
395 t.Skip("IPv4 is required")
398 defer dnsWaitGroup.Wait()
400 for _, tt := range lookupGoogleHostTests {
401 addrs, err := LookupHost(tt.name)
402 if err != nil {
403 t.Fatal(err)
405 if len(addrs) == 0 {
406 t.Error("got no record")
408 for _, addr := range addrs {
409 if ParseIP(addr) == nil {
410 t.Errorf("got %q; want a literal IP address", addr)
416 func TestLookupLongTXT(t *testing.T) {
417 testenv.SkipFlaky(t, 22857)
418 mustHaveExternalNetwork(t)
420 defer dnsWaitGroup.Wait()
422 txts, err := LookupTXT("golang.rsc.io")
423 if err != nil {
424 t.Fatal(err)
426 sort.Strings(txts)
427 want := []string{
428 strings.Repeat("abcdefghijklmnopqrstuvwxyABCDEFGHJIKLMNOPQRSTUVWXY", 10),
429 "gophers rule",
431 if !reflect.DeepEqual(txts, want) {
432 t.Fatalf("LookupTXT golang.rsc.io incorrect\nhave %q\nwant %q", txts, want)
436 var lookupGoogleIPTests = []struct {
437 name string
439 {"google.com"},
440 {"google.com."},
443 func TestLookupGoogleIP(t *testing.T) {
444 mustHaveExternalNetwork(t)
446 if !supportsIPv4() || !*testIPv4 {
447 t.Skip("IPv4 is required")
450 defer dnsWaitGroup.Wait()
452 for _, tt := range lookupGoogleIPTests {
453 ips, err := LookupIP(tt.name)
454 if err != nil {
455 t.Fatal(err)
457 if len(ips) == 0 {
458 t.Error("got no record")
460 for _, ip := range ips {
461 if ip.To4() == nil && ip.To16() == nil {
462 t.Errorf("got %v; want an IP address", ip)
468 var revAddrTests = []struct {
469 Addr string
470 Reverse string
471 ErrPrefix string
473 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
474 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
475 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
476 {"::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.", ""},
477 {"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.", ""},
478 {"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.", ""},
479 {"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.", ""},
480 {"1.2.3", "", "unrecognized address"},
481 {"1.2.3.4.5", "", "unrecognized address"},
482 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
483 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
486 func TestReverseAddress(t *testing.T) {
487 defer dnsWaitGroup.Wait()
488 for i, tt := range revAddrTests {
489 a, err := reverseaddr(tt.Addr)
490 if len(tt.ErrPrefix) > 0 && err == nil {
491 t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
492 continue
494 if len(tt.ErrPrefix) == 0 && err != nil {
495 t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
497 if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
498 t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
500 if a != tt.Reverse {
501 t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
506 func TestDNSFlood(t *testing.T) {
507 if !*testDNSFlood {
508 t.Skip("test disabled; use -dnsflood to enable")
511 defer dnsWaitGroup.Wait()
513 var N = 5000
514 if runtime.GOOS == "darwin" {
515 // On Darwin this test consumes kernel threads much
516 // than other platforms for some reason.
517 // When we monitor the number of allocated Ms by
518 // observing on runtime.newm calls, we can see that it
519 // easily reaches the per process ceiling
520 // kern.num_threads when CGO_ENABLED=1 and
521 // GODEBUG=netdns=go.
522 N = 500
525 const timeout = 3 * time.Second
526 ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2)
527 defer cancel()
528 ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
529 defer cancel()
531 c := make(chan error, 2*N)
532 for i := 0; i < N; i++ {
533 name := fmt.Sprintf("%d.net-test.golang.org", i)
534 go func() {
535 _, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name)
536 c <- err
538 go func() {
539 _, err := DefaultResolver.LookupIPAddr(ctxTimeout, name)
540 c <- err
543 qstats := struct {
544 succeeded, failed int
545 timeout, temporary, other int
546 unknown int
548 deadline := time.After(timeout + time.Second)
549 for i := 0; i < 2*N; i++ {
550 select {
551 case <-deadline:
552 t.Fatal("deadline exceeded")
553 case err := <-c:
554 switch err := err.(type) {
555 case nil:
556 qstats.succeeded++
557 case Error:
558 qstats.failed++
559 if err.Timeout() {
560 qstats.timeout++
562 if err.Temporary() {
563 qstats.temporary++
565 if !err.Timeout() && !err.Temporary() {
566 qstats.other++
568 default:
569 qstats.failed++
570 qstats.unknown++
575 // A high volume of DNS queries for sub-domain of golang.org
576 // would be coordinated by authoritative or recursive server,
577 // or stub resolver which implements query-response rate
578 // limitation, so we can expect some query successes and more
579 // failures including timeout, temporary and other here.
580 // As a rule, unknown must not be shown but it might possibly
581 // happen due to issue 4856 for now.
582 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)
585 func TestLookupDotsWithLocalSource(t *testing.T) {
586 if !supportsIPv4() || !*testIPv4 {
587 t.Skip("IPv4 is required")
590 mustHaveExternalNetwork(t)
592 defer dnsWaitGroup.Wait()
594 for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
595 fixup := fn()
596 if fixup == nil {
597 continue
599 names, err := LookupAddr("127.0.0.1")
600 fixup()
601 if err != nil {
602 t.Logf("#%d: %v", i, err)
603 continue
605 mode := "netgo"
606 if i == 1 {
607 mode = "netcgo"
609 loop:
610 for i, name := range names {
611 if strings.Index(name, ".") == len(name)-1 { // "localhost" not "localhost."
612 for j := range names {
613 if j == i {
614 continue
616 if names[j] == name[:len(name)-1] {
617 // It's OK if we find the name without the dot,
618 // as some systems say 127.0.0.1 localhost localhost.
619 continue loop
622 t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1])
623 } else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") { // "localhost.localdomain." not "localhost.localdomain"
624 t.Errorf("%s: got %s; want name ending with trailing dot", mode, name)
630 func TestLookupDotsWithRemoteSource(t *testing.T) {
631 if runtime.GOOS == "darwin" {
632 testenv.SkipFlaky(t, 27992)
634 mustHaveExternalNetwork(t)
636 if !supportsIPv4() || !*testIPv4 {
637 t.Skip("IPv4 is required")
640 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
641 t.Skip("no resolv.conf on iOS")
644 defer dnsWaitGroup.Wait()
646 if fixup := forceGoDNS(); fixup != nil {
647 testDots(t, "go")
648 fixup()
650 if fixup := forceCgoDNS(); fixup != nil {
651 testDots(t, "cgo")
652 fixup()
656 func testDots(t *testing.T, mode string) {
657 names, err := LookupAddr("8.8.8.8") // Google dns server
658 if err != nil {
659 testenv.SkipFlakyNet(t)
660 t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
661 } else {
662 for _, name := range names {
663 if !hasSuffixFold(name, ".google.com.") && !hasSuffixFold(name, ".google.") {
664 t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
665 break
670 cname, err := LookupCNAME("www.mit.edu")
671 if err != nil {
672 testenv.SkipFlakyNet(t)
673 t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err)
674 } else if !strings.HasSuffix(cname, ".") {
675 t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode)
678 mxs, err := LookupMX("google.com")
679 if err != nil {
680 testenv.SkipFlakyNet(t)
681 t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
682 } else {
683 for _, mx := range mxs {
684 if !hasSuffixFold(mx.Host, ".google.com.") {
685 t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
686 break
691 nss, err := LookupNS("google.com")
692 if err != nil {
693 testenv.SkipFlakyNet(t)
694 t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
695 } else {
696 for _, ns := range nss {
697 if !hasSuffixFold(ns.Host, ".google.com.") {
698 t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
699 break
704 cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
705 if err != nil {
706 testenv.SkipFlakyNet(t)
707 t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
708 } else {
709 if !hasSuffixFold(cname, ".google.com.") {
710 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
712 for _, srv := range srvs {
713 if !hasSuffixFold(srv.Target, ".google.com.") {
714 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)
715 break
721 func mxString(mxs []*MX) string {
722 var buf bytes.Buffer
723 sep := ""
724 fmt.Fprintf(&buf, "[")
725 for _, mx := range mxs {
726 fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
727 sep = " "
729 fmt.Fprintf(&buf, "]")
730 return buf.String()
733 func nsString(nss []*NS) string {
734 var buf bytes.Buffer
735 sep := ""
736 fmt.Fprintf(&buf, "[")
737 for _, ns := range nss {
738 fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
739 sep = " "
741 fmt.Fprintf(&buf, "]")
742 return buf.String()
745 func srvString(srvs []*SRV) string {
746 var buf bytes.Buffer
747 sep := ""
748 fmt.Fprintf(&buf, "[")
749 for _, srv := range srvs {
750 fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
751 sep = " "
753 fmt.Fprintf(&buf, "]")
754 return buf.String()
757 func TestLookupPort(t *testing.T) {
758 // See https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
760 // Please be careful about adding new test cases.
761 // There are platforms which have incomplete mappings for
762 // restricted resource access and security reasons.
763 type test struct {
764 network string
765 name string
766 port int
767 ok bool
769 var tests = []test{
770 {"tcp", "0", 0, true},
771 {"udp", "0", 0, true},
772 {"udp", "domain", 53, true},
774 {"--badnet--", "zzz", 0, false},
775 {"tcp", "--badport--", 0, false},
776 {"tcp", "-1", 0, false},
777 {"tcp", "65536", 0, false},
778 {"udp", "-1", 0, false},
779 {"udp", "65536", 0, false},
780 {"tcp", "123456789", 0, false},
782 // Issue 13610: LookupPort("tcp", "")
783 {"tcp", "", 0, true},
784 {"tcp4", "", 0, true},
785 {"tcp6", "", 0, true},
786 {"udp", "", 0, true},
787 {"udp4", "", 0, true},
788 {"udp6", "", 0, true},
791 switch runtime.GOOS {
792 case "android":
793 if netGo {
794 t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
796 default:
797 tests = append(tests, test{"tcp", "http", 80, true})
800 for _, tt := range tests {
801 port, err := LookupPort(tt.network, tt.name)
802 if port != tt.port || (err == nil) != tt.ok {
803 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok)
805 if err != nil {
806 if perr := parseLookupPortError(err); perr != nil {
807 t.Error(perr)
813 // Like TestLookupPort but with minimal tests that should always pass
814 // because the answers are baked-in to the net package.
815 func TestLookupPort_Minimal(t *testing.T) {
816 type test struct {
817 network string
818 name string
819 port int
821 var tests = []test{
822 {"tcp", "http", 80},
823 {"tcp", "HTTP", 80}, // case shouldn't matter
824 {"tcp", "https", 443},
825 {"tcp", "ssh", 22},
826 {"tcp", "gopher", 70},
827 {"tcp4", "http", 80},
828 {"tcp6", "http", 80},
831 for _, tt := range tests {
832 port, err := LookupPort(tt.network, tt.name)
833 if port != tt.port || err != nil {
834 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port)
839 func TestLookupProtocol_Minimal(t *testing.T) {
840 type test struct {
841 name string
842 want int
844 var tests = []test{
845 {"tcp", 6},
846 {"TcP", 6}, // case shouldn't matter
847 {"icmp", 1},
848 {"igmp", 2},
849 {"udp", 17},
850 {"ipv6-icmp", 58},
853 for _, tt := range tests {
854 got, err := lookupProtocol(context.Background(), tt.name)
855 if got != tt.want || err != nil {
856 t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
862 func TestLookupNonLDH(t *testing.T) {
863 defer dnsWaitGroup.Wait()
865 if fixup := forceGoDNS(); fixup != nil {
866 defer fixup()
869 // "LDH" stands for letters, digits, and hyphens and is the usual
870 // description of standard DNS names.
871 // This test is checking that other kinds of names are reported
872 // as not found, not reported as invalid names.
873 addrs, err := LookupHost("!!!.###.bogus..domain.")
874 if err == nil {
875 t.Fatalf("lookup succeeded: %v", addrs)
877 if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) {
878 t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
880 if !err.(*DNSError).IsNotFound {
881 t.Fatalf("lookup error = %v, want true", err.(*DNSError).IsNotFound)
885 func TestLookupContextCancel(t *testing.T) {
886 mustHaveExternalNetwork(t)
887 defer dnsWaitGroup.Wait()
889 ctx, ctxCancel := context.WithCancel(context.Background())
890 ctxCancel()
891 _, err := DefaultResolver.LookupIPAddr(ctx, "google.com")
892 if err != errCanceled {
893 testenv.SkipFlakyNet(t)
894 t.Fatal(err)
896 ctx = context.Background()
897 _, err = DefaultResolver.LookupIPAddr(ctx, "google.com")
898 if err != nil {
899 testenv.SkipFlakyNet(t)
900 t.Fatal(err)
904 // Issue 24330: treat the nil *Resolver like a zero value. Verify nothing
905 // crashes if nil is used.
906 func TestNilResolverLookup(t *testing.T) {
907 mustHaveExternalNetwork(t)
908 var r *Resolver = nil
909 ctx := context.Background()
911 // Don't care about the results, just that nothing panics:
912 r.LookupAddr(ctx, "8.8.8.8")
913 r.LookupCNAME(ctx, "google.com")
914 r.LookupHost(ctx, "google.com")
915 r.LookupIPAddr(ctx, "google.com")
916 r.LookupMX(ctx, "gmail.com")
917 r.LookupNS(ctx, "google.com")
918 r.LookupPort(ctx, "tcp", "smtp")
919 r.LookupSRV(ctx, "service", "proto", "name")
920 r.LookupTXT(ctx, "gmail.com")
923 // TestLookupHostCancel verifies that lookup works even after many
924 // canceled lookups (see golang.org/issue/24178 for details).
925 func TestLookupHostCancel(t *testing.T) {
926 mustHaveExternalNetwork(t)
927 const (
928 google = "www.google.com"
929 invalidDomain = "invalid.invalid" // RFC 2606 reserves .invalid
930 n = 600 // this needs to be larger than threadLimit size
933 _, err := LookupHost(google)
934 if err != nil {
935 t.Fatal(err)
938 ctx, cancel := context.WithCancel(context.Background())
939 cancel()
940 for i := 0; i < n; i++ {
941 addr, err := DefaultResolver.LookupHost(ctx, invalidDomain)
942 if err == nil {
943 t.Fatalf("LookupHost(%q): returns %v, but should fail", invalidDomain, addr)
945 if !strings.Contains(err.Error(), "canceled") {
946 t.Fatalf("LookupHost(%q): failed with unexpected error: %v", invalidDomain, err)
948 time.Sleep(time.Millisecond * 1)
951 _, err = LookupHost(google)
952 if err != nil {
953 t.Fatal(err)
957 type lookupCustomResolver struct {
958 *Resolver
959 mu sync.RWMutex
960 dialed bool
963 func (lcr *lookupCustomResolver) dial() func(ctx context.Context, network, address string) (Conn, error) {
964 return func(ctx context.Context, network, address string) (Conn, error) {
965 lcr.mu.Lock()
966 lcr.dialed = true
967 lcr.mu.Unlock()
968 return Dial(network, address)
972 // TestConcurrentPreferGoResolversDial tests that multiple resolvers with the
973 // PreferGo option used concurrently are all dialed properly.
974 func TestConcurrentPreferGoResolversDial(t *testing.T) {
975 // The windows and plan9 implementation of the resolver does not use
976 // the Dial function.
977 switch runtime.GOOS {
978 case "windows", "plan9":
979 t.Skipf("skip on %v", runtime.GOOS)
982 testenv.MustHaveExternalNetwork(t)
983 testenv.SkipFlakyNet(t)
985 defer dnsWaitGroup.Wait()
987 resolvers := make([]*lookupCustomResolver, 2)
988 for i := range resolvers {
989 cs := lookupCustomResolver{Resolver: &Resolver{PreferGo: true}}
990 cs.Dial = cs.dial()
991 resolvers[i] = &cs
994 var wg sync.WaitGroup
995 wg.Add(len(resolvers))
996 for i, resolver := range resolvers {
997 go func(r *Resolver, index int) {
998 defer wg.Done()
999 _, err := r.LookupIPAddr(context.Background(), "google.com")
1000 if err != nil {
1001 t.Fatalf("lookup failed for resolver %d: %q", index, err)
1003 }(resolver.Resolver, i)
1005 wg.Wait()
1007 for i, resolver := range resolvers {
1008 if !resolver.dialed {
1009 t.Errorf("custom resolver %d not dialed during lookup", i)
1014 var ipVersionTests = []struct {
1015 network string
1016 version byte
1018 {"tcp", 0},
1019 {"tcp4", '4'},
1020 {"tcp6", '6'},
1021 {"udp", 0},
1022 {"udp4", '4'},
1023 {"udp6", '6'},
1024 {"ip", 0},
1025 {"ip4", '4'},
1026 {"ip6", '6'},
1027 {"ip7", 0},
1028 {"", 0},
1031 func TestIPVersion(t *testing.T) {
1032 for _, tt := range ipVersionTests {
1033 if version := ipVersion(tt.network); version != tt.version {
1034 t.Errorf("Family for: %s. Expected: %s, Got: %s", tt.network,
1035 string(tt.version), string(version))
1040 // Issue 28600: The context that is used to lookup ips should always
1041 // preserve the values from the context that was passed into LookupIPAddr.
1042 func TestLookupIPAddrPreservesContextValues(t *testing.T) {
1043 origTestHookLookupIP := testHookLookupIP
1044 defer func() { testHookLookupIP = origTestHookLookupIP }()
1046 keyValues := []struct {
1047 key, value interface{}
1049 {"key-1", 12},
1050 {384, "value2"},
1051 {new(float64), 137},
1053 ctx := context.Background()
1054 for _, kv := range keyValues {
1055 ctx = context.WithValue(ctx, kv.key, kv.value)
1058 wantIPs := []IPAddr{
1059 {IP: IPv4(127, 0, 0, 1)},
1060 {IP: IPv6loopback},
1063 checkCtxValues := func(ctx_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
1064 for _, kv := range keyValues {
1065 g, w := ctx_.Value(kv.key), kv.value
1066 if !reflect.DeepEqual(g, w) {
1067 t.Errorf("Value lookup:\n\tGot: %v\n\tWant: %v", g, w)
1070 return wantIPs, nil
1072 testHookLookupIP = checkCtxValues
1074 resolvers := []*Resolver{
1075 nil,
1076 new(Resolver),
1079 for i, resolver := range resolvers {
1080 gotIPs, err := resolver.LookupIPAddr(ctx, "golang.org")
1081 if err != nil {
1082 t.Errorf("Resolver #%d: unexpected error: %v", i, err)
1084 if !reflect.DeepEqual(gotIPs, wantIPs) {
1085 t.Errorf("#%d: mismatched IPAddr results\n\tGot: %v\n\tWant: %v", i, gotIPs, wantIPs)
1090 // Issue 30521: The lookup group should call the resolver for each network.
1091 func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
1092 origTestHookLookupIP := testHookLookupIP
1093 defer func() { testHookLookupIP = origTestHookLookupIP }()
1095 queries := [][]string{
1096 {"udp", "golang.org"},
1097 {"udp4", "golang.org"},
1098 {"udp6", "golang.org"},
1099 {"udp", "golang.org"},
1100 {"udp", "golang.org"},
1102 results := map[[2]string][]IPAddr{
1103 {"udp", "golang.org"}: {
1104 {IP: IPv4(127, 0, 0, 1)},
1105 {IP: IPv6loopback},
1107 {"udp4", "golang.org"}: {
1108 {IP: IPv4(127, 0, 0, 1)},
1110 {"udp6", "golang.org"}: {
1111 {IP: IPv6loopback},
1114 calls := int32(0)
1115 waitCh := make(chan struct{})
1116 testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
1117 // We'll block until this is called one time for each different
1118 // expected result. This will ensure that the lookup group would wait
1119 // for the existing call if it was to be reused.
1120 if atomic.AddInt32(&calls, 1) == int32(len(results)) {
1121 close(waitCh)
1123 select {
1124 case <-waitCh:
1125 case <-ctx.Done():
1126 return nil, ctx.Err()
1128 return results[[2]string{network, host}], nil
1131 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
1132 defer cancel()
1133 wg := sync.WaitGroup{}
1134 for _, q := range queries {
1135 network := q[0]
1136 host := q[1]
1137 wg.Add(1)
1138 go func() {
1139 defer wg.Done()
1140 gotIPs, err := DefaultResolver.lookupIPAddr(ctx, network, host)
1141 if err != nil {
1142 t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
1144 wantIPs := results[[2]string{network, host}]
1145 if !reflect.DeepEqual(gotIPs, wantIPs) {
1146 t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
1150 wg.Wait()
1153 func TestWithUnexpiredValuesPreserved(t *testing.T) {
1154 ctx, cancel := context.WithCancel(context.Background())
1156 // Insert a value into it.
1157 key, value := "key-1", 2
1158 ctx = context.WithValue(ctx, key, value)
1160 // Now use the "values preserving context" like
1161 // we would for LookupIPAddr. See Issue 28600.
1162 ctx = withUnexpiredValuesPreserved(ctx)
1164 // Lookup before expiry.
1165 if g, w := ctx.Value(key), value; g != w {
1166 t.Errorf("Lookup before expiry: Got %v Want %v", g, w)
1169 // Cancel the context.
1170 cancel()
1172 // Lookup after expiry should return nil
1173 if g := ctx.Value(key); g != nil {
1174 t.Errorf("Lookup after expiry: Got %v want nil", g)
1178 // Issue 31586: don't crash on null byte in name
1179 func TestLookupNullByte(t *testing.T) {
1180 testenv.MustHaveExternalNetwork(t)
1181 testenv.SkipFlakyNet(t)
1182 _, err := LookupHost("foo\x00bar") // used to crash on Windows
1183 if err == nil {
1184 t.Errorf("unexpected success")