1 // Copyright 2013 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.
25 "golang.org/x/net/dns/dnsmessage"
28 var goResolver = Resolver{PreferGo: true}
30 // Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
31 var TestAddr = [4]byte{0xc0, 0x00, 0x02, 0x01}
33 // Test address from 2001:db8::/32 block, reserved by RFC 3849 for documentation.
34 var TestAddr6 = [16]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
36 func mustNewName(name string) dnsmessage.Name {
37 nn, err := dnsmessage.NewName(name)
39 panic(fmt.Sprint("creating name: ", err))
44 func mustQuestion(name string, qtype dnsmessage.Type, class dnsmessage.Class) dnsmessage.Question {
45 return dnsmessage.Question{
46 Name: mustNewName(name),
52 var dnsTransportFallbackTests = []struct {
54 question dnsmessage.Question
56 rcode dnsmessage.RCode
58 // Querying "com." with qtype=255 usually makes an answer
59 // which requires more than 512 bytes.
60 {"8.8.8.8:53", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), 2, dnsmessage.RCodeSuccess},
61 {"8.8.4.4:53", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), 4, dnsmessage.RCodeSuccess},
64 func TestDNSTransportFallback(t *testing.T) {
65 fake := fakeDNSServer{
66 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
67 r := dnsmessage.Message{
68 Header: dnsmessage.Header{
71 RCode: dnsmessage.RCodeSuccess,
73 Questions: q.Questions,
76 r.Header.Truncated = true
81 r := Resolver{PreferGo: true, Dial: fake.DialContext}
82 for _, tt := range dnsTransportFallbackTests {
83 ctx, cancel := context.WithCancel(context.Background())
85 _, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, useUDPOrTCP, false)
90 if h.RCode != tt.rcode {
91 t.Errorf("got %v from %v; want %v", h.RCode, tt.server, tt.rcode)
97 // See RFC 6761 for further information about the reserved, pseudo
99 var specialDomainNameTests = []struct {
100 question dnsmessage.Question
101 rcode dnsmessage.RCode
103 // Name resolution APIs and libraries should not recognize the
104 // followings as special.
105 {mustQuestion("1.0.168.192.in-addr.arpa.", dnsmessage.TypePTR, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
106 {mustQuestion("test.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
107 {mustQuestion("example.com.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeSuccess},
109 // Name resolution APIs and libraries should recognize the
110 // followings as special and should not send any queries.
111 // Though, we test those names here for verifying negative
112 // answers at DNS query-response interaction level.
113 {mustQuestion("localhost.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
114 {mustQuestion("invalid.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
117 func TestSpecialDomainName(t *testing.T) {
118 fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
119 r := dnsmessage.Message{
120 Header: dnsmessage.Header{
124 Questions: q.Questions,
127 switch q.Questions[0].Name.String() {
129 r.Header.RCode = dnsmessage.RCodeSuccess
131 r.Header.RCode = dnsmessage.RCodeNameError
136 r := Resolver{PreferGo: true, Dial: fake.DialContext}
137 server := "8.8.8.8:53"
138 for _, tt := range specialDomainNameTests {
139 ctx, cancel := context.WithCancel(context.Background())
141 _, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, useUDPOrTCP, false)
146 if h.RCode != tt.rcode {
147 t.Errorf("got %v from %v; want %v", h.RCode, server, tt.rcode)
153 // Issue 13705: don't try to resolve onion addresses, etc
154 func TestAvoidDNSName(t *testing.T) {
162 {"foo.onion.", true},
165 {"foo.ONION.", true},
167 // But do resolve *.local address; Issue 16739
168 {"foo.local.", false},
169 {"foo.local", false},
170 {"foo.LOCAL", false},
171 {"foo.LOCAL.", false},
173 {"", true}, // will be rejected earlier too
175 // Without stuff before onion/local, they're fine to
176 // use DNS. With a search path,
177 // "onion.vegetables.com" can use DNS. Without a
178 // search path (or with a trailing dot), the queries
179 // are just kinda useless, but don't reveal anything
186 for _, tt := range tests {
187 got := avoidDNS(tt.name)
189 t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
194 func TestNameListAvoidDNS(t *testing.T) {
195 c := &dnsConfig{search: []string{"go.dev.", "onion."}}
196 got := c.nameList("www")
197 if !slices.Equal(got, []string{"www.", "www.go.dev."}) {
198 t.Fatalf(`nameList("www") = %v, want "www.", "www.go.dev."`, got)
201 got = c.nameList("www.onion")
202 if !slices.Equal(got, []string{"www.onion.go.dev."}) {
203 t.Fatalf(`nameList("www.onion") = %v, want "www.onion.go.dev."`, got)
207 var fakeDNSServerSuccessful = fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
208 r := dnsmessage.Message{
209 Header: dnsmessage.Header{
213 Questions: q.Questions,
215 if len(q.Questions) == 1 && q.Questions[0].Type == dnsmessage.TypeA {
216 r.Answers = []dnsmessage.Resource{
218 Header: dnsmessage.ResourceHeader{
219 Name: q.Questions[0].Name,
220 Type: dnsmessage.TypeA,
221 Class: dnsmessage.ClassINET,
224 Body: &dnsmessage.AResource{
233 // Issue 13705: don't try to resolve onion addresses, etc
234 func TestLookupTorOnion(t *testing.T) {
235 defer dnsWaitGroup.Wait()
236 r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
237 addrs, err := r.LookupIPAddr(context.Background(), "foo.onion.")
239 t.Fatalf("lookup = %v; want nil", err)
242 t.Errorf("unexpected addresses: %v", addrs)
246 type resolvConfTest struct {
252 func newResolvConfTest() (*resolvConfTest, error) {
253 dir, err := os.MkdirTemp("", "go-resolvconftest")
257 conf := &resolvConfTest{
259 path: path.Join(dir, "resolv.conf"),
260 resolverConfig: &resolvConf,
262 conf.initOnce.Do(conf.init)
266 func (conf *resolvConfTest) write(lines []string) error {
267 f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
271 if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
279 func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
280 return conf.writeAndUpdateWithLastCheckedTime(lines, time.Now().Add(time.Hour))
283 func (conf *resolvConfTest) writeAndUpdateWithLastCheckedTime(lines []string, lastChecked time.Time) error {
284 if err := conf.write(lines); err != nil {
287 return conf.forceUpdate(conf.path, lastChecked)
290 func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
291 dnsConf := dnsReadConfig(name)
292 if !conf.forceUpdateConf(dnsConf, lastChecked) {
293 return fmt.Errorf("tryAcquireSema for %s failed", name)
298 func (conf *resolvConfTest) forceUpdateConf(c *dnsConfig, lastChecked time.Time) bool {
299 conf.dnsConfig.Store(c)
300 for i := 0; i < 5; i++ {
301 if conf.tryAcquireSema() {
302 conf.lastChecked = lastChecked
310 func (conf *resolvConfTest) servers() []string {
311 return conf.dnsConfig.Load().servers
314 func (conf *resolvConfTest) teardown() error {
315 err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
316 os.RemoveAll(conf.dir)
320 var updateResolvConfTests = []struct {
321 name string // query name
322 lines []string // resolver configuration lines
323 servers []string // expected name servers
327 lines: []string{"nameserver 8.8.8.8"},
328 servers: []string{"8.8.8.8:53"},
332 lines: nil, // an empty resolv.conf should use defaultNS as name servers
336 name: "www.example.com",
337 lines: []string{"nameserver 8.8.4.4"},
338 servers: []string{"8.8.4.4:53"},
342 func TestUpdateResolvConf(t *testing.T) {
343 defer dnsWaitGroup.Wait()
345 r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
347 conf, err := newResolvConfTest()
351 defer conf.teardown()
353 for i, tt := range updateResolvConfTests {
354 if err := conf.writeAndUpdate(tt.lines); err != nil {
359 var wg sync.WaitGroup
362 for j := 0; j < N; j++ {
363 go func(name string) {
365 ips, err := r.LookupIPAddr(context.Background(), name)
371 t.Errorf("no records for %s", name)
378 servers := conf.servers()
379 if !reflect.DeepEqual(servers, tt.servers) {
380 t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
386 var goLookupIPWithResolverConfigTests = []struct {
388 lines []string // resolver configuration lines
390 a, aaaa bool // whether response contains A, AAAA-record
392 // no records, transport timeout
394 "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
396 "options timeout:1 attempts:1",
397 "nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
399 &DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
403 // no records, non-existent domain
405 "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
407 "options timeout:3 attempts:1",
408 "nameserver 8.8.8.8",
410 &DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
414 // a few A records, no AAAA records
418 "nameserver 8.8.8.8",
419 "nameserver 2001:4860:4860::8888",
428 "nameserver 2001:4860:4860::8888",
429 "nameserver 8.8.8.8",
437 "search x.golang.org y.golang.org",
438 "nameserver 2001:4860:4860::8888",
439 "nameserver 8.8.8.8",
445 // no A records, a few AAAA records
449 "nameserver 2001:4860:4860::8888",
450 "nameserver 8.8.8.8",
459 "nameserver 8.8.8.8",
460 "nameserver 2001:4860:4860::8888",
468 "search x.golang.org y.golang.org",
469 "nameserver 8.8.8.8",
470 "nameserver 2001:4860:4860::8888",
476 // both A and AAAA records
478 "hostname.as112.net", // see RFC 7534
481 "nameserver 2001:4860:4860::8888",
482 "nameserver 8.8.8.8",
488 "hostname.as112.net", // see RFC 7534
490 "search x.golang.org y.golang.org",
491 "nameserver 2001:4860:4860::8888",
492 "nameserver 8.8.8.8",
499 func TestGoLookupIPWithResolverConfig(t *testing.T) {
500 defer dnsWaitGroup.Wait()
501 fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
503 case "[2001:4860:4860::8888]:53", "8.8.8.8:53":
506 time.Sleep(10 * time.Millisecond)
507 return dnsmessage.Message{}, os.ErrDeadlineExceeded
509 r := dnsmessage.Message{
510 Header: dnsmessage.Header{
514 Questions: q.Questions,
516 for _, question := range q.Questions {
517 switch question.Type {
518 case dnsmessage.TypeA:
519 switch question.Name.String() {
520 case "hostname.as112.net.":
522 case "ipv4.google.com.":
523 r.Answers = append(r.Answers, dnsmessage.Resource{
524 Header: dnsmessage.ResourceHeader{
525 Name: q.Questions[0].Name,
526 Type: dnsmessage.TypeA,
527 Class: dnsmessage.ClassINET,
530 Body: &dnsmessage.AResource{
537 case dnsmessage.TypeAAAA:
538 switch question.Name.String() {
539 case "hostname.as112.net.":
541 case "ipv6.google.com.":
542 r.Answers = append(r.Answers, dnsmessage.Resource{
543 Header: dnsmessage.ResourceHeader{
544 Name: q.Questions[0].Name,
545 Type: dnsmessage.TypeAAAA,
546 Class: dnsmessage.ClassINET,
549 Body: &dnsmessage.AAAAResource{
558 r := Resolver{PreferGo: true, Dial: fake.DialContext}
560 conf, err := newResolvConfTest()
564 defer conf.teardown()
566 for _, tt := range goLookupIPWithResolverConfigTests {
567 if err := conf.writeAndUpdate(tt.lines); err != nil {
571 addrs, err := r.LookupIPAddr(context.Background(), tt.name)
573 if err, ok := err.(*DNSError); !ok || tt.error != nil && (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
574 t.Errorf("got %v; want %v", err, tt.error)
579 t.Errorf("no records for %s", tt.name)
581 if !tt.a && !tt.aaaa && len(addrs) > 0 {
582 t.Errorf("unexpected %v for %s", addrs, tt.name)
584 for _, addr := range addrs {
585 if !tt.a && addr.IP.To4() != nil {
586 t.Errorf("got %v; must not be IPv4 address", addr)
588 if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
589 t.Errorf("got %v; must not be IPv6 address", addr)
595 // Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
596 func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
597 defer dnsWaitGroup.Wait()
599 fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, tm time.Time) (dnsmessage.Message, error) {
600 r := dnsmessage.Message{
601 Header: dnsmessage.Header{
605 Questions: q.Questions,
609 r := Resolver{PreferGo: true, Dial: fake.DialContext}
611 // Add a config that simulates no dns servers being available.
612 conf, err := newResolvConfTest()
616 defer conf.teardown()
618 if err := conf.writeAndUpdate([]string{}); err != nil {
621 // Redirect host file lookups.
622 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
623 hostsFilePath = "testdata/hosts"
625 for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
626 name := fmt.Sprintf("order %v", order)
627 // First ensure that we get an error when contacting a non-existent host.
628 _, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "notarealhost", order, nil)
630 t.Errorf("%s: expected error while looking up name not in hosts file", name)
634 // Now check that we get an address when the name appears in the hosts file.
635 addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "thor", order, nil) // entry is in "testdata/hosts"
637 t.Errorf("%s: expected to successfully lookup host entry", name)
641 t.Errorf("%s: expected exactly one result, but got %v", name, addrs)
644 if got, want := addrs[0].String(), "127.1.1.1"; got != want {
645 t.Errorf("%s: address doesn't match expectation. got %v, want %v", name, got, want)
651 // When using search domains, return the error encountered
652 // querying the original name instead of an error encountered
653 // querying a generated name.
654 func TestErrorForOriginalNameWhenSearching(t *testing.T) {
655 defer dnsWaitGroup.Wait()
657 const fqdn = "doesnotexist.domain"
659 conf, err := newResolvConfTest()
663 defer conf.teardown()
665 if err := conf.writeAndUpdate([]string{"search servfail"}); err != nil {
669 fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
670 r := dnsmessage.Message{
671 Header: dnsmessage.Header{
675 Questions: q.Questions,
678 switch q.Questions[0].Name.String() {
679 case fqdn + ".servfail.":
680 r.Header.RCode = dnsmessage.RCodeServerFailure
682 r.Header.RCode = dnsmessage.RCodeNameError
692 {true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}},
693 {false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error(), IsNotFound: true}},
695 for _, tt := range cases {
696 r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext}
697 _, err = r.LookupIPAddr(context.Background(), fqdn)
699 t.Fatal("expected an error")
703 if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err || err.IsTemporary != want.IsTemporary {
704 t.Errorf("got %v; want %v", err, want)
709 // Issue 15434. If a name server gives a lame referral, continue to the next.
710 func TestIgnoreLameReferrals(t *testing.T) {
711 defer dnsWaitGroup.Wait()
713 conf, err := newResolvConfTest()
717 defer conf.teardown()
719 if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
720 "nameserver 192.0.2.2"}); err != nil {
724 fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
726 r := dnsmessage.Message{
727 Header: dnsmessage.Header{
731 Questions: q.Questions,
734 if s == "192.0.2.2:53" {
735 r.Header.RecursionAvailable = true
736 if q.Questions[0].Type == dnsmessage.TypeA {
737 r.Answers = []dnsmessage.Resource{
739 Header: dnsmessage.ResourceHeader{
740 Name: q.Questions[0].Name,
741 Type: dnsmessage.TypeA,
742 Class: dnsmessage.ClassINET,
745 Body: &dnsmessage.AResource{
755 r := Resolver{PreferGo: true, Dial: fake.DialContext}
757 addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
762 if got := len(addrs); got != 1 {
763 t.Fatalf("got %d addresses, want 1", got)
766 if got, want := addrs[0].String(), "192.0.2.1"; got != want {
767 t.Fatalf("got address %v, want %v", got, want)
771 func BenchmarkGoLookupIP(b *testing.B) {
772 testHookUninstaller.Do(uninstallTestHooks)
773 ctx := context.Background()
776 for i := 0; i < b.N; i++ {
777 goResolver.LookupIPAddr(ctx, "www.example.com")
781 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
782 testHookUninstaller.Do(uninstallTestHooks)
783 ctx := context.Background()
786 for i := 0; i < b.N; i++ {
787 goResolver.LookupIPAddr(ctx, "some.nonexistent")
791 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
792 testHookUninstaller.Do(uninstallTestHooks)
794 conf, err := newResolvConfTest()
798 defer conf.teardown()
801 "nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
802 "nameserver 8.8.8.8",
804 if err := conf.writeAndUpdate(lines); err != nil {
807 ctx := context.Background()
810 for i := 0; i < b.N; i++ {
811 goResolver.LookupIPAddr(ctx, "www.example.com")
815 type fakeDNSServer struct {
816 rh func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error)
820 func (server *fakeDNSServer) DialContext(_ context.Context, n, s string) (Conn, error) {
821 if server.alwaysTCP || n == "tcp" || n == "tcp4" || n == "tcp6" {
822 return &fakeDNSConn{tcp: true, server: server, n: n, s: s}, nil
824 return &fakeDNSPacketConn{fakeDNSConn: fakeDNSConn{tcp: false, server: server, n: n, s: s}}, nil
827 type fakeDNSConn struct {
830 server *fakeDNSServer
838 func (f *fakeDNSConn) Close() error {
842 func (f *fakeDNSConn) Read(b []byte) (int, error) {
849 resp, err := f.server.rh(f.n, f.s, f.q, f.t)
854 bb := make([]byte, 2, 514)
855 bb, err = resp.AppendPack(bb)
857 return 0, fmt.Errorf("cannot marshal DNS message: %v", err)
869 if len(b) < len(bb) {
870 return 0, errors.New("read would fragment DNS message")
877 func (f *fakeDNSConn) Write(b []byte) (int, error) {
878 if f.tcp && len(b) >= 2 {
881 if f.q.Unpack(b) != nil {
882 return 0, fmt.Errorf("cannot unmarshal DNS message fake %s (%d)", f.n, len(b))
887 func (f *fakeDNSConn) SetDeadline(t time.Time) error {
892 type fakeDNSPacketConn struct {
897 func (f *fakeDNSPacketConn) SetDeadline(t time.Time) error {
898 return f.fakeDNSConn.SetDeadline(t)
901 func (f *fakeDNSPacketConn) Close() error {
902 return f.fakeDNSConn.Close()
905 // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
906 func TestIgnoreDNSForgeries(t *testing.T) {
909 b := make([]byte, maxDNSPacketSize)
916 var msg dnsmessage.Message
917 if msg.Unpack(b[:n]) != nil {
918 t.Error("invalid DNS query:", err)
922 s.Write([]byte("garbage DNS response packet"))
924 msg.Header.Response = true
925 msg.Header.ID++ // make invalid ID
927 if b, err = msg.Pack(); err != nil {
928 t.Error("failed to pack DNS response:", err)
933 msg.Header.ID-- // restore original ID
934 msg.Answers = []dnsmessage.Resource{
936 Header: dnsmessage.ResourceHeader{
937 Name: mustNewName("www.example.com."),
938 Type: dnsmessage.TypeA,
939 Class: dnsmessage.ClassINET,
942 Body: &dnsmessage.AResource{
950 t.Error("failed to pack DNS response:", err)
956 msg := dnsmessage.Message{
957 Header: dnsmessage.Header{
960 Questions: []dnsmessage.Question{
962 Name: mustNewName("www.example.com."),
963 Type: dnsmessage.TypeA,
964 Class: dnsmessage.ClassINET,
971 t.Fatal("Pack failed:", err)
974 p, _, err := dnsPacketRoundTrip(c, 42, msg.Questions[0], b)
976 t.Fatalf("dnsPacketRoundTrip failed: %v", err)
980 as, err := p.AllAnswers()
982 t.Fatal("AllAnswers failed:", err)
984 if got := as[0].Body.(*dnsmessage.AResource).A; got != TestAddr {
985 t.Errorf("got address %v, want %v", got, TestAddr)
989 // Issue 16865. If a name server times out, continue to the next.
990 func TestRetryTimeout(t *testing.T) {
991 defer dnsWaitGroup.Wait()
993 conf, err := newResolvConfTest()
997 defer conf.teardown()
999 testConf := []string{
1000 "nameserver 192.0.2.1", // the one that will timeout
1001 "nameserver 192.0.2.2",
1003 if err := conf.writeAndUpdate(testConf); err != nil {
1007 var deadline0 time.Time
1009 fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
1010 t.Log(s, q, deadline)
1012 if deadline.IsZero() {
1013 t.Error("zero deadline")
1016 if s == "192.0.2.1:53" {
1017 deadline0 = deadline
1018 time.Sleep(10 * time.Millisecond)
1019 return dnsmessage.Message{}, os.ErrDeadlineExceeded
1022 if deadline.Equal(deadline0) {
1023 t.Error("deadline didn't change")
1026 return mockTXTResponse(q), nil
1028 r := &Resolver{PreferGo: true, Dial: fake.DialContext}
1030 _, err = r.LookupTXT(context.Background(), "www.golang.org")
1035 if deadline0.IsZero() {
1036 t.Error("deadline0 still zero", deadline0)
1040 func TestRotate(t *testing.T) {
1041 // without rotation, always uses the first server
1042 testRotate(t, false, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.1:53", "192.0.2.1:53"})
1044 // with rotation, rotates through back to first
1045 testRotate(t, true, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.2:53", "192.0.2.1:53"})
1048 func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
1049 defer dnsWaitGroup.Wait()
1051 conf, err := newResolvConfTest()
1055 defer conf.teardown()
1057 var confLines []string
1058 for _, ns := range nameservers {
1059 confLines = append(confLines, "nameserver "+ns)
1062 confLines = append(confLines, "options rotate")
1065 if err := conf.writeAndUpdate(confLines); err != nil {
1069 var usedServers []string
1070 fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
1071 usedServers = append(usedServers, s)
1072 return mockTXTResponse(q), nil
1074 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1076 // len(nameservers) + 1 to allow rotation to get back to start
1077 for i := 0; i < len(nameservers)+1; i++ {
1078 if _, err := r.LookupTXT(context.Background(), "www.golang.org"); err != nil {
1083 if !reflect.DeepEqual(usedServers, wantServers) {
1084 t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
1088 func mockTXTResponse(q dnsmessage.Message) dnsmessage.Message {
1089 r := dnsmessage.Message{
1090 Header: dnsmessage.Header{
1093 RecursionAvailable: true,
1095 Questions: q.Questions,
1096 Answers: []dnsmessage.Resource{
1098 Header: dnsmessage.ResourceHeader{
1099 Name: q.Questions[0].Name,
1100 Type: dnsmessage.TypeTXT,
1101 Class: dnsmessage.ClassINET,
1103 Body: &dnsmessage.TXTResource{
1104 TXT: []string{"ok"},
1113 // Issue 17448. With StrictErrors enabled, temporary errors should make
1114 // LookupIP fail rather than return a partial result.
1115 func TestStrictErrorsLookupIP(t *testing.T) {
1116 defer dnsWaitGroup.Wait()
1118 conf, err := newResolvConfTest()
1122 defer conf.teardown()
1124 confData := []string{
1125 "nameserver 192.0.2.53",
1126 "search x.golang.org y.golang.org",
1128 if err := conf.writeAndUpdate(confData); err != nil {
1132 const name = "test-issue19592"
1133 const server = "192.0.2.53:53"
1134 const searchX = "test-issue19592.x.golang.org."
1135 const searchY = "test-issue19592.y.golang.org."
1136 const ip4 = "192.0.2.1"
1137 const ip6 = "2001:db8::1"
1139 type resolveWhichEnum int
1141 resolveOK resolveWhichEnum = iota
1147 makeTempError := func(err string) error {
1155 makeTimeout := func() error {
1157 Err: os.ErrDeadlineExceeded.Error(),
1163 makeNxDomain := func() error {
1165 Err: errNoSuchHost.Error(),
1174 resolveWhich func(quest dnsmessage.Question) resolveWhichEnum
1181 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1184 wantIPs: []string{ip4, ip6},
1187 desc: "searchX error fails in strict mode",
1188 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1189 if quest.Name.String() == searchX {
1190 return resolveTimeout
1194 wantStrictErr: makeTimeout(),
1195 wantIPs: []string{ip4, ip6},
1198 desc: "searchX IPv4-only timeout fails in strict mode",
1199 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1200 if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeA {
1201 return resolveTimeout
1205 wantStrictErr: makeTimeout(),
1206 wantIPs: []string{ip4, ip6},
1209 desc: "searchX IPv6-only servfail fails in strict mode",
1210 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1211 if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeAAAA {
1212 return resolveServfail
1216 wantStrictErr: makeTempError("server misbehaving"),
1217 wantIPs: []string{ip4, ip6},
1220 desc: "searchY error always fails",
1221 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1222 if quest.Name.String() == searchY {
1223 return resolveTimeout
1227 wantStrictErr: makeTimeout(),
1228 wantLaxErr: makeNxDomain(), // This one reaches the "test." FQDN.
1231 desc: "searchY IPv4-only socket error fails in strict mode",
1232 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1233 if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeA {
1234 return resolveOpError
1238 wantStrictErr: makeTempError("write: socket on fire"),
1239 wantIPs: []string{ip6},
1242 desc: "searchY IPv6-only timeout fails in strict mode",
1243 resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
1244 if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeAAAA {
1245 return resolveTimeout
1249 wantStrictErr: makeTimeout(),
1250 wantIPs: []string{ip4},
1254 for i, tt := range cases {
1255 fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
1258 switch tt.resolveWhich(q.Questions[0]) {
1261 case resolveOpError:
1262 return dnsmessage.Message{}, &OpError{Op: "write", Err: fmt.Errorf("socket on fire")}
1263 case resolveServfail:
1264 return dnsmessage.Message{
1265 Header: dnsmessage.Header{
1268 RCode: dnsmessage.RCodeServerFailure,
1270 Questions: q.Questions,
1272 case resolveTimeout:
1273 return dnsmessage.Message{}, os.ErrDeadlineExceeded
1275 t.Fatal("Impossible resolveWhich")
1278 switch q.Questions[0].Name.String() {
1279 case searchX, name + ".":
1280 // Return NXDOMAIN to utilize the search list.
1281 return dnsmessage.Message{
1282 Header: dnsmessage.Header{
1285 RCode: dnsmessage.RCodeNameError,
1287 Questions: q.Questions,
1290 // Return records below.
1292 return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
1295 r := dnsmessage.Message{
1296 Header: dnsmessage.Header{
1300 Questions: q.Questions,
1302 switch q.Questions[0].Type {
1303 case dnsmessage.TypeA:
1304 r.Answers = []dnsmessage.Resource{
1306 Header: dnsmessage.ResourceHeader{
1307 Name: q.Questions[0].Name,
1308 Type: dnsmessage.TypeA,
1309 Class: dnsmessage.ClassINET,
1312 Body: &dnsmessage.AResource{
1317 case dnsmessage.TypeAAAA:
1318 r.Answers = []dnsmessage.Resource{
1320 Header: dnsmessage.ResourceHeader{
1321 Name: q.Questions[0].Name,
1322 Type: dnsmessage.TypeAAAA,
1323 Class: dnsmessage.ClassINET,
1326 Body: &dnsmessage.AAAAResource{
1332 return dnsmessage.Message{}, fmt.Errorf("Unexpected Type: %v", q.Questions[0].Type)
1337 for _, strict := range []bool{true, false} {
1338 r := Resolver{PreferGo: true, StrictErrors: strict, Dial: fake.DialContext}
1339 ips, err := r.LookupIPAddr(context.Background(), name)
1343 wantErr = tt.wantStrictErr
1345 wantErr = tt.wantLaxErr
1347 if !reflect.DeepEqual(err, wantErr) {
1348 t.Errorf("#%d (%s) strict=%v: got err %#v; want %#v", i, tt.desc, strict, err, wantErr)
1351 gotIPs := map[string]struct{}{}
1352 for _, ip := range ips {
1353 gotIPs[ip.String()] = struct{}{}
1355 wantIPs := map[string]struct{}{}
1357 for _, ip := range tt.wantIPs {
1358 wantIPs[ip] = struct{}{}
1361 if !reflect.DeepEqual(gotIPs, wantIPs) {
1362 t.Errorf("#%d (%s) strict=%v: got ips %v; want %v", i, tt.desc, strict, gotIPs, wantIPs)
1368 // Issue 17448. With StrictErrors enabled, temporary errors should make
1369 // LookupTXT stop walking the search list.
1370 func TestStrictErrorsLookupTXT(t *testing.T) {
1371 defer dnsWaitGroup.Wait()
1373 conf, err := newResolvConfTest()
1377 defer conf.teardown()
1379 confData := []string{
1380 "nameserver 192.0.2.53",
1381 "search x.golang.org y.golang.org",
1383 if err := conf.writeAndUpdate(confData); err != nil {
1388 const server = "192.0.2.53:53"
1389 const searchX = "test.x.golang.org."
1390 const searchY = "test.y.golang.org."
1391 const txt = "Hello World"
1393 fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
1396 switch q.Questions[0].Name.String() {
1398 return dnsmessage.Message{}, os.ErrDeadlineExceeded
1400 return mockTXTResponse(q), nil
1402 return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
1406 for _, strict := range []bool{true, false} {
1407 r := Resolver{StrictErrors: strict, Dial: fake.DialContext}
1408 p, _, err := r.lookup(context.Background(), name, dnsmessage.TypeTXT, nil)
1412 wantErr = &DNSError{
1413 Err: os.ErrDeadlineExceeded.Error(),
1421 if !reflect.DeepEqual(err, wantErr) {
1422 t.Errorf("strict=%v: got err %#v; want %#v", strict, err, wantErr)
1424 a, err := p.AllAnswers()
1428 if len(a) != wantRRs {
1429 t.Errorf("strict=%v: got %v; want %v", strict, len(a), wantRRs)
1434 // Test for a race between uninstalling the test hooks and closing a
1435 // socket connection. This used to fail when testing with -race.
1436 func TestDNSGoroutineRace(t *testing.T) {
1437 defer dnsWaitGroup.Wait()
1439 fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error) {
1440 time.Sleep(10 * time.Microsecond)
1441 return dnsmessage.Message{}, os.ErrDeadlineExceeded
1443 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1445 // The timeout here is less than the timeout used by the server,
1446 // so the goroutine started to query the (fake) server will hang
1447 // around after this test is done if we don't call dnsWaitGroup.Wait.
1448 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Microsecond)
1450 _, err := r.LookupIPAddr(ctx, "where.are.they.now")
1452 t.Fatal("fake DNS lookup unexpectedly succeeded")
1456 func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
1457 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1459 conf := getSystemDNSConfig()
1461 ctx, cancel := context.WithCancel(context.Background())
1464 _, _, err := r.tryOneName(ctx, conf, name, typ)
1468 // Issue 8434: verify that Temporary returns true on an error when rcode
1470 func TestIssue8434(t *testing.T) {
1471 err := lookupWithFake(fakeDNSServer{
1472 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1473 return dnsmessage.Message{
1474 Header: dnsmessage.Header{
1477 RCode: dnsmessage.RCodeServerFailure,
1479 Questions: q.Questions,
1482 }, "golang.org.", dnsmessage.TypeALL)
1484 t.Fatal("expected an error")
1486 if ne, ok := err.(Error); !ok {
1487 t.Fatalf("err = %#v; wanted something supporting net.Error", err)
1488 } else if !ne.Temporary() {
1489 t.Fatalf("Temporary = false for err = %#v; want Temporary == true", err)
1491 if de, ok := err.(*DNSError); !ok {
1492 t.Fatalf("err = %#v; wanted a *net.DNSError", err)
1493 } else if !de.IsTemporary {
1494 t.Fatalf("IsTemporary = false for err = %#v; want IsTemporary == true", err)
1498 func TestIssueNoSuchHostExists(t *testing.T) {
1499 err := lookupWithFake(fakeDNSServer{
1500 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1501 return dnsmessage.Message{
1502 Header: dnsmessage.Header{
1505 RCode: dnsmessage.RCodeNameError,
1507 Questions: q.Questions,
1510 }, "golang.org.", dnsmessage.TypeALL)
1512 t.Fatal("expected an error")
1514 if _, ok := err.(Error); !ok {
1515 t.Fatalf("err = %#v; wanted something supporting net.Error", err)
1517 if de, ok := err.(*DNSError); !ok {
1518 t.Fatalf("err = %#v; wanted a *net.DNSError", err)
1519 } else if !de.IsNotFound {
1520 t.Fatalf("IsNotFound = false for err = %#v; want IsNotFound == true", err)
1524 // TestNoSuchHost verifies that tryOneName works correctly when the domain does
1527 // Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
1528 // and not "server misbehaving"
1530 // Issue 25336: verify that NXDOMAIN errors fail fast.
1532 // Issue 27525: verify that empty answers fail fast.
1533 func TestNoSuchHost(t *testing.T) {
1536 f func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
1540 func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1541 return dnsmessage.Message{
1542 Header: dnsmessage.Header{
1545 RCode: dnsmessage.RCodeNameError,
1546 RecursionAvailable: false,
1548 Questions: q.Questions,
1554 func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1555 return dnsmessage.Message{
1556 Header: dnsmessage.Header{
1559 RCode: dnsmessage.RCodeSuccess,
1560 RecursionAvailable: false,
1561 Authoritative: true,
1563 Questions: q.Questions,
1569 for _, test := range tests {
1570 t.Run(test.name, func(t *testing.T) {
1572 err := lookupWithFake(fakeDNSServer{
1573 rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
1575 return test.f(n, s, q, d)
1577 }, ".", dnsmessage.TypeALL)
1580 t.Errorf("got %d lookups, wanted 1", lookups)
1584 t.Fatal("expected an error")
1586 de, ok := err.(*DNSError)
1588 t.Fatalf("err = %#v; wanted a *net.DNSError", err)
1590 if de.Err != errNoSuchHost.Error() {
1591 t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
1594 t.Fatalf("IsNotFound = %v wanted true", de.IsNotFound)
1600 // Issue 26573: verify that Conns that don't implement PacketConn are treated
1601 // as streams even when udp was requested.
1602 func TestDNSDialTCP(t *testing.T) {
1603 fake := fakeDNSServer{
1604 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1605 r := dnsmessage.Message{
1606 Header: dnsmessage.Header{
1609 RCode: dnsmessage.RCodeSuccess,
1611 Questions: q.Questions,
1617 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1618 ctx := context.Background()
1619 _, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useUDPOrTCP, false)
1621 t.Fatal("exchange failed:", err)
1625 // Issue 27763: verify that two strings in one TXT record are concatenated.
1626 func TestTXTRecordTwoStrings(t *testing.T) {
1627 fake := fakeDNSServer{
1628 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1629 r := dnsmessage.Message{
1630 Header: dnsmessage.Header{
1633 RCode: dnsmessage.RCodeSuccess,
1635 Questions: q.Questions,
1636 Answers: []dnsmessage.Resource{
1638 Header: dnsmessage.ResourceHeader{
1639 Name: q.Questions[0].Name,
1640 Type: dnsmessage.TypeA,
1641 Class: dnsmessage.ClassINET,
1643 Body: &dnsmessage.TXTResource{
1644 TXT: []string{"string1 ", "string2"},
1648 Header: dnsmessage.ResourceHeader{
1649 Name: q.Questions[0].Name,
1650 Type: dnsmessage.TypeA,
1651 Class: dnsmessage.ClassINET,
1653 Body: &dnsmessage.TXTResource{
1654 TXT: []string{"onestring"},
1662 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1663 txt, err := r.lookupTXT(context.Background(), "golang.org")
1665 t.Fatal("LookupTXT failed:", err)
1667 if want := 2; len(txt) != want {
1668 t.Fatalf("len(txt), got %d, want %d", len(txt), want)
1670 if want := "string1 string2"; txt[0] != want {
1671 t.Errorf("txt[0], got %q, want %q", txt[0], want)
1673 if want := "onestring"; txt[1] != want {
1674 t.Errorf("txt[1], got %q, want %q", txt[1], want)
1678 // Issue 29644: support single-request resolv.conf option in pure Go resolver.
1679 // The A and AAAA queries will be sent sequentially, not in parallel.
1680 func TestSingleRequestLookup(t *testing.T) {
1681 defer dnsWaitGroup.Wait()
1687 fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1688 r := dnsmessage.Message{
1689 Header: dnsmessage.Header{
1693 Questions: q.Questions,
1695 for _, question := range q.Questions {
1696 switch question.Type {
1697 case dnsmessage.TypeA:
1698 if question.Name.String() == "slowipv4.example.net." {
1699 time.Sleep(10 * time.Millisecond)
1701 if !atomic.CompareAndSwapInt32(&firstcalled, 0, ipv4) {
1702 t.Errorf("the A query was received after the AAAA query !")
1704 r.Answers = append(r.Answers, dnsmessage.Resource{
1705 Header: dnsmessage.ResourceHeader{
1706 Name: q.Questions[0].Name,
1707 Type: dnsmessage.TypeA,
1708 Class: dnsmessage.ClassINET,
1711 Body: &dnsmessage.AResource{
1715 case dnsmessage.TypeAAAA:
1716 atomic.CompareAndSwapInt32(&firstcalled, 0, ipv6)
1717 r.Answers = append(r.Answers, dnsmessage.Resource{
1718 Header: dnsmessage.ResourceHeader{
1719 Name: q.Questions[0].Name,
1720 Type: dnsmessage.TypeAAAA,
1721 Class: dnsmessage.ClassINET,
1724 Body: &dnsmessage.AAAAResource{
1732 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1734 conf, err := newResolvConfTest()
1738 defer conf.teardown()
1739 if err := conf.writeAndUpdate([]string{"options single-request"}); err != nil {
1742 for _, name := range []string{"hostname.example.net", "slowipv4.example.net"} {
1744 _, err := r.LookupIPAddr(context.Background(), name)
1751 // Issue 29358. Add configuration knob to force TCP-only DNS requests in the pure Go resolver.
1752 func TestDNSUseTCP(t *testing.T) {
1753 fake := fakeDNSServer{
1754 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1755 r := dnsmessage.Message{
1756 Header: dnsmessage.Header{
1759 RCode: dnsmessage.RCodeSuccess,
1761 Questions: q.Questions,
1764 t.Fatal("udp protocol was used instead of tcp")
1769 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1770 ctx, cancel := context.WithCancel(context.Background())
1772 _, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly, false)
1774 t.Fatal("exchange failed:", err)
1778 // Issue 34660: PTR response with non-PTR answers should ignore non-PTR
1779 func TestPTRandNonPTR(t *testing.T) {
1780 fake := fakeDNSServer{
1781 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1782 r := dnsmessage.Message{
1783 Header: dnsmessage.Header{
1786 RCode: dnsmessage.RCodeSuccess,
1788 Questions: q.Questions,
1789 Answers: []dnsmessage.Resource{
1791 Header: dnsmessage.ResourceHeader{
1792 Name: q.Questions[0].Name,
1793 Type: dnsmessage.TypePTR,
1794 Class: dnsmessage.ClassINET,
1796 Body: &dnsmessage.PTRResource{
1797 PTR: dnsmessage.MustNewName("golang.org."),
1801 Header: dnsmessage.ResourceHeader{
1802 Name: q.Questions[0].Name,
1803 Type: dnsmessage.TypeTXT,
1804 Class: dnsmessage.ClassINET,
1806 Body: &dnsmessage.TXTResource{
1807 TXT: []string{"PTR 8 6 60 ..."}, // fake RRSIG
1815 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1816 names, err := r.lookupAddr(context.Background(), "192.0.2.123")
1818 t.Fatalf("LookupAddr: %v", err)
1820 if want := []string{"golang.org."}; !reflect.DeepEqual(names, want) {
1821 t.Errorf("names = %q; want %q", names, want)
1825 func TestCVE202133195(t *testing.T) {
1826 fake := fakeDNSServer{
1827 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
1828 r := dnsmessage.Message{
1829 Header: dnsmessage.Header{
1832 RCode: dnsmessage.RCodeSuccess,
1833 RecursionAvailable: true,
1835 Questions: q.Questions,
1837 switch q.Questions[0].Type {
1838 case dnsmessage.TypeCNAME:
1839 r.Answers = []dnsmessage.Resource{}
1840 case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy
1841 r.Answers = append(r.Answers,
1842 dnsmessage.Resource{
1843 Header: dnsmessage.ResourceHeader{
1844 Name: dnsmessage.MustNewName("<html>.golang.org."),
1845 Type: dnsmessage.TypeA,
1846 Class: dnsmessage.ClassINET,
1849 Body: &dnsmessage.AResource{
1854 case dnsmessage.TypeSRV:
1855 n := q.Questions[0].Name
1856 if n.String() == "_hdr._tcp.golang.org." {
1857 n = dnsmessage.MustNewName("<html>.golang.org.")
1859 r.Answers = append(r.Answers,
1860 dnsmessage.Resource{
1861 Header: dnsmessage.ResourceHeader{
1863 Type: dnsmessage.TypeSRV,
1864 Class: dnsmessage.ClassINET,
1867 Body: &dnsmessage.SRVResource{
1868 Target: dnsmessage.MustNewName("<html>.golang.org."),
1871 dnsmessage.Resource{
1872 Header: dnsmessage.ResourceHeader{
1874 Type: dnsmessage.TypeSRV,
1875 Class: dnsmessage.ClassINET,
1878 Body: &dnsmessage.SRVResource{
1879 Target: dnsmessage.MustNewName("good.golang.org."),
1883 case dnsmessage.TypeMX:
1884 r.Answers = append(r.Answers,
1885 dnsmessage.Resource{
1886 Header: dnsmessage.ResourceHeader{
1887 Name: dnsmessage.MustNewName("<html>.golang.org."),
1888 Type: dnsmessage.TypeMX,
1889 Class: dnsmessage.ClassINET,
1892 Body: &dnsmessage.MXResource{
1893 MX: dnsmessage.MustNewName("<html>.golang.org."),
1896 dnsmessage.Resource{
1897 Header: dnsmessage.ResourceHeader{
1898 Name: dnsmessage.MustNewName("good.golang.org."),
1899 Type: dnsmessage.TypeMX,
1900 Class: dnsmessage.ClassINET,
1903 Body: &dnsmessage.MXResource{
1904 MX: dnsmessage.MustNewName("good.golang.org."),
1908 case dnsmessage.TypeNS:
1909 r.Answers = append(r.Answers,
1910 dnsmessage.Resource{
1911 Header: dnsmessage.ResourceHeader{
1912 Name: dnsmessage.MustNewName("<html>.golang.org."),
1913 Type: dnsmessage.TypeNS,
1914 Class: dnsmessage.ClassINET,
1917 Body: &dnsmessage.NSResource{
1918 NS: dnsmessage.MustNewName("<html>.golang.org."),
1921 dnsmessage.Resource{
1922 Header: dnsmessage.ResourceHeader{
1923 Name: dnsmessage.MustNewName("good.golang.org."),
1924 Type: dnsmessage.TypeNS,
1925 Class: dnsmessage.ClassINET,
1928 Body: &dnsmessage.NSResource{
1929 NS: dnsmessage.MustNewName("good.golang.org."),
1933 case dnsmessage.TypePTR:
1934 r.Answers = append(r.Answers,
1935 dnsmessage.Resource{
1936 Header: dnsmessage.ResourceHeader{
1937 Name: dnsmessage.MustNewName("<html>.golang.org."),
1938 Type: dnsmessage.TypePTR,
1939 Class: dnsmessage.ClassINET,
1942 Body: &dnsmessage.PTRResource{
1943 PTR: dnsmessage.MustNewName("<html>.golang.org."),
1946 dnsmessage.Resource{
1947 Header: dnsmessage.ResourceHeader{
1948 Name: dnsmessage.MustNewName("good.golang.org."),
1949 Type: dnsmessage.TypePTR,
1950 Class: dnsmessage.ClassINET,
1953 Body: &dnsmessage.PTRResource{
1954 PTR: dnsmessage.MustNewName("good.golang.org."),
1963 r := Resolver{PreferGo: true, Dial: fake.DialContext}
1964 // Change the default resolver to match our manipulated resolver
1965 originalDefault := DefaultResolver
1966 DefaultResolver = &r
1967 defer func() { DefaultResolver = originalDefault }()
1968 // Redirect host file lookups.
1969 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
1970 hostsFilePath = "testdata/hosts"
1978 f: func(t *testing.T) {
1979 expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
1980 _, err := r.LookupCNAME(context.Background(), "golang.org")
1981 if err.Error() != expectedErr.Error() {
1982 t.Fatalf("unexpected error: %s", err)
1984 _, err = LookupCNAME("golang.org")
1985 if err.Error() != expectedErr.Error() {
1986 t.Fatalf("unexpected error: %s", err)
1991 name: "SRV (bad record)",
1992 f: func(t *testing.T) {
1995 Target: "good.golang.org.",
1998 expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
1999 _, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
2000 if err.Error() != expectedErr.Error() {
2001 t.Fatalf("unexpected error: %s", err)
2003 if !reflect.DeepEqual(records, expected) {
2004 t.Error("Unexpected record set")
2006 _, records, err = LookupSRV("target", "tcp", "golang.org")
2007 if err.Error() != expectedErr.Error() {
2008 t.Errorf("unexpected error: %s", err)
2010 if !reflect.DeepEqual(records, expected) {
2011 t.Error("Unexpected record set")
2016 name: "SRV (bad header)",
2017 f: func(t *testing.T) {
2018 _, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
2019 if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
2020 t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
2022 _, _, err = LookupSRV("hdr", "tcp", "golang.org.")
2023 if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
2024 t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
2030 f: func(t *testing.T) {
2033 Host: "good.golang.org.",
2036 expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
2037 records, err := r.LookupMX(context.Background(), "golang.org")
2038 if err.Error() != expectedErr.Error() {
2039 t.Fatalf("unexpected error: %s", err)
2041 if !reflect.DeepEqual(records, expected) {
2042 t.Error("Unexpected record set")
2044 records, err = LookupMX("golang.org")
2045 if err.Error() != expectedErr.Error() {
2046 t.Fatalf("unexpected error: %s", err)
2048 if !reflect.DeepEqual(records, expected) {
2049 t.Error("Unexpected record set")
2055 f: func(t *testing.T) {
2058 Host: "good.golang.org.",
2061 expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
2062 records, err := r.LookupNS(context.Background(), "golang.org")
2063 if err.Error() != expectedErr.Error() {
2064 t.Fatalf("unexpected error: %s", err)
2066 if !reflect.DeepEqual(records, expected) {
2067 t.Error("Unexpected record set")
2069 records, err = LookupNS("golang.org")
2070 if err.Error() != expectedErr.Error() {
2071 t.Fatalf("unexpected error: %s", err)
2073 if !reflect.DeepEqual(records, expected) {
2074 t.Error("Unexpected record set")
2080 f: func(t *testing.T) {
2081 expected := []string{"good.golang.org."}
2082 expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
2083 records, err := r.LookupAddr(context.Background(), "192.0.2.42")
2084 if err.Error() != expectedErr.Error() {
2085 t.Fatalf("unexpected error: %s", err)
2087 if !reflect.DeepEqual(records, expected) {
2088 t.Error("Unexpected record set")
2090 records, err = LookupAddr("192.0.2.42")
2091 if err.Error() != expectedErr.Error() {
2092 t.Fatalf("unexpected error: %s", err)
2094 if !reflect.DeepEqual(records, expected) {
2095 t.Error("Unexpected record set")
2101 for _, tc := range tests {
2102 t.Run(tc.name, tc.f)
2107 func TestNullMX(t *testing.T) {
2108 fake := fakeDNSServer{
2109 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2110 r := dnsmessage.Message{
2111 Header: dnsmessage.Header{
2114 RCode: dnsmessage.RCodeSuccess,
2116 Questions: q.Questions,
2117 Answers: []dnsmessage.Resource{
2119 Header: dnsmessage.ResourceHeader{
2120 Name: q.Questions[0].Name,
2121 Type: dnsmessage.TypeMX,
2122 Class: dnsmessage.ClassINET,
2124 Body: &dnsmessage.MXResource{
2125 MX: dnsmessage.MustNewName("."),
2133 r := Resolver{PreferGo: true, Dial: fake.DialContext}
2134 rrset, err := r.LookupMX(context.Background(), "golang.org")
2136 t.Fatalf("LookupMX: %v", err)
2138 if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) {
2139 records := []string{}
2140 for _, rr := range rrset {
2141 records = append(records, fmt.Sprintf("%v", rr))
2143 t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
2147 func TestRootNS(t *testing.T) {
2148 // See https://golang.org/issue/45715.
2149 fake := fakeDNSServer{
2150 rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2151 r := dnsmessage.Message{
2152 Header: dnsmessage.Header{
2155 RCode: dnsmessage.RCodeSuccess,
2157 Questions: q.Questions,
2158 Answers: []dnsmessage.Resource{
2160 Header: dnsmessage.ResourceHeader{
2161 Name: q.Questions[0].Name,
2162 Type: dnsmessage.TypeNS,
2163 Class: dnsmessage.ClassINET,
2165 Body: &dnsmessage.NSResource{
2166 NS: dnsmessage.MustNewName("i.root-servers.net."),
2174 r := Resolver{PreferGo: true, Dial: fake.DialContext}
2175 rrset, err := r.LookupNS(context.Background(), ".")
2177 t.Fatalf("LookupNS: %v", err)
2179 if want := []*NS{&NS{Host: "i.root-servers.net."}}; !reflect.DeepEqual(rrset, want) {
2180 records := []string{}
2181 for _, rr := range rrset {
2182 records = append(records, fmt.Sprintf("%v", rr))
2184 t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
2188 func TestGoLookupIPCNAMEOrderHostsAliasesFilesOnlyMode(t *testing.T) {
2189 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
2190 hostsFilePath = "testdata/aliases"
2191 mode := hostLookupFiles
2193 for _, v := range lookupStaticHostAliasesTest {
2194 testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
2198 func TestGoLookupIPCNAMEOrderHostsAliasesFilesDNSMode(t *testing.T) {
2199 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
2200 hostsFilePath = "testdata/aliases"
2201 mode := hostLookupFilesDNS
2203 for _, v := range lookupStaticHostAliasesTest {
2204 testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
2208 var goLookupIPCNAMEOrderDNSFilesModeTests = []struct {
2212 {"invalid.invalid", "invalid.test"},
2215 func TestGoLookupIPCNAMEOrderHostsAliasesDNSFilesMode(t *testing.T) {
2216 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
2217 hostsFilePath = "testdata/aliases"
2218 mode := hostLookupDNSFiles
2220 for _, v := range goLookupIPCNAMEOrderDNSFilesModeTests {
2221 testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
2225 func testGoLookupIPCNAMEOrderHostsAliases(t *testing.T, mode hostLookupOrder, lookup, lookupRes string) {
2226 fake := fakeDNSServer{
2227 rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2228 var answers []dnsmessage.Resource
2230 if mode != hostLookupDNSFiles {
2231 t.Fatal("received unexpected DNS query")
2234 return dnsmessage.Message{
2235 Header: dnsmessage.Header{
2239 Questions: []dnsmessage.Question{q.Questions[0]},
2245 r := Resolver{PreferGo: true, Dial: fake.DialContext}
2246 ins := []string{lookup, absDomainName(lookup), strings.ToLower(lookup), strings.ToUpper(lookup)}
2247 for _, in := range ins {
2248 _, res, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", in, mode, nil)
2250 t.Errorf("expected err == nil, but got error: %v", err)
2252 if res.String() != lookupRes {
2253 t.Errorf("goLookupIPCNAMEOrder(%v): got %v, want %v", in, res, lookupRes)
2258 // Test that we advertise support for a larger DNS packet size.
2259 // This isn't a great test as it just tests the dnsmessage package
2261 func TestDNSPacketSize(t *testing.T) {
2262 fake := fakeDNSServer{
2263 rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2264 if len(q.Additionals) == 0 {
2265 t.Error("missing EDNS record")
2266 } else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok {
2267 t.Errorf("additional record type %T, expected OPTResource", q.Additionals[0])
2268 } else if len(opt.Options) != 0 {
2269 t.Errorf("found %d Options, expected none", len(opt.Options))
2271 got := int(q.Additionals[0].Header.Class)
2272 t.Logf("EDNS packet size == %d", got)
2273 if got != maxDNSPacketSize {
2274 t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize)
2278 // Hand back a dummy answer to verify that
2279 // LookupIPAddr completes.
2280 r := dnsmessage.Message{
2281 Header: dnsmessage.Header{
2284 RCode: dnsmessage.RCodeSuccess,
2286 Questions: q.Questions,
2288 if q.Questions[0].Type == dnsmessage.TypeA {
2289 r.Answers = []dnsmessage.Resource{
2291 Header: dnsmessage.ResourceHeader{
2292 Name: q.Questions[0].Name,
2293 Type: dnsmessage.TypeA,
2294 Class: dnsmessage.ClassINET,
2297 Body: &dnsmessage.AResource{
2307 r := &Resolver{PreferGo: true, Dial: fake.DialContext}
2308 if _, err := r.LookupIPAddr(context.Background(), "go.dev"); err != nil {
2309 t.Errorf("lookup failed: %v", err)
2313 func TestLongDNSNames(t *testing.T) {
2314 const longDNSsuffix = ".go.dev."
2315 const longDNSsuffixNoEndingDot = ".go.dev"
2317 var longDNSPrefix = strings.Repeat("verylongdomainlabel.", 20)
2319 var longDNSNamesTests = []struct {
2323 {req: longDNSPrefix[:255-len(longDNSsuffix)] + longDNSsuffix, fail: true},
2324 {req: longDNSPrefix[:254-len(longDNSsuffix)] + longDNSsuffix},
2325 {req: longDNSPrefix[:253-len(longDNSsuffix)] + longDNSsuffix},
2327 {req: longDNSPrefix[:253-len(longDNSsuffixNoEndingDot)] + longDNSsuffixNoEndingDot},
2328 {req: longDNSPrefix[:254-len(longDNSsuffixNoEndingDot)] + longDNSsuffixNoEndingDot, fail: true},
2331 fake := fakeDNSServer{
2332 rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2333 r := dnsmessage.Message{
2334 Header: dnsmessage.Header{
2337 RCode: dnsmessage.RCodeSuccess,
2339 Questions: q.Questions,
2340 Answers: []dnsmessage.Resource{
2342 Header: dnsmessage.ResourceHeader{
2343 Name: q.Questions[0].Name,
2344 Type: q.Questions[0].Type,
2345 Class: dnsmessage.ClassINET,
2351 switch q.Questions[0].Type {
2352 case dnsmessage.TypeA:
2353 r.Answers[0].Body = &dnsmessage.AResource{A: TestAddr}
2354 case dnsmessage.TypeAAAA:
2355 r.Answers[0].Body = &dnsmessage.AAAAResource{AAAA: TestAddr6}
2356 case dnsmessage.TypeTXT:
2357 r.Answers[0].Body = &dnsmessage.TXTResource{TXT: []string{"."}}
2358 case dnsmessage.TypeMX:
2359 r.Answers[0].Body = &dnsmessage.MXResource{
2360 MX: dnsmessage.MustNewName("go.dev."),
2362 case dnsmessage.TypeNS:
2363 r.Answers[0].Body = &dnsmessage.NSResource{
2364 NS: dnsmessage.MustNewName("go.dev."),
2366 case dnsmessage.TypeSRV:
2367 r.Answers[0].Body = &dnsmessage.SRVResource{
2368 Target: dnsmessage.MustNewName("go.dev."),
2370 case dnsmessage.TypeCNAME:
2371 r.Answers[0].Body = &dnsmessage.CNAMEResource{
2372 CNAME: dnsmessage.MustNewName("fake.cname."),
2375 panic("unknown dnsmessage type")
2382 r := &Resolver{PreferGo: true, Dial: fake.DialContext}
2384 methodTests := []string{"CNAME", "Host", "IP", "IPAddr", "MX", "NS", "NetIP", "SRV", "TXT"}
2385 query := func(t string, req string) error {
2388 _, err := r.LookupCNAME(context.Background(), req)
2391 _, err := r.LookupHost(context.Background(), req)
2394 _, err := r.LookupIP(context.Background(), "ip", req)
2397 _, err := r.LookupIPAddr(context.Background(), req)
2400 _, err := r.LookupMX(context.Background(), req)
2403 _, err := r.LookupNS(context.Background(), req)
2406 _, err := r.LookupNetIP(context.Background(), "ip", req)
2409 const service = "service"
2410 const proto = "proto"
2411 req = req[len(service)+len(proto)+4:]
2412 _, _, err := r.LookupSRV(context.Background(), service, proto, req)
2415 _, err := r.LookupTXT(context.Background(), req)
2418 panic("unknown query method")
2421 for i, v := range longDNSNamesTests {
2422 for _, testName := range methodTests {
2423 err := query(testName, v.req)
2426 t.Errorf("%v: Lookup%v: unexpected success", i, testName)
2430 expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: v.req, IsNotFound: true}
2431 var dnsErr *DNSError
2432 errors.As(err, &dnsErr)
2433 if dnsErr == nil || *dnsErr != expectedErr {
2434 t.Errorf("%v: Lookup%v: unexpected error: %v", i, testName, err)
2439 t.Errorf("%v: Lookup%v: unexpected error: %v", i, testName, err)
2445 func TestDNSTrustAD(t *testing.T) {
2446 fake := fakeDNSServer{
2447 rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2448 if q.Questions[0].Name.String() == "notrustad.go.dev." && q.Header.AuthenticData {
2449 t.Error("unexpected AD bit")
2452 if q.Questions[0].Name.String() == "trustad.go.dev." && !q.Header.AuthenticData {
2453 t.Error("expected AD bit")
2456 r := dnsmessage.Message{
2457 Header: dnsmessage.Header{
2460 RCode: dnsmessage.RCodeSuccess,
2462 Questions: q.Questions,
2464 if q.Questions[0].Type == dnsmessage.TypeA {
2465 r.Answers = []dnsmessage.Resource{
2467 Header: dnsmessage.ResourceHeader{
2468 Name: q.Questions[0].Name,
2469 Type: dnsmessage.TypeA,
2470 Class: dnsmessage.ClassINET,
2473 Body: &dnsmessage.AResource{
2483 r := &Resolver{PreferGo: true, Dial: fake.DialContext}
2485 conf, err := newResolvConfTest()
2489 defer conf.teardown()
2491 err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1"})
2496 if _, err := r.LookupIPAddr(context.Background(), "notrustad.go.dev"); err != nil {
2497 t.Errorf("lookup failed: %v", err)
2500 err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1", "options trust-ad"})
2505 if _, err := r.LookupIPAddr(context.Background(), "trustad.go.dev"); err != nil {
2506 t.Errorf("lookup failed: %v", err)
2510 func TestDNSConfigNoReload(t *testing.T) {
2511 r := &Resolver{PreferGo: true, Dial: func(ctx context.Context, network, address string) (Conn, error) {
2512 if address != "192.0.2.1:53" {
2513 return nil, errors.New("configuration unexpectedly changed")
2515 return fakeDNSServerSuccessful.DialContext(ctx, network, address)
2518 conf, err := newResolvConfTest()
2522 defer conf.teardown()
2524 err = conf.writeAndUpdateWithLastCheckedTime([]string{"nameserver 192.0.2.1", "options no-reload"}, time.Now().Add(-time.Hour))
2529 if _, err = r.LookupHost(context.Background(), "go.dev"); err != nil {
2533 err = conf.write([]string{"nameserver 192.0.2.200"})
2538 if _, err = r.LookupHost(context.Background(), "go.dev"); err != nil {
2543 func TestLookupOrderFilesNoSuchHost(t *testing.T) {
2544 defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
2545 if runtime.GOOS != "openbsd" {
2546 defer setSystemNSS(getSystemNSS(), 0)
2547 setSystemNSS(nssStr(t, "hosts: files"), time.Hour)
2550 conf, err := newResolvConfTest()
2554 defer conf.teardown()
2556 resolvConf := dnsConfig{servers: defaultNS}
2557 if runtime.GOOS == "openbsd" {
2558 // Set error to ErrNotExist, so that the hostLookupOrder
2559 // returns hostLookupFiles for openbsd.
2560 resolvConf.err = os.ErrNotExist
2563 if !conf.forceUpdateConf(&resolvConf, time.Now().Add(time.Hour)) {
2564 t.Fatal("failed to update resolv config")
2567 tmpFile := filepath.Join(t.TempDir(), "hosts")
2568 if err := os.WriteFile(tmpFile, []byte{}, 0660); err != nil {
2571 hostsFilePath = tmpFile
2573 const testName = "test.invalid"
2575 order, _ := systemConf().hostLookupOrder(DefaultResolver, testName)
2576 if order != hostLookupFiles {
2577 // skip test for systems which do not return hostLookupFiles
2578 t.Skipf("hostLookupOrder did not return hostLookupFiles")
2581 var lookupTests = []struct {
2583 lookup func(name string) error
2587 lookup: func(name string) error {
2588 _, err = DefaultResolver.LookupHost(context.Background(), name)
2594 lookup: func(name string) error {
2595 _, err = DefaultResolver.LookupIP(context.Background(), "ip", name)
2601 lookup: func(name string) error {
2602 _, err = DefaultResolver.LookupIPAddr(context.Background(), name)
2608 lookup: func(name string) error {
2609 _, err = DefaultResolver.LookupNetIP(context.Background(), "ip", name)
2615 for _, v := range lookupTests {
2616 err := v.lookup(testName)
2619 t.Errorf("Lookup%v: unexpected success", v.name)
2623 expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: testName, IsNotFound: true}
2624 var dnsErr *DNSError
2625 errors.As(err, &dnsErr)
2626 if dnsErr == nil || *dnsErr != expectedErr {
2627 t.Errorf("Lookup%v: unexpected error: %v", v.name, err)
2632 func TestExtendedRCode(t *testing.T) {
2633 fake := fakeDNSServer{
2634 rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
2635 fraudSuccessCode := dnsmessage.RCodeSuccess | 1<<10
2637 var edns0Hdr dnsmessage.ResourceHeader
2638 edns0Hdr.SetEDNS0(maxDNSPacketSize, fraudSuccessCode, false)
2640 return dnsmessage.Message{
2641 Header: dnsmessage.Header{
2644 RCode: fraudSuccessCode,
2646 Questions: []dnsmessage.Question{q.Questions[0]},
2647 Additionals: []dnsmessage.Resource{{
2649 Body: &dnsmessage.OPTResource{},
2655 r := &Resolver{PreferGo: true, Dial: fake.DialContext}
2656 _, _, err := r.tryOneName(context.Background(), getSystemDNSConfig(), "go.dev.", dnsmessage.TypeA)
2657 var dnsErr *DNSError
2658 if !(errors.As(err, &dnsErr) && dnsErr.Err == errServerMisbehaving.Error()) {
2659 t.Fatalf("r.tryOneName(): unexpected error: %v", err)