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

View as plain text