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.
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
) {
32 {IP
: IPv4(127, 0, 0, 1)},
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
47 var lookupGoogleSRVTests
= []struct {
48 service
, proto
, name
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
) {
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")
86 for i
:= 0; i
< len(lookupGoogleSRVTests
); i
++ {
87 tt
:= lookupGoogleSRVTests
[i
]
88 cname
, srvs
, err
:= LookupSRV(tt
.service
, tt
.proto
, tt
.name
)
90 testenv
.SkipFlakyNet(t
)
91 if attempts
< len(backoffDuration
) {
92 dur
:= backoffDuration
[attempts
]
93 t
.Logf("backoff %v after failure %v\n", dur
, err
)
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 {
118 {"gmail.com", "google.com."},
119 {"gmail.com.", "google.com."},
122 func TestLookupGmailMX(t
*testing
.T
) {
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")
135 for i
:= 0; i
< len(lookupGmailMXTests
); i
++ {
136 tt
:= lookupGmailMXTests
[i
]
137 mxs
, err
:= LookupMX(tt
.name
)
139 testenv
.SkipFlakyNet(t
)
140 if attempts
< len(backoffDuration
) {
141 dur
:= backoffDuration
[attempts
]
142 t
.Logf("backoff %v after failure %v\n", dur
, err
)
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 {
164 {"gmail.com", "google.com."},
165 {"gmail.com.", "google.com."},
168 func TestLookupGmailNS(t
*testing
.T
) {
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")
181 for i
:= 0; i
< len(lookupGmailNSTests
); i
++ {
182 tt
:= lookupGmailNSTests
[i
]
183 nss
, err
:= LookupNS(tt
.name
)
185 testenv
.SkipFlakyNet(t
)
186 if attempts
< len(backoffDuration
) {
187 dur
:= backoffDuration
[attempts
]
188 t
.Logf("backoff %v after failure %v\n", dur
, err
)
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")
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")
230 for i
:= 0; i
< len(lookupGmailTXTTests
); i
++ {
231 tt
:= lookupGmailTXTTests
[i
]
232 txts
, err
:= LookupTXT(tt
.name
)
234 testenv
.SkipFlakyNet(t
)
235 if attempts
< len(backoffDuration
) {
236 dur
:= backoffDuration
[attempts
]
237 t
.Logf("backoff %v after failure %v\n", dur
, err
)
246 t
.Error("got no record")
249 for _
, txt
:= range txts
{
250 if strings
.Contains(txt
, tt
.txt
) && (strings
.HasSuffix(txt
, tt
.host
) || strings
.HasSuffix(txt
, tt
.host
+".")) {
256 t
.Errorf("got %v; want a record containing %s, %s", txts
, tt
.txt
, tt
.host
)
261 var lookupGooglePublicDNSAddrTests
= []string{
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
)
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")
305 for _
, addr
:= range addrs
{
306 if addr
== "fe80::1%lo0" {
312 t
.Skipf("not supported on %s", runtime
.GOOS
)
314 if _
, err
:= LookupAddr("fe80::1%lo0"); err
!= nil {
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")
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")
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 {
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()
363 for i
:= 0; i
< len(lookupCNAMETests
); i
++ {
364 tt
:= lookupCNAMETests
[i
]
365 cname
, err
:= LookupCNAME(tt
.name
)
367 testenv
.SkipFlakyNet(t
)
368 if attempts
< len(backoffDuration
) {
369 dur
:= backoffDuration
[attempts
]
370 t
.Logf("backoff %v after failure %v\n", dur
, err
)
378 if !hasSuffixFold(cname
, tt
.cname
) {
379 t
.Errorf("got %s; want a record containing %s", cname
, tt
.cname
)
384 var lookupGoogleHostTests
= []struct {
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
)
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")
428 strings
.Repeat("abcdefghijklmnopqrstuvwxyABCDEFGHJIKLMNOPQRSTUVWXY", 10),
431 if !reflect
.DeepEqual(txts
, want
) {
432 t
.Fatalf("LookupTXT golang.rsc.io incorrect\nhave %q\nwant %q", txts
, want
)
436 var lookupGoogleIPTests
= []struct {
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
)
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 {
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
)
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
)
501 t
.Errorf("#%d: expected %q, got %q (reverse address)", i
, tt
.Reverse
, a
)
506 func TestDNSFlood(t
*testing
.T
) {
508 t
.Skip("test disabled; use -dnsflood to enable")
511 defer dnsWaitGroup
.Wait()
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.
525 const timeout
= 3 * time
.Second
526 ctxHalfTimeout
, cancel
:= context
.WithTimeout(context
.Background(), timeout
/2)
528 ctxTimeout
, cancel
:= context
.WithTimeout(context
.Background(), timeout
)
531 c
:= make(chan error
, 2*N
)
532 for i
:= 0; i
< N
; i
++ {
533 name
:= fmt
.Sprintf("%d.net-test.golang.org", i
)
535 _
, err
:= DefaultResolver
.LookupIPAddr(ctxHalfTimeout
, name
)
539 _
, err
:= DefaultResolver
.LookupIPAddr(ctxTimeout
, name
)
544 succeeded
, failed
int
545 timeout
, temporary
, other
int
548 deadline
:= time
.After(timeout
+ time
.Second
)
549 for i
:= 0; i
< 2*N
; i
++ {
552 t
.Fatal("deadline exceeded")
554 switch err
:= err
.(type) {
565 if !err
.Timeout() && !err
.Temporary() {
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
} {
599 names
, err
:= LookupAddr("127.0.0.1")
602 t
.Logf("#%d: %v", i
, err
)
610 for i
, name
:= range names
{
611 if strings
.Index(name
, ".") == len(name
)-1 { // "localhost" not "localhost."
612 for j
:= range names
{
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.
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 {
650 if fixup
:= forceCgoDNS(); fixup
!= nil {
656 func testDots(t
*testing
.T
, mode
string) {
657 names
, err
:= LookupAddr("8.8.8.8") // Google dns server
659 testenv
.SkipFlakyNet(t
)
660 t
.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err
, mode
)
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
)
670 cname
, err
:= LookupCNAME("www.mit.edu")
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")
680 testenv
.SkipFlakyNet(t
)
681 t
.Errorf("LookupMX(google.com): %v (mode=%v)", err
, mode
)
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
)
691 nss
, err
:= LookupNS("google.com")
693 testenv
.SkipFlakyNet(t
)
694 t
.Errorf("LookupNS(google.com): %v (mode=%v)", err
, mode
)
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
)
704 cname
, srvs
, err
:= LookupSRV("xmpp-server", "tcp", "google.com")
706 testenv
.SkipFlakyNet(t
)
707 t
.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err
, mode
)
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
)
721 func mxString(mxs
[]*MX
) string {
724 fmt
.Fprintf(&buf
, "[")
725 for _
, mx
:= range mxs
{
726 fmt
.Fprintf(&buf
, "%s%s:%d", sep
, mx
.Host
, mx
.Pref
)
729 fmt
.Fprintf(&buf
, "]")
733 func nsString(nss
[]*NS
) string {
736 fmt
.Fprintf(&buf
, "[")
737 for _
, ns
:= range nss
{
738 fmt
.Fprintf(&buf
, "%s%s", sep
, ns
.Host
)
741 fmt
.Fprintf(&buf
, "]")
745 func srvString(srvs
[]*SRV
) string {
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
)
753 fmt
.Fprintf(&buf
, "]")
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.
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
{
794 t
.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime
.GOOS
)
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
)
806 if perr
:= parseLookupPortError(err
); perr
!= nil {
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
) {
823 {"tcp", "HTTP", 80}, // case shouldn't matter
824 {"tcp", "https", 443},
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
) {
846 {"TcP", 6}, // case shouldn't matter
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 {
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.")
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())
891 _
, err
:= DefaultResolver
.LookupIPAddr(ctx
, "google.com")
892 if err
!= errCanceled
{
893 testenv
.SkipFlakyNet(t
)
896 ctx
= context
.Background()
897 _
, err
= DefaultResolver
.LookupIPAddr(ctx
, "google.com")
899 testenv
.SkipFlakyNet(t
)
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
)
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
)
938 ctx
, cancel
:= context
.WithCancel(context
.Background())
940 for i
:= 0; i
< n
; i
++ {
941 addr
, err
:= DefaultResolver
.LookupHost(ctx
, invalidDomain
)
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
)
957 type lookupCustomResolver
struct {
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
) {
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}}
994 var wg sync
.WaitGroup
995 wg
.Add(len(resolvers
))
996 for i
, resolver
:= range resolvers
{
997 go func(r
*Resolver
, index
int) {
999 _
, err
:= r
.LookupIPAddr(context
.Background(), "google.com")
1001 t
.Fatalf("lookup failed for resolver %d: %q", index
, err
)
1003 }(resolver
.Resolver
, i
)
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 {
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{}
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)},
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
)
1072 testHookLookupIP
= checkCtxValues
1074 resolvers
:= []*Resolver
{
1079 for i
, resolver
:= range resolvers
{
1080 gotIPs
, err
:= resolver
.LookupIPAddr(ctx
, "golang.org")
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)},
1107 {"udp4", "golang.org"}: {
1108 {IP
: IPv4(127, 0, 0, 1)},
1110 {"udp6", "golang.org"}: {
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
)) {
1126 return nil, ctx
.Err()
1128 return results
[[2]string{network
, host
}], nil
1131 ctx
, cancel
:= context
.WithTimeout(context
.Background(), 10*time
.Second
)
1133 wg
:= sync
.WaitGroup
{}
1134 for _
, q
:= range queries
{
1140 gotIPs
, err
:= DefaultResolver
.lookupIPAddr(ctx
, network
, host
)
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
)
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.
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
1184 t
.Errorf("unexpected success")