Source file
src/net/lookup_test.go
Documentation: net
1
2
3
4
5
6
7
8 package net
9
10 import (
11 "bytes"
12 "context"
13 "fmt"
14 "internal/testenv"
15 "reflect"
16 "runtime"
17 "sort"
18 "strings"
19 "sync"
20 "sync/atomic"
21 "testing"
22 "time"
23 )
24
25 func hasSuffixFold(s, suffix string) bool {
26 return strings.HasSuffix(strings.ToLower(s), strings.ToLower(suffix))
27 }
28
29 func lookupLocalhost(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
30 switch host {
31 case "localhost":
32 return []IPAddr{
33 {IP: IPv4(127, 0, 0, 1)},
34 {IP: IPv6loopback},
35 }, nil
36 default:
37 return fn(ctx, network, host)
38 }
39 }
40
41
42
43
44
45
46
47
48 var lookupGoogleSRVTests = []struct {
49 service, proto, name string
50 cname, target string
51 }{
52 {
53 "xmpp-server", "tcp", "google.com",
54 "google.com.", "google.com.",
55 },
56 {
57 "xmpp-server", "tcp", "google.com.",
58 "google.com.", "google.com.",
59 },
60
61
62 {
63 "", "", "_xmpp-server._tcp.google.com",
64 "google.com.", "google.com.",
65 },
66 {
67 "", "", "_xmpp-server._tcp.google.com.",
68 "google.com.", "google.com.",
69 },
70 }
71
72 var backoffDuration = [...]time.Duration{time.Second, 5 * time.Second, 30 * time.Second}
73
74 func TestLookupGoogleSRV(t *testing.T) {
75 t.Parallel()
76 mustHaveExternalNetwork(t)
77
78 if iOS() {
79 t.Skip("no resolv.conf on iOS")
80 }
81
82 if !supportsIPv4() || !*testIPv4 {
83 t.Skip("IPv4 is required")
84 }
85
86 attempts := 0
87 for i := 0; i < len(lookupGoogleSRVTests); i++ {
88 tt := lookupGoogleSRVTests[i]
89 cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
90 if err != nil {
91 testenv.SkipFlakyNet(t)
92 if attempts < len(backoffDuration) {
93 dur := backoffDuration[attempts]
94 t.Logf("backoff %v after failure %v\n", dur, err)
95 time.Sleep(dur)
96 attempts++
97 i--
98 continue
99 }
100 t.Fatal(err)
101 }
102 if len(srvs) == 0 {
103 t.Error("got no record")
104 }
105 if !hasSuffixFold(cname, tt.cname) {
106 t.Errorf("got %s; want %s", cname, tt.cname)
107 }
108 for _, srv := range srvs {
109 if !hasSuffixFold(srv.Target, tt.target) {
110 t.Errorf("got %v; want a record containing %s", srv, tt.target)
111 }
112 }
113 }
114 }
115
116 var lookupGmailMXTests = []struct {
117 name, host string
118 }{
119 {"gmail.com", "google.com."},
120 {"gmail.com.", "google.com."},
121 }
122
123 func TestLookupGmailMX(t *testing.T) {
124 t.Parallel()
125 mustHaveExternalNetwork(t)
126
127 if iOS() {
128 t.Skip("no resolv.conf on iOS")
129 }
130
131 if !supportsIPv4() || !*testIPv4 {
132 t.Skip("IPv4 is required")
133 }
134
135 attempts := 0
136 for i := 0; i < len(lookupGmailMXTests); i++ {
137 tt := lookupGmailMXTests[i]
138 mxs, err := LookupMX(tt.name)
139 if err != nil {
140 testenv.SkipFlakyNet(t)
141 if attempts < len(backoffDuration) {
142 dur := backoffDuration[attempts]
143 t.Logf("backoff %v after failure %v\n", dur, err)
144 time.Sleep(dur)
145 attempts++
146 i--
147 continue
148 }
149 t.Fatal(err)
150 }
151 if len(mxs) == 0 {
152 t.Error("got no record")
153 }
154 for _, mx := range mxs {
155 if !hasSuffixFold(mx.Host, tt.host) {
156 t.Errorf("got %v; want a record containing %s", mx, tt.host)
157 }
158 }
159 }
160 }
161
162 var lookupGmailNSTests = []struct {
163 name, host string
164 }{
165 {"gmail.com", "google.com."},
166 {"gmail.com.", "google.com."},
167 }
168
169 func TestLookupGmailNS(t *testing.T) {
170 t.Parallel()
171 mustHaveExternalNetwork(t)
172
173 if iOS() {
174 t.Skip("no resolv.conf on iOS")
175 }
176
177 if !supportsIPv4() || !*testIPv4 {
178 t.Skip("IPv4 is required")
179 }
180
181 attempts := 0
182 for i := 0; i < len(lookupGmailNSTests); i++ {
183 tt := lookupGmailNSTests[i]
184 nss, err := LookupNS(tt.name)
185 if err != nil {
186 testenv.SkipFlakyNet(t)
187 if attempts < len(backoffDuration) {
188 dur := backoffDuration[attempts]
189 t.Logf("backoff %v after failure %v\n", dur, err)
190 time.Sleep(dur)
191 attempts++
192 i--
193 continue
194 }
195 t.Fatal(err)
196 }
197 if len(nss) == 0 {
198 t.Error("got no record")
199 }
200 for _, ns := range nss {
201 if !hasSuffixFold(ns.Host, tt.host) {
202 t.Errorf("got %v; want a record containing %s", ns, tt.host)
203 }
204 }
205 }
206 }
207
208 var lookupGmailTXTTests = []struct {
209 name, txt, host string
210 }{
211 {"gmail.com", "spf", "google.com"},
212 {"gmail.com.", "spf", "google.com"},
213 }
214
215 func TestLookupGmailTXT(t *testing.T) {
216 if runtime.GOOS == "plan9" {
217 t.Skip("skipping on plan9; see https://golang.org/issue/29722")
218 }
219 t.Parallel()
220 mustHaveExternalNetwork(t)
221
222 if iOS() {
223 t.Skip("no resolv.conf on iOS")
224 }
225
226 if !supportsIPv4() || !*testIPv4 {
227 t.Skip("IPv4 is required")
228 }
229
230 attempts := 0
231 for i := 0; i < len(lookupGmailTXTTests); i++ {
232 tt := lookupGmailTXTTests[i]
233 txts, err := LookupTXT(tt.name)
234 if err != nil {
235 testenv.SkipFlakyNet(t)
236 if attempts < len(backoffDuration) {
237 dur := backoffDuration[attempts]
238 t.Logf("backoff %v after failure %v\n", dur, err)
239 time.Sleep(dur)
240 attempts++
241 i--
242 continue
243 }
244 t.Fatal(err)
245 }
246 if len(txts) == 0 {
247 t.Error("got no record")
248 }
249 found := false
250 for _, txt := range txts {
251 if strings.Contains(txt, tt.txt) && (strings.HasSuffix(txt, tt.host) || strings.HasSuffix(txt, tt.host+".")) {
252 found = true
253 break
254 }
255 }
256 if !found {
257 t.Errorf("got %v; want a record containing %s, %s", txts, tt.txt, tt.host)
258 }
259 }
260 }
261
262 var lookupGooglePublicDNSAddrTests = []string{
263 "8.8.8.8",
264 "8.8.4.4",
265 "2001:4860:4860::8888",
266 "2001:4860:4860::8844",
267 }
268
269 func TestLookupGooglePublicDNSAddr(t *testing.T) {
270 mustHaveExternalNetwork(t)
271
272 if !supportsIPv4() || !supportsIPv6() || !*testIPv4 || !*testIPv6 {
273 t.Skip("both IPv4 and IPv6 are required")
274 }
275
276 defer dnsWaitGroup.Wait()
277
278 for _, ip := range lookupGooglePublicDNSAddrTests {
279 names, err := LookupAddr(ip)
280 if err != nil {
281 t.Fatal(err)
282 }
283 if len(names) == 0 {
284 t.Error("got no record")
285 }
286 for _, name := range names {
287 if !hasSuffixFold(name, ".google.com.") && !hasSuffixFold(name, ".google.") {
288 t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
289 }
290 }
291 }
292 }
293
294 func TestLookupIPv6LinkLocalAddr(t *testing.T) {
295 if !supportsIPv6() || !*testIPv6 {
296 t.Skip("IPv6 is required")
297 }
298
299 defer dnsWaitGroup.Wait()
300
301 addrs, err := LookupHost("localhost")
302 if err != nil {
303 t.Fatal(err)
304 }
305 found := false
306 for _, addr := range addrs {
307 if addr == "fe80::1%lo0" {
308 found = true
309 break
310 }
311 }
312 if !found {
313 t.Skipf("not supported on %s", runtime.GOOS)
314 }
315 if _, err := LookupAddr("fe80::1%lo0"); err != nil {
316 t.Error(err)
317 }
318 }
319
320 func TestLookupIPv6LinkLocalAddrWithZone(t *testing.T) {
321 if !supportsIPv6() || !*testIPv6 {
322 t.Skip("IPv6 is required")
323 }
324
325 ipaddrs, err := DefaultResolver.LookupIPAddr(context.Background(), "fe80::1%lo0")
326 if err != nil {
327 t.Error(err)
328 }
329 for _, addr := range ipaddrs {
330 if e, a := "lo0", addr.Zone; e != a {
331 t.Errorf("wrong zone: want %q, got %q", e, a)
332 }
333 }
334
335 addrs, err := DefaultResolver.LookupHost(context.Background(), "fe80::1%lo0")
336 if err != nil {
337 t.Error(err)
338 }
339 for _, addr := range addrs {
340 if e, a := "fe80::1%lo0", addr; e != a {
341 t.Errorf("wrong host: want %q got %q", e, a)
342 }
343 }
344 }
345
346 var lookupCNAMETests = []struct {
347 name, cname string
348 }{
349 {"www.iana.org", "icann.org."},
350 {"www.iana.org.", "icann.org."},
351 {"www.google.com", "google.com."},
352 }
353
354 func TestLookupCNAME(t *testing.T) {
355 mustHaveExternalNetwork(t)
356
357 if !supportsIPv4() || !*testIPv4 {
358 t.Skip("IPv4 is required")
359 }
360
361 defer dnsWaitGroup.Wait()
362
363 attempts := 0
364 for i := 0; i < len(lookupCNAMETests); i++ {
365 tt := lookupCNAMETests[i]
366 cname, err := LookupCNAME(tt.name)
367 if err != nil {
368 testenv.SkipFlakyNet(t)
369 if attempts < len(backoffDuration) {
370 dur := backoffDuration[attempts]
371 t.Logf("backoff %v after failure %v\n", dur, err)
372 time.Sleep(dur)
373 attempts++
374 i--
375 continue
376 }
377 t.Fatal(err)
378 }
379 if !hasSuffixFold(cname, tt.cname) {
380 t.Errorf("got %s; want a record containing %s", cname, tt.cname)
381 }
382 }
383 }
384
385 var lookupGoogleHostTests = []struct {
386 name string
387 }{
388 {"google.com"},
389 {"google.com."},
390 }
391
392 func TestLookupGoogleHost(t *testing.T) {
393 mustHaveExternalNetwork(t)
394
395 if !supportsIPv4() || !*testIPv4 {
396 t.Skip("IPv4 is required")
397 }
398
399 defer dnsWaitGroup.Wait()
400
401 for _, tt := range lookupGoogleHostTests {
402 addrs, err := LookupHost(tt.name)
403 if err != nil {
404 t.Fatal(err)
405 }
406 if len(addrs) == 0 {
407 t.Error("got no record")
408 }
409 for _, addr := range addrs {
410 if ParseIP(addr) == nil {
411 t.Errorf("got %q; want a literal IP address", addr)
412 }
413 }
414 }
415 }
416
417 func TestLookupLongTXT(t *testing.T) {
418 testenv.SkipFlaky(t, 22857)
419 mustHaveExternalNetwork(t)
420
421 defer dnsWaitGroup.Wait()
422
423 txts, err := LookupTXT("golang.rsc.io")
424 if err != nil {
425 t.Fatal(err)
426 }
427 sort.Strings(txts)
428 want := []string{
429 strings.Repeat("abcdefghijklmnopqrstuvwxyABCDEFGHJIKLMNOPQRSTUVWXY", 10),
430 "gophers rule",
431 }
432 if !reflect.DeepEqual(txts, want) {
433 t.Fatalf("LookupTXT golang.rsc.io incorrect\nhave %q\nwant %q", txts, want)
434 }
435 }
436
437 var lookupGoogleIPTests = []struct {
438 name string
439 }{
440 {"google.com"},
441 {"google.com."},
442 }
443
444 func TestLookupGoogleIP(t *testing.T) {
445 mustHaveExternalNetwork(t)
446
447 if !supportsIPv4() || !*testIPv4 {
448 t.Skip("IPv4 is required")
449 }
450
451 defer dnsWaitGroup.Wait()
452
453 for _, tt := range lookupGoogleIPTests {
454 ips, err := LookupIP(tt.name)
455 if err != nil {
456 t.Fatal(err)
457 }
458 if len(ips) == 0 {
459 t.Error("got no record")
460 }
461 for _, ip := range ips {
462 if ip.To4() == nil && ip.To16() == nil {
463 t.Errorf("got %v; want an IP address", ip)
464 }
465 }
466 }
467 }
468
469 var revAddrTests = []struct {
470 Addr string
471 Reverse string
472 ErrPrefix string
473 }{
474 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
475 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
476 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
477 {"::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.", ""},
478 {"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.", ""},
479 {"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.", ""},
480 {"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.", ""},
481 {"1.2.3", "", "unrecognized address"},
482 {"1.2.3.4.5", "", "unrecognized address"},
483 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
484 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
485 }
486
487 func TestReverseAddress(t *testing.T) {
488 defer dnsWaitGroup.Wait()
489 for i, tt := range revAddrTests {
490 a, err := reverseaddr(tt.Addr)
491 if len(tt.ErrPrefix) > 0 && err == nil {
492 t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
493 continue
494 }
495 if len(tt.ErrPrefix) == 0 && err != nil {
496 t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
497 }
498 if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
499 t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
500 }
501 if a != tt.Reverse {
502 t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
503 }
504 }
505 }
506
507 func TestDNSFlood(t *testing.T) {
508 if !*testDNSFlood {
509 t.Skip("test disabled; use -dnsflood to enable")
510 }
511
512 defer dnsWaitGroup.Wait()
513
514 var N = 5000
515 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
516
517
518
519
520
521
522
523 N = 500
524 }
525
526 const timeout = 3 * time.Second
527 ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2)
528 defer cancel()
529 ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
530 defer cancel()
531
532 c := make(chan error, 2*N)
533 for i := 0; i < N; i++ {
534 name := fmt.Sprintf("%d.net-test.golang.org", i)
535 go func() {
536 _, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name)
537 c <- err
538 }()
539 go func() {
540 _, err := DefaultResolver.LookupIPAddr(ctxTimeout, name)
541 c <- err
542 }()
543 }
544 qstats := struct {
545 succeeded, failed int
546 timeout, temporary, other int
547 unknown int
548 }{}
549 deadline := time.After(timeout + time.Second)
550 for i := 0; i < 2*N; i++ {
551 select {
552 case <-deadline:
553 t.Fatal("deadline exceeded")
554 case err := <-c:
555 switch err := err.(type) {
556 case nil:
557 qstats.succeeded++
558 case Error:
559 qstats.failed++
560 if err.Timeout() {
561 qstats.timeout++
562 }
563 if err.Temporary() {
564 qstats.temporary++
565 }
566 if !err.Timeout() && !err.Temporary() {
567 qstats.other++
568 }
569 default:
570 qstats.failed++
571 qstats.unknown++
572 }
573 }
574 }
575
576
577
578
579
580
581
582
583 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)
584 }
585
586 func TestLookupDotsWithLocalSource(t *testing.T) {
587 if !supportsIPv4() || !*testIPv4 {
588 t.Skip("IPv4 is required")
589 }
590
591 mustHaveExternalNetwork(t)
592
593 defer dnsWaitGroup.Wait()
594
595 for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
596 fixup := fn()
597 if fixup == nil {
598 continue
599 }
600 names, err := LookupAddr("127.0.0.1")
601 fixup()
602 if err != nil {
603 t.Logf("#%d: %v", i, err)
604 continue
605 }
606 mode := "netgo"
607 if i == 1 {
608 mode = "netcgo"
609 }
610 loop:
611 for i, name := range names {
612 if strings.Index(name, ".") == len(name)-1 {
613 for j := range names {
614 if j == i {
615 continue
616 }
617 if names[j] == name[:len(name)-1] {
618
619
620 continue loop
621 }
622 }
623 t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1])
624 } else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") {
625 t.Errorf("%s: got %s; want name ending with trailing dot", mode, name)
626 }
627 }
628 }
629 }
630
631 func TestLookupDotsWithRemoteSource(t *testing.T) {
632 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
633 testenv.SkipFlaky(t, 27992)
634 }
635 mustHaveExternalNetwork(t)
636
637 if !supportsIPv4() || !*testIPv4 {
638 t.Skip("IPv4 is required")
639 }
640
641 if iOS() {
642 t.Skip("no resolv.conf on iOS")
643 }
644
645 defer dnsWaitGroup.Wait()
646
647 if fixup := forceGoDNS(); fixup != nil {
648 testDots(t, "go")
649 fixup()
650 }
651 if fixup := forceCgoDNS(); fixup != nil {
652 testDots(t, "cgo")
653 fixup()
654 }
655 }
656
657 func testDots(t *testing.T, mode string) {
658 names, err := LookupAddr("8.8.8.8")
659 if err != nil {
660 testenv.SkipFlakyNet(t)
661 t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
662 } else {
663 for _, name := range names {
664 if !hasSuffixFold(name, ".google.com.") && !hasSuffixFold(name, ".google.") {
665 t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
666 break
667 }
668 }
669 }
670
671 cname, err := LookupCNAME("www.mit.edu")
672 if err != nil {
673 testenv.SkipFlakyNet(t)
674 t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err)
675 } else if !strings.HasSuffix(cname, ".") {
676 t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode)
677 }
678
679 mxs, err := LookupMX("google.com")
680 if err != nil {
681 testenv.SkipFlakyNet(t)
682 t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
683 } else {
684 for _, mx := range mxs {
685 if !hasSuffixFold(mx.Host, ".google.com.") {
686 t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
687 break
688 }
689 }
690 }
691
692 nss, err := LookupNS("google.com")
693 if err != nil {
694 testenv.SkipFlakyNet(t)
695 t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
696 } else {
697 for _, ns := range nss {
698 if !hasSuffixFold(ns.Host, ".google.com.") {
699 t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
700 break
701 }
702 }
703 }
704
705 cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
706 if err != nil {
707 testenv.SkipFlakyNet(t)
708 t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
709 } else {
710 if !hasSuffixFold(cname, ".google.com.") {
711 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 }
713 for _, srv := range srvs {
714 if !hasSuffixFold(srv.Target, ".google.com.") {
715 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)
716 break
717 }
718 }
719 }
720 }
721
722 func mxString(mxs []*MX) string {
723 var buf bytes.Buffer
724 sep := ""
725 fmt.Fprintf(&buf, "[")
726 for _, mx := range mxs {
727 fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
728 sep = " "
729 }
730 fmt.Fprintf(&buf, "]")
731 return buf.String()
732 }
733
734 func nsString(nss []*NS) string {
735 var buf bytes.Buffer
736 sep := ""
737 fmt.Fprintf(&buf, "[")
738 for _, ns := range nss {
739 fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
740 sep = " "
741 }
742 fmt.Fprintf(&buf, "]")
743 return buf.String()
744 }
745
746 func srvString(srvs []*SRV) string {
747 var buf bytes.Buffer
748 sep := ""
749 fmt.Fprintf(&buf, "[")
750 for _, srv := range srvs {
751 fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
752 sep = " "
753 }
754 fmt.Fprintf(&buf, "]")
755 return buf.String()
756 }
757
758 func TestLookupPort(t *testing.T) {
759
760
761
762
763
764 type test struct {
765 network string
766 name string
767 port int
768 ok bool
769 }
770 var tests = []test{
771 {"tcp", "0", 0, true},
772 {"udp", "0", 0, true},
773 {"udp", "domain", 53, true},
774
775 {"--badnet--", "zzz", 0, false},
776 {"tcp", "--badport--", 0, false},
777 {"tcp", "-1", 0, false},
778 {"tcp", "65536", 0, false},
779 {"udp", "-1", 0, false},
780 {"udp", "65536", 0, false},
781 {"tcp", "123456789", 0, false},
782
783
784 {"tcp", "", 0, true},
785 {"tcp4", "", 0, true},
786 {"tcp6", "", 0, true},
787 {"udp", "", 0, true},
788 {"udp4", "", 0, true},
789 {"udp6", "", 0, true},
790 }
791
792 switch runtime.GOOS {
793 case "android":
794 if netGo {
795 t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
796 }
797 default:
798 tests = append(tests, test{"tcp", "http", 80, true})
799 }
800
801 for _, tt := range tests {
802 port, err := LookupPort(tt.network, tt.name)
803 if port != tt.port || (err == nil) != tt.ok {
804 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok)
805 }
806 if err != nil {
807 if perr := parseLookupPortError(err); perr != nil {
808 t.Error(perr)
809 }
810 }
811 }
812 }
813
814
815
816 func TestLookupPort_Minimal(t *testing.T) {
817 type test struct {
818 network string
819 name string
820 port int
821 }
822 var tests = []test{
823 {"tcp", "http", 80},
824 {"tcp", "HTTP", 80},
825 {"tcp", "https", 443},
826 {"tcp", "ssh", 22},
827 {"tcp", "gopher", 70},
828 {"tcp4", "http", 80},
829 {"tcp6", "http", 80},
830 }
831
832 for _, tt := range tests {
833 port, err := LookupPort(tt.network, tt.name)
834 if port != tt.port || err != nil {
835 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port)
836 }
837 }
838 }
839
840 func TestLookupProtocol_Minimal(t *testing.T) {
841 type test struct {
842 name string
843 want int
844 }
845 var tests = []test{
846 {"tcp", 6},
847 {"TcP", 6},
848 {"icmp", 1},
849 {"igmp", 2},
850 {"udp", 17},
851 {"ipv6-icmp", 58},
852 }
853
854 for _, tt := range tests {
855 got, err := lookupProtocol(context.Background(), tt.name)
856 if got != tt.want || err != nil {
857 t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
858 }
859 }
860
861 }
862
863 func TestLookupNonLDH(t *testing.T) {
864 defer dnsWaitGroup.Wait()
865
866 if fixup := forceGoDNS(); fixup != nil {
867 defer fixup()
868 }
869
870
871
872
873
874 addrs, err := LookupHost("!!!.###.bogus..domain.")
875 if err == nil {
876 t.Fatalf("lookup succeeded: %v", addrs)
877 }
878 if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) {
879 t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
880 }
881 if !err.(*DNSError).IsNotFound {
882 t.Fatalf("lookup error = %v, want true", err.(*DNSError).IsNotFound)
883 }
884 }
885
886 func TestLookupContextCancel(t *testing.T) {
887 mustHaveExternalNetwork(t)
888 defer dnsWaitGroup.Wait()
889
890 ctx, ctxCancel := context.WithCancel(context.Background())
891 ctxCancel()
892 _, err := DefaultResolver.LookupIPAddr(ctx, "google.com")
893 if err != errCanceled {
894 testenv.SkipFlakyNet(t)
895 t.Fatal(err)
896 }
897 ctx = context.Background()
898 _, err = DefaultResolver.LookupIPAddr(ctx, "google.com")
899 if err != nil {
900 testenv.SkipFlakyNet(t)
901 t.Fatal(err)
902 }
903 }
904
905
906
907 func TestNilResolverLookup(t *testing.T) {
908 mustHaveExternalNetwork(t)
909 var r *Resolver = nil
910 ctx := context.Background()
911
912
913 r.LookupAddr(ctx, "8.8.8.8")
914 r.LookupCNAME(ctx, "google.com")
915 r.LookupHost(ctx, "google.com")
916 r.LookupIPAddr(ctx, "google.com")
917 r.LookupIP(ctx, "ip", "google.com")
918 r.LookupMX(ctx, "gmail.com")
919 r.LookupNS(ctx, "google.com")
920 r.LookupPort(ctx, "tcp", "smtp")
921 r.LookupSRV(ctx, "service", "proto", "name")
922 r.LookupTXT(ctx, "gmail.com")
923 }
924
925
926
927 func TestLookupHostCancel(t *testing.T) {
928 mustHaveExternalNetwork(t)
929 const (
930 google = "www.google.com"
931 invalidDomain = "invalid.invalid"
932 n = 600
933 )
934
935 _, err := LookupHost(google)
936 if err != nil {
937 t.Fatal(err)
938 }
939
940 ctx, cancel := context.WithCancel(context.Background())
941 cancel()
942 for i := 0; i < n; i++ {
943 addr, err := DefaultResolver.LookupHost(ctx, invalidDomain)
944 if err == nil {
945 t.Fatalf("LookupHost(%q): returns %v, but should fail", invalidDomain, addr)
946 }
947 if !strings.Contains(err.Error(), "canceled") {
948 t.Fatalf("LookupHost(%q): failed with unexpected error: %v", invalidDomain, err)
949 }
950 time.Sleep(time.Millisecond * 1)
951 }
952
953 _, err = LookupHost(google)
954 if err != nil {
955 t.Fatal(err)
956 }
957 }
958
959 type lookupCustomResolver struct {
960 *Resolver
961 mu sync.RWMutex
962 dialed bool
963 }
964
965 func (lcr *lookupCustomResolver) dial() func(ctx context.Context, network, address string) (Conn, error) {
966 return func(ctx context.Context, network, address string) (Conn, error) {
967 lcr.mu.Lock()
968 lcr.dialed = true
969 lcr.mu.Unlock()
970 return Dial(network, address)
971 }
972 }
973
974
975
976 func TestConcurrentPreferGoResolversDial(t *testing.T) {
977
978
979 switch runtime.GOOS {
980 case "windows", "plan9":
981 t.Skipf("skip on %v", runtime.GOOS)
982 }
983
984 testenv.MustHaveExternalNetwork(t)
985 testenv.SkipFlakyNet(t)
986
987 defer dnsWaitGroup.Wait()
988
989 resolvers := make([]*lookupCustomResolver, 2)
990 for i := range resolvers {
991 cs := lookupCustomResolver{Resolver: &Resolver{PreferGo: true}}
992 cs.Dial = cs.dial()
993 resolvers[i] = &cs
994 }
995
996 var wg sync.WaitGroup
997 wg.Add(len(resolvers))
998 for i, resolver := range resolvers {
999 go func(r *Resolver, index int) {
1000 defer wg.Done()
1001 _, err := r.LookupIPAddr(context.Background(), "google.com")
1002 if err != nil {
1003 t.Errorf("lookup failed for resolver %d: %q", index, err)
1004 }
1005 }(resolver.Resolver, i)
1006 }
1007 wg.Wait()
1008
1009 if t.Failed() {
1010 t.FailNow()
1011 }
1012
1013 for i, resolver := range resolvers {
1014 if !resolver.dialed {
1015 t.Errorf("custom resolver %d not dialed during lookup", i)
1016 }
1017 }
1018 }
1019
1020 var ipVersionTests = []struct {
1021 network string
1022 version byte
1023 }{
1024 {"tcp", 0},
1025 {"tcp4", '4'},
1026 {"tcp6", '6'},
1027 {"udp", 0},
1028 {"udp4", '4'},
1029 {"udp6", '6'},
1030 {"ip", 0},
1031 {"ip4", '4'},
1032 {"ip6", '6'},
1033 {"ip7", 0},
1034 {"", 0},
1035 }
1036
1037 func TestIPVersion(t *testing.T) {
1038 for _, tt := range ipVersionTests {
1039 if version := ipVersion(tt.network); version != tt.version {
1040 t.Errorf("Family for: %s. Expected: %s, Got: %s", tt.network,
1041 string(tt.version), string(version))
1042 }
1043 }
1044 }
1045
1046
1047
1048 func TestLookupIPAddrPreservesContextValues(t *testing.T) {
1049 origTestHookLookupIP := testHookLookupIP
1050 defer func() { testHookLookupIP = origTestHookLookupIP }()
1051
1052 keyValues := []struct {
1053 key, value interface{}
1054 }{
1055 {"key-1", 12},
1056 {384, "value2"},
1057 {new(float64), 137},
1058 }
1059 ctx := context.Background()
1060 for _, kv := range keyValues {
1061 ctx = context.WithValue(ctx, kv.key, kv.value)
1062 }
1063
1064 wantIPs := []IPAddr{
1065 {IP: IPv4(127, 0, 0, 1)},
1066 {IP: IPv6loopback},
1067 }
1068
1069 checkCtxValues := func(ctx_ context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
1070 for _, kv := range keyValues {
1071 g, w := ctx_.Value(kv.key), kv.value
1072 if !reflect.DeepEqual(g, w) {
1073 t.Errorf("Value lookup:\n\tGot: %v\n\tWant: %v", g, w)
1074 }
1075 }
1076 return wantIPs, nil
1077 }
1078 testHookLookupIP = checkCtxValues
1079
1080 resolvers := []*Resolver{
1081 nil,
1082 new(Resolver),
1083 }
1084
1085 for i, resolver := range resolvers {
1086 gotIPs, err := resolver.LookupIPAddr(ctx, "golang.org")
1087 if err != nil {
1088 t.Errorf("Resolver #%d: unexpected error: %v", i, err)
1089 }
1090 if !reflect.DeepEqual(gotIPs, wantIPs) {
1091 t.Errorf("#%d: mismatched IPAddr results\n\tGot: %v\n\tWant: %v", i, gotIPs, wantIPs)
1092 }
1093 }
1094 }
1095
1096
1097 func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
1098 origTestHookLookupIP := testHookLookupIP
1099 defer func() { testHookLookupIP = origTestHookLookupIP }()
1100
1101 queries := [][]string{
1102 {"udp", "golang.org"},
1103 {"udp4", "golang.org"},
1104 {"udp6", "golang.org"},
1105 {"udp", "golang.org"},
1106 {"udp", "golang.org"},
1107 }
1108 results := map[[2]string][]IPAddr{
1109 {"udp", "golang.org"}: {
1110 {IP: IPv4(127, 0, 0, 1)},
1111 {IP: IPv6loopback},
1112 },
1113 {"udp4", "golang.org"}: {
1114 {IP: IPv4(127, 0, 0, 1)},
1115 },
1116 {"udp6", "golang.org"}: {
1117 {IP: IPv6loopback},
1118 },
1119 }
1120 calls := int32(0)
1121 waitCh := make(chan struct{})
1122 testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
1123
1124
1125
1126 if atomic.AddInt32(&calls, 1) == int32(len(results)) {
1127 close(waitCh)
1128 }
1129 select {
1130 case <-waitCh:
1131 case <-ctx.Done():
1132 return nil, ctx.Err()
1133 }
1134 return results[[2]string{network, host}], nil
1135 }
1136
1137 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
1138 defer cancel()
1139 wg := sync.WaitGroup{}
1140 for _, q := range queries {
1141 network := q[0]
1142 host := q[1]
1143 wg.Add(1)
1144 go func() {
1145 defer wg.Done()
1146 gotIPs, err := DefaultResolver.lookupIPAddr(ctx, network, host)
1147 if err != nil {
1148 t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
1149 }
1150 wantIPs := results[[2]string{network, host}]
1151 if !reflect.DeepEqual(gotIPs, wantIPs) {
1152 t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
1153 }
1154 }()
1155 }
1156 wg.Wait()
1157 }
1158
1159 func TestWithUnexpiredValuesPreserved(t *testing.T) {
1160 ctx, cancel := context.WithCancel(context.Background())
1161
1162
1163 key, value := "key-1", 2
1164 ctx = context.WithValue(ctx, key, value)
1165
1166
1167
1168 ctx = withUnexpiredValuesPreserved(ctx)
1169
1170
1171 if g, w := ctx.Value(key), value; g != w {
1172 t.Errorf("Lookup before expiry: Got %v Want %v", g, w)
1173 }
1174
1175
1176 cancel()
1177
1178
1179 if g := ctx.Value(key); g != nil {
1180 t.Errorf("Lookup after expiry: Got %v want nil", g)
1181 }
1182 }
1183
1184
1185 func TestLookupNullByte(t *testing.T) {
1186 testenv.MustHaveExternalNetwork(t)
1187 testenv.SkipFlakyNet(t)
1188 LookupHost("foo\x00bar")
1189 }
1190
1191 func TestResolverLookupIP(t *testing.T) {
1192 testenv.MustHaveExternalNetwork(t)
1193
1194 v4Ok := supportsIPv4() && *testIPv4
1195 v6Ok := supportsIPv6() && *testIPv6
1196
1197 defer dnsWaitGroup.Wait()
1198
1199 for _, impl := range []struct {
1200 name string
1201 fn func() func()
1202 }{
1203 {"go", forceGoDNS},
1204 {"cgo", forceCgoDNS},
1205 } {
1206 t.Run("implementation: "+impl.name, func(t *testing.T) {
1207 fixup := impl.fn()
1208 if fixup == nil {
1209 t.Skip("not supported")
1210 }
1211 defer fixup()
1212
1213 for _, network := range []string{"ip", "ip4", "ip6"} {
1214 t.Run("network: "+network, func(t *testing.T) {
1215 switch {
1216 case network == "ip4" && !v4Ok:
1217 t.Skip("IPv4 is not supported")
1218 case network == "ip6" && !v6Ok:
1219 t.Skip("IPv6 is not supported")
1220 }
1221
1222
1223 const host = "google.com"
1224 ips, err := DefaultResolver.LookupIP(context.Background(), network, host)
1225 if err != nil {
1226 testenv.SkipFlakyNet(t)
1227 t.Fatalf("DefaultResolver.LookupIP(%q, %q): failed with unexpected error: %v", network, host, err)
1228 }
1229
1230 var v4Addrs []IP
1231 var v6Addrs []IP
1232 for _, ip := range ips {
1233 switch {
1234 case ip.To4() != nil:
1235
1236
1237
1238 v4Addrs = append(v4Addrs, ip)
1239 case ip.To16() != nil:
1240 v6Addrs = append(v6Addrs, ip)
1241 default:
1242 t.Fatalf("IP=%q is neither IPv4 nor IPv6", ip)
1243 }
1244 }
1245
1246
1247 if network == "ip4" || network == "ip" && v4Ok {
1248 if len(v4Addrs) == 0 {
1249 t.Errorf("DefaultResolver.LookupIP(%q, %q): no IPv4 addresses", network, host)
1250 }
1251 }
1252 if network == "ip6" || network == "ip" && v6Ok {
1253 if len(v6Addrs) == 0 {
1254 t.Errorf("DefaultResolver.LookupIP(%q, %q): no IPv6 addresses", network, host)
1255 }
1256 }
1257
1258
1259 if network == "ip6" && len(v4Addrs) > 0 {
1260 t.Errorf("DefaultResolver.LookupIP(%q, %q): unexpected IPv4 addresses: %v", network, host, v4Addrs)
1261 }
1262 if network == "ip4" && len(v6Addrs) > 0 {
1263 t.Errorf("DefaultResolver.LookupIP(%q, %q): unexpected IPv6 addresses: %v", network, host, v6Addrs)
1264 }
1265 })
1266 }
1267 })
1268 }
1269 }
1270
View as plain text