Source file src/net/dnsclient_unix_test.go

     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.
     4  
     5  //go:build unix
     6  
     7  package net
     8  
     9  import (
    10  	"context"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"path"
    15  	"path/filepath"
    16  	"reflect"
    17  	"runtime"
    18  	"slices"
    19  	"strings"
    20  	"sync"
    21  	"sync/atomic"
    22  	"testing"
    23  	"time"
    24  
    25  	"golang.org/x/net/dns/dnsmessage"
    26  )
    27  
    28  // Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
    29  var TestAddr = [4]byte{0xc0, 0x00, 0x02, 0x01}
    30  
    31  // Test address from 2001:db8::/32 block, reserved by RFC 3849 for documentation.
    32  var TestAddr6 = [16]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
    33  
    34  func mustNewName(name string) dnsmessage.Name {
    35  	nn, err := dnsmessage.NewName(name)
    36  	if err != nil {
    37  		panic(fmt.Sprint("creating name: ", err))
    38  	}
    39  	return nn
    40  }
    41  
    42  func mustQuestion(name string, qtype dnsmessage.Type, class dnsmessage.Class) dnsmessage.Question {
    43  	return dnsmessage.Question{
    44  		Name:  mustNewName(name),
    45  		Type:  qtype,
    46  		Class: class,
    47  	}
    48  }
    49  
    50  var dnsTransportFallbackTests = []struct {
    51  	server   string
    52  	question dnsmessage.Question
    53  	timeout  int
    54  	rcode    dnsmessage.RCode
    55  }{
    56  	// Querying "com." with qtype=255 usually makes an answer
    57  	// which requires more than 512 bytes.
    58  	{"8.8.8.8:53", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), 2, dnsmessage.RCodeSuccess},
    59  	{"8.8.4.4:53", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), 4, dnsmessage.RCodeSuccess},
    60  }
    61  
    62  func TestDNSTransportFallback(t *testing.T) {
    63  	fake := fakeDNSServer{
    64  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
    65  			r := dnsmessage.Message{
    66  				Header: dnsmessage.Header{
    67  					ID:       q.Header.ID,
    68  					Response: true,
    69  					RCode:    dnsmessage.RCodeSuccess,
    70  				},
    71  				Questions: q.Questions,
    72  			}
    73  			if n == "udp" {
    74  				r.Header.Truncated = true
    75  			}
    76  			return r, nil
    77  		},
    78  	}
    79  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
    80  	for _, tt := range dnsTransportFallbackTests {
    81  		ctx, cancel := context.WithCancel(context.Background())
    82  		defer cancel()
    83  		_, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, useUDPOrTCP, false)
    84  		if err != nil {
    85  			t.Error(err)
    86  			continue
    87  		}
    88  		if h.RCode != tt.rcode {
    89  			t.Errorf("got %v from %v; want %v", h.RCode, tt.server, tt.rcode)
    90  			continue
    91  		}
    92  	}
    93  }
    94  
    95  func TestDNSTransportNoFallbackOnTCP(t *testing.T) {
    96  	fake := fakeDNSServer{
    97  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
    98  			r := dnsmessage.Message{
    99  				Header: dnsmessage.Header{
   100  					ID:        q.Header.ID,
   101  					Response:  true,
   102  					RCode:     dnsmessage.RCodeSuccess,
   103  					Truncated: true,
   104  				},
   105  				Questions: q.Questions,
   106  			}
   107  			if n == "tcp" {
   108  				r.Answers = []dnsmessage.Resource{
   109  					{
   110  						Header: dnsmessage.ResourceHeader{
   111  							Name:   q.Questions[0].Name,
   112  							Type:   dnsmessage.TypeA,
   113  							Class:  dnsmessage.ClassINET,
   114  							Length: 4,
   115  						},
   116  						Body: &dnsmessage.AResource{
   117  							A: TestAddr,
   118  						},
   119  					},
   120  				}
   121  			}
   122  			return r, nil
   123  		},
   124  	}
   125  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
   126  	for _, tt := range dnsTransportFallbackTests {
   127  		ctx, cancel := context.WithCancel(context.Background())
   128  		defer cancel()
   129  		p, h, err := r.exchange(ctx, tt.server, tt.question, time.Second, useUDPOrTCP, false)
   130  		if err != nil {
   131  			t.Error(err)
   132  			continue
   133  		}
   134  		if h.RCode != tt.rcode {
   135  			t.Errorf("got %v from %v; want %v", h.RCode, tt.server, tt.rcode)
   136  			continue
   137  		}
   138  		a, err := p.AllAnswers()
   139  		if err != nil {
   140  			t.Errorf("unexpected error %v getting all answers from %v", err, tt.server)
   141  			continue
   142  		}
   143  		if len(a) != 1 {
   144  			t.Errorf("got %d answers from %v; want 1", len(a), tt.server)
   145  			continue
   146  		}
   147  	}
   148  }
   149  
   150  // See RFC 6761 for further information about the reserved, pseudo
   151  // domain names.
   152  var specialDomainNameTests = []struct {
   153  	question dnsmessage.Question
   154  	rcode    dnsmessage.RCode
   155  }{
   156  	// Name resolution APIs and libraries should not recognize the
   157  	// followings as special.
   158  	{mustQuestion("1.0.168.192.in-addr.arpa.", dnsmessage.TypePTR, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
   159  	{mustQuestion("test.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
   160  	{mustQuestion("example.com.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeSuccess},
   161  
   162  	// Name resolution APIs and libraries should recognize the
   163  	// followings as special and should not send any queries.
   164  	// Though, we test those names here for verifying negative
   165  	// answers at DNS query-response interaction level.
   166  	{mustQuestion("localhost.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
   167  	{mustQuestion("invalid.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
   168  }
   169  
   170  func TestSpecialDomainName(t *testing.T) {
   171  	fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
   172  		r := dnsmessage.Message{
   173  			Header: dnsmessage.Header{
   174  				ID:       q.ID,
   175  				Response: true,
   176  			},
   177  			Questions: q.Questions,
   178  		}
   179  
   180  		switch q.Questions[0].Name.String() {
   181  		case "example.com.":
   182  			r.Header.RCode = dnsmessage.RCodeSuccess
   183  		default:
   184  			r.Header.RCode = dnsmessage.RCodeNameError
   185  		}
   186  
   187  		return r, nil
   188  	}}
   189  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
   190  	server := "8.8.8.8:53"
   191  	for _, tt := range specialDomainNameTests {
   192  		ctx, cancel := context.WithCancel(context.Background())
   193  		defer cancel()
   194  		_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, useUDPOrTCP, false)
   195  		if err != nil {
   196  			t.Error(err)
   197  			continue
   198  		}
   199  		if h.RCode != tt.rcode {
   200  			t.Errorf("got %v from %v; want %v", h.RCode, server, tt.rcode)
   201  			continue
   202  		}
   203  	}
   204  }
   205  
   206  // Issue 13705: don't try to resolve onion addresses, etc
   207  func TestAvoidDNSName(t *testing.T) {
   208  	tests := []struct {
   209  		name  string
   210  		avoid bool
   211  	}{
   212  		{"foo.com", false},
   213  		{"foo.com.", false},
   214  
   215  		{"foo.onion.", true},
   216  		{"foo.onion", true},
   217  		{"foo.ONION", true},
   218  		{"foo.ONION.", true},
   219  
   220  		// But do resolve *.local address; Issue 16739
   221  		{"foo.local.", false},
   222  		{"foo.local", false},
   223  		{"foo.LOCAL", false},
   224  		{"foo.LOCAL.", false},
   225  
   226  		{"", true}, // will be rejected earlier too
   227  
   228  		// Without stuff before onion/local, they're fine to
   229  		// use DNS. With a search path,
   230  		// "onion.vegetables.com" can use DNS. Without a
   231  		// search path (or with a trailing dot), the queries
   232  		// are just kinda useless, but don't reveal anything
   233  		// private.
   234  		{"local", false},
   235  		{"onion", false},
   236  		{"local.", false},
   237  		{"onion.", false},
   238  	}
   239  	for _, tt := range tests {
   240  		got := avoidDNS(tt.name)
   241  		if got != tt.avoid {
   242  			t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
   243  		}
   244  	}
   245  }
   246  
   247  func TestNameListAvoidDNS(t *testing.T) {
   248  	c := &dnsConfig{search: []string{"go.dev.", "onion."}}
   249  	got := c.nameList("www")
   250  	if !slices.Equal(got, []string{"www.", "www.go.dev."}) {
   251  		t.Fatalf(`nameList("www") = %v, want "www.", "www.go.dev."`, got)
   252  	}
   253  
   254  	got = c.nameList("www.onion")
   255  	if !slices.Equal(got, []string{"www.onion.go.dev."}) {
   256  		t.Fatalf(`nameList("www.onion") = %v, want "www.onion.go.dev."`, got)
   257  	}
   258  }
   259  
   260  var fakeDNSServerSuccessful = fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
   261  	r := dnsmessage.Message{
   262  		Header: dnsmessage.Header{
   263  			ID:       q.ID,
   264  			Response: true,
   265  		},
   266  		Questions: q.Questions,
   267  	}
   268  	if len(q.Questions) == 1 && q.Questions[0].Type == dnsmessage.TypeA {
   269  		r.Answers = []dnsmessage.Resource{
   270  			{
   271  				Header: dnsmessage.ResourceHeader{
   272  					Name:   q.Questions[0].Name,
   273  					Type:   dnsmessage.TypeA,
   274  					Class:  dnsmessage.ClassINET,
   275  					Length: 4,
   276  				},
   277  				Body: &dnsmessage.AResource{
   278  					A: TestAddr,
   279  				},
   280  			},
   281  		}
   282  	}
   283  	return r, nil
   284  }}
   285  
   286  // Issue 13705: don't try to resolve onion addresses, etc
   287  func TestLookupTorOnion(t *testing.T) {
   288  	defer dnsWaitGroup.Wait()
   289  	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
   290  	addrs, err := r.LookupIPAddr(context.Background(), "foo.onion.")
   291  	if err != nil {
   292  		t.Fatalf("lookup = %v; want nil", err)
   293  	}
   294  	if len(addrs) > 0 {
   295  		t.Errorf("unexpected addresses: %v", addrs)
   296  	}
   297  }
   298  
   299  type resolvConfTest struct {
   300  	dir  string
   301  	path string
   302  	*resolverConfig
   303  }
   304  
   305  func newResolvConfTest() (*resolvConfTest, error) {
   306  	dir, err := os.MkdirTemp("", "go-resolvconftest")
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  	conf := &resolvConfTest{
   311  		dir:            dir,
   312  		path:           path.Join(dir, "resolv.conf"),
   313  		resolverConfig: &resolvConf,
   314  	}
   315  	conf.initOnce.Do(conf.init)
   316  	return conf, nil
   317  }
   318  
   319  func (conf *resolvConfTest) write(lines []string) error {
   320  	f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
   325  		f.Close()
   326  		return err
   327  	}
   328  	f.Close()
   329  	return nil
   330  }
   331  
   332  func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
   333  	return conf.writeAndUpdateWithLastCheckedTime(lines, time.Now().Add(time.Hour))
   334  }
   335  
   336  func (conf *resolvConfTest) writeAndUpdateWithLastCheckedTime(lines []string, lastChecked time.Time) error {
   337  	if err := conf.write(lines); err != nil {
   338  		return err
   339  	}
   340  	return conf.forceUpdate(conf.path, lastChecked)
   341  }
   342  
   343  func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
   344  	dnsConf := dnsReadConfig(name)
   345  	if !conf.forceUpdateConf(dnsConf, lastChecked) {
   346  		return fmt.Errorf("tryAcquireSema for %s failed", name)
   347  	}
   348  	return nil
   349  }
   350  
   351  func (conf *resolvConfTest) forceUpdateConf(c *dnsConfig, lastChecked time.Time) bool {
   352  	conf.dnsConfig.Store(c)
   353  	for i := 0; i < 5; i++ {
   354  		if conf.tryAcquireSema() {
   355  			conf.lastChecked = lastChecked
   356  			conf.releaseSema()
   357  			return true
   358  		}
   359  	}
   360  	return false
   361  }
   362  
   363  func (conf *resolvConfTest) servers() []string {
   364  	return conf.dnsConfig.Load().servers
   365  }
   366  
   367  func (conf *resolvConfTest) teardown() error {
   368  	err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
   369  	os.RemoveAll(conf.dir)
   370  	return err
   371  }
   372  
   373  var updateResolvConfTests = []struct {
   374  	name    string   // query name
   375  	lines   []string // resolver configuration lines
   376  	servers []string // expected name servers
   377  }{
   378  	{
   379  		name:    "golang.org",
   380  		lines:   []string{"nameserver 8.8.8.8"},
   381  		servers: []string{"8.8.8.8:53"},
   382  	},
   383  	{
   384  		name:    "",
   385  		lines:   nil, // an empty resolv.conf should use defaultNS as name servers
   386  		servers: defaultNS,
   387  	},
   388  	{
   389  		name:    "www.example.com",
   390  		lines:   []string{"nameserver 8.8.4.4"},
   391  		servers: []string{"8.8.4.4:53"},
   392  	},
   393  }
   394  
   395  func TestUpdateResolvConf(t *testing.T) {
   396  	defer dnsWaitGroup.Wait()
   397  
   398  	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
   399  
   400  	conf, err := newResolvConfTest()
   401  	if err != nil {
   402  		t.Fatal(err)
   403  	}
   404  	defer conf.teardown()
   405  
   406  	for i, tt := range updateResolvConfTests {
   407  		if err := conf.writeAndUpdate(tt.lines); err != nil {
   408  			t.Error(err)
   409  			continue
   410  		}
   411  		if tt.name != "" {
   412  			var wg sync.WaitGroup
   413  			const N = 10
   414  			wg.Add(N)
   415  			for j := 0; j < N; j++ {
   416  				go func(name string) {
   417  					defer wg.Done()
   418  					ips, err := r.LookupIPAddr(context.Background(), name)
   419  					if err != nil {
   420  						t.Error(err)
   421  						return
   422  					}
   423  					if len(ips) == 0 {
   424  						t.Errorf("no records for %s", name)
   425  						return
   426  					}
   427  				}(tt.name)
   428  			}
   429  			wg.Wait()
   430  		}
   431  		servers := conf.servers()
   432  		if !reflect.DeepEqual(servers, tt.servers) {
   433  			t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
   434  			continue
   435  		}
   436  	}
   437  }
   438  
   439  var goLookupIPWithResolverConfigTests = []struct {
   440  	name  string
   441  	lines []string // resolver configuration lines
   442  	error
   443  	a, aaaa bool // whether response contains A, AAAA-record
   444  }{
   445  	// no records, transport timeout
   446  	{
   447  		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
   448  		[]string{
   449  			"options timeout:1 attempts:1",
   450  			"nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
   451  		},
   452  		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
   453  		false, false,
   454  	},
   455  
   456  	// no records, non-existent domain
   457  	{
   458  		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
   459  		[]string{
   460  			"options timeout:3 attempts:1",
   461  			"nameserver 8.8.8.8",
   462  		},
   463  		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
   464  		false, false,
   465  	},
   466  
   467  	// a few A records, no AAAA records
   468  	{
   469  		"ipv4.google.com.",
   470  		[]string{
   471  			"nameserver 8.8.8.8",
   472  			"nameserver 2001:4860:4860::8888",
   473  		},
   474  		nil,
   475  		true, false,
   476  	},
   477  	{
   478  		"ipv4.google.com",
   479  		[]string{
   480  			"domain golang.org",
   481  			"nameserver 2001:4860:4860::8888",
   482  			"nameserver 8.8.8.8",
   483  		},
   484  		nil,
   485  		true, false,
   486  	},
   487  	{
   488  		"ipv4.google.com",
   489  		[]string{
   490  			"search x.golang.org y.golang.org",
   491  			"nameserver 2001:4860:4860::8888",
   492  			"nameserver 8.8.8.8",
   493  		},
   494  		nil,
   495  		true, false,
   496  	},
   497  
   498  	// no A records, a few AAAA records
   499  	{
   500  		"ipv6.google.com.",
   501  		[]string{
   502  			"nameserver 2001:4860:4860::8888",
   503  			"nameserver 8.8.8.8",
   504  		},
   505  		nil,
   506  		false, true,
   507  	},
   508  	{
   509  		"ipv6.google.com",
   510  		[]string{
   511  			"domain golang.org",
   512  			"nameserver 8.8.8.8",
   513  			"nameserver 2001:4860:4860::8888",
   514  		},
   515  		nil,
   516  		false, true,
   517  	},
   518  	{
   519  		"ipv6.google.com",
   520  		[]string{
   521  			"search x.golang.org y.golang.org",
   522  			"nameserver 8.8.8.8",
   523  			"nameserver 2001:4860:4860::8888",
   524  		},
   525  		nil,
   526  		false, true,
   527  	},
   528  
   529  	// both A and AAAA records
   530  	{
   531  		"hostname.as112.net", // see RFC 7534
   532  		[]string{
   533  			"domain golang.org",
   534  			"nameserver 2001:4860:4860::8888",
   535  			"nameserver 8.8.8.8",
   536  		},
   537  		nil,
   538  		true, true,
   539  	},
   540  	{
   541  		"hostname.as112.net", // see RFC 7534
   542  		[]string{
   543  			"search x.golang.org y.golang.org",
   544  			"nameserver 2001:4860:4860::8888",
   545  			"nameserver 8.8.8.8",
   546  		},
   547  		nil,
   548  		true, true,
   549  	},
   550  }
   551  
   552  func TestGoLookupIPWithResolverConfig(t *testing.T) {
   553  	defer dnsWaitGroup.Wait()
   554  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
   555  		switch s {
   556  		case "[2001:4860:4860::8888]:53", "8.8.8.8:53":
   557  			break
   558  		default:
   559  			time.Sleep(10 * time.Millisecond)
   560  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
   561  		}
   562  		r := dnsmessage.Message{
   563  			Header: dnsmessage.Header{
   564  				ID:       q.ID,
   565  				Response: true,
   566  			},
   567  			Questions: q.Questions,
   568  		}
   569  		for _, question := range q.Questions {
   570  			switch question.Type {
   571  			case dnsmessage.TypeA:
   572  				switch question.Name.String() {
   573  				case "hostname.as112.net.":
   574  					break
   575  				case "ipv4.google.com.":
   576  					r.Answers = append(r.Answers, dnsmessage.Resource{
   577  						Header: dnsmessage.ResourceHeader{
   578  							Name:   q.Questions[0].Name,
   579  							Type:   dnsmessage.TypeA,
   580  							Class:  dnsmessage.ClassINET,
   581  							Length: 4,
   582  						},
   583  						Body: &dnsmessage.AResource{
   584  							A: TestAddr,
   585  						},
   586  					})
   587  				default:
   588  
   589  				}
   590  			case dnsmessage.TypeAAAA:
   591  				switch question.Name.String() {
   592  				case "hostname.as112.net.":
   593  					break
   594  				case "ipv6.google.com.":
   595  					r.Answers = append(r.Answers, dnsmessage.Resource{
   596  						Header: dnsmessage.ResourceHeader{
   597  							Name:   q.Questions[0].Name,
   598  							Type:   dnsmessage.TypeAAAA,
   599  							Class:  dnsmessage.ClassINET,
   600  							Length: 16,
   601  						},
   602  						Body: &dnsmessage.AAAAResource{
   603  							AAAA: TestAddr6,
   604  						},
   605  					})
   606  				}
   607  			}
   608  		}
   609  		return r, nil
   610  	}}
   611  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
   612  
   613  	conf, err := newResolvConfTest()
   614  	if err != nil {
   615  		t.Fatal(err)
   616  	}
   617  	defer conf.teardown()
   618  
   619  	for _, tt := range goLookupIPWithResolverConfigTests {
   620  		if err := conf.writeAndUpdate(tt.lines); err != nil {
   621  			t.Error(err)
   622  			continue
   623  		}
   624  		addrs, err := r.LookupIPAddr(context.Background(), tt.name)
   625  		if err != nil {
   626  			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) {
   627  				t.Errorf("got %v; want %v", err, tt.error)
   628  			}
   629  			continue
   630  		}
   631  		if len(addrs) == 0 {
   632  			t.Errorf("no records for %s", tt.name)
   633  		}
   634  		if !tt.a && !tt.aaaa && len(addrs) > 0 {
   635  			t.Errorf("unexpected %v for %s", addrs, tt.name)
   636  		}
   637  		for _, addr := range addrs {
   638  			if !tt.a && addr.IP.To4() != nil {
   639  				t.Errorf("got %v; must not be IPv4 address", addr)
   640  			}
   641  			if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
   642  				t.Errorf("got %v; must not be IPv6 address", addr)
   643  			}
   644  		}
   645  	}
   646  }
   647  
   648  // Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
   649  func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
   650  	defer dnsWaitGroup.Wait()
   651  
   652  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, tm time.Time) (dnsmessage.Message, error) {
   653  		r := dnsmessage.Message{
   654  			Header: dnsmessage.Header{
   655  				ID:       q.ID,
   656  				Response: true,
   657  			},
   658  			Questions: q.Questions,
   659  		}
   660  		return r, nil
   661  	}}
   662  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
   663  
   664  	// Add a config that simulates no dns servers being available.
   665  	conf, err := newResolvConfTest()
   666  	if err != nil {
   667  		t.Fatal(err)
   668  	}
   669  	defer conf.teardown()
   670  
   671  	if err := conf.writeAndUpdate([]string{}); err != nil {
   672  		t.Fatal(err)
   673  	}
   674  	// Redirect host file lookups.
   675  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
   676  	hostsFilePath = "testdata/hosts"
   677  
   678  	for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
   679  		name := fmt.Sprintf("order %v", order)
   680  		// First ensure that we get an error when contacting a non-existent host.
   681  		_, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "notarealhost", order, nil)
   682  		if err == nil {
   683  			t.Errorf("%s: expected error while looking up name not in hosts file", name)
   684  			continue
   685  		}
   686  
   687  		// Now check that we get an address when the name appears in the hosts file.
   688  		addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "thor", order, nil) // entry is in "testdata/hosts"
   689  		if err != nil {
   690  			t.Errorf("%s: expected to successfully lookup host entry", name)
   691  			continue
   692  		}
   693  		if len(addrs) != 1 {
   694  			t.Errorf("%s: expected exactly one result, but got %v", name, addrs)
   695  			continue
   696  		}
   697  		if got, want := addrs[0].String(), "127.1.1.1"; got != want {
   698  			t.Errorf("%s: address doesn't match expectation. got %v, want %v", name, got, want)
   699  		}
   700  	}
   701  }
   702  
   703  // Issue 12712.
   704  // When using search domains, return the error encountered
   705  // querying the original name instead of an error encountered
   706  // querying a generated name.
   707  func TestErrorForOriginalNameWhenSearching(t *testing.T) {
   708  	defer dnsWaitGroup.Wait()
   709  
   710  	const fqdn = "doesnotexist.domain"
   711  
   712  	conf, err := newResolvConfTest()
   713  	if err != nil {
   714  		t.Fatal(err)
   715  	}
   716  	defer conf.teardown()
   717  
   718  	if err := conf.writeAndUpdate([]string{"search servfail"}); err != nil {
   719  		t.Fatal(err)
   720  	}
   721  
   722  	fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
   723  		r := dnsmessage.Message{
   724  			Header: dnsmessage.Header{
   725  				ID:       q.ID,
   726  				Response: true,
   727  			},
   728  			Questions: q.Questions,
   729  		}
   730  
   731  		switch q.Questions[0].Name.String() {
   732  		case fqdn + ".servfail.":
   733  			r.Header.RCode = dnsmessage.RCodeServerFailure
   734  		default:
   735  			r.Header.RCode = dnsmessage.RCodeNameError
   736  		}
   737  
   738  		return r, nil
   739  	}}
   740  
   741  	cases := []struct {
   742  		strictErrors bool
   743  		wantErr      *DNSError
   744  	}{
   745  		{true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}},
   746  		{false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error(), IsNotFound: true}},
   747  	}
   748  	for _, tt := range cases {
   749  		r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext}
   750  		_, err = r.LookupIPAddr(context.Background(), fqdn)
   751  		if err == nil {
   752  			t.Fatal("expected an error")
   753  		}
   754  
   755  		want := tt.wantErr
   756  		if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err || err.IsTemporary != want.IsTemporary {
   757  			t.Errorf("got %v; want %v", err, want)
   758  		}
   759  	}
   760  }
   761  
   762  // Issue 15434. If a name server gives a lame referral, continue to the next.
   763  func TestIgnoreLameReferrals(t *testing.T) {
   764  	defer dnsWaitGroup.Wait()
   765  
   766  	conf, err := newResolvConfTest()
   767  	if err != nil {
   768  		t.Fatal(err)
   769  	}
   770  	defer conf.teardown()
   771  
   772  	if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
   773  		"nameserver 192.0.2.2"}); err != nil {
   774  		t.Fatal(err)
   775  	}
   776  
   777  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
   778  		t.Log(s, q)
   779  		r := dnsmessage.Message{
   780  			Header: dnsmessage.Header{
   781  				ID:       q.ID,
   782  				Response: true,
   783  			},
   784  			Questions: q.Questions,
   785  		}
   786  
   787  		if s == "192.0.2.2:53" {
   788  			r.Header.RecursionAvailable = true
   789  			if q.Questions[0].Type == dnsmessage.TypeA {
   790  				r.Answers = []dnsmessage.Resource{
   791  					{
   792  						Header: dnsmessage.ResourceHeader{
   793  							Name:   q.Questions[0].Name,
   794  							Type:   dnsmessage.TypeA,
   795  							Class:  dnsmessage.ClassINET,
   796  							Length: 4,
   797  						},
   798  						Body: &dnsmessage.AResource{
   799  							A: TestAddr,
   800  						},
   801  					},
   802  				}
   803  			}
   804  		} else if s == "192.0.2.1:53" {
   805  			if q.Questions[0].Type == dnsmessage.TypeA && strings.HasPrefix(q.Questions[0].Name.String(), "empty.com.") {
   806  				var edns0Hdr dnsmessage.ResourceHeader
   807  				edns0Hdr.SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false)
   808  
   809  				r.Additionals = []dnsmessage.Resource{
   810  					{
   811  						Header: edns0Hdr,
   812  						Body:   &dnsmessage.OPTResource{},
   813  					},
   814  				}
   815  			}
   816  		}
   817  
   818  		return r, nil
   819  	}}
   820  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
   821  
   822  	addrs, err := r.LookupIP(context.Background(), "ip4", "www.golang.org")
   823  	if err != nil {
   824  		t.Fatal(err)
   825  	}
   826  
   827  	if got := len(addrs); got != 1 {
   828  		t.Fatalf("got %d addresses, want 1", got)
   829  	}
   830  
   831  	if got, want := addrs[0].String(), "192.0.2.1"; got != want {
   832  		t.Fatalf("got address %v, want %v", got, want)
   833  	}
   834  
   835  	_, err = r.LookupIP(context.Background(), "ip4", "empty.com")
   836  	de, ok := err.(*DNSError)
   837  	if !ok {
   838  		t.Fatalf("err = %#v; wanted a *net.DNSError", err)
   839  	}
   840  	if de.Err != errNoSuchHost.Error() {
   841  		t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
   842  	}
   843  }
   844  
   845  func BenchmarkGoLookupIP(b *testing.B) {
   846  	testHookUninstaller.Do(uninstallTestHooks)
   847  	ctx := context.Background()
   848  	b.ReportAllocs()
   849  
   850  	for i := 0; i < b.N; i++ {
   851  		goResolver.LookupIPAddr(ctx, "www.example.com")
   852  	}
   853  }
   854  
   855  func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
   856  	testHookUninstaller.Do(uninstallTestHooks)
   857  	ctx := context.Background()
   858  	b.ReportAllocs()
   859  
   860  	for i := 0; i < b.N; i++ {
   861  		goResolver.LookupIPAddr(ctx, "some.nonexistent")
   862  	}
   863  }
   864  
   865  func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
   866  	testHookUninstaller.Do(uninstallTestHooks)
   867  
   868  	conf, err := newResolvConfTest()
   869  	if err != nil {
   870  		b.Fatal(err)
   871  	}
   872  	defer conf.teardown()
   873  
   874  	lines := []string{
   875  		"nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
   876  		"nameserver 8.8.8.8",
   877  	}
   878  	if err := conf.writeAndUpdate(lines); err != nil {
   879  		b.Fatal(err)
   880  	}
   881  	ctx := context.Background()
   882  	b.ReportAllocs()
   883  
   884  	for i := 0; i < b.N; i++ {
   885  		goResolver.LookupIPAddr(ctx, "www.example.com")
   886  	}
   887  }
   888  
   889  type fakeDNSServer struct {
   890  	rh        func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error)
   891  	alwaysTCP bool
   892  }
   893  
   894  func (server *fakeDNSServer) DialContext(_ context.Context, n, s string) (Conn, error) {
   895  	if server.alwaysTCP || n == "tcp" || n == "tcp4" || n == "tcp6" {
   896  		return &fakeDNSConn{tcp: true, server: server, n: n, s: s}, nil
   897  	}
   898  	return &fakeDNSPacketConn{fakeDNSConn: fakeDNSConn{tcp: false, server: server, n: n, s: s}}, nil
   899  }
   900  
   901  type fakeDNSConn struct {
   902  	Conn
   903  	tcp    bool
   904  	server *fakeDNSServer
   905  	n      string
   906  	s      string
   907  	q      dnsmessage.Message
   908  	t      time.Time
   909  	buf    []byte
   910  }
   911  
   912  func (f *fakeDNSConn) Close() error {
   913  	return nil
   914  }
   915  
   916  func (f *fakeDNSConn) Read(b []byte) (int, error) {
   917  	if len(f.buf) > 0 {
   918  		n := copy(b, f.buf)
   919  		f.buf = f.buf[n:]
   920  		return n, nil
   921  	}
   922  
   923  	resp, err := f.server.rh(f.n, f.s, f.q, f.t)
   924  	if err != nil {
   925  		return 0, err
   926  	}
   927  
   928  	bb := make([]byte, 2, 514)
   929  	bb, err = resp.AppendPack(bb)
   930  	if err != nil {
   931  		return 0, fmt.Errorf("cannot marshal DNS message: %v", err)
   932  	}
   933  
   934  	if f.tcp {
   935  		l := len(bb) - 2
   936  		bb[0] = byte(l >> 8)
   937  		bb[1] = byte(l)
   938  		f.buf = bb
   939  		return f.Read(b)
   940  	}
   941  
   942  	bb = bb[2:]
   943  	if len(b) < len(bb) {
   944  		return 0, errors.New("read would fragment DNS message")
   945  	}
   946  
   947  	copy(b, bb)
   948  	return len(bb), nil
   949  }
   950  
   951  func (f *fakeDNSConn) Write(b []byte) (int, error) {
   952  	if f.tcp && len(b) >= 2 {
   953  		b = b[2:]
   954  	}
   955  	if f.q.Unpack(b) != nil {
   956  		return 0, fmt.Errorf("cannot unmarshal DNS message fake %s (%d)", f.n, len(b))
   957  	}
   958  	return len(b), nil
   959  }
   960  
   961  func (f *fakeDNSConn) SetDeadline(t time.Time) error {
   962  	f.t = t
   963  	return nil
   964  }
   965  
   966  type fakeDNSPacketConn struct {
   967  	PacketConn
   968  	fakeDNSConn
   969  }
   970  
   971  func (f *fakeDNSPacketConn) SetDeadline(t time.Time) error {
   972  	return f.fakeDNSConn.SetDeadline(t)
   973  }
   974  
   975  func (f *fakeDNSPacketConn) Close() error {
   976  	return f.fakeDNSConn.Close()
   977  }
   978  
   979  // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
   980  func TestIgnoreDNSForgeries(t *testing.T) {
   981  	c, s := Pipe()
   982  	go func() {
   983  		b := make([]byte, maxDNSPacketSize)
   984  		n, err := s.Read(b)
   985  		if err != nil {
   986  			t.Error(err)
   987  			return
   988  		}
   989  
   990  		var msg dnsmessage.Message
   991  		if msg.Unpack(b[:n]) != nil {
   992  			t.Error("invalid DNS query:", err)
   993  			return
   994  		}
   995  
   996  		s.Write([]byte("garbage DNS response packet"))
   997  
   998  		msg.Header.Response = true
   999  		msg.Header.ID++ // make invalid ID
  1000  
  1001  		if b, err = msg.Pack(); err != nil {
  1002  			t.Error("failed to pack DNS response:", err)
  1003  			return
  1004  		}
  1005  		s.Write(b)
  1006  
  1007  		msg.Header.ID-- // restore original ID
  1008  		msg.Answers = []dnsmessage.Resource{
  1009  			{
  1010  				Header: dnsmessage.ResourceHeader{
  1011  					Name:   mustNewName("www.example.com."),
  1012  					Type:   dnsmessage.TypeA,
  1013  					Class:  dnsmessage.ClassINET,
  1014  					Length: 4,
  1015  				},
  1016  				Body: &dnsmessage.AResource{
  1017  					A: TestAddr,
  1018  				},
  1019  			},
  1020  		}
  1021  
  1022  		b, err = msg.Pack()
  1023  		if err != nil {
  1024  			t.Error("failed to pack DNS response:", err)
  1025  			return
  1026  		}
  1027  		s.Write(b)
  1028  	}()
  1029  
  1030  	msg := dnsmessage.Message{
  1031  		Header: dnsmessage.Header{
  1032  			ID: 42,
  1033  		},
  1034  		Questions: []dnsmessage.Question{
  1035  			{
  1036  				Name:  mustNewName("www.example.com."),
  1037  				Type:  dnsmessage.TypeA,
  1038  				Class: dnsmessage.ClassINET,
  1039  			},
  1040  		},
  1041  	}
  1042  
  1043  	b, err := msg.Pack()
  1044  	if err != nil {
  1045  		t.Fatal("Pack failed:", err)
  1046  	}
  1047  
  1048  	p, _, err := dnsPacketRoundTrip(c, 42, msg.Questions[0], b)
  1049  	if err != nil {
  1050  		t.Fatalf("dnsPacketRoundTrip failed: %v", err)
  1051  	}
  1052  
  1053  	p.SkipAllQuestions()
  1054  	as, err := p.AllAnswers()
  1055  	if err != nil {
  1056  		t.Fatal("AllAnswers failed:", err)
  1057  	}
  1058  	if got := as[0].Body.(*dnsmessage.AResource).A; got != TestAddr {
  1059  		t.Errorf("got address %v, want %v", got, TestAddr)
  1060  	}
  1061  }
  1062  
  1063  // Issue 16865. If a name server times out, continue to the next.
  1064  func TestRetryTimeout(t *testing.T) {
  1065  	defer dnsWaitGroup.Wait()
  1066  
  1067  	conf, err := newResolvConfTest()
  1068  	if err != nil {
  1069  		t.Fatal(err)
  1070  	}
  1071  	defer conf.teardown()
  1072  
  1073  	testConf := []string{
  1074  		"nameserver 192.0.2.1", // the one that will timeout
  1075  		"nameserver 192.0.2.2",
  1076  	}
  1077  	if err := conf.writeAndUpdate(testConf); err != nil {
  1078  		t.Fatal(err)
  1079  	}
  1080  
  1081  	var deadline0 time.Time
  1082  
  1083  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
  1084  		t.Log(s, q, deadline)
  1085  
  1086  		if deadline.IsZero() {
  1087  			t.Error("zero deadline")
  1088  		}
  1089  
  1090  		if s == "192.0.2.1:53" {
  1091  			deadline0 = deadline
  1092  			time.Sleep(10 * time.Millisecond)
  1093  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
  1094  		}
  1095  
  1096  		if deadline.Equal(deadline0) {
  1097  			t.Error("deadline didn't change")
  1098  		}
  1099  
  1100  		return mockTXTResponse(q), nil
  1101  	}}
  1102  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
  1103  
  1104  	_, err = r.LookupTXT(context.Background(), "www.golang.org")
  1105  	if err != nil {
  1106  		t.Fatal(err)
  1107  	}
  1108  
  1109  	if deadline0.IsZero() {
  1110  		t.Error("deadline0 still zero", deadline0)
  1111  	}
  1112  }
  1113  
  1114  func TestRotate(t *testing.T) {
  1115  	// without rotation, always uses the first server
  1116  	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"})
  1117  
  1118  	// with rotation, rotates through back to first
  1119  	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"})
  1120  }
  1121  
  1122  func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
  1123  	defer dnsWaitGroup.Wait()
  1124  
  1125  	conf, err := newResolvConfTest()
  1126  	if err != nil {
  1127  		t.Fatal(err)
  1128  	}
  1129  	defer conf.teardown()
  1130  
  1131  	var confLines []string
  1132  	for _, ns := range nameservers {
  1133  		confLines = append(confLines, "nameserver "+ns)
  1134  	}
  1135  	if rotate {
  1136  		confLines = append(confLines, "options rotate")
  1137  	}
  1138  
  1139  	if err := conf.writeAndUpdate(confLines); err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  
  1143  	var usedServers []string
  1144  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
  1145  		usedServers = append(usedServers, s)
  1146  		return mockTXTResponse(q), nil
  1147  	}}
  1148  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1149  
  1150  	// len(nameservers) + 1 to allow rotation to get back to start
  1151  	for i := 0; i < len(nameservers)+1; i++ {
  1152  		if _, err := r.LookupTXT(context.Background(), "www.golang.org"); err != nil {
  1153  			t.Fatal(err)
  1154  		}
  1155  	}
  1156  
  1157  	if !reflect.DeepEqual(usedServers, wantServers) {
  1158  		t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
  1159  	}
  1160  }
  1161  
  1162  func mockTXTResponse(q dnsmessage.Message) dnsmessage.Message {
  1163  	r := dnsmessage.Message{
  1164  		Header: dnsmessage.Header{
  1165  			ID:                 q.ID,
  1166  			Response:           true,
  1167  			RecursionAvailable: true,
  1168  		},
  1169  		Questions: q.Questions,
  1170  		Answers: []dnsmessage.Resource{
  1171  			{
  1172  				Header: dnsmessage.ResourceHeader{
  1173  					Name:  q.Questions[0].Name,
  1174  					Type:  dnsmessage.TypeTXT,
  1175  					Class: dnsmessage.ClassINET,
  1176  				},
  1177  				Body: &dnsmessage.TXTResource{
  1178  					TXT: []string{"ok"},
  1179  				},
  1180  			},
  1181  		},
  1182  	}
  1183  
  1184  	return r
  1185  }
  1186  
  1187  // Issue 17448. With StrictErrors enabled, temporary errors should make
  1188  // LookupIP fail rather than return a partial result.
  1189  func TestStrictErrorsLookupIP(t *testing.T) {
  1190  	defer dnsWaitGroup.Wait()
  1191  
  1192  	conf, err := newResolvConfTest()
  1193  	if err != nil {
  1194  		t.Fatal(err)
  1195  	}
  1196  	defer conf.teardown()
  1197  
  1198  	confData := []string{
  1199  		"nameserver 192.0.2.53",
  1200  		"search x.golang.org y.golang.org",
  1201  	}
  1202  	if err := conf.writeAndUpdate(confData); err != nil {
  1203  		t.Fatal(err)
  1204  	}
  1205  
  1206  	const name = "test-issue19592"
  1207  	const server = "192.0.2.53:53"
  1208  	const searchX = "test-issue19592.x.golang.org."
  1209  	const searchY = "test-issue19592.y.golang.org."
  1210  	const ip4 = "192.0.2.1"
  1211  	const ip6 = "2001:db8::1"
  1212  
  1213  	type resolveWhichEnum int
  1214  	const (
  1215  		resolveOK resolveWhichEnum = iota
  1216  		resolveOpError
  1217  		resolveServfail
  1218  		resolveTimeout
  1219  	)
  1220  
  1221  	makeTempError := func(err string) error {
  1222  		return &DNSError{
  1223  			Err:         err,
  1224  			Name:        name,
  1225  			Server:      server,
  1226  			IsTemporary: true,
  1227  		}
  1228  	}
  1229  	makeTimeout := func() error {
  1230  		return &DNSError{
  1231  			Err:         os.ErrDeadlineExceeded.Error(),
  1232  			Name:        name,
  1233  			Server:      server,
  1234  			IsTimeout:   true,
  1235  			IsTemporary: true,
  1236  		}
  1237  	}
  1238  	makeNxDomain := func() error {
  1239  		return &DNSError{
  1240  			Err:        errNoSuchHost.Error(),
  1241  			Name:       name,
  1242  			Server:     server,
  1243  			IsNotFound: true,
  1244  		}
  1245  	}
  1246  
  1247  	cases := []struct {
  1248  		desc          string
  1249  		resolveWhich  func(quest dnsmessage.Question) resolveWhichEnum
  1250  		wantStrictErr error
  1251  		wantLaxErr    error
  1252  		wantIPs       []string
  1253  	}{
  1254  		{
  1255  			desc: "No errors",
  1256  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1257  				return resolveOK
  1258  			},
  1259  			wantIPs: []string{ip4, ip6},
  1260  		},
  1261  		{
  1262  			desc: "searchX error fails in strict mode",
  1263  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1264  				if quest.Name.String() == searchX {
  1265  					return resolveTimeout
  1266  				}
  1267  				return resolveOK
  1268  			},
  1269  			wantStrictErr: makeTimeout(),
  1270  			wantIPs:       []string{ip4, ip6},
  1271  		},
  1272  		{
  1273  			desc: "searchX IPv4-only timeout fails in strict mode",
  1274  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1275  				if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeA {
  1276  					return resolveTimeout
  1277  				}
  1278  				return resolveOK
  1279  			},
  1280  			wantStrictErr: makeTimeout(),
  1281  			wantIPs:       []string{ip4, ip6},
  1282  		},
  1283  		{
  1284  			desc: "searchX IPv6-only servfail fails in strict mode",
  1285  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1286  				if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeAAAA {
  1287  					return resolveServfail
  1288  				}
  1289  				return resolveOK
  1290  			},
  1291  			wantStrictErr: makeTempError("server misbehaving"),
  1292  			wantIPs:       []string{ip4, ip6},
  1293  		},
  1294  		{
  1295  			desc: "searchY error always fails",
  1296  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1297  				if quest.Name.String() == searchY {
  1298  					return resolveTimeout
  1299  				}
  1300  				return resolveOK
  1301  			},
  1302  			wantStrictErr: makeTimeout(),
  1303  			wantLaxErr:    makeNxDomain(), // This one reaches the "test." FQDN.
  1304  		},
  1305  		{
  1306  			desc: "searchY IPv4-only socket error fails in strict mode",
  1307  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1308  				if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeA {
  1309  					return resolveOpError
  1310  				}
  1311  				return resolveOK
  1312  			},
  1313  			wantStrictErr: makeTempError("write: socket on fire"),
  1314  			wantIPs:       []string{ip6},
  1315  		},
  1316  		{
  1317  			desc: "searchY IPv6-only timeout fails in strict mode",
  1318  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
  1319  				if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeAAAA {
  1320  					return resolveTimeout
  1321  				}
  1322  				return resolveOK
  1323  			},
  1324  			wantStrictErr: makeTimeout(),
  1325  			wantIPs:       []string{ip4},
  1326  		},
  1327  	}
  1328  
  1329  	for i, tt := range cases {
  1330  		fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
  1331  			t.Log(s, q)
  1332  
  1333  			switch tt.resolveWhich(q.Questions[0]) {
  1334  			case resolveOK:
  1335  				// Handle below.
  1336  			case resolveOpError:
  1337  				return dnsmessage.Message{}, &OpError{Op: "write", Err: fmt.Errorf("socket on fire")}
  1338  			case resolveServfail:
  1339  				return dnsmessage.Message{
  1340  					Header: dnsmessage.Header{
  1341  						ID:       q.ID,
  1342  						Response: true,
  1343  						RCode:    dnsmessage.RCodeServerFailure,
  1344  					},
  1345  					Questions: q.Questions,
  1346  				}, nil
  1347  			case resolveTimeout:
  1348  				return dnsmessage.Message{}, os.ErrDeadlineExceeded
  1349  			default:
  1350  				t.Fatal("Impossible resolveWhich")
  1351  			}
  1352  
  1353  			switch q.Questions[0].Name.String() {
  1354  			case searchX, name + ".":
  1355  				// Return NXDOMAIN to utilize the search list.
  1356  				return dnsmessage.Message{
  1357  					Header: dnsmessage.Header{
  1358  						ID:       q.ID,
  1359  						Response: true,
  1360  						RCode:    dnsmessage.RCodeNameError,
  1361  					},
  1362  					Questions: q.Questions,
  1363  				}, nil
  1364  			case searchY:
  1365  				// Return records below.
  1366  			default:
  1367  				return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
  1368  			}
  1369  
  1370  			r := dnsmessage.Message{
  1371  				Header: dnsmessage.Header{
  1372  					ID:       q.ID,
  1373  					Response: true,
  1374  				},
  1375  				Questions: q.Questions,
  1376  			}
  1377  			switch q.Questions[0].Type {
  1378  			case dnsmessage.TypeA:
  1379  				r.Answers = []dnsmessage.Resource{
  1380  					{
  1381  						Header: dnsmessage.ResourceHeader{
  1382  							Name:   q.Questions[0].Name,
  1383  							Type:   dnsmessage.TypeA,
  1384  							Class:  dnsmessage.ClassINET,
  1385  							Length: 4,
  1386  						},
  1387  						Body: &dnsmessage.AResource{
  1388  							A: TestAddr,
  1389  						},
  1390  					},
  1391  				}
  1392  			case dnsmessage.TypeAAAA:
  1393  				r.Answers = []dnsmessage.Resource{
  1394  					{
  1395  						Header: dnsmessage.ResourceHeader{
  1396  							Name:   q.Questions[0].Name,
  1397  							Type:   dnsmessage.TypeAAAA,
  1398  							Class:  dnsmessage.ClassINET,
  1399  							Length: 16,
  1400  						},
  1401  						Body: &dnsmessage.AAAAResource{
  1402  							AAAA: TestAddr6,
  1403  						},
  1404  					},
  1405  				}
  1406  			default:
  1407  				return dnsmessage.Message{}, fmt.Errorf("Unexpected Type: %v", q.Questions[0].Type)
  1408  			}
  1409  			return r, nil
  1410  		}}
  1411  
  1412  		for _, strict := range []bool{true, false} {
  1413  			r := Resolver{PreferGo: true, StrictErrors: strict, Dial: fake.DialContext}
  1414  			ips, err := r.LookupIPAddr(context.Background(), name)
  1415  
  1416  			var wantErr error
  1417  			if strict {
  1418  				wantErr = tt.wantStrictErr
  1419  			} else {
  1420  				wantErr = tt.wantLaxErr
  1421  			}
  1422  			if !reflect.DeepEqual(err, wantErr) {
  1423  				t.Errorf("#%d (%s) strict=%v: got err %#v; want %#v", i, tt.desc, strict, err, wantErr)
  1424  			}
  1425  
  1426  			gotIPs := map[string]struct{}{}
  1427  			for _, ip := range ips {
  1428  				gotIPs[ip.String()] = struct{}{}
  1429  			}
  1430  			wantIPs := map[string]struct{}{}
  1431  			if wantErr == nil {
  1432  				for _, ip := range tt.wantIPs {
  1433  					wantIPs[ip] = struct{}{}
  1434  				}
  1435  			}
  1436  			if !reflect.DeepEqual(gotIPs, wantIPs) {
  1437  				t.Errorf("#%d (%s) strict=%v: got ips %v; want %v", i, tt.desc, strict, gotIPs, wantIPs)
  1438  			}
  1439  		}
  1440  	}
  1441  }
  1442  
  1443  // Issue 17448. With StrictErrors enabled, temporary errors should make
  1444  // LookupTXT stop walking the search list.
  1445  func TestStrictErrorsLookupTXT(t *testing.T) {
  1446  	defer dnsWaitGroup.Wait()
  1447  
  1448  	conf, err := newResolvConfTest()
  1449  	if err != nil {
  1450  		t.Fatal(err)
  1451  	}
  1452  	defer conf.teardown()
  1453  
  1454  	confData := []string{
  1455  		"nameserver 192.0.2.53",
  1456  		"search x.golang.org y.golang.org",
  1457  	}
  1458  	if err := conf.writeAndUpdate(confData); err != nil {
  1459  		t.Fatal(err)
  1460  	}
  1461  
  1462  	const name = "test"
  1463  	const server = "192.0.2.53:53"
  1464  	const searchX = "test.x.golang.org."
  1465  	const searchY = "test.y.golang.org."
  1466  	const txt = "Hello World"
  1467  
  1468  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
  1469  		t.Log(s, q)
  1470  
  1471  		switch q.Questions[0].Name.String() {
  1472  		case searchX:
  1473  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
  1474  		case searchY:
  1475  			return mockTXTResponse(q), nil
  1476  		default:
  1477  			return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
  1478  		}
  1479  	}}
  1480  
  1481  	for _, strict := range []bool{true, false} {
  1482  		r := Resolver{StrictErrors: strict, Dial: fake.DialContext}
  1483  		p, _, err := r.lookup(context.Background(), name, dnsmessage.TypeTXT, nil)
  1484  		var wantErr error
  1485  		var wantRRs int
  1486  		if strict {
  1487  			wantErr = &DNSError{
  1488  				Err:         os.ErrDeadlineExceeded.Error(),
  1489  				Name:        name,
  1490  				Server:      server,
  1491  				IsTimeout:   true,
  1492  				IsTemporary: true,
  1493  			}
  1494  		} else {
  1495  			wantRRs = 1
  1496  		}
  1497  		if !reflect.DeepEqual(err, wantErr) {
  1498  			t.Errorf("strict=%v: got err %#v; want %#v", strict, err, wantErr)
  1499  		}
  1500  		a, err := p.AllAnswers()
  1501  		if err != nil {
  1502  			a = nil
  1503  		}
  1504  		if len(a) != wantRRs {
  1505  			t.Errorf("strict=%v: got %v; want %v", strict, len(a), wantRRs)
  1506  		}
  1507  	}
  1508  }
  1509  
  1510  // Test for a race between uninstalling the test hooks and closing a
  1511  // socket connection. This used to fail when testing with -race.
  1512  func TestDNSGoroutineRace(t *testing.T) {
  1513  	defer dnsWaitGroup.Wait()
  1514  
  1515  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error) {
  1516  		time.Sleep(10 * time.Microsecond)
  1517  		return dnsmessage.Message{}, os.ErrDeadlineExceeded
  1518  	}}
  1519  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1520  
  1521  	// The timeout here is less than the timeout used by the server,
  1522  	// so the goroutine started to query the (fake) server will hang
  1523  	// around after this test is done if we don't call dnsWaitGroup.Wait.
  1524  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Microsecond)
  1525  	defer cancel()
  1526  	_, err := r.LookupIPAddr(ctx, "where.are.they.now")
  1527  	if err == nil {
  1528  		t.Fatal("fake DNS lookup unexpectedly succeeded")
  1529  	}
  1530  }
  1531  
  1532  func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
  1533  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1534  
  1535  	conf := getSystemDNSConfig()
  1536  
  1537  	ctx, cancel := context.WithCancel(context.Background())
  1538  	defer cancel()
  1539  
  1540  	_, _, err := r.tryOneName(ctx, conf, name, typ)
  1541  	return err
  1542  }
  1543  
  1544  // Issue 8434: verify that Temporary returns true on an error when rcode
  1545  // is SERVFAIL
  1546  func TestIssue8434(t *testing.T) {
  1547  	err := lookupWithFake(fakeDNSServer{
  1548  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1549  			return dnsmessage.Message{
  1550  				Header: dnsmessage.Header{
  1551  					ID:       q.ID,
  1552  					Response: true,
  1553  					RCode:    dnsmessage.RCodeServerFailure,
  1554  				},
  1555  				Questions: q.Questions,
  1556  			}, nil
  1557  		},
  1558  	}, "golang.org.", dnsmessage.TypeALL)
  1559  	if err == nil {
  1560  		t.Fatal("expected an error")
  1561  	}
  1562  	if ne, ok := err.(Error); !ok {
  1563  		t.Fatalf("err = %#v; wanted something supporting net.Error", err)
  1564  	} else if !ne.Temporary() {
  1565  		t.Fatalf("Temporary = false for err = %#v; want Temporary == true", err)
  1566  	}
  1567  	if de, ok := err.(*DNSError); !ok {
  1568  		t.Fatalf("err = %#v; wanted a *net.DNSError", err)
  1569  	} else if !de.IsTemporary {
  1570  		t.Fatalf("IsTemporary = false for err = %#v; want IsTemporary == true", err)
  1571  	}
  1572  }
  1573  
  1574  func TestIssueNoSuchHostExists(t *testing.T) {
  1575  	err := lookupWithFake(fakeDNSServer{
  1576  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1577  			return dnsmessage.Message{
  1578  				Header: dnsmessage.Header{
  1579  					ID:       q.ID,
  1580  					Response: true,
  1581  					RCode:    dnsmessage.RCodeNameError,
  1582  				},
  1583  				Questions: q.Questions,
  1584  			}, nil
  1585  		},
  1586  	}, "golang.org.", dnsmessage.TypeALL)
  1587  	if err == nil {
  1588  		t.Fatal("expected an error")
  1589  	}
  1590  	if _, ok := err.(Error); !ok {
  1591  		t.Fatalf("err = %#v; wanted something supporting net.Error", err)
  1592  	}
  1593  	if de, ok := err.(*DNSError); !ok {
  1594  		t.Fatalf("err = %#v; wanted a *net.DNSError", err)
  1595  	} else if !de.IsNotFound {
  1596  		t.Fatalf("IsNotFound = false for err = %#v; want IsNotFound == true", err)
  1597  	}
  1598  }
  1599  
  1600  // TestNoSuchHost verifies that tryOneName works correctly when the domain does
  1601  // not exist.
  1602  //
  1603  // Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
  1604  // and not "server misbehaving"
  1605  //
  1606  // Issue 25336: verify that NXDOMAIN errors fail fast.
  1607  //
  1608  // Issue 27525: verify that empty answers fail fast.
  1609  func TestNoSuchHost(t *testing.T) {
  1610  	tests := []struct {
  1611  		name string
  1612  		f    func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
  1613  	}{
  1614  		{
  1615  			"NXDOMAIN",
  1616  			func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1617  				return dnsmessage.Message{
  1618  					Header: dnsmessage.Header{
  1619  						ID:                 q.ID,
  1620  						Response:           true,
  1621  						RCode:              dnsmessage.RCodeNameError,
  1622  						RecursionAvailable: false,
  1623  					},
  1624  					Questions: q.Questions,
  1625  				}, nil
  1626  			},
  1627  		},
  1628  		{
  1629  			"no answers",
  1630  			func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1631  				return dnsmessage.Message{
  1632  					Header: dnsmessage.Header{
  1633  						ID:                 q.ID,
  1634  						Response:           true,
  1635  						RCode:              dnsmessage.RCodeSuccess,
  1636  						RecursionAvailable: false,
  1637  						Authoritative:      true,
  1638  					},
  1639  					Questions: q.Questions,
  1640  				}, nil
  1641  			},
  1642  		},
  1643  	}
  1644  
  1645  	for _, test := range tests {
  1646  		t.Run(test.name, func(t *testing.T) {
  1647  			lookups := 0
  1648  			err := lookupWithFake(fakeDNSServer{
  1649  				rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
  1650  					lookups++
  1651  					return test.f(n, s, q, d)
  1652  				},
  1653  			}, ".", dnsmessage.TypeALL)
  1654  
  1655  			if lookups != 1 {
  1656  				t.Errorf("got %d lookups, wanted 1", lookups)
  1657  			}
  1658  
  1659  			if err == nil {
  1660  				t.Fatal("expected an error")
  1661  			}
  1662  			de, ok := err.(*DNSError)
  1663  			if !ok {
  1664  				t.Fatalf("err = %#v; wanted a *net.DNSError", err)
  1665  			}
  1666  			if de.Err != errNoSuchHost.Error() {
  1667  				t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
  1668  			}
  1669  			if !de.IsNotFound {
  1670  				t.Fatalf("IsNotFound = %v wanted true", de.IsNotFound)
  1671  			}
  1672  		})
  1673  	}
  1674  }
  1675  
  1676  // Issue 26573: verify that Conns that don't implement PacketConn are treated
  1677  // as streams even when udp was requested.
  1678  func TestDNSDialTCP(t *testing.T) {
  1679  	fake := fakeDNSServer{
  1680  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1681  			r := dnsmessage.Message{
  1682  				Header: dnsmessage.Header{
  1683  					ID:       q.Header.ID,
  1684  					Response: true,
  1685  					RCode:    dnsmessage.RCodeSuccess,
  1686  				},
  1687  				Questions: q.Questions,
  1688  			}
  1689  			return r, nil
  1690  		},
  1691  		alwaysTCP: true,
  1692  	}
  1693  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1694  	ctx := context.Background()
  1695  	_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useUDPOrTCP, false)
  1696  	if err != nil {
  1697  		t.Fatal("exchange failed:", err)
  1698  	}
  1699  }
  1700  
  1701  // Issue 27763: verify that two strings in one TXT record are concatenated.
  1702  func TestTXTRecordTwoStrings(t *testing.T) {
  1703  	fake := fakeDNSServer{
  1704  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1705  			r := dnsmessage.Message{
  1706  				Header: dnsmessage.Header{
  1707  					ID:       q.Header.ID,
  1708  					Response: true,
  1709  					RCode:    dnsmessage.RCodeSuccess,
  1710  				},
  1711  				Questions: q.Questions,
  1712  				Answers: []dnsmessage.Resource{
  1713  					{
  1714  						Header: dnsmessage.ResourceHeader{
  1715  							Name:  q.Questions[0].Name,
  1716  							Type:  dnsmessage.TypeA,
  1717  							Class: dnsmessage.ClassINET,
  1718  						},
  1719  						Body: &dnsmessage.TXTResource{
  1720  							TXT: []string{"string1 ", "string2"},
  1721  						},
  1722  					},
  1723  					{
  1724  						Header: dnsmessage.ResourceHeader{
  1725  							Name:  q.Questions[0].Name,
  1726  							Type:  dnsmessage.TypeA,
  1727  							Class: dnsmessage.ClassINET,
  1728  						},
  1729  						Body: &dnsmessage.TXTResource{
  1730  							TXT: []string{"onestring"},
  1731  						},
  1732  					},
  1733  				},
  1734  			}
  1735  			return r, nil
  1736  		},
  1737  	}
  1738  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1739  	txt, err := r.lookupTXT(context.Background(), "golang.org")
  1740  	if err != nil {
  1741  		t.Fatal("LookupTXT failed:", err)
  1742  	}
  1743  	if want := 2; len(txt) != want {
  1744  		t.Fatalf("len(txt), got %d, want %d", len(txt), want)
  1745  	}
  1746  	if want := "string1 string2"; txt[0] != want {
  1747  		t.Errorf("txt[0], got %q, want %q", txt[0], want)
  1748  	}
  1749  	if want := "onestring"; txt[1] != want {
  1750  		t.Errorf("txt[1], got %q, want %q", txt[1], want)
  1751  	}
  1752  }
  1753  
  1754  // Issue 29644: support single-request resolv.conf option in pure Go resolver.
  1755  // The A and AAAA queries will be sent sequentially, not in parallel.
  1756  func TestSingleRequestLookup(t *testing.T) {
  1757  	defer dnsWaitGroup.Wait()
  1758  	var (
  1759  		firstcalled int32
  1760  		ipv4        int32 = 1
  1761  		ipv6        int32 = 2
  1762  	)
  1763  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1764  		r := dnsmessage.Message{
  1765  			Header: dnsmessage.Header{
  1766  				ID:       q.ID,
  1767  				Response: true,
  1768  			},
  1769  			Questions: q.Questions,
  1770  		}
  1771  		for _, question := range q.Questions {
  1772  			switch question.Type {
  1773  			case dnsmessage.TypeA:
  1774  				if question.Name.String() == "slowipv4.example.net." {
  1775  					time.Sleep(10 * time.Millisecond)
  1776  				}
  1777  				if !atomic.CompareAndSwapInt32(&firstcalled, 0, ipv4) {
  1778  					t.Errorf("the A query was received after the AAAA query !")
  1779  				}
  1780  				r.Answers = append(r.Answers, dnsmessage.Resource{
  1781  					Header: dnsmessage.ResourceHeader{
  1782  						Name:   q.Questions[0].Name,
  1783  						Type:   dnsmessage.TypeA,
  1784  						Class:  dnsmessage.ClassINET,
  1785  						Length: 4,
  1786  					},
  1787  					Body: &dnsmessage.AResource{
  1788  						A: TestAddr,
  1789  					},
  1790  				})
  1791  			case dnsmessage.TypeAAAA:
  1792  				atomic.CompareAndSwapInt32(&firstcalled, 0, ipv6)
  1793  				r.Answers = append(r.Answers, dnsmessage.Resource{
  1794  					Header: dnsmessage.ResourceHeader{
  1795  						Name:   q.Questions[0].Name,
  1796  						Type:   dnsmessage.TypeAAAA,
  1797  						Class:  dnsmessage.ClassINET,
  1798  						Length: 16,
  1799  					},
  1800  					Body: &dnsmessage.AAAAResource{
  1801  						AAAA: TestAddr6,
  1802  					},
  1803  				})
  1804  			}
  1805  		}
  1806  		return r, nil
  1807  	}}
  1808  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1809  
  1810  	conf, err := newResolvConfTest()
  1811  	if err != nil {
  1812  		t.Fatal(err)
  1813  	}
  1814  	defer conf.teardown()
  1815  	if err := conf.writeAndUpdate([]string{"options single-request"}); err != nil {
  1816  		t.Fatal(err)
  1817  	}
  1818  	for _, name := range []string{"hostname.example.net", "slowipv4.example.net"} {
  1819  		firstcalled = 0
  1820  		_, err := r.LookupIPAddr(context.Background(), name)
  1821  		if err != nil {
  1822  			t.Error(err)
  1823  		}
  1824  	}
  1825  }
  1826  
  1827  // Issue 29358. Add configuration knob to force TCP-only DNS requests in the pure Go resolver.
  1828  func TestDNSUseTCP(t *testing.T) {
  1829  	fake := fakeDNSServer{
  1830  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1831  			r := dnsmessage.Message{
  1832  				Header: dnsmessage.Header{
  1833  					ID:       q.Header.ID,
  1834  					Response: true,
  1835  					RCode:    dnsmessage.RCodeSuccess,
  1836  				},
  1837  				Questions: q.Questions,
  1838  			}
  1839  			if n == "udp" {
  1840  				t.Fatal("udp protocol was used instead of tcp")
  1841  			}
  1842  			return r, nil
  1843  		},
  1844  	}
  1845  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1846  	ctx, cancel := context.WithCancel(context.Background())
  1847  	defer cancel()
  1848  	_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly, false)
  1849  	if err != nil {
  1850  		t.Fatal("exchange failed:", err)
  1851  	}
  1852  }
  1853  
  1854  func TestDNSUseTCPTruncated(t *testing.T) {
  1855  	fake := fakeDNSServer{
  1856  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1857  			r := dnsmessage.Message{
  1858  				Header: dnsmessage.Header{
  1859  					ID:        q.Header.ID,
  1860  					Response:  true,
  1861  					RCode:     dnsmessage.RCodeSuccess,
  1862  					Truncated: true,
  1863  				},
  1864  				Questions: q.Questions,
  1865  				Answers: []dnsmessage.Resource{
  1866  					{
  1867  						Header: dnsmessage.ResourceHeader{
  1868  							Name:   q.Questions[0].Name,
  1869  							Type:   dnsmessage.TypeA,
  1870  							Class:  dnsmessage.ClassINET,
  1871  							Length: 4,
  1872  						},
  1873  						Body: &dnsmessage.AResource{
  1874  							A: TestAddr,
  1875  						},
  1876  					},
  1877  				},
  1878  			}
  1879  			if n == "udp" {
  1880  				t.Fatal("udp protocol was used instead of tcp")
  1881  			}
  1882  			return r, nil
  1883  		},
  1884  	}
  1885  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1886  	ctx, cancel := context.WithCancel(context.Background())
  1887  	defer cancel()
  1888  	p, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly, false)
  1889  	if err != nil {
  1890  		t.Fatal("exchange failed:", err)
  1891  	}
  1892  	a, err := p.AllAnswers()
  1893  	if err != nil {
  1894  		t.Fatalf("unexpected error %v getting all answers", err)
  1895  	}
  1896  	if len(a) != 1 {
  1897  		t.Fatalf("got %d answers; want 1", len(a))
  1898  	}
  1899  }
  1900  
  1901  // Issue 34660: PTR response with non-PTR answers should ignore non-PTR
  1902  func TestPTRandNonPTR(t *testing.T) {
  1903  	fake := fakeDNSServer{
  1904  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1905  			r := dnsmessage.Message{
  1906  				Header: dnsmessage.Header{
  1907  					ID:       q.Header.ID,
  1908  					Response: true,
  1909  					RCode:    dnsmessage.RCodeSuccess,
  1910  				},
  1911  				Questions: q.Questions,
  1912  				Answers: []dnsmessage.Resource{
  1913  					{
  1914  						Header: dnsmessage.ResourceHeader{
  1915  							Name:  q.Questions[0].Name,
  1916  							Type:  dnsmessage.TypePTR,
  1917  							Class: dnsmessage.ClassINET,
  1918  						},
  1919  						Body: &dnsmessage.PTRResource{
  1920  							PTR: dnsmessage.MustNewName("golang.org."),
  1921  						},
  1922  					},
  1923  					{
  1924  						Header: dnsmessage.ResourceHeader{
  1925  							Name:  q.Questions[0].Name,
  1926  							Type:  dnsmessage.TypeTXT,
  1927  							Class: dnsmessage.ClassINET,
  1928  						},
  1929  						Body: &dnsmessage.TXTResource{
  1930  							TXT: []string{"PTR 8 6 60 ..."}, // fake RRSIG
  1931  						},
  1932  					},
  1933  				},
  1934  			}
  1935  			return r, nil
  1936  		},
  1937  	}
  1938  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  1939  	names, err := r.lookupAddr(context.Background(), "192.0.2.123")
  1940  	if err != nil {
  1941  		t.Fatalf("LookupAddr: %v", err)
  1942  	}
  1943  	if want := []string{"golang.org."}; !reflect.DeepEqual(names, want) {
  1944  		t.Errorf("names = %q; want %q", names, want)
  1945  	}
  1946  }
  1947  
  1948  func TestCVE202133195(t *testing.T) {
  1949  	fake := fakeDNSServer{
  1950  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  1951  			r := dnsmessage.Message{
  1952  				Header: dnsmessage.Header{
  1953  					ID:                 q.Header.ID,
  1954  					Response:           true,
  1955  					RCode:              dnsmessage.RCodeSuccess,
  1956  					RecursionAvailable: true,
  1957  				},
  1958  				Questions: q.Questions,
  1959  			}
  1960  			switch q.Questions[0].Type {
  1961  			case dnsmessage.TypeCNAME:
  1962  				r.Answers = []dnsmessage.Resource{}
  1963  			case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy
  1964  				r.Answers = append(r.Answers,
  1965  					dnsmessage.Resource{
  1966  						Header: dnsmessage.ResourceHeader{
  1967  							Name:   dnsmessage.MustNewName("<html>.golang.org."),
  1968  							Type:   dnsmessage.TypeA,
  1969  							Class:  dnsmessage.ClassINET,
  1970  							Length: 4,
  1971  						},
  1972  						Body: &dnsmessage.AResource{
  1973  							A: TestAddr,
  1974  						},
  1975  					},
  1976  				)
  1977  			case dnsmessage.TypeSRV:
  1978  				n := q.Questions[0].Name
  1979  				if n.String() == "_hdr._tcp.golang.org." {
  1980  					n = dnsmessage.MustNewName("<html>.golang.org.")
  1981  				}
  1982  				r.Answers = append(r.Answers,
  1983  					dnsmessage.Resource{
  1984  						Header: dnsmessage.ResourceHeader{
  1985  							Name:   n,
  1986  							Type:   dnsmessage.TypeSRV,
  1987  							Class:  dnsmessage.ClassINET,
  1988  							Length: 4,
  1989  						},
  1990  						Body: &dnsmessage.SRVResource{
  1991  							Target: dnsmessage.MustNewName("<html>.golang.org."),
  1992  						},
  1993  					},
  1994  					dnsmessage.Resource{
  1995  						Header: dnsmessage.ResourceHeader{
  1996  							Name:   n,
  1997  							Type:   dnsmessage.TypeSRV,
  1998  							Class:  dnsmessage.ClassINET,
  1999  							Length: 4,
  2000  						},
  2001  						Body: &dnsmessage.SRVResource{
  2002  							Target: dnsmessage.MustNewName("good.golang.org."),
  2003  						},
  2004  					},
  2005  				)
  2006  			case dnsmessage.TypeMX:
  2007  				r.Answers = append(r.Answers,
  2008  					dnsmessage.Resource{
  2009  						Header: dnsmessage.ResourceHeader{
  2010  							Name:   dnsmessage.MustNewName("<html>.golang.org."),
  2011  							Type:   dnsmessage.TypeMX,
  2012  							Class:  dnsmessage.ClassINET,
  2013  							Length: 4,
  2014  						},
  2015  						Body: &dnsmessage.MXResource{
  2016  							MX: dnsmessage.MustNewName("<html>.golang.org."),
  2017  						},
  2018  					},
  2019  					dnsmessage.Resource{
  2020  						Header: dnsmessage.ResourceHeader{
  2021  							Name:   dnsmessage.MustNewName("good.golang.org."),
  2022  							Type:   dnsmessage.TypeMX,
  2023  							Class:  dnsmessage.ClassINET,
  2024  							Length: 4,
  2025  						},
  2026  						Body: &dnsmessage.MXResource{
  2027  							MX: dnsmessage.MustNewName("good.golang.org."),
  2028  						},
  2029  					},
  2030  				)
  2031  			case dnsmessage.TypeNS:
  2032  				r.Answers = append(r.Answers,
  2033  					dnsmessage.Resource{
  2034  						Header: dnsmessage.ResourceHeader{
  2035  							Name:   dnsmessage.MustNewName("<html>.golang.org."),
  2036  							Type:   dnsmessage.TypeNS,
  2037  							Class:  dnsmessage.ClassINET,
  2038  							Length: 4,
  2039  						},
  2040  						Body: &dnsmessage.NSResource{
  2041  							NS: dnsmessage.MustNewName("<html>.golang.org."),
  2042  						},
  2043  					},
  2044  					dnsmessage.Resource{
  2045  						Header: dnsmessage.ResourceHeader{
  2046  							Name:   dnsmessage.MustNewName("good.golang.org."),
  2047  							Type:   dnsmessage.TypeNS,
  2048  							Class:  dnsmessage.ClassINET,
  2049  							Length: 4,
  2050  						},
  2051  						Body: &dnsmessage.NSResource{
  2052  							NS: dnsmessage.MustNewName("good.golang.org."),
  2053  						},
  2054  					},
  2055  				)
  2056  			case dnsmessage.TypePTR:
  2057  				r.Answers = append(r.Answers,
  2058  					dnsmessage.Resource{
  2059  						Header: dnsmessage.ResourceHeader{
  2060  							Name:   dnsmessage.MustNewName("<html>.golang.org."),
  2061  							Type:   dnsmessage.TypePTR,
  2062  							Class:  dnsmessage.ClassINET,
  2063  							Length: 4,
  2064  						},
  2065  						Body: &dnsmessage.PTRResource{
  2066  							PTR: dnsmessage.MustNewName("<html>.golang.org."),
  2067  						},
  2068  					},
  2069  					dnsmessage.Resource{
  2070  						Header: dnsmessage.ResourceHeader{
  2071  							Name:   dnsmessage.MustNewName("good.golang.org."),
  2072  							Type:   dnsmessage.TypePTR,
  2073  							Class:  dnsmessage.ClassINET,
  2074  							Length: 4,
  2075  						},
  2076  						Body: &dnsmessage.PTRResource{
  2077  							PTR: dnsmessage.MustNewName("good.golang.org."),
  2078  						},
  2079  					},
  2080  				)
  2081  			}
  2082  			return r, nil
  2083  		},
  2084  	}
  2085  
  2086  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  2087  	// Change the default resolver to match our manipulated resolver
  2088  	originalDefault := DefaultResolver
  2089  	DefaultResolver = &r
  2090  	defer func() { DefaultResolver = originalDefault }()
  2091  	// Redirect host file lookups.
  2092  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
  2093  	hostsFilePath = "testdata/hosts"
  2094  
  2095  	tests := []struct {
  2096  		name string
  2097  		f    func(*testing.T)
  2098  	}{
  2099  		{
  2100  			name: "CNAME",
  2101  			f: func(t *testing.T) {
  2102  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
  2103  				_, err := r.LookupCNAME(context.Background(), "golang.org")
  2104  				if err.Error() != expectedErr.Error() {
  2105  					t.Fatalf("unexpected error: %s", err)
  2106  				}
  2107  				_, err = LookupCNAME("golang.org")
  2108  				if err.Error() != expectedErr.Error() {
  2109  					t.Fatalf("unexpected error: %s", err)
  2110  				}
  2111  			},
  2112  		},
  2113  		{
  2114  			name: "SRV (bad record)",
  2115  			f: func(t *testing.T) {
  2116  				expected := []*SRV{
  2117  					{
  2118  						Target: "good.golang.org.",
  2119  					},
  2120  				}
  2121  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
  2122  				_, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
  2123  				if err.Error() != expectedErr.Error() {
  2124  					t.Fatalf("unexpected error: %s", err)
  2125  				}
  2126  				if !reflect.DeepEqual(records, expected) {
  2127  					t.Error("Unexpected record set")
  2128  				}
  2129  				_, records, err = LookupSRV("target", "tcp", "golang.org")
  2130  				if err.Error() != expectedErr.Error() {
  2131  					t.Errorf("unexpected error: %s", err)
  2132  				}
  2133  				if !reflect.DeepEqual(records, expected) {
  2134  					t.Error("Unexpected record set")
  2135  				}
  2136  			},
  2137  		},
  2138  		{
  2139  			name: "SRV (bad header)",
  2140  			f: func(t *testing.T) {
  2141  				_, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
  2142  				if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
  2143  					t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
  2144  				}
  2145  				_, _, err = LookupSRV("hdr", "tcp", "golang.org.")
  2146  				if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
  2147  					t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
  2148  				}
  2149  			},
  2150  		},
  2151  		{
  2152  			name: "MX",
  2153  			f: func(t *testing.T) {
  2154  				expected := []*MX{
  2155  					{
  2156  						Host: "good.golang.org.",
  2157  					},
  2158  				}
  2159  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
  2160  				records, err := r.LookupMX(context.Background(), "golang.org")
  2161  				if err.Error() != expectedErr.Error() {
  2162  					t.Fatalf("unexpected error: %s", err)
  2163  				}
  2164  				if !reflect.DeepEqual(records, expected) {
  2165  					t.Error("Unexpected record set")
  2166  				}
  2167  				records, err = LookupMX("golang.org")
  2168  				if err.Error() != expectedErr.Error() {
  2169  					t.Fatalf("unexpected error: %s", err)
  2170  				}
  2171  				if !reflect.DeepEqual(records, expected) {
  2172  					t.Error("Unexpected record set")
  2173  				}
  2174  			},
  2175  		},
  2176  		{
  2177  			name: "NS",
  2178  			f: func(t *testing.T) {
  2179  				expected := []*NS{
  2180  					{
  2181  						Host: "good.golang.org.",
  2182  					},
  2183  				}
  2184  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
  2185  				records, err := r.LookupNS(context.Background(), "golang.org")
  2186  				if err.Error() != expectedErr.Error() {
  2187  					t.Fatalf("unexpected error: %s", err)
  2188  				}
  2189  				if !reflect.DeepEqual(records, expected) {
  2190  					t.Error("Unexpected record set")
  2191  				}
  2192  				records, err = LookupNS("golang.org")
  2193  				if err.Error() != expectedErr.Error() {
  2194  					t.Fatalf("unexpected error: %s", err)
  2195  				}
  2196  				if !reflect.DeepEqual(records, expected) {
  2197  					t.Error("Unexpected record set")
  2198  				}
  2199  			},
  2200  		},
  2201  		{
  2202  			name: "Addr",
  2203  			f: func(t *testing.T) {
  2204  				expected := []string{"good.golang.org."}
  2205  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
  2206  				records, err := r.LookupAddr(context.Background(), "192.0.2.42")
  2207  				if err.Error() != expectedErr.Error() {
  2208  					t.Fatalf("unexpected error: %s", err)
  2209  				}
  2210  				if !reflect.DeepEqual(records, expected) {
  2211  					t.Error("Unexpected record set")
  2212  				}
  2213  				records, err = LookupAddr("192.0.2.42")
  2214  				if err.Error() != expectedErr.Error() {
  2215  					t.Fatalf("unexpected error: %s", err)
  2216  				}
  2217  				if !reflect.DeepEqual(records, expected) {
  2218  					t.Error("Unexpected record set")
  2219  				}
  2220  			},
  2221  		},
  2222  	}
  2223  
  2224  	for _, tc := range tests {
  2225  		t.Run(tc.name, tc.f)
  2226  	}
  2227  
  2228  }
  2229  
  2230  func TestNullMX(t *testing.T) {
  2231  	fake := fakeDNSServer{
  2232  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2233  			r := dnsmessage.Message{
  2234  				Header: dnsmessage.Header{
  2235  					ID:       q.Header.ID,
  2236  					Response: true,
  2237  					RCode:    dnsmessage.RCodeSuccess,
  2238  				},
  2239  				Questions: q.Questions,
  2240  				Answers: []dnsmessage.Resource{
  2241  					{
  2242  						Header: dnsmessage.ResourceHeader{
  2243  							Name:  q.Questions[0].Name,
  2244  							Type:  dnsmessage.TypeMX,
  2245  							Class: dnsmessage.ClassINET,
  2246  						},
  2247  						Body: &dnsmessage.MXResource{
  2248  							MX: dnsmessage.MustNewName("."),
  2249  						},
  2250  					},
  2251  				},
  2252  			}
  2253  			return r, nil
  2254  		},
  2255  	}
  2256  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  2257  	rrset, err := r.LookupMX(context.Background(), "golang.org")
  2258  	if err != nil {
  2259  		t.Fatalf("LookupMX: %v", err)
  2260  	}
  2261  	if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) {
  2262  		records := []string{}
  2263  		for _, rr := range rrset {
  2264  			records = append(records, fmt.Sprintf("%v", rr))
  2265  		}
  2266  		t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
  2267  	}
  2268  }
  2269  
  2270  func TestRootNS(t *testing.T) {
  2271  	// See https://golang.org/issue/45715.
  2272  	fake := fakeDNSServer{
  2273  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2274  			r := dnsmessage.Message{
  2275  				Header: dnsmessage.Header{
  2276  					ID:       q.Header.ID,
  2277  					Response: true,
  2278  					RCode:    dnsmessage.RCodeSuccess,
  2279  				},
  2280  				Questions: q.Questions,
  2281  				Answers: []dnsmessage.Resource{
  2282  					{
  2283  						Header: dnsmessage.ResourceHeader{
  2284  							Name:  q.Questions[0].Name,
  2285  							Type:  dnsmessage.TypeNS,
  2286  							Class: dnsmessage.ClassINET,
  2287  						},
  2288  						Body: &dnsmessage.NSResource{
  2289  							NS: dnsmessage.MustNewName("i.root-servers.net."),
  2290  						},
  2291  					},
  2292  				},
  2293  			}
  2294  			return r, nil
  2295  		},
  2296  	}
  2297  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  2298  	rrset, err := r.LookupNS(context.Background(), ".")
  2299  	if err != nil {
  2300  		t.Fatalf("LookupNS: %v", err)
  2301  	}
  2302  	if want := []*NS{&NS{Host: "i.root-servers.net."}}; !reflect.DeepEqual(rrset, want) {
  2303  		records := []string{}
  2304  		for _, rr := range rrset {
  2305  			records = append(records, fmt.Sprintf("%v", rr))
  2306  		}
  2307  		t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
  2308  	}
  2309  }
  2310  
  2311  func TestGoLookupIPCNAMEOrderHostsAliasesFilesOnlyMode(t *testing.T) {
  2312  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
  2313  	hostsFilePath = "testdata/aliases"
  2314  	mode := hostLookupFiles
  2315  
  2316  	for _, v := range lookupStaticHostAliasesTest {
  2317  		testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
  2318  	}
  2319  }
  2320  
  2321  func TestGoLookupIPCNAMEOrderHostsAliasesFilesDNSMode(t *testing.T) {
  2322  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
  2323  	hostsFilePath = "testdata/aliases"
  2324  	mode := hostLookupFilesDNS
  2325  
  2326  	for _, v := range lookupStaticHostAliasesTest {
  2327  		testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
  2328  	}
  2329  }
  2330  
  2331  var goLookupIPCNAMEOrderDNSFilesModeTests = []struct {
  2332  	lookup, res string
  2333  }{
  2334  	// 127.0.1.1
  2335  	{"invalid.invalid", "invalid.test"},
  2336  }
  2337  
  2338  func TestGoLookupIPCNAMEOrderHostsAliasesDNSFilesMode(t *testing.T) {
  2339  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
  2340  	hostsFilePath = "testdata/aliases"
  2341  	mode := hostLookupDNSFiles
  2342  
  2343  	for _, v := range goLookupIPCNAMEOrderDNSFilesModeTests {
  2344  		testGoLookupIPCNAMEOrderHostsAliases(t, mode, v.lookup, absDomainName(v.res))
  2345  	}
  2346  }
  2347  
  2348  func testGoLookupIPCNAMEOrderHostsAliases(t *testing.T, mode hostLookupOrder, lookup, lookupRes string) {
  2349  	fake := fakeDNSServer{
  2350  		rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2351  			var answers []dnsmessage.Resource
  2352  
  2353  			if mode != hostLookupDNSFiles {
  2354  				t.Fatal("received unexpected DNS query")
  2355  			}
  2356  
  2357  			return dnsmessage.Message{
  2358  				Header: dnsmessage.Header{
  2359  					ID:       q.Header.ID,
  2360  					Response: true,
  2361  				},
  2362  				Questions: []dnsmessage.Question{q.Questions[0]},
  2363  				Answers:   answers,
  2364  			}, nil
  2365  		},
  2366  	}
  2367  
  2368  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
  2369  	ins := []string{lookup, absDomainName(lookup), strings.ToLower(lookup), strings.ToUpper(lookup)}
  2370  	for _, in := range ins {
  2371  		_, res, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", in, mode, nil)
  2372  		if err != nil {
  2373  			t.Errorf("expected err == nil, but got error: %v", err)
  2374  		}
  2375  		if res.String() != lookupRes {
  2376  			t.Errorf("goLookupIPCNAMEOrder(%v): got %v, want %v", in, res, lookupRes)
  2377  		}
  2378  	}
  2379  }
  2380  
  2381  // Test that we advertise support for a larger DNS packet size.
  2382  // This isn't a great test as it just tests the dnsmessage package
  2383  // against itself.
  2384  func TestDNSPacketSize(t *testing.T) {
  2385  	fake := fakeDNSServer{
  2386  		rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2387  			if len(q.Additionals) == 0 {
  2388  				t.Error("missing EDNS record")
  2389  			} else if opt, ok := q.Additionals[0].Body.(*dnsmessage.OPTResource); !ok {
  2390  				t.Errorf("additional record type %T, expected OPTResource", q.Additionals[0])
  2391  			} else if len(opt.Options) != 0 {
  2392  				t.Errorf("found %d Options, expected none", len(opt.Options))
  2393  			} else {
  2394  				got := int(q.Additionals[0].Header.Class)
  2395  				t.Logf("EDNS packet size == %d", got)
  2396  				if got != maxDNSPacketSize {
  2397  					t.Errorf("EDNS packet size == %d, want %d", got, maxDNSPacketSize)
  2398  				}
  2399  			}
  2400  
  2401  			// Hand back a dummy answer to verify that
  2402  			// LookupIPAddr completes.
  2403  			r := dnsmessage.Message{
  2404  				Header: dnsmessage.Header{
  2405  					ID:       q.Header.ID,
  2406  					Response: true,
  2407  					RCode:    dnsmessage.RCodeSuccess,
  2408  				},
  2409  				Questions: q.Questions,
  2410  			}
  2411  			if q.Questions[0].Type == dnsmessage.TypeA {
  2412  				r.Answers = []dnsmessage.Resource{
  2413  					{
  2414  						Header: dnsmessage.ResourceHeader{
  2415  							Name:   q.Questions[0].Name,
  2416  							Type:   dnsmessage.TypeA,
  2417  							Class:  dnsmessage.ClassINET,
  2418  							Length: 4,
  2419  						},
  2420  						Body: &dnsmessage.AResource{
  2421  							A: TestAddr,
  2422  						},
  2423  					},
  2424  				}
  2425  			}
  2426  			return r, nil
  2427  		},
  2428  	}
  2429  
  2430  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
  2431  	if _, err := r.LookupIPAddr(context.Background(), "go.dev"); err != nil {
  2432  		t.Errorf("lookup failed: %v", err)
  2433  	}
  2434  }
  2435  
  2436  func TestLongDNSNames(t *testing.T) {
  2437  	const longDNSsuffix = ".go.dev."
  2438  	const longDNSsuffixNoEndingDot = ".go.dev"
  2439  
  2440  	var longDNSPrefix = strings.Repeat("verylongdomainlabel.", 20)
  2441  
  2442  	var longDNSNamesTests = []struct {
  2443  		req  string
  2444  		fail bool
  2445  	}{
  2446  		{req: longDNSPrefix[:255-len(longDNSsuffix)] + longDNSsuffix, fail: true},
  2447  		{req: longDNSPrefix[:254-len(longDNSsuffix)] + longDNSsuffix},
  2448  		{req: longDNSPrefix[:253-len(longDNSsuffix)] + longDNSsuffix},
  2449  
  2450  		{req: longDNSPrefix[:253-len(longDNSsuffixNoEndingDot)] + longDNSsuffixNoEndingDot},
  2451  		{req: longDNSPrefix[:254-len(longDNSsuffixNoEndingDot)] + longDNSsuffixNoEndingDot, fail: true},
  2452  	}
  2453  
  2454  	fake := fakeDNSServer{
  2455  		rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2456  			r := dnsmessage.Message{
  2457  				Header: dnsmessage.Header{
  2458  					ID:       q.Header.ID,
  2459  					Response: true,
  2460  					RCode:    dnsmessage.RCodeSuccess,
  2461  				},
  2462  				Questions: q.Questions,
  2463  				Answers: []dnsmessage.Resource{
  2464  					{
  2465  						Header: dnsmessage.ResourceHeader{
  2466  							Name:  q.Questions[0].Name,
  2467  							Type:  q.Questions[0].Type,
  2468  							Class: dnsmessage.ClassINET,
  2469  						},
  2470  					},
  2471  				},
  2472  			}
  2473  
  2474  			switch q.Questions[0].Type {
  2475  			case dnsmessage.TypeA:
  2476  				r.Answers[0].Body = &dnsmessage.AResource{A: TestAddr}
  2477  			case dnsmessage.TypeAAAA:
  2478  				r.Answers[0].Body = &dnsmessage.AAAAResource{AAAA: TestAddr6}
  2479  			case dnsmessage.TypeTXT:
  2480  				r.Answers[0].Body = &dnsmessage.TXTResource{TXT: []string{"."}}
  2481  			case dnsmessage.TypeMX:
  2482  				r.Answers[0].Body = &dnsmessage.MXResource{
  2483  					MX: dnsmessage.MustNewName("go.dev."),
  2484  				}
  2485  			case dnsmessage.TypeNS:
  2486  				r.Answers[0].Body = &dnsmessage.NSResource{
  2487  					NS: dnsmessage.MustNewName("go.dev."),
  2488  				}
  2489  			case dnsmessage.TypeSRV:
  2490  				r.Answers[0].Body = &dnsmessage.SRVResource{
  2491  					Target: dnsmessage.MustNewName("go.dev."),
  2492  				}
  2493  			case dnsmessage.TypeCNAME:
  2494  				r.Answers[0].Body = &dnsmessage.CNAMEResource{
  2495  					CNAME: dnsmessage.MustNewName("fake.cname."),
  2496  				}
  2497  			default:
  2498  				panic("unknown dnsmessage type")
  2499  			}
  2500  
  2501  			return r, nil
  2502  		},
  2503  	}
  2504  
  2505  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
  2506  
  2507  	methodTests := []string{"CNAME", "Host", "IP", "IPAddr", "MX", "NS", "NetIP", "SRV", "TXT"}
  2508  	query := func(t string, req string) error {
  2509  		switch t {
  2510  		case "CNAME":
  2511  			_, err := r.LookupCNAME(context.Background(), req)
  2512  			return err
  2513  		case "Host":
  2514  			_, err := r.LookupHost(context.Background(), req)
  2515  			return err
  2516  		case "IP":
  2517  			_, err := r.LookupIP(context.Background(), "ip", req)
  2518  			return err
  2519  		case "IPAddr":
  2520  			_, err := r.LookupIPAddr(context.Background(), req)
  2521  			return err
  2522  		case "MX":
  2523  			_, err := r.LookupMX(context.Background(), req)
  2524  			return err
  2525  		case "NS":
  2526  			_, err := r.LookupNS(context.Background(), req)
  2527  			return err
  2528  		case "NetIP":
  2529  			_, err := r.LookupNetIP(context.Background(), "ip", req)
  2530  			return err
  2531  		case "SRV":
  2532  			const service = "service"
  2533  			const proto = "proto"
  2534  			req = req[len(service)+len(proto)+4:]
  2535  			_, _, err := r.LookupSRV(context.Background(), service, proto, req)
  2536  			return err
  2537  		case "TXT":
  2538  			_, err := r.LookupTXT(context.Background(), req)
  2539  			return err
  2540  		}
  2541  		panic("unknown query method")
  2542  	}
  2543  
  2544  	for i, v := range longDNSNamesTests {
  2545  		for _, testName := range methodTests {
  2546  			err := query(testName, v.req)
  2547  			if v.fail {
  2548  				if err == nil {
  2549  					t.Errorf("%v: Lookup%v: unexpected success", i, testName)
  2550  					break
  2551  				}
  2552  
  2553  				expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: v.req, IsNotFound: true}
  2554  				var dnsErr *DNSError
  2555  				errors.As(err, &dnsErr)
  2556  				if dnsErr == nil || *dnsErr != expectedErr {
  2557  					t.Errorf("%v: Lookup%v: unexpected error: %v", i, testName, err)
  2558  				}
  2559  				break
  2560  			}
  2561  			if err != nil {
  2562  				t.Errorf("%v: Lookup%v: unexpected error: %v", i, testName, err)
  2563  			}
  2564  		}
  2565  	}
  2566  }
  2567  
  2568  func TestDNSTrustAD(t *testing.T) {
  2569  	fake := fakeDNSServer{
  2570  		rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2571  			if q.Questions[0].Name.String() == "notrustad.go.dev." && q.Header.AuthenticData {
  2572  				t.Error("unexpected AD bit")
  2573  			}
  2574  
  2575  			if q.Questions[0].Name.String() == "trustad.go.dev." && !q.Header.AuthenticData {
  2576  				t.Error("expected AD bit")
  2577  			}
  2578  
  2579  			r := dnsmessage.Message{
  2580  				Header: dnsmessage.Header{
  2581  					ID:       q.Header.ID,
  2582  					Response: true,
  2583  					RCode:    dnsmessage.RCodeSuccess,
  2584  				},
  2585  				Questions: q.Questions,
  2586  			}
  2587  			if q.Questions[0].Type == dnsmessage.TypeA {
  2588  				r.Answers = []dnsmessage.Resource{
  2589  					{
  2590  						Header: dnsmessage.ResourceHeader{
  2591  							Name:   q.Questions[0].Name,
  2592  							Type:   dnsmessage.TypeA,
  2593  							Class:  dnsmessage.ClassINET,
  2594  							Length: 4,
  2595  						},
  2596  						Body: &dnsmessage.AResource{
  2597  							A: TestAddr,
  2598  						},
  2599  					},
  2600  				}
  2601  			}
  2602  
  2603  			return r, nil
  2604  		}}
  2605  
  2606  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
  2607  
  2608  	conf, err := newResolvConfTest()
  2609  	if err != nil {
  2610  		t.Fatal(err)
  2611  	}
  2612  	defer conf.teardown()
  2613  
  2614  	err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1"})
  2615  	if err != nil {
  2616  		t.Fatal(err)
  2617  	}
  2618  
  2619  	if _, err := r.LookupIPAddr(context.Background(), "notrustad.go.dev"); err != nil {
  2620  		t.Errorf("lookup failed: %v", err)
  2621  	}
  2622  
  2623  	err = conf.writeAndUpdate([]string{"nameserver 127.0.0.1", "options trust-ad"})
  2624  	if err != nil {
  2625  		t.Fatal(err)
  2626  	}
  2627  
  2628  	if _, err := r.LookupIPAddr(context.Background(), "trustad.go.dev"); err != nil {
  2629  		t.Errorf("lookup failed: %v", err)
  2630  	}
  2631  }
  2632  
  2633  func TestDNSConfigNoReload(t *testing.T) {
  2634  	r := &Resolver{PreferGo: true, Dial: func(ctx context.Context, network, address string) (Conn, error) {
  2635  		if address != "192.0.2.1:53" {
  2636  			return nil, errors.New("configuration unexpectedly changed")
  2637  		}
  2638  		return fakeDNSServerSuccessful.DialContext(ctx, network, address)
  2639  	}}
  2640  
  2641  	conf, err := newResolvConfTest()
  2642  	if err != nil {
  2643  		t.Fatal(err)
  2644  	}
  2645  	defer conf.teardown()
  2646  
  2647  	err = conf.writeAndUpdateWithLastCheckedTime([]string{"nameserver 192.0.2.1", "options no-reload"}, time.Now().Add(-time.Hour))
  2648  	if err != nil {
  2649  		t.Fatal(err)
  2650  	}
  2651  
  2652  	if _, err = r.LookupHost(context.Background(), "go.dev"); err != nil {
  2653  		t.Fatal(err)
  2654  	}
  2655  
  2656  	err = conf.write([]string{"nameserver 192.0.2.200"})
  2657  	if err != nil {
  2658  		t.Fatal(err)
  2659  	}
  2660  
  2661  	if _, err = r.LookupHost(context.Background(), "go.dev"); err != nil {
  2662  		t.Fatal(err)
  2663  	}
  2664  }
  2665  
  2666  func TestLookupOrderFilesNoSuchHost(t *testing.T) {
  2667  	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
  2668  	if runtime.GOOS != "openbsd" {
  2669  		defer setSystemNSS(getSystemNSS(), 0)
  2670  		setSystemNSS(nssStr(t, "hosts: files"), time.Hour)
  2671  	}
  2672  
  2673  	conf, err := newResolvConfTest()
  2674  	if err != nil {
  2675  		t.Fatal(err)
  2676  	}
  2677  	defer conf.teardown()
  2678  
  2679  	resolvConf := dnsConfig{servers: defaultNS}
  2680  	if runtime.GOOS == "openbsd" {
  2681  		// Set error to ErrNotExist, so that the hostLookupOrder
  2682  		// returns hostLookupFiles for openbsd.
  2683  		resolvConf.err = os.ErrNotExist
  2684  	}
  2685  
  2686  	if !conf.forceUpdateConf(&resolvConf, time.Now().Add(time.Hour)) {
  2687  		t.Fatal("failed to update resolv config")
  2688  	}
  2689  
  2690  	tmpFile := filepath.Join(t.TempDir(), "hosts")
  2691  	if err := os.WriteFile(tmpFile, []byte{}, 0660); err != nil {
  2692  		t.Fatal(err)
  2693  	}
  2694  	hostsFilePath = tmpFile
  2695  
  2696  	const testName = "test.invalid"
  2697  
  2698  	order, _ := systemConf().hostLookupOrder(DefaultResolver, testName)
  2699  	if order != hostLookupFiles {
  2700  		// skip test for systems which do not return hostLookupFiles
  2701  		t.Skipf("hostLookupOrder did not return hostLookupFiles")
  2702  	}
  2703  
  2704  	var lookupTests = []struct {
  2705  		name   string
  2706  		lookup func(name string) error
  2707  	}{
  2708  		{
  2709  			name: "Host",
  2710  			lookup: func(name string) error {
  2711  				_, err = DefaultResolver.LookupHost(context.Background(), name)
  2712  				return err
  2713  			},
  2714  		},
  2715  		{
  2716  			name: "IP",
  2717  			lookup: func(name string) error {
  2718  				_, err = DefaultResolver.LookupIP(context.Background(), "ip", name)
  2719  				return err
  2720  			},
  2721  		},
  2722  		{
  2723  			name: "IPAddr",
  2724  			lookup: func(name string) error {
  2725  				_, err = DefaultResolver.LookupIPAddr(context.Background(), name)
  2726  				return err
  2727  			},
  2728  		},
  2729  		{
  2730  			name: "NetIP",
  2731  			lookup: func(name string) error {
  2732  				_, err = DefaultResolver.LookupNetIP(context.Background(), "ip", name)
  2733  				return err
  2734  			},
  2735  		},
  2736  	}
  2737  
  2738  	for _, v := range lookupTests {
  2739  		err := v.lookup(testName)
  2740  
  2741  		if err == nil {
  2742  			t.Errorf("Lookup%v: unexpected success", v.name)
  2743  			continue
  2744  		}
  2745  
  2746  		expectedErr := DNSError{Err: errNoSuchHost.Error(), Name: testName, IsNotFound: true}
  2747  		var dnsErr *DNSError
  2748  		errors.As(err, &dnsErr)
  2749  		if dnsErr == nil || *dnsErr != expectedErr {
  2750  			t.Errorf("Lookup%v: unexpected error: %v", v.name, err)
  2751  		}
  2752  	}
  2753  }
  2754  
  2755  func TestExtendedRCode(t *testing.T) {
  2756  	fake := fakeDNSServer{
  2757  		rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
  2758  			fraudSuccessCode := dnsmessage.RCodeSuccess | 1<<10
  2759  
  2760  			var edns0Hdr dnsmessage.ResourceHeader
  2761  			edns0Hdr.SetEDNS0(maxDNSPacketSize, fraudSuccessCode, false)
  2762  
  2763  			return dnsmessage.Message{
  2764  				Header: dnsmessage.Header{
  2765  					ID:       q.Header.ID,
  2766  					Response: true,
  2767  					RCode:    fraudSuccessCode,
  2768  				},
  2769  				Questions: []dnsmessage.Question{q.Questions[0]},
  2770  				Additionals: []dnsmessage.Resource{{
  2771  					Header: edns0Hdr,
  2772  					Body:   &dnsmessage.OPTResource{},
  2773  				}},
  2774  			}, nil
  2775  		},
  2776  	}
  2777  
  2778  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
  2779  	_, _, err := r.tryOneName(context.Background(), getSystemDNSConfig(), "go.dev.", dnsmessage.TypeA)
  2780  	var dnsErr *DNSError
  2781  	if !(errors.As(err, &dnsErr) && dnsErr.Err == errServerMisbehaving.Error()) {
  2782  		t.Fatalf("r.tryOneName(): unexpected error: %v", err)
  2783  	}
  2784  }
  2785  

View as plain text