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.
18 func lookupLocalhost(ctx context
.Context
, fn
func(context
.Context
, string) ([]IPAddr
, error
), host
string) ([]IPAddr
, error
) {
22 {IP
: IPv4(127, 0, 0, 1)},
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
37 var lookupGoogleSRVTests
= []struct {
38 service
, proto
, name
string
42 "xmpp-server", "tcp", "google.com",
43 "google.com.", "google.com.",
46 "xmpp-server", "tcp", "google.com.",
47 "google.com.", "google.com.",
50 // non-standard back door
52 "", "", "_xmpp-server._tcp.google.com",
53 "google.com.", "google.com.",
56 "", "", "_xmpp-server._tcp.google.com.",
57 "google.com.", "google.com.",
61 func TestLookupGoogleSRV(t
*testing
.T
) {
62 if testenv
.Builder() == "" {
63 testenv
.MustHaveExternalNetwork(t
)
66 if !supportsIPv4 ||
!*testIPv4
{
67 t
.Skip("IPv4 is required")
70 for _
, tt
:= range lookupGoogleSRVTests
{
71 cname
, srvs
, err
:= LookupSRV(tt
.service
, tt
.proto
, tt
.name
)
73 testenv
.SkipFlakyNet(t
)
77 t
.Error("got no record")
79 if !strings
.HasSuffix(cname
, tt
.cname
) {
80 t
.Errorf("got %s; want %s", cname
, tt
.cname
)
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
)
90 var lookupGmailMXTests
= []struct {
93 {"gmail.com", "google.com."},
94 {"gmail.com.", "google.com."},
97 func TestLookupGmailMX(t
*testing
.T
) {
98 if testenv
.Builder() == "" {
99 testenv
.MustHaveExternalNetwork(t
)
102 if !supportsIPv4 ||
!*testIPv4
{
103 t
.Skip("IPv4 is required")
106 for _
, tt
:= range lookupGmailMXTests
{
107 mxs
, err
:= LookupMX(tt
.name
)
112 t
.Error("got no record")
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
)
122 var lookupGmailNSTests
= []struct {
125 {"gmail.com", "google.com."},
126 {"gmail.com.", "google.com."},
129 func TestLookupGmailNS(t
*testing
.T
) {
130 if testenv
.Builder() == "" {
131 testenv
.MustHaveExternalNetwork(t
)
134 if !supportsIPv4 ||
!*testIPv4
{
135 t
.Skip("IPv4 is required")
138 for _
, tt
:= range lookupGmailNSTests
{
139 nss
, err
:= LookupNS(tt
.name
)
141 testenv
.SkipFlakyNet(t
)
145 t
.Error("got no record")
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
)
155 var lookupGmailTXTTests
= []struct {
156 name
, txt
, host
string
158 {"gmail.com", "spf", "google.com"},
159 {"gmail.com.", "spf", "google.com"},
162 func TestLookupGmailTXT(t
*testing
.T
) {
163 if testenv
.Builder() == "" {
164 testenv
.MustHaveExternalNetwork(t
)
167 if !supportsIPv4 ||
!*testIPv4
{
168 t
.Skip("IPv4 is required")
171 for _
, tt
:= range lookupGmailTXTTests
{
172 txts
, err
:= LookupTXT(tt
.name
)
177 t
.Error("got no record")
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
)
187 var lookupGooglePublicDNSAddrTests
= []struct {
190 {"8.8.8.8", ".google.com."},
191 {"8.8.4.4", ".google.com."},
193 {"2001:4860:4860::8888", ".google.com."},
194 {"2001:4860:4860::8844", ".google.com."},
197 func TestLookupGooglePublicDNSAddr(t
*testing
.T
) {
198 if testenv
.Builder() == "" {
199 testenv
.MustHaveExternalNetwork(t
)
202 if !supportsIPv4 ||
!supportsIPv6 ||
!*testIPv4 ||
!*testIPv6
{
203 t
.Skip("both IPv4 and IPv6 are required")
206 for _
, tt
:= range lookupGooglePublicDNSAddrTests
{
207 names
, err
:= LookupAddr(tt
.addr
)
212 t
.Error("got no record")
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
)
222 func TestLookupIPv6LinkLocalAddr(t
*testing
.T
) {
223 if !supportsIPv6 ||
!*testIPv6
{
224 t
.Skip("IPv6 is required")
227 addrs
, err
:= LookupHost("localhost")
232 for _
, addr
:= range addrs
{
233 if addr
== "fe80::1%lo0" {
239 t
.Skipf("not supported on %s", runtime
.GOOS
)
241 if _
, err
:= LookupAddr("fe80::1%lo0"); err
!= nil {
246 var lookupCNAMETests
= []struct {
249 {"www.iana.org", "icann.org."},
250 {"www.iana.org.", "icann.org."},
251 {"www.google.com", "google.com."},
254 func TestLookupCNAME(t
*testing
.T
) {
255 if testenv
.Builder() == "" {
256 testenv
.MustHaveExternalNetwork(t
)
259 if !supportsIPv4 ||
!*testIPv4
{
260 t
.Skip("IPv4 is required")
263 for _
, tt
:= range lookupCNAMETests
{
264 cname
, err
:= LookupCNAME(tt
.name
)
268 if !strings
.HasSuffix(cname
, tt
.cname
) {
269 t
.Errorf("got %s; want a record containing %s", cname
, tt
.cname
)
274 var lookupGoogleHostTests
= []struct {
281 func TestLookupGoogleHost(t
*testing
.T
) {
282 if testenv
.Builder() == "" {
283 testenv
.MustHaveExternalNetwork(t
)
286 if !supportsIPv4 ||
!*testIPv4
{
287 t
.Skip("IPv4 is required")
290 for _
, tt
:= range lookupGoogleHostTests
{
291 addrs
, err
:= LookupHost(tt
.name
)
296 t
.Error("got no record")
298 for _
, addr
:= range addrs
{
299 if ParseIP(addr
) == nil {
300 t
.Errorf("got %q; want a literal IP address", addr
)
306 var lookupGoogleIPTests
= []struct {
313 func TestLookupGoogleIP(t
*testing
.T
) {
314 if testenv
.Builder() == "" {
315 testenv
.MustHaveExternalNetwork(t
)
318 if !supportsIPv4 ||
!*testIPv4
{
319 t
.Skip("IPv4 is required")
322 for _
, tt
:= range lookupGoogleIPTests
{
323 ips
, err
:= LookupIP(tt
.name
)
328 t
.Error("got no record")
330 for _
, ip
:= range ips
{
331 if ip
.To4() == nil && ip
.To16() == nil {
332 t
.Errorf("got %v; want an IP address", ip
)
338 var revAddrTests
= []struct {
343 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
344 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
345 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
346 {"::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.", ""},
347 {"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.", ""},
348 {"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.", ""},
349 {"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.", ""},
350 {"1.2.3", "", "unrecognized address"},
351 {"1.2.3.4.5", "", "unrecognized address"},
352 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
353 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
356 func TestReverseAddress(t
*testing
.T
) {
357 for i
, tt
:= range revAddrTests
{
358 a
, err
:= reverseaddr(tt
.Addr
)
359 if len(tt
.ErrPrefix
) > 0 && err
== nil {
360 t
.Errorf("#%d: expected %q, got <nil> (error)", i
, tt
.ErrPrefix
)
363 if len(tt
.ErrPrefix
) == 0 && err
!= nil {
364 t
.Errorf("#%d: expected <nil>, got %q (error)", i
, err
)
366 if err
!= nil && err
.(*DNSError
).Err
!= tt
.ErrPrefix
{
367 t
.Errorf("#%d: expected %q, got %q (mismatched error)", i
, tt
.ErrPrefix
, err
.(*DNSError
).Err
)
370 t
.Errorf("#%d: expected %q, got %q (reverse address)", i
, tt
.Reverse
, a
)
375 func TestDNSFlood(t
*testing
.T
) {
377 t
.Skip("test disabled; use -dnsflood to enable")
381 if runtime
.GOOS
== "darwin" {
382 // On Darwin this test consumes kernel threads much
383 // than other platforms for some reason.
384 // When we monitor the number of allocated Ms by
385 // observing on runtime.newm calls, we can see that it
386 // easily reaches the per process ceiling
387 // kern.num_threads when CGO_ENABLED=1 and
388 // GODEBUG=netdns=go.
392 const timeout
= 3 * time
.Second
393 ctxHalfTimeout
, cancel
:= context
.WithTimeout(context
.Background(), timeout
/2)
395 ctxTimeout
, cancel
:= context
.WithTimeout(context
.Background(), timeout
)
398 c
:= make(chan error
, 2*N
)
399 for i
:= 0; i
< N
; i
++ {
400 name
:= fmt
.Sprintf("%d.net-test.golang.org", i
)
402 _
, err
:= DefaultResolver
.LookupIPAddr(ctxHalfTimeout
, name
)
406 _
, err
:= DefaultResolver
.LookupIPAddr(ctxTimeout
, name
)
411 succeeded
, failed
int
412 timeout
, temporary
, other
int
415 deadline
:= time
.After(timeout
+ time
.Second
)
416 for i
:= 0; i
< 2*N
; i
++ {
419 t
.Fatal("deadline exceeded")
421 switch err
:= err
.(type) {
432 if !err
.Timeout() && !err
.Temporary() {
442 // A high volume of DNS queries for sub-domain of golang.org
443 // would be coordinated by authoritative or recursive server,
444 // or stub resolver which implements query-response rate
445 // limitation, so we can expect some query successes and more
446 // failures including timeout, temporary and other here.
447 // As a rule, unknown must not be shown but it might possibly
448 // happen due to issue 4856 for now.
449 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
)
452 func TestLookupDotsWithLocalSource(t
*testing
.T
) {
453 if !supportsIPv4 ||
!*testIPv4
{
454 t
.Skip("IPv4 is required")
457 if testenv
.Builder() == "" {
458 testenv
.MustHaveExternalNetwork(t
)
461 for i
, fn
:= range []func() func(){forceGoDNS
, forceCgoDNS
} {
466 names
, err
:= LookupAddr("127.0.0.1")
469 t
.Logf("#%d: %v", i
, err
)
477 for i
, name
:= range names
{
478 if strings
.Index(name
, ".") == len(name
)-1 { // "localhost" not "localhost."
479 for j
:= range names
{
483 if names
[j
] == name
[:len(name
)-1] {
484 // It's OK if we find the name without the dot,
485 // as some systems say 127.0.0.1 localhost localhost.
489 t
.Errorf("%s: got %s; want %s", mode
, name
, name
[:len(name
)-1])
490 } else if strings
.Contains(name
, ".") && !strings
.HasSuffix(name
, ".") { // "localhost.localdomain." not "localhost.localdomain"
491 t
.Errorf("%s: got %s; want name ending with trailing dot", mode
, name
)
497 func TestLookupDotsWithRemoteSource(t
*testing
.T
) {
498 if testenv
.Builder() == "" {
499 testenv
.MustHaveExternalNetwork(t
)
502 if !supportsIPv4 ||
!*testIPv4
{
503 t
.Skip("IPv4 is required")
506 if fixup
:= forceGoDNS(); fixup
!= nil {
510 if fixup
:= forceCgoDNS(); fixup
!= nil {
516 func testDots(t
*testing
.T
, mode
string) {
517 names
, err
:= LookupAddr("8.8.8.8") // Google dns server
519 testenv
.SkipFlakyNet(t
)
520 t
.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err
, mode
)
522 for _
, name
:= range names
{
523 if !strings
.HasSuffix(name
, ".google.com.") {
524 t
.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names
, mode
)
530 cname
, err
:= LookupCNAME("www.mit.edu")
532 testenv
.SkipFlakyNet(t
)
533 t
.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode
, err
)
534 } else if !strings
.HasSuffix(cname
, ".") {
535 t
.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname
, mode
)
538 mxs
, err
:= LookupMX("google.com")
540 testenv
.SkipFlakyNet(t
)
541 t
.Errorf("LookupMX(google.com): %v (mode=%v)", err
, mode
)
543 for _
, mx
:= range mxs
{
544 if !strings
.HasSuffix(mx
.Host
, ".google.com.") {
545 t
.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs
), mode
)
551 nss
, err
:= LookupNS("google.com")
553 testenv
.SkipFlakyNet(t
)
554 t
.Errorf("LookupNS(google.com): %v (mode=%v)", err
, mode
)
556 for _
, ns
:= range nss
{
557 if !strings
.HasSuffix(ns
.Host
, ".google.com.") {
558 t
.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss
), mode
)
564 cname
, srvs
, err
:= LookupSRV("xmpp-server", "tcp", "google.com")
566 testenv
.SkipFlakyNet(t
)
567 t
.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err
, mode
)
569 if !strings
.HasSuffix(cname
, ".google.com.") {
570 t
.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname
, mode
)
572 for _
, srv
:= range srvs
{
573 if !strings
.HasSuffix(srv
.Target
, ".google.com.") {
574 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
)
581 func mxString(mxs
[]*MX
) string {
584 fmt
.Fprintf(&buf
, "[")
585 for _
, mx
:= range mxs
{
586 fmt
.Fprintf(&buf
, "%s%s:%d", sep
, mx
.Host
, mx
.Pref
)
589 fmt
.Fprintf(&buf
, "]")
593 func nsString(nss
[]*NS
) string {
596 fmt
.Fprintf(&buf
, "[")
597 for _
, ns
:= range nss
{
598 fmt
.Fprintf(&buf
, "%s%s", sep
, ns
.Host
)
601 fmt
.Fprintf(&buf
, "]")
605 func srvString(srvs
[]*SRV
) string {
608 fmt
.Fprintf(&buf
, "[")
609 for _
, srv
:= range srvs
{
610 fmt
.Fprintf(&buf
, "%s%s:%d:%d:%d", sep
, srv
.Target
, srv
.Port
, srv
.Priority
, srv
.Weight
)
613 fmt
.Fprintf(&buf
, "]")
617 func TestLookupPort(t
*testing
.T
) {
618 // See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
620 // Please be careful about adding new test cases.
621 // There are platforms having incomplete mappings for
622 // restricted resource access and security reasons.
630 {"tcp", "0", 0, true},
631 {"udp", "0", 0, true},
632 {"udp", "domain", 53, true},
634 {"--badnet--", "zzz", 0, false},
635 {"tcp", "--badport--", 0, false},
636 {"tcp", "-1", 0, false},
637 {"tcp", "65536", 0, false},
638 {"udp", "-1", 0, false},
639 {"udp", "65536", 0, false},
640 {"tcp", "123456789", 0, false},
642 // Issue 13610: LookupPort("tcp", "")
643 {"tcp", "", 0, true},
644 {"tcp4", "", 0, true},
645 {"tcp6", "", 0, true},
646 {"udp", "", 0, true},
647 {"udp4", "", 0, true},
648 {"udp6", "", 0, true},
651 switch runtime
.GOOS
{
654 t
.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime
.GOOS
)
657 tests
= append(tests
, test
{"tcp", "http", 80, true})
660 for _
, tt
:= range tests
{
661 port
, err
:= LookupPort(tt
.network
, tt
.name
)
662 if port
!= tt
.port ||
(err
== nil) != tt
.ok
{
663 t
.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt
.network
, tt
.name
, port
, err
, tt
.port
, !tt
.ok
)
666 if perr
:= parseLookupPortError(err
); perr
!= nil {
673 // Like TestLookupPort but with minimal tests that should always pass
674 // because the answers are baked-in to the net package.
675 func TestLookupPort_Minimal(t
*testing
.T
) {
683 {"tcp", "HTTP", 80}, // case shouldn't matter
684 {"tcp", "https", 443},
686 {"tcp", "gopher", 70},
687 {"tcp4", "http", 80},
688 {"tcp6", "http", 80},
691 for _
, tt
:= range tests
{
692 port
, err
:= LookupPort(tt
.network
, tt
.name
)
693 if port
!= tt
.port || err
!= nil {
694 t
.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt
.network
, tt
.name
, port
, err
, tt
.port
)
699 func TestLookupProtocol_Minimal(t
*testing
.T
) {
706 {"TcP", 6}, // case shouldn't matter
713 for _
, tt
:= range tests
{
714 got
, err
:= lookupProtocol(context
.Background(), tt
.name
)
715 if got
!= tt
.want || err
!= nil {
716 t
.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt
.name
, got
, err
, tt
.want
)
722 func TestLookupNonLDH(t
*testing
.T
) {
723 if runtime
.GOOS
== "nacl" {
724 t
.Skip("skip on nacl")
726 if fixup
:= forceGoDNS(); fixup
!= nil {
730 // "LDH" stands for letters, digits, and hyphens and is the usual
731 // description of standard DNS names.
732 // This test is checking that other kinds of names are reported
733 // as not found, not reported as invalid names.
734 addrs
, err
:= LookupHost("!!!.###.bogus..domain.")
736 t
.Fatalf("lookup succeeded: %v", addrs
)
738 if !strings
.HasSuffix(err
.Error(), errNoSuchHost
.Error()) {
739 t
.Fatalf("lookup error = %v, want %v", err
, errNoSuchHost
)