...

Source file src/net/dnsclient_unix_test.go

Documentation: net

		 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
		 6  // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
		 7  
		 8  package net
		 9  
		10  import (
		11  	"context"
		12  	"errors"
		13  	"fmt"
		14  	"os"
		15  	"path"
		16  	"reflect"
		17  	"strings"
		18  	"sync"
		19  	"sync/atomic"
		20  	"testing"
		21  	"time"
		22  
		23  	"golang.org/x/net/dns/dnsmessage"
		24  )
		25  
		26  var goResolver = Resolver{PreferGo: true}
		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)
		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  // See RFC 6761 for further information about the reserved, pseudo
		96  // domain names.
		97  var specialDomainNameTests = []struct {
		98  	question dnsmessage.Question
		99  	rcode		dnsmessage.RCode
	 100  }{
	 101  	// Name resolution APIs and libraries should not recognize the
	 102  	// followings as special.
	 103  	{mustQuestion("1.0.168.192.in-addr.arpa.", dnsmessage.TypePTR, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
	 104  	{mustQuestion("test.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
	 105  	{mustQuestion("example.com.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeSuccess},
	 106  
	 107  	// Name resolution APIs and libraries should recognize the
	 108  	// followings as special and should not send any queries.
	 109  	// Though, we test those names here for verifying negative
	 110  	// answers at DNS query-response interaction level.
	 111  	{mustQuestion("localhost.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
	 112  	{mustQuestion("invalid.", dnsmessage.TypeALL, dnsmessage.ClassINET), dnsmessage.RCodeNameError},
	 113  }
	 114  
	 115  func TestSpecialDomainName(t *testing.T) {
	 116  	fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	 117  		r := dnsmessage.Message{
	 118  			Header: dnsmessage.Header{
	 119  				ID:			 q.ID,
	 120  				Response: true,
	 121  			},
	 122  			Questions: q.Questions,
	 123  		}
	 124  
	 125  		switch q.Questions[0].Name.String() {
	 126  		case "example.com.":
	 127  			r.Header.RCode = dnsmessage.RCodeSuccess
	 128  		default:
	 129  			r.Header.RCode = dnsmessage.RCodeNameError
	 130  		}
	 131  
	 132  		return r, nil
	 133  	}}
	 134  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	 135  	server := "8.8.8.8:53"
	 136  	for _, tt := range specialDomainNameTests {
	 137  		ctx, cancel := context.WithCancel(context.Background())
	 138  		defer cancel()
	 139  		_, h, err := r.exchange(ctx, server, tt.question, 3*time.Second, useUDPOrTCP)
	 140  		if err != nil {
	 141  			t.Error(err)
	 142  			continue
	 143  		}
	 144  		if h.RCode != tt.rcode {
	 145  			t.Errorf("got %v from %v; want %v", h.RCode, server, tt.rcode)
	 146  			continue
	 147  		}
	 148  	}
	 149  }
	 150  
	 151  // Issue 13705: don't try to resolve onion addresses, etc
	 152  func TestAvoidDNSName(t *testing.T) {
	 153  	tests := []struct {
	 154  		name	string
	 155  		avoid bool
	 156  	}{
	 157  		{"foo.com", false},
	 158  		{"foo.com.", false},
	 159  
	 160  		{"foo.onion.", true},
	 161  		{"foo.onion", true},
	 162  		{"foo.ONION", true},
	 163  		{"foo.ONION.", true},
	 164  
	 165  		// But do resolve *.local address; Issue 16739
	 166  		{"foo.local.", false},
	 167  		{"foo.local", false},
	 168  		{"foo.LOCAL", false},
	 169  		{"foo.LOCAL.", false},
	 170  
	 171  		{"", true}, // will be rejected earlier too
	 172  
	 173  		// Without stuff before onion/local, they're fine to
	 174  		// use DNS. With a search path,
	 175  		// "onion.vegetables.com" can use DNS. Without a
	 176  		// search path (or with a trailing dot), the queries
	 177  		// are just kinda useless, but don't reveal anything
	 178  		// private.
	 179  		{"local", false},
	 180  		{"onion", false},
	 181  		{"local.", false},
	 182  		{"onion.", false},
	 183  	}
	 184  	for _, tt := range tests {
	 185  		got := avoidDNS(tt.name)
	 186  		if got != tt.avoid {
	 187  			t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
	 188  		}
	 189  	}
	 190  }
	 191  
	 192  var fakeDNSServerSuccessful = fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	 193  	r := dnsmessage.Message{
	 194  		Header: dnsmessage.Header{
	 195  			ID:			 q.ID,
	 196  			Response: true,
	 197  		},
	 198  		Questions: q.Questions,
	 199  	}
	 200  	if len(q.Questions) == 1 && q.Questions[0].Type == dnsmessage.TypeA {
	 201  		r.Answers = []dnsmessage.Resource{
	 202  			{
	 203  				Header: dnsmessage.ResourceHeader{
	 204  					Name:	 q.Questions[0].Name,
	 205  					Type:	 dnsmessage.TypeA,
	 206  					Class:	dnsmessage.ClassINET,
	 207  					Length: 4,
	 208  				},
	 209  				Body: &dnsmessage.AResource{
	 210  					A: TestAddr,
	 211  				},
	 212  			},
	 213  		}
	 214  	}
	 215  	return r, nil
	 216  }}
	 217  
	 218  // Issue 13705: don't try to resolve onion addresses, etc
	 219  func TestLookupTorOnion(t *testing.T) {
	 220  	defer dnsWaitGroup.Wait()
	 221  	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
	 222  	addrs, err := r.LookupIPAddr(context.Background(), "foo.onion")
	 223  	if err != nil {
	 224  		t.Fatalf("lookup = %v; want nil", err)
	 225  	}
	 226  	if len(addrs) > 0 {
	 227  		t.Errorf("unexpected addresses: %v", addrs)
	 228  	}
	 229  }
	 230  
	 231  type resolvConfTest struct {
	 232  	dir	string
	 233  	path string
	 234  	*resolverConfig
	 235  }
	 236  
	 237  func newResolvConfTest() (*resolvConfTest, error) {
	 238  	dir, err := os.MkdirTemp("", "go-resolvconftest")
	 239  	if err != nil {
	 240  		return nil, err
	 241  	}
	 242  	conf := &resolvConfTest{
	 243  		dir:						dir,
	 244  		path:					 path.Join(dir, "resolv.conf"),
	 245  		resolverConfig: &resolvConf,
	 246  	}
	 247  	conf.initOnce.Do(conf.init)
	 248  	return conf, nil
	 249  }
	 250  
	 251  func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
	 252  	f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	 253  	if err != nil {
	 254  		return err
	 255  	}
	 256  	if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
	 257  		f.Close()
	 258  		return err
	 259  	}
	 260  	f.Close()
	 261  	if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil {
	 262  		return err
	 263  	}
	 264  	return nil
	 265  }
	 266  
	 267  func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error {
	 268  	dnsConf := dnsReadConfig(name)
	 269  	conf.mu.Lock()
	 270  	conf.dnsConfig = dnsConf
	 271  	conf.mu.Unlock()
	 272  	for i := 0; i < 5; i++ {
	 273  		if conf.tryAcquireSema() {
	 274  			conf.lastChecked = lastChecked
	 275  			conf.releaseSema()
	 276  			return nil
	 277  		}
	 278  	}
	 279  	return fmt.Errorf("tryAcquireSema for %s failed", name)
	 280  }
	 281  
	 282  func (conf *resolvConfTest) servers() []string {
	 283  	conf.mu.RLock()
	 284  	servers := conf.dnsConfig.servers
	 285  	conf.mu.RUnlock()
	 286  	return servers
	 287  }
	 288  
	 289  func (conf *resolvConfTest) teardown() error {
	 290  	err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
	 291  	os.RemoveAll(conf.dir)
	 292  	return err
	 293  }
	 294  
	 295  var updateResolvConfTests = []struct {
	 296  	name		string	 // query name
	 297  	lines	 []string // resolver configuration lines
	 298  	servers []string // expected name servers
	 299  }{
	 300  	{
	 301  		name:		"golang.org",
	 302  		lines:	 []string{"nameserver 8.8.8.8"},
	 303  		servers: []string{"8.8.8.8:53"},
	 304  	},
	 305  	{
	 306  		name:		"",
	 307  		lines:	 nil, // an empty resolv.conf should use defaultNS as name servers
	 308  		servers: defaultNS,
	 309  	},
	 310  	{
	 311  		name:		"www.example.com",
	 312  		lines:	 []string{"nameserver 8.8.4.4"},
	 313  		servers: []string{"8.8.4.4:53"},
	 314  	},
	 315  }
	 316  
	 317  func TestUpdateResolvConf(t *testing.T) {
	 318  	defer dnsWaitGroup.Wait()
	 319  
	 320  	r := Resolver{PreferGo: true, Dial: fakeDNSServerSuccessful.DialContext}
	 321  
	 322  	conf, err := newResolvConfTest()
	 323  	if err != nil {
	 324  		t.Fatal(err)
	 325  	}
	 326  	defer conf.teardown()
	 327  
	 328  	for i, tt := range updateResolvConfTests {
	 329  		if err := conf.writeAndUpdate(tt.lines); err != nil {
	 330  			t.Error(err)
	 331  			continue
	 332  		}
	 333  		if tt.name != "" {
	 334  			var wg sync.WaitGroup
	 335  			const N = 10
	 336  			wg.Add(N)
	 337  			for j := 0; j < N; j++ {
	 338  				go func(name string) {
	 339  					defer wg.Done()
	 340  					ips, err := r.LookupIPAddr(context.Background(), name)
	 341  					if err != nil {
	 342  						t.Error(err)
	 343  						return
	 344  					}
	 345  					if len(ips) == 0 {
	 346  						t.Errorf("no records for %s", name)
	 347  						return
	 348  					}
	 349  				}(tt.name)
	 350  			}
	 351  			wg.Wait()
	 352  		}
	 353  		servers := conf.servers()
	 354  		if !reflect.DeepEqual(servers, tt.servers) {
	 355  			t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
	 356  			continue
	 357  		}
	 358  	}
	 359  }
	 360  
	 361  var goLookupIPWithResolverConfigTests = []struct {
	 362  	name	string
	 363  	lines []string // resolver configuration lines
	 364  	error
	 365  	a, aaaa bool // whether response contains A, AAAA-record
	 366  }{
	 367  	// no records, transport timeout
	 368  	{
	 369  		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
	 370  		[]string{
	 371  			"options timeout:1 attempts:1",
	 372  			"nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
	 373  		},
	 374  		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
	 375  		false, false,
	 376  	},
	 377  
	 378  	// no records, non-existent domain
	 379  	{
	 380  		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
	 381  		[]string{
	 382  			"options timeout:3 attempts:1",
	 383  			"nameserver 8.8.8.8",
	 384  		},
	 385  		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
	 386  		false, false,
	 387  	},
	 388  
	 389  	// a few A records, no AAAA records
	 390  	{
	 391  		"ipv4.google.com.",
	 392  		[]string{
	 393  			"nameserver 8.8.8.8",
	 394  			"nameserver 2001:4860:4860::8888",
	 395  		},
	 396  		nil,
	 397  		true, false,
	 398  	},
	 399  	{
	 400  		"ipv4.google.com",
	 401  		[]string{
	 402  			"domain golang.org",
	 403  			"nameserver 2001:4860:4860::8888",
	 404  			"nameserver 8.8.8.8",
	 405  		},
	 406  		nil,
	 407  		true, false,
	 408  	},
	 409  	{
	 410  		"ipv4.google.com",
	 411  		[]string{
	 412  			"search x.golang.org y.golang.org",
	 413  			"nameserver 2001:4860:4860::8888",
	 414  			"nameserver 8.8.8.8",
	 415  		},
	 416  		nil,
	 417  		true, false,
	 418  	},
	 419  
	 420  	// no A records, a few AAAA records
	 421  	{
	 422  		"ipv6.google.com.",
	 423  		[]string{
	 424  			"nameserver 2001:4860:4860::8888",
	 425  			"nameserver 8.8.8.8",
	 426  		},
	 427  		nil,
	 428  		false, true,
	 429  	},
	 430  	{
	 431  		"ipv6.google.com",
	 432  		[]string{
	 433  			"domain golang.org",
	 434  			"nameserver 8.8.8.8",
	 435  			"nameserver 2001:4860:4860::8888",
	 436  		},
	 437  		nil,
	 438  		false, true,
	 439  	},
	 440  	{
	 441  		"ipv6.google.com",
	 442  		[]string{
	 443  			"search x.golang.org y.golang.org",
	 444  			"nameserver 8.8.8.8",
	 445  			"nameserver 2001:4860:4860::8888",
	 446  		},
	 447  		nil,
	 448  		false, true,
	 449  	},
	 450  
	 451  	// both A and AAAA records
	 452  	{
	 453  		"hostname.as112.net", // see RFC 7534
	 454  		[]string{
	 455  			"domain golang.org",
	 456  			"nameserver 2001:4860:4860::8888",
	 457  			"nameserver 8.8.8.8",
	 458  		},
	 459  		nil,
	 460  		true, true,
	 461  	},
	 462  	{
	 463  		"hostname.as112.net", // see RFC 7534
	 464  		[]string{
	 465  			"search x.golang.org y.golang.org",
	 466  			"nameserver 2001:4860:4860::8888",
	 467  			"nameserver 8.8.8.8",
	 468  		},
	 469  		nil,
	 470  		true, true,
	 471  	},
	 472  }
	 473  
	 474  func TestGoLookupIPWithResolverConfig(t *testing.T) {
	 475  	defer dnsWaitGroup.Wait()
	 476  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	 477  		switch s {
	 478  		case "[2001:4860:4860::8888]:53", "8.8.8.8:53":
	 479  			break
	 480  		default:
	 481  			time.Sleep(10 * time.Millisecond)
	 482  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
	 483  		}
	 484  		r := dnsmessage.Message{
	 485  			Header: dnsmessage.Header{
	 486  				ID:			 q.ID,
	 487  				Response: true,
	 488  			},
	 489  			Questions: q.Questions,
	 490  		}
	 491  		for _, question := range q.Questions {
	 492  			switch question.Type {
	 493  			case dnsmessage.TypeA:
	 494  				switch question.Name.String() {
	 495  				case "hostname.as112.net.":
	 496  					break
	 497  				case "ipv4.google.com.":
	 498  					r.Answers = append(r.Answers, dnsmessage.Resource{
	 499  						Header: dnsmessage.ResourceHeader{
	 500  							Name:	 q.Questions[0].Name,
	 501  							Type:	 dnsmessage.TypeA,
	 502  							Class:	dnsmessage.ClassINET,
	 503  							Length: 4,
	 504  						},
	 505  						Body: &dnsmessage.AResource{
	 506  							A: TestAddr,
	 507  						},
	 508  					})
	 509  				default:
	 510  
	 511  				}
	 512  			case dnsmessage.TypeAAAA:
	 513  				switch question.Name.String() {
	 514  				case "hostname.as112.net.":
	 515  					break
	 516  				case "ipv6.google.com.":
	 517  					r.Answers = append(r.Answers, dnsmessage.Resource{
	 518  						Header: dnsmessage.ResourceHeader{
	 519  							Name:	 q.Questions[0].Name,
	 520  							Type:	 dnsmessage.TypeAAAA,
	 521  							Class:	dnsmessage.ClassINET,
	 522  							Length: 16,
	 523  						},
	 524  						Body: &dnsmessage.AAAAResource{
	 525  							AAAA: TestAddr6,
	 526  						},
	 527  					})
	 528  				}
	 529  			}
	 530  		}
	 531  		return r, nil
	 532  	}}
	 533  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	 534  
	 535  	conf, err := newResolvConfTest()
	 536  	if err != nil {
	 537  		t.Fatal(err)
	 538  	}
	 539  	defer conf.teardown()
	 540  
	 541  	for _, tt := range goLookupIPWithResolverConfigTests {
	 542  		if err := conf.writeAndUpdate(tt.lines); err != nil {
	 543  			t.Error(err)
	 544  			continue
	 545  		}
	 546  		addrs, err := r.LookupIPAddr(context.Background(), tt.name)
	 547  		if err != nil {
	 548  			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) {
	 549  				t.Errorf("got %v; want %v", err, tt.error)
	 550  			}
	 551  			continue
	 552  		}
	 553  		if len(addrs) == 0 {
	 554  			t.Errorf("no records for %s", tt.name)
	 555  		}
	 556  		if !tt.a && !tt.aaaa && len(addrs) > 0 {
	 557  			t.Errorf("unexpected %v for %s", addrs, tt.name)
	 558  		}
	 559  		for _, addr := range addrs {
	 560  			if !tt.a && addr.IP.To4() != nil {
	 561  				t.Errorf("got %v; must not be IPv4 address", addr)
	 562  			}
	 563  			if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
	 564  				t.Errorf("got %v; must not be IPv6 address", addr)
	 565  			}
	 566  		}
	 567  	}
	 568  }
	 569  
	 570  // Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
	 571  func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
	 572  	defer dnsWaitGroup.Wait()
	 573  
	 574  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, tm time.Time) (dnsmessage.Message, error) {
	 575  		r := dnsmessage.Message{
	 576  			Header: dnsmessage.Header{
	 577  				ID:			 q.ID,
	 578  				Response: true,
	 579  			},
	 580  			Questions: q.Questions,
	 581  		}
	 582  		return r, nil
	 583  	}}
	 584  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	 585  
	 586  	// Add a config that simulates no dns servers being available.
	 587  	conf, err := newResolvConfTest()
	 588  	if err != nil {
	 589  		t.Fatal(err)
	 590  	}
	 591  	defer conf.teardown()
	 592  
	 593  	if err := conf.writeAndUpdate([]string{}); err != nil {
	 594  		t.Fatal(err)
	 595  	}
	 596  	// Redirect host file lookups.
	 597  	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
	 598  	testHookHostsPath = "testdata/hosts"
	 599  
	 600  	for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
	 601  		name := fmt.Sprintf("order %v", order)
	 602  
	 603  		// First ensure that we get an error when contacting a non-existent host.
	 604  		_, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "notarealhost", order)
	 605  		if err == nil {
	 606  			t.Errorf("%s: expected error while looking up name not in hosts file", name)
	 607  			continue
	 608  		}
	 609  
	 610  		// Now check that we get an address when the name appears in the hosts file.
	 611  		addrs, _, err := r.goLookupIPCNAMEOrder(context.Background(), "ip", "thor", order) // entry is in "testdata/hosts"
	 612  		if err != nil {
	 613  			t.Errorf("%s: expected to successfully lookup host entry", name)
	 614  			continue
	 615  		}
	 616  		if len(addrs) != 1 {
	 617  			t.Errorf("%s: expected exactly one result, but got %v", name, addrs)
	 618  			continue
	 619  		}
	 620  		if got, want := addrs[0].String(), "127.1.1.1"; got != want {
	 621  			t.Errorf("%s: address doesn't match expectation. got %v, want %v", name, got, want)
	 622  		}
	 623  	}
	 624  }
	 625  
	 626  // Issue 12712.
	 627  // When using search domains, return the error encountered
	 628  // querying the original name instead of an error encountered
	 629  // querying a generated name.
	 630  func TestErrorForOriginalNameWhenSearching(t *testing.T) {
	 631  	defer dnsWaitGroup.Wait()
	 632  
	 633  	const fqdn = "doesnotexist.domain"
	 634  
	 635  	conf, err := newResolvConfTest()
	 636  	if err != nil {
	 637  		t.Fatal(err)
	 638  	}
	 639  	defer conf.teardown()
	 640  
	 641  	if err := conf.writeAndUpdate([]string{"search servfail"}); err != nil {
	 642  		t.Fatal(err)
	 643  	}
	 644  
	 645  	fake := fakeDNSServer{rh: func(_, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	 646  		r := dnsmessage.Message{
	 647  			Header: dnsmessage.Header{
	 648  				ID:			 q.ID,
	 649  				Response: true,
	 650  			},
	 651  			Questions: q.Questions,
	 652  		}
	 653  
	 654  		switch q.Questions[0].Name.String() {
	 655  		case fqdn + ".servfail.":
	 656  			r.Header.RCode = dnsmessage.RCodeServerFailure
	 657  		default:
	 658  			r.Header.RCode = dnsmessage.RCodeNameError
	 659  		}
	 660  
	 661  		return r, nil
	 662  	}}
	 663  
	 664  	cases := []struct {
	 665  		strictErrors bool
	 666  		wantErr			*DNSError
	 667  	}{
	 668  		{true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}},
	 669  		{false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error(), IsNotFound: true}},
	 670  	}
	 671  	for _, tt := range cases {
	 672  		r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext}
	 673  		_, err = r.LookupIPAddr(context.Background(), fqdn)
	 674  		if err == nil {
	 675  			t.Fatal("expected an error")
	 676  		}
	 677  
	 678  		want := tt.wantErr
	 679  		if err, ok := err.(*DNSError); !ok || err.Name != want.Name || err.Err != want.Err || err.IsTemporary != want.IsTemporary {
	 680  			t.Errorf("got %v; want %v", err, want)
	 681  		}
	 682  	}
	 683  }
	 684  
	 685  // Issue 15434. If a name server gives a lame referral, continue to the next.
	 686  func TestIgnoreLameReferrals(t *testing.T) {
	 687  	defer dnsWaitGroup.Wait()
	 688  
	 689  	conf, err := newResolvConfTest()
	 690  	if err != nil {
	 691  		t.Fatal(err)
	 692  	}
	 693  	defer conf.teardown()
	 694  
	 695  	if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
	 696  		"nameserver 192.0.2.2"}); err != nil {
	 697  		t.Fatal(err)
	 698  	}
	 699  
	 700  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	 701  		t.Log(s, q)
	 702  		r := dnsmessage.Message{
	 703  			Header: dnsmessage.Header{
	 704  				ID:			 q.ID,
	 705  				Response: true,
	 706  			},
	 707  			Questions: q.Questions,
	 708  		}
	 709  
	 710  		if s == "192.0.2.2:53" {
	 711  			r.Header.RecursionAvailable = true
	 712  			if q.Questions[0].Type == dnsmessage.TypeA {
	 713  				r.Answers = []dnsmessage.Resource{
	 714  					{
	 715  						Header: dnsmessage.ResourceHeader{
	 716  							Name:	 q.Questions[0].Name,
	 717  							Type:	 dnsmessage.TypeA,
	 718  							Class:	dnsmessage.ClassINET,
	 719  							Length: 4,
	 720  						},
	 721  						Body: &dnsmessage.AResource{
	 722  							A: TestAddr,
	 723  						},
	 724  					},
	 725  				}
	 726  			}
	 727  		}
	 728  
	 729  		return r, nil
	 730  	}}
	 731  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	 732  
	 733  	addrs, err := r.LookupIPAddr(context.Background(), "www.golang.org")
	 734  	if err != nil {
	 735  		t.Fatal(err)
	 736  	}
	 737  
	 738  	if got := len(addrs); got != 1 {
	 739  		t.Fatalf("got %d addresses, want 1", got)
	 740  	}
	 741  
	 742  	if got, want := addrs[0].String(), "192.0.2.1"; got != want {
	 743  		t.Fatalf("got address %v, want %v", got, want)
	 744  	}
	 745  }
	 746  
	 747  func BenchmarkGoLookupIP(b *testing.B) {
	 748  	testHookUninstaller.Do(uninstallTestHooks)
	 749  	ctx := context.Background()
	 750  	b.ReportAllocs()
	 751  
	 752  	for i := 0; i < b.N; i++ {
	 753  		goResolver.LookupIPAddr(ctx, "www.example.com")
	 754  	}
	 755  }
	 756  
	 757  func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
	 758  	testHookUninstaller.Do(uninstallTestHooks)
	 759  	ctx := context.Background()
	 760  	b.ReportAllocs()
	 761  
	 762  	for i := 0; i < b.N; i++ {
	 763  		goResolver.LookupIPAddr(ctx, "some.nonexistent")
	 764  	}
	 765  }
	 766  
	 767  func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
	 768  	testHookUninstaller.Do(uninstallTestHooks)
	 769  
	 770  	conf, err := newResolvConfTest()
	 771  	if err != nil {
	 772  		b.Fatal(err)
	 773  	}
	 774  	defer conf.teardown()
	 775  
	 776  	lines := []string{
	 777  		"nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
	 778  		"nameserver 8.8.8.8",
	 779  	}
	 780  	if err := conf.writeAndUpdate(lines); err != nil {
	 781  		b.Fatal(err)
	 782  	}
	 783  	ctx := context.Background()
	 784  	b.ReportAllocs()
	 785  
	 786  	for i := 0; i < b.N; i++ {
	 787  		goResolver.LookupIPAddr(ctx, "www.example.com")
	 788  	}
	 789  }
	 790  
	 791  type fakeDNSServer struct {
	 792  	rh				func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error)
	 793  	alwaysTCP bool
	 794  }
	 795  
	 796  func (server *fakeDNSServer) DialContext(_ context.Context, n, s string) (Conn, error) {
	 797  	if server.alwaysTCP || n == "tcp" || n == "tcp4" || n == "tcp6" {
	 798  		return &fakeDNSConn{tcp: true, server: server, n: n, s: s}, nil
	 799  	}
	 800  	return &fakeDNSPacketConn{fakeDNSConn: fakeDNSConn{tcp: false, server: server, n: n, s: s}}, nil
	 801  }
	 802  
	 803  type fakeDNSConn struct {
	 804  	Conn
	 805  	tcp		bool
	 806  	server *fakeDNSServer
	 807  	n			string
	 808  	s			string
	 809  	q			dnsmessage.Message
	 810  	t			time.Time
	 811  	buf		[]byte
	 812  }
	 813  
	 814  func (f *fakeDNSConn) Close() error {
	 815  	return nil
	 816  }
	 817  
	 818  func (f *fakeDNSConn) Read(b []byte) (int, error) {
	 819  	if len(f.buf) > 0 {
	 820  		n := copy(b, f.buf)
	 821  		f.buf = f.buf[n:]
	 822  		return n, nil
	 823  	}
	 824  
	 825  	resp, err := f.server.rh(f.n, f.s, f.q, f.t)
	 826  	if err != nil {
	 827  		return 0, err
	 828  	}
	 829  
	 830  	bb := make([]byte, 2, 514)
	 831  	bb, err = resp.AppendPack(bb)
	 832  	if err != nil {
	 833  		return 0, fmt.Errorf("cannot marshal DNS message: %v", err)
	 834  	}
	 835  
	 836  	if f.tcp {
	 837  		l := len(bb) - 2
	 838  		bb[0] = byte(l >> 8)
	 839  		bb[1] = byte(l)
	 840  		f.buf = bb
	 841  		return f.Read(b)
	 842  	}
	 843  
	 844  	bb = bb[2:]
	 845  	if len(b) < len(bb) {
	 846  		return 0, errors.New("read would fragment DNS message")
	 847  	}
	 848  
	 849  	copy(b, bb)
	 850  	return len(bb), nil
	 851  }
	 852  
	 853  func (f *fakeDNSConn) Write(b []byte) (int, error) {
	 854  	if f.tcp && len(b) >= 2 {
	 855  		b = b[2:]
	 856  	}
	 857  	if f.q.Unpack(b) != nil {
	 858  		return 0, fmt.Errorf("cannot unmarshal DNS message fake %s (%d)", f.n, len(b))
	 859  	}
	 860  	return len(b), nil
	 861  }
	 862  
	 863  func (f *fakeDNSConn) SetDeadline(t time.Time) error {
	 864  	f.t = t
	 865  	return nil
	 866  }
	 867  
	 868  type fakeDNSPacketConn struct {
	 869  	PacketConn
	 870  	fakeDNSConn
	 871  }
	 872  
	 873  func (f *fakeDNSPacketConn) SetDeadline(t time.Time) error {
	 874  	return f.fakeDNSConn.SetDeadline(t)
	 875  }
	 876  
	 877  func (f *fakeDNSPacketConn) Close() error {
	 878  	return f.fakeDNSConn.Close()
	 879  }
	 880  
	 881  // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
	 882  func TestIgnoreDNSForgeries(t *testing.T) {
	 883  	c, s := Pipe()
	 884  	go func() {
	 885  		b := make([]byte, maxDNSPacketSize)
	 886  		n, err := s.Read(b)
	 887  		if err != nil {
	 888  			t.Error(err)
	 889  			return
	 890  		}
	 891  
	 892  		var msg dnsmessage.Message
	 893  		if msg.Unpack(b[:n]) != nil {
	 894  			t.Error("invalid DNS query:", err)
	 895  			return
	 896  		}
	 897  
	 898  		s.Write([]byte("garbage DNS response packet"))
	 899  
	 900  		msg.Header.Response = true
	 901  		msg.Header.ID++ // make invalid ID
	 902  
	 903  		if b, err = msg.Pack(); err != nil {
	 904  			t.Error("failed to pack DNS response:", err)
	 905  			return
	 906  		}
	 907  		s.Write(b)
	 908  
	 909  		msg.Header.ID-- // restore original ID
	 910  		msg.Answers = []dnsmessage.Resource{
	 911  			{
	 912  				Header: dnsmessage.ResourceHeader{
	 913  					Name:	 mustNewName("www.example.com."),
	 914  					Type:	 dnsmessage.TypeA,
	 915  					Class:	dnsmessage.ClassINET,
	 916  					Length: 4,
	 917  				},
	 918  				Body: &dnsmessage.AResource{
	 919  					A: TestAddr,
	 920  				},
	 921  			},
	 922  		}
	 923  
	 924  		b, err = msg.Pack()
	 925  		if err != nil {
	 926  			t.Error("failed to pack DNS response:", err)
	 927  			return
	 928  		}
	 929  		s.Write(b)
	 930  	}()
	 931  
	 932  	msg := dnsmessage.Message{
	 933  		Header: dnsmessage.Header{
	 934  			ID: 42,
	 935  		},
	 936  		Questions: []dnsmessage.Question{
	 937  			{
	 938  				Name:	mustNewName("www.example.com."),
	 939  				Type:	dnsmessage.TypeA,
	 940  				Class: dnsmessage.ClassINET,
	 941  			},
	 942  		},
	 943  	}
	 944  
	 945  	b, err := msg.Pack()
	 946  	if err != nil {
	 947  		t.Fatal("Pack failed:", err)
	 948  	}
	 949  
	 950  	p, _, err := dnsPacketRoundTrip(c, 42, msg.Questions[0], b)
	 951  	if err != nil {
	 952  		t.Fatalf("dnsPacketRoundTrip failed: %v", err)
	 953  	}
	 954  
	 955  	p.SkipAllQuestions()
	 956  	as, err := p.AllAnswers()
	 957  	if err != nil {
	 958  		t.Fatal("AllAnswers failed:", err)
	 959  	}
	 960  	if got := as[0].Body.(*dnsmessage.AResource).A; got != TestAddr {
	 961  		t.Errorf("got address %v, want %v", got, TestAddr)
	 962  	}
	 963  }
	 964  
	 965  // Issue 16865. If a name server times out, continue to the next.
	 966  func TestRetryTimeout(t *testing.T) {
	 967  	defer dnsWaitGroup.Wait()
	 968  
	 969  	conf, err := newResolvConfTest()
	 970  	if err != nil {
	 971  		t.Fatal(err)
	 972  	}
	 973  	defer conf.teardown()
	 974  
	 975  	testConf := []string{
	 976  		"nameserver 192.0.2.1", // the one that will timeout
	 977  		"nameserver 192.0.2.2",
	 978  	}
	 979  	if err := conf.writeAndUpdate(testConf); err != nil {
	 980  		t.Fatal(err)
	 981  	}
	 982  
	 983  	var deadline0 time.Time
	 984  
	 985  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
	 986  		t.Log(s, q, deadline)
	 987  
	 988  		if deadline.IsZero() {
	 989  			t.Error("zero deadline")
	 990  		}
	 991  
	 992  		if s == "192.0.2.1:53" {
	 993  			deadline0 = deadline
	 994  			time.Sleep(10 * time.Millisecond)
	 995  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
	 996  		}
	 997  
	 998  		if deadline.Equal(deadline0) {
	 999  			t.Error("deadline didn't change")
	1000  		}
	1001  
	1002  		return mockTXTResponse(q), nil
	1003  	}}
	1004  	r := &Resolver{PreferGo: true, Dial: fake.DialContext}
	1005  
	1006  	_, err = r.LookupTXT(context.Background(), "www.golang.org")
	1007  	if err != nil {
	1008  		t.Fatal(err)
	1009  	}
	1010  
	1011  	if deadline0.IsZero() {
	1012  		t.Error("deadline0 still zero", deadline0)
	1013  	}
	1014  }
	1015  
	1016  func TestRotate(t *testing.T) {
	1017  	// without rotation, always uses the first server
	1018  	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"})
	1019  
	1020  	// with rotation, rotates through back to first
	1021  	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"})
	1022  }
	1023  
	1024  func testRotate(t *testing.T, rotate bool, nameservers, wantServers []string) {
	1025  	defer dnsWaitGroup.Wait()
	1026  
	1027  	conf, err := newResolvConfTest()
	1028  	if err != nil {
	1029  		t.Fatal(err)
	1030  	}
	1031  	defer conf.teardown()
	1032  
	1033  	var confLines []string
	1034  	for _, ns := range nameservers {
	1035  		confLines = append(confLines, "nameserver "+ns)
	1036  	}
	1037  	if rotate {
	1038  		confLines = append(confLines, "options rotate")
	1039  	}
	1040  
	1041  	if err := conf.writeAndUpdate(confLines); err != nil {
	1042  		t.Fatal(err)
	1043  	}
	1044  
	1045  	var usedServers []string
	1046  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
	1047  		usedServers = append(usedServers, s)
	1048  		return mockTXTResponse(q), nil
	1049  	}}
	1050  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1051  
	1052  	// len(nameservers) + 1 to allow rotation to get back to start
	1053  	for i := 0; i < len(nameservers)+1; i++ {
	1054  		if _, err := r.LookupTXT(context.Background(), "www.golang.org"); err != nil {
	1055  			t.Fatal(err)
	1056  		}
	1057  	}
	1058  
	1059  	if !reflect.DeepEqual(usedServers, wantServers) {
	1060  		t.Errorf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
	1061  	}
	1062  }
	1063  
	1064  func mockTXTResponse(q dnsmessage.Message) dnsmessage.Message {
	1065  	r := dnsmessage.Message{
	1066  		Header: dnsmessage.Header{
	1067  			ID:								 q.ID,
	1068  			Response:					 true,
	1069  			RecursionAvailable: true,
	1070  		},
	1071  		Questions: q.Questions,
	1072  		Answers: []dnsmessage.Resource{
	1073  			{
	1074  				Header: dnsmessage.ResourceHeader{
	1075  					Name:	q.Questions[0].Name,
	1076  					Type:	dnsmessage.TypeTXT,
	1077  					Class: dnsmessage.ClassINET,
	1078  				},
	1079  				Body: &dnsmessage.TXTResource{
	1080  					TXT: []string{"ok"},
	1081  				},
	1082  			},
	1083  		},
	1084  	}
	1085  
	1086  	return r
	1087  }
	1088  
	1089  // Issue 17448. With StrictErrors enabled, temporary errors should make
	1090  // LookupIP fail rather than return a partial result.
	1091  func TestStrictErrorsLookupIP(t *testing.T) {
	1092  	defer dnsWaitGroup.Wait()
	1093  
	1094  	conf, err := newResolvConfTest()
	1095  	if err != nil {
	1096  		t.Fatal(err)
	1097  	}
	1098  	defer conf.teardown()
	1099  
	1100  	confData := []string{
	1101  		"nameserver 192.0.2.53",
	1102  		"search x.golang.org y.golang.org",
	1103  	}
	1104  	if err := conf.writeAndUpdate(confData); err != nil {
	1105  		t.Fatal(err)
	1106  	}
	1107  
	1108  	const name = "test-issue19592"
	1109  	const server = "192.0.2.53:53"
	1110  	const searchX = "test-issue19592.x.golang.org."
	1111  	const searchY = "test-issue19592.y.golang.org."
	1112  	const ip4 = "192.0.2.1"
	1113  	const ip6 = "2001:db8::1"
	1114  
	1115  	type resolveWhichEnum int
	1116  	const (
	1117  		resolveOK resolveWhichEnum = iota
	1118  		resolveOpError
	1119  		resolveServfail
	1120  		resolveTimeout
	1121  	)
	1122  
	1123  	makeTempError := func(err string) error {
	1124  		return &DNSError{
	1125  			Err:				 err,
	1126  			Name:				name,
	1127  			Server:			server,
	1128  			IsTemporary: true,
	1129  		}
	1130  	}
	1131  	makeTimeout := func() error {
	1132  		return &DNSError{
	1133  			Err:			 os.ErrDeadlineExceeded.Error(),
	1134  			Name:			name,
	1135  			Server:		server,
	1136  			IsTimeout: true,
	1137  		}
	1138  	}
	1139  	makeNxDomain := func() error {
	1140  		return &DNSError{
	1141  			Err:				errNoSuchHost.Error(),
	1142  			Name:			 name,
	1143  			Server:		 server,
	1144  			IsNotFound: true,
	1145  		}
	1146  	}
	1147  
	1148  	cases := []struct {
	1149  		desc					string
	1150  		resolveWhich	func(quest dnsmessage.Question) resolveWhichEnum
	1151  		wantStrictErr error
	1152  		wantLaxErr		error
	1153  		wantIPs			 []string
	1154  	}{
	1155  		{
	1156  			desc: "No errors",
	1157  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1158  				return resolveOK
	1159  			},
	1160  			wantIPs: []string{ip4, ip6},
	1161  		},
	1162  		{
	1163  			desc: "searchX error fails in strict mode",
	1164  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1165  				if quest.Name.String() == searchX {
	1166  					return resolveTimeout
	1167  				}
	1168  				return resolveOK
	1169  			},
	1170  			wantStrictErr: makeTimeout(),
	1171  			wantIPs:			 []string{ip4, ip6},
	1172  		},
	1173  		{
	1174  			desc: "searchX IPv4-only timeout fails in strict mode",
	1175  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1176  				if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeA {
	1177  					return resolveTimeout
	1178  				}
	1179  				return resolveOK
	1180  			},
	1181  			wantStrictErr: makeTimeout(),
	1182  			wantIPs:			 []string{ip4, ip6},
	1183  		},
	1184  		{
	1185  			desc: "searchX IPv6-only servfail fails in strict mode",
	1186  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1187  				if quest.Name.String() == searchX && quest.Type == dnsmessage.TypeAAAA {
	1188  					return resolveServfail
	1189  				}
	1190  				return resolveOK
	1191  			},
	1192  			wantStrictErr: makeTempError("server misbehaving"),
	1193  			wantIPs:			 []string{ip4, ip6},
	1194  		},
	1195  		{
	1196  			desc: "searchY error always fails",
	1197  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1198  				if quest.Name.String() == searchY {
	1199  					return resolveTimeout
	1200  				}
	1201  				return resolveOK
	1202  			},
	1203  			wantStrictErr: makeTimeout(),
	1204  			wantLaxErr:		makeNxDomain(), // This one reaches the "test." FQDN.
	1205  		},
	1206  		{
	1207  			desc: "searchY IPv4-only socket error fails in strict mode",
	1208  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1209  				if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeA {
	1210  					return resolveOpError
	1211  				}
	1212  				return resolveOK
	1213  			},
	1214  			wantStrictErr: makeTempError("write: socket on fire"),
	1215  			wantIPs:			 []string{ip6},
	1216  		},
	1217  		{
	1218  			desc: "searchY IPv6-only timeout fails in strict mode",
	1219  			resolveWhich: func(quest dnsmessage.Question) resolveWhichEnum {
	1220  				if quest.Name.String() == searchY && quest.Type == dnsmessage.TypeAAAA {
	1221  					return resolveTimeout
	1222  				}
	1223  				return resolveOK
	1224  			},
	1225  			wantStrictErr: makeTimeout(),
	1226  			wantIPs:			 []string{ip4},
	1227  		},
	1228  	}
	1229  
	1230  	for i, tt := range cases {
	1231  		fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
	1232  			t.Log(s, q)
	1233  
	1234  			switch tt.resolveWhich(q.Questions[0]) {
	1235  			case resolveOK:
	1236  				// Handle below.
	1237  			case resolveOpError:
	1238  				return dnsmessage.Message{}, &OpError{Op: "write", Err: fmt.Errorf("socket on fire")}
	1239  			case resolveServfail:
	1240  				return dnsmessage.Message{
	1241  					Header: dnsmessage.Header{
	1242  						ID:			 q.ID,
	1243  						Response: true,
	1244  						RCode:		dnsmessage.RCodeServerFailure,
	1245  					},
	1246  					Questions: q.Questions,
	1247  				}, nil
	1248  			case resolveTimeout:
	1249  				return dnsmessage.Message{}, os.ErrDeadlineExceeded
	1250  			default:
	1251  				t.Fatal("Impossible resolveWhich")
	1252  			}
	1253  
	1254  			switch q.Questions[0].Name.String() {
	1255  			case searchX, name + ".":
	1256  				// Return NXDOMAIN to utilize the search list.
	1257  				return dnsmessage.Message{
	1258  					Header: dnsmessage.Header{
	1259  						ID:			 q.ID,
	1260  						Response: true,
	1261  						RCode:		dnsmessage.RCodeNameError,
	1262  					},
	1263  					Questions: q.Questions,
	1264  				}, nil
	1265  			case searchY:
	1266  				// Return records below.
	1267  			default:
	1268  				return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
	1269  			}
	1270  
	1271  			r := dnsmessage.Message{
	1272  				Header: dnsmessage.Header{
	1273  					ID:			 q.ID,
	1274  					Response: true,
	1275  				},
	1276  				Questions: q.Questions,
	1277  			}
	1278  			switch q.Questions[0].Type {
	1279  			case dnsmessage.TypeA:
	1280  				r.Answers = []dnsmessage.Resource{
	1281  					{
	1282  						Header: dnsmessage.ResourceHeader{
	1283  							Name:	 q.Questions[0].Name,
	1284  							Type:	 dnsmessage.TypeA,
	1285  							Class:	dnsmessage.ClassINET,
	1286  							Length: 4,
	1287  						},
	1288  						Body: &dnsmessage.AResource{
	1289  							A: TestAddr,
	1290  						},
	1291  					},
	1292  				}
	1293  			case dnsmessage.TypeAAAA:
	1294  				r.Answers = []dnsmessage.Resource{
	1295  					{
	1296  						Header: dnsmessage.ResourceHeader{
	1297  							Name:	 q.Questions[0].Name,
	1298  							Type:	 dnsmessage.TypeAAAA,
	1299  							Class:	dnsmessage.ClassINET,
	1300  							Length: 16,
	1301  						},
	1302  						Body: &dnsmessage.AAAAResource{
	1303  							AAAA: TestAddr6,
	1304  						},
	1305  					},
	1306  				}
	1307  			default:
	1308  				return dnsmessage.Message{}, fmt.Errorf("Unexpected Type: %v", q.Questions[0].Type)
	1309  			}
	1310  			return r, nil
	1311  		}}
	1312  
	1313  		for _, strict := range []bool{true, false} {
	1314  			r := Resolver{PreferGo: true, StrictErrors: strict, Dial: fake.DialContext}
	1315  			ips, err := r.LookupIPAddr(context.Background(), name)
	1316  
	1317  			var wantErr error
	1318  			if strict {
	1319  				wantErr = tt.wantStrictErr
	1320  			} else {
	1321  				wantErr = tt.wantLaxErr
	1322  			}
	1323  			if !reflect.DeepEqual(err, wantErr) {
	1324  				t.Errorf("#%d (%s) strict=%v: got err %#v; want %#v", i, tt.desc, strict, err, wantErr)
	1325  			}
	1326  
	1327  			gotIPs := map[string]struct{}{}
	1328  			for _, ip := range ips {
	1329  				gotIPs[ip.String()] = struct{}{}
	1330  			}
	1331  			wantIPs := map[string]struct{}{}
	1332  			if wantErr == nil {
	1333  				for _, ip := range tt.wantIPs {
	1334  					wantIPs[ip] = struct{}{}
	1335  				}
	1336  			}
	1337  			if !reflect.DeepEqual(gotIPs, wantIPs) {
	1338  				t.Errorf("#%d (%s) strict=%v: got ips %v; want %v", i, tt.desc, strict, gotIPs, wantIPs)
	1339  			}
	1340  		}
	1341  	}
	1342  }
	1343  
	1344  // Issue 17448. With StrictErrors enabled, temporary errors should make
	1345  // LookupTXT stop walking the search list.
	1346  func TestStrictErrorsLookupTXT(t *testing.T) {
	1347  	defer dnsWaitGroup.Wait()
	1348  
	1349  	conf, err := newResolvConfTest()
	1350  	if err != nil {
	1351  		t.Fatal(err)
	1352  	}
	1353  	defer conf.teardown()
	1354  
	1355  	confData := []string{
	1356  		"nameserver 192.0.2.53",
	1357  		"search x.golang.org y.golang.org",
	1358  	}
	1359  	if err := conf.writeAndUpdate(confData); err != nil {
	1360  		t.Fatal(err)
	1361  	}
	1362  
	1363  	const name = "test"
	1364  	const server = "192.0.2.53:53"
	1365  	const searchX = "test.x.golang.org."
	1366  	const searchY = "test.y.golang.org."
	1367  	const txt = "Hello World"
	1368  
	1369  	fake := fakeDNSServer{rh: func(_, s string, q dnsmessage.Message, deadline time.Time) (dnsmessage.Message, error) {
	1370  		t.Log(s, q)
	1371  
	1372  		switch q.Questions[0].Name.String() {
	1373  		case searchX:
	1374  			return dnsmessage.Message{}, os.ErrDeadlineExceeded
	1375  		case searchY:
	1376  			return mockTXTResponse(q), nil
	1377  		default:
	1378  			return dnsmessage.Message{}, fmt.Errorf("Unexpected Name: %v", q.Questions[0].Name)
	1379  		}
	1380  	}}
	1381  
	1382  	for _, strict := range []bool{true, false} {
	1383  		r := Resolver{StrictErrors: strict, Dial: fake.DialContext}
	1384  		p, _, err := r.lookup(context.Background(), name, dnsmessage.TypeTXT)
	1385  		var wantErr error
	1386  		var wantRRs int
	1387  		if strict {
	1388  			wantErr = &DNSError{
	1389  				Err:			 os.ErrDeadlineExceeded.Error(),
	1390  				Name:			name,
	1391  				Server:		server,
	1392  				IsTimeout: true,
	1393  			}
	1394  		} else {
	1395  			wantRRs = 1
	1396  		}
	1397  		if !reflect.DeepEqual(err, wantErr) {
	1398  			t.Errorf("strict=%v: got err %#v; want %#v", strict, err, wantErr)
	1399  		}
	1400  		a, err := p.AllAnswers()
	1401  		if err != nil {
	1402  			a = nil
	1403  		}
	1404  		if len(a) != wantRRs {
	1405  			t.Errorf("strict=%v: got %v; want %v", strict, len(a), wantRRs)
	1406  		}
	1407  	}
	1408  }
	1409  
	1410  // Test for a race between uninstalling the test hooks and closing a
	1411  // socket connection. This used to fail when testing with -race.
	1412  func TestDNSGoroutineRace(t *testing.T) {
	1413  	defer dnsWaitGroup.Wait()
	1414  
	1415  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, t time.Time) (dnsmessage.Message, error) {
	1416  		time.Sleep(10 * time.Microsecond)
	1417  		return dnsmessage.Message{}, os.ErrDeadlineExceeded
	1418  	}}
	1419  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1420  
	1421  	// The timeout here is less than the timeout used by the server,
	1422  	// so the goroutine started to query the (fake) server will hang
	1423  	// around after this test is done if we don't call dnsWaitGroup.Wait.
	1424  	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Microsecond)
	1425  	defer cancel()
	1426  	_, err := r.LookupIPAddr(ctx, "where.are.they.now")
	1427  	if err == nil {
	1428  		t.Fatal("fake DNS lookup unexpectedly succeeded")
	1429  	}
	1430  }
	1431  
	1432  func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
	1433  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1434  
	1435  	resolvConf.mu.RLock()
	1436  	conf := resolvConf.dnsConfig
	1437  	resolvConf.mu.RUnlock()
	1438  
	1439  	ctx, cancel := context.WithCancel(context.Background())
	1440  	defer cancel()
	1441  
	1442  	_, _, err := r.tryOneName(ctx, conf, name, typ)
	1443  	return err
	1444  }
	1445  
	1446  // Issue 8434: verify that Temporary returns true on an error when rcode
	1447  // is SERVFAIL
	1448  func TestIssue8434(t *testing.T) {
	1449  	err := lookupWithFake(fakeDNSServer{
	1450  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1451  			return dnsmessage.Message{
	1452  				Header: dnsmessage.Header{
	1453  					ID:			 q.ID,
	1454  					Response: true,
	1455  					RCode:		dnsmessage.RCodeServerFailure,
	1456  				},
	1457  				Questions: q.Questions,
	1458  			}, nil
	1459  		},
	1460  	}, "golang.org.", dnsmessage.TypeALL)
	1461  	if err == nil {
	1462  		t.Fatal("expected an error")
	1463  	}
	1464  	if ne, ok := err.(Error); !ok {
	1465  		t.Fatalf("err = %#v; wanted something supporting net.Error", err)
	1466  	} else if !ne.Temporary() {
	1467  		t.Fatalf("Temporary = false for err = %#v; want Temporary == true", err)
	1468  	}
	1469  	if de, ok := err.(*DNSError); !ok {
	1470  		t.Fatalf("err = %#v; wanted a *net.DNSError", err)
	1471  	} else if !de.IsTemporary {
	1472  		t.Fatalf("IsTemporary = false for err = %#v; want IsTemporary == true", err)
	1473  	}
	1474  }
	1475  
	1476  func TestIssueNoSuchHostExists(t *testing.T) {
	1477  	err := lookupWithFake(fakeDNSServer{
	1478  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1479  			return dnsmessage.Message{
	1480  				Header: dnsmessage.Header{
	1481  					ID:			 q.ID,
	1482  					Response: true,
	1483  					RCode:		dnsmessage.RCodeNameError,
	1484  				},
	1485  				Questions: q.Questions,
	1486  			}, nil
	1487  		},
	1488  	}, "golang.org.", dnsmessage.TypeALL)
	1489  	if err == nil {
	1490  		t.Fatal("expected an error")
	1491  	}
	1492  	if _, ok := err.(Error); !ok {
	1493  		t.Fatalf("err = %#v; wanted something supporting net.Error", err)
	1494  	}
	1495  	if de, ok := err.(*DNSError); !ok {
	1496  		t.Fatalf("err = %#v; wanted a *net.DNSError", err)
	1497  	} else if !de.IsNotFound {
	1498  		t.Fatalf("IsNotFound = false for err = %#v; want IsNotFound == true", err)
	1499  	}
	1500  }
	1501  
	1502  // TestNoSuchHost verifies that tryOneName works correctly when the domain does
	1503  // not exist.
	1504  //
	1505  // Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host"
	1506  // and not "server misbehaving"
	1507  //
	1508  // Issue 25336: verify that NXDOMAIN errors fail fast.
	1509  //
	1510  // Issue 27525: verify that empty answers fail fast.
	1511  func TestNoSuchHost(t *testing.T) {
	1512  	tests := []struct {
	1513  		name string
	1514  		f		func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error)
	1515  	}{
	1516  		{
	1517  			"NXDOMAIN",
	1518  			func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1519  				return dnsmessage.Message{
	1520  					Header: dnsmessage.Header{
	1521  						ID:								 q.ID,
	1522  						Response:					 true,
	1523  						RCode:							dnsmessage.RCodeNameError,
	1524  						RecursionAvailable: false,
	1525  					},
	1526  					Questions: q.Questions,
	1527  				}, nil
	1528  			},
	1529  		},
	1530  		{
	1531  			"no answers",
	1532  			func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1533  				return dnsmessage.Message{
	1534  					Header: dnsmessage.Header{
	1535  						ID:								 q.ID,
	1536  						Response:					 true,
	1537  						RCode:							dnsmessage.RCodeSuccess,
	1538  						RecursionAvailable: false,
	1539  						Authoritative:			true,
	1540  					},
	1541  					Questions: q.Questions,
	1542  				}, nil
	1543  			},
	1544  		},
	1545  	}
	1546  
	1547  	for _, test := range tests {
	1548  		t.Run(test.name, func(t *testing.T) {
	1549  			lookups := 0
	1550  			err := lookupWithFake(fakeDNSServer{
	1551  				rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) {
	1552  					lookups++
	1553  					return test.f(n, s, q, d)
	1554  				},
	1555  			}, ".", dnsmessage.TypeALL)
	1556  
	1557  			if lookups != 1 {
	1558  				t.Errorf("got %d lookups, wanted 1", lookups)
	1559  			}
	1560  
	1561  			if err == nil {
	1562  				t.Fatal("expected an error")
	1563  			}
	1564  			de, ok := err.(*DNSError)
	1565  			if !ok {
	1566  				t.Fatalf("err = %#v; wanted a *net.DNSError", err)
	1567  			}
	1568  			if de.Err != errNoSuchHost.Error() {
	1569  				t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error())
	1570  			}
	1571  			if !de.IsNotFound {
	1572  				t.Fatalf("IsNotFound = %v wanted true", de.IsNotFound)
	1573  			}
	1574  		})
	1575  	}
	1576  }
	1577  
	1578  // Issue 26573: verify that Conns that don't implement PacketConn are treated
	1579  // as streams even when udp was requested.
	1580  func TestDNSDialTCP(t *testing.T) {
	1581  	fake := fakeDNSServer{
	1582  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1583  			r := dnsmessage.Message{
	1584  				Header: dnsmessage.Header{
	1585  					ID:			 q.Header.ID,
	1586  					Response: true,
	1587  					RCode:		dnsmessage.RCodeSuccess,
	1588  				},
	1589  				Questions: q.Questions,
	1590  			}
	1591  			return r, nil
	1592  		},
	1593  		alwaysTCP: true,
	1594  	}
	1595  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1596  	ctx := context.Background()
	1597  	_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useUDPOrTCP)
	1598  	if err != nil {
	1599  		t.Fatal("exhange failed:", err)
	1600  	}
	1601  }
	1602  
	1603  // Issue 27763: verify that two strings in one TXT record are concatenated.
	1604  func TestTXTRecordTwoStrings(t *testing.T) {
	1605  	fake := fakeDNSServer{
	1606  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1607  			r := dnsmessage.Message{
	1608  				Header: dnsmessage.Header{
	1609  					ID:			 q.Header.ID,
	1610  					Response: true,
	1611  					RCode:		dnsmessage.RCodeSuccess,
	1612  				},
	1613  				Questions: q.Questions,
	1614  				Answers: []dnsmessage.Resource{
	1615  					{
	1616  						Header: dnsmessage.ResourceHeader{
	1617  							Name:	q.Questions[0].Name,
	1618  							Type:	dnsmessage.TypeA,
	1619  							Class: dnsmessage.ClassINET,
	1620  						},
	1621  						Body: &dnsmessage.TXTResource{
	1622  							TXT: []string{"string1 ", "string2"},
	1623  						},
	1624  					},
	1625  					{
	1626  						Header: dnsmessage.ResourceHeader{
	1627  							Name:	q.Questions[0].Name,
	1628  							Type:	dnsmessage.TypeA,
	1629  							Class: dnsmessage.ClassINET,
	1630  						},
	1631  						Body: &dnsmessage.TXTResource{
	1632  							TXT: []string{"onestring"},
	1633  						},
	1634  					},
	1635  				},
	1636  			}
	1637  			return r, nil
	1638  		},
	1639  	}
	1640  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1641  	txt, err := r.lookupTXT(context.Background(), "golang.org")
	1642  	if err != nil {
	1643  		t.Fatal("LookupTXT failed:", err)
	1644  	}
	1645  	if want := 2; len(txt) != want {
	1646  		t.Fatalf("len(txt), got %d, want %d", len(txt), want)
	1647  	}
	1648  	if want := "string1 string2"; txt[0] != want {
	1649  		t.Errorf("txt[0], got %q, want %q", txt[0], want)
	1650  	}
	1651  	if want := "onestring"; txt[1] != want {
	1652  		t.Errorf("txt[1], got %q, want %q", txt[1], want)
	1653  	}
	1654  }
	1655  
	1656  // Issue 29644: support single-request resolv.conf option in pure Go resolver.
	1657  // The A and AAAA queries will be sent sequentially, not in parallel.
	1658  func TestSingleRequestLookup(t *testing.T) {
	1659  	defer dnsWaitGroup.Wait()
	1660  	var (
	1661  		firstcalled int32
	1662  		ipv4				int32 = 1
	1663  		ipv6				int32 = 2
	1664  	)
	1665  	fake := fakeDNSServer{rh: func(n, s string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1666  		r := dnsmessage.Message{
	1667  			Header: dnsmessage.Header{
	1668  				ID:			 q.ID,
	1669  				Response: true,
	1670  			},
	1671  			Questions: q.Questions,
	1672  		}
	1673  		for _, question := range q.Questions {
	1674  			switch question.Type {
	1675  			case dnsmessage.TypeA:
	1676  				if question.Name.String() == "slowipv4.example.net." {
	1677  					time.Sleep(10 * time.Millisecond)
	1678  				}
	1679  				if !atomic.CompareAndSwapInt32(&firstcalled, 0, ipv4) {
	1680  					t.Errorf("the A query was received after the AAAA query !")
	1681  				}
	1682  				r.Answers = append(r.Answers, dnsmessage.Resource{
	1683  					Header: dnsmessage.ResourceHeader{
	1684  						Name:	 q.Questions[0].Name,
	1685  						Type:	 dnsmessage.TypeA,
	1686  						Class:	dnsmessage.ClassINET,
	1687  						Length: 4,
	1688  					},
	1689  					Body: &dnsmessage.AResource{
	1690  						A: TestAddr,
	1691  					},
	1692  				})
	1693  			case dnsmessage.TypeAAAA:
	1694  				atomic.CompareAndSwapInt32(&firstcalled, 0, ipv6)
	1695  				r.Answers = append(r.Answers, dnsmessage.Resource{
	1696  					Header: dnsmessage.ResourceHeader{
	1697  						Name:	 q.Questions[0].Name,
	1698  						Type:	 dnsmessage.TypeAAAA,
	1699  						Class:	dnsmessage.ClassINET,
	1700  						Length: 16,
	1701  					},
	1702  					Body: &dnsmessage.AAAAResource{
	1703  						AAAA: TestAddr6,
	1704  					},
	1705  				})
	1706  			}
	1707  		}
	1708  		return r, nil
	1709  	}}
	1710  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1711  
	1712  	conf, err := newResolvConfTest()
	1713  	if err != nil {
	1714  		t.Fatal(err)
	1715  	}
	1716  	defer conf.teardown()
	1717  	if err := conf.writeAndUpdate([]string{"options single-request"}); err != nil {
	1718  		t.Fatal(err)
	1719  	}
	1720  	for _, name := range []string{"hostname.example.net", "slowipv4.example.net"} {
	1721  		firstcalled = 0
	1722  		_, err := r.LookupIPAddr(context.Background(), name)
	1723  		if err != nil {
	1724  			t.Error(err)
	1725  		}
	1726  	}
	1727  }
	1728  
	1729  // Issue 29358. Add configuration knob to force TCP-only DNS requests in the pure Go resolver.
	1730  func TestDNSUseTCP(t *testing.T) {
	1731  	fake := fakeDNSServer{
	1732  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1733  			r := dnsmessage.Message{
	1734  				Header: dnsmessage.Header{
	1735  					ID:			 q.Header.ID,
	1736  					Response: true,
	1737  					RCode:		dnsmessage.RCodeSuccess,
	1738  				},
	1739  				Questions: q.Questions,
	1740  			}
	1741  			if n == "udp" {
	1742  				t.Fatal("udp protocol was used instead of tcp")
	1743  			}
	1744  			return r, nil
	1745  		},
	1746  	}
	1747  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1748  	ctx, cancel := context.WithCancel(context.Background())
	1749  	defer cancel()
	1750  	_, _, err := r.exchange(ctx, "0.0.0.0", mustQuestion("com.", dnsmessage.TypeALL, dnsmessage.ClassINET), time.Second, useTCPOnly)
	1751  	if err != nil {
	1752  		t.Fatal("exchange failed:", err)
	1753  	}
	1754  }
	1755  
	1756  // Issue 34660: PTR response with non-PTR answers should ignore non-PTR
	1757  func TestPTRandNonPTR(t *testing.T) {
	1758  	fake := fakeDNSServer{
	1759  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1760  			r := dnsmessage.Message{
	1761  				Header: dnsmessage.Header{
	1762  					ID:			 q.Header.ID,
	1763  					Response: true,
	1764  					RCode:		dnsmessage.RCodeSuccess,
	1765  				},
	1766  				Questions: q.Questions,
	1767  				Answers: []dnsmessage.Resource{
	1768  					{
	1769  						Header: dnsmessage.ResourceHeader{
	1770  							Name:	q.Questions[0].Name,
	1771  							Type:	dnsmessage.TypePTR,
	1772  							Class: dnsmessage.ClassINET,
	1773  						},
	1774  						Body: &dnsmessage.PTRResource{
	1775  							PTR: dnsmessage.MustNewName("golang.org."),
	1776  						},
	1777  					},
	1778  					{
	1779  						Header: dnsmessage.ResourceHeader{
	1780  							Name:	q.Questions[0].Name,
	1781  							Type:	dnsmessage.TypeTXT,
	1782  							Class: dnsmessage.ClassINET,
	1783  						},
	1784  						Body: &dnsmessage.TXTResource{
	1785  							TXT: []string{"PTR 8 6 60 ..."}, // fake RRSIG
	1786  						},
	1787  					},
	1788  				},
	1789  			}
	1790  			return r, nil
	1791  		},
	1792  	}
	1793  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1794  	names, err := r.lookupAddr(context.Background(), "192.0.2.123")
	1795  	if err != nil {
	1796  		t.Fatalf("LookupAddr: %v", err)
	1797  	}
	1798  	if want := []string{"golang.org."}; !reflect.DeepEqual(names, want) {
	1799  		t.Errorf("names = %q; want %q", names, want)
	1800  	}
	1801  }
	1802  
	1803  func TestCVE202133195(t *testing.T) {
	1804  	fake := fakeDNSServer{
	1805  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	1806  			r := dnsmessage.Message{
	1807  				Header: dnsmessage.Header{
	1808  					ID:								 q.Header.ID,
	1809  					Response:					 true,
	1810  					RCode:							dnsmessage.RCodeSuccess,
	1811  					RecursionAvailable: true,
	1812  				},
	1813  				Questions: q.Questions,
	1814  			}
	1815  			switch q.Questions[0].Type {
	1816  			case dnsmessage.TypeCNAME:
	1817  				r.Answers = []dnsmessage.Resource{}
	1818  			case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy
	1819  				r.Answers = append(r.Answers,
	1820  					dnsmessage.Resource{
	1821  						Header: dnsmessage.ResourceHeader{
	1822  							Name:	 dnsmessage.MustNewName("<html>.golang.org."),
	1823  							Type:	 dnsmessage.TypeA,
	1824  							Class:	dnsmessage.ClassINET,
	1825  							Length: 4,
	1826  						},
	1827  						Body: &dnsmessage.AResource{
	1828  							A: TestAddr,
	1829  						},
	1830  					},
	1831  				)
	1832  			case dnsmessage.TypeSRV:
	1833  				n := q.Questions[0].Name
	1834  				if n.String() == "_hdr._tcp.golang.org." {
	1835  					n = dnsmessage.MustNewName("<html>.golang.org.")
	1836  				}
	1837  				r.Answers = append(r.Answers,
	1838  					dnsmessage.Resource{
	1839  						Header: dnsmessage.ResourceHeader{
	1840  							Name:	 n,
	1841  							Type:	 dnsmessage.TypeSRV,
	1842  							Class:	dnsmessage.ClassINET,
	1843  							Length: 4,
	1844  						},
	1845  						Body: &dnsmessage.SRVResource{
	1846  							Target: dnsmessage.MustNewName("<html>.golang.org."),
	1847  						},
	1848  					},
	1849  					dnsmessage.Resource{
	1850  						Header: dnsmessage.ResourceHeader{
	1851  							Name:	 n,
	1852  							Type:	 dnsmessage.TypeSRV,
	1853  							Class:	dnsmessage.ClassINET,
	1854  							Length: 4,
	1855  						},
	1856  						Body: &dnsmessage.SRVResource{
	1857  							Target: dnsmessage.MustNewName("good.golang.org."),
	1858  						},
	1859  					},
	1860  				)
	1861  			case dnsmessage.TypeMX:
	1862  				r.Answers = append(r.Answers,
	1863  					dnsmessage.Resource{
	1864  						Header: dnsmessage.ResourceHeader{
	1865  							Name:	 dnsmessage.MustNewName("<html>.golang.org."),
	1866  							Type:	 dnsmessage.TypeMX,
	1867  							Class:	dnsmessage.ClassINET,
	1868  							Length: 4,
	1869  						},
	1870  						Body: &dnsmessage.MXResource{
	1871  							MX: dnsmessage.MustNewName("<html>.golang.org."),
	1872  						},
	1873  					},
	1874  					dnsmessage.Resource{
	1875  						Header: dnsmessage.ResourceHeader{
	1876  							Name:	 dnsmessage.MustNewName("good.golang.org."),
	1877  							Type:	 dnsmessage.TypeMX,
	1878  							Class:	dnsmessage.ClassINET,
	1879  							Length: 4,
	1880  						},
	1881  						Body: &dnsmessage.MXResource{
	1882  							MX: dnsmessage.MustNewName("good.golang.org."),
	1883  						},
	1884  					},
	1885  				)
	1886  			case dnsmessage.TypeNS:
	1887  				r.Answers = append(r.Answers,
	1888  					dnsmessage.Resource{
	1889  						Header: dnsmessage.ResourceHeader{
	1890  							Name:	 dnsmessage.MustNewName("<html>.golang.org."),
	1891  							Type:	 dnsmessage.TypeNS,
	1892  							Class:	dnsmessage.ClassINET,
	1893  							Length: 4,
	1894  						},
	1895  						Body: &dnsmessage.NSResource{
	1896  							NS: dnsmessage.MustNewName("<html>.golang.org."),
	1897  						},
	1898  					},
	1899  					dnsmessage.Resource{
	1900  						Header: dnsmessage.ResourceHeader{
	1901  							Name:	 dnsmessage.MustNewName("good.golang.org."),
	1902  							Type:	 dnsmessage.TypeNS,
	1903  							Class:	dnsmessage.ClassINET,
	1904  							Length: 4,
	1905  						},
	1906  						Body: &dnsmessage.NSResource{
	1907  							NS: dnsmessage.MustNewName("good.golang.org."),
	1908  						},
	1909  					},
	1910  				)
	1911  			case dnsmessage.TypePTR:
	1912  				r.Answers = append(r.Answers,
	1913  					dnsmessage.Resource{
	1914  						Header: dnsmessage.ResourceHeader{
	1915  							Name:	 dnsmessage.MustNewName("<html>.golang.org."),
	1916  							Type:	 dnsmessage.TypePTR,
	1917  							Class:	dnsmessage.ClassINET,
	1918  							Length: 4,
	1919  						},
	1920  						Body: &dnsmessage.PTRResource{
	1921  							PTR: dnsmessage.MustNewName("<html>.golang.org."),
	1922  						},
	1923  					},
	1924  					dnsmessage.Resource{
	1925  						Header: dnsmessage.ResourceHeader{
	1926  							Name:	 dnsmessage.MustNewName("good.golang.org."),
	1927  							Type:	 dnsmessage.TypePTR,
	1928  							Class:	dnsmessage.ClassINET,
	1929  							Length: 4,
	1930  						},
	1931  						Body: &dnsmessage.PTRResource{
	1932  							PTR: dnsmessage.MustNewName("good.golang.org."),
	1933  						},
	1934  					},
	1935  				)
	1936  			}
	1937  			return r, nil
	1938  		},
	1939  	}
	1940  
	1941  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	1942  	// Change the default resolver to match our manipulated resolver
	1943  	originalDefault := DefaultResolver
	1944  	DefaultResolver = &r
	1945  	defer func() { DefaultResolver = originalDefault }()
	1946  	// Redirect host file lookups.
	1947  	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
	1948  	testHookHostsPath = "testdata/hosts"
	1949  
	1950  	tests := []struct {
	1951  		name string
	1952  		f		func(*testing.T)
	1953  	}{
	1954  		{
	1955  			name: "CNAME",
	1956  			f: func(t *testing.T) {
	1957  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
	1958  				_, err := r.LookupCNAME(context.Background(), "golang.org")
	1959  				if err.Error() != expectedErr.Error() {
	1960  					t.Fatalf("unexpected error: %s", err)
	1961  				}
	1962  				_, err = LookupCNAME("golang.org")
	1963  				if err.Error() != expectedErr.Error() {
	1964  					t.Fatalf("unexpected error: %s", err)
	1965  				}
	1966  			},
	1967  		},
	1968  		{
	1969  			name: "SRV (bad record)",
	1970  			f: func(t *testing.T) {
	1971  				expected := []*SRV{
	1972  					{
	1973  						Target: "good.golang.org.",
	1974  					},
	1975  				}
	1976  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
	1977  				_, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
	1978  				if err.Error() != expectedErr.Error() {
	1979  					t.Fatalf("unexpected error: %s", err)
	1980  				}
	1981  				if !reflect.DeepEqual(records, expected) {
	1982  					t.Error("Unexpected record set")
	1983  				}
	1984  				_, records, err = LookupSRV("target", "tcp", "golang.org")
	1985  				if err.Error() != expectedErr.Error() {
	1986  					t.Errorf("unexpected error: %s", err)
	1987  				}
	1988  				if !reflect.DeepEqual(records, expected) {
	1989  					t.Error("Unexpected record set")
	1990  				}
	1991  			},
	1992  		},
	1993  		{
	1994  			name: "SRV (bad header)",
	1995  			f: func(t *testing.T) {
	1996  				_, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
	1997  				if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
	1998  					t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
	1999  				}
	2000  				_, _, err = LookupSRV("hdr", "tcp", "golang.org.")
	2001  				if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected {
	2002  					t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
	2003  				}
	2004  			},
	2005  		},
	2006  		{
	2007  			name: "MX",
	2008  			f: func(t *testing.T) {
	2009  				expected := []*MX{
	2010  					{
	2011  						Host: "good.golang.org.",
	2012  					},
	2013  				}
	2014  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
	2015  				records, err := r.LookupMX(context.Background(), "golang.org")
	2016  				if err.Error() != expectedErr.Error() {
	2017  					t.Fatalf("unexpected error: %s", err)
	2018  				}
	2019  				if !reflect.DeepEqual(records, expected) {
	2020  					t.Error("Unexpected record set")
	2021  				}
	2022  				records, err = LookupMX("golang.org")
	2023  				if err.Error() != expectedErr.Error() {
	2024  					t.Fatalf("unexpected error: %s", err)
	2025  				}
	2026  				if !reflect.DeepEqual(records, expected) {
	2027  					t.Error("Unexpected record set")
	2028  				}
	2029  			},
	2030  		},
	2031  		{
	2032  			name: "NS",
	2033  			f: func(t *testing.T) {
	2034  				expected := []*NS{
	2035  					{
	2036  						Host: "good.golang.org.",
	2037  					},
	2038  				}
	2039  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
	2040  				records, err := r.LookupNS(context.Background(), "golang.org")
	2041  				if err.Error() != expectedErr.Error() {
	2042  					t.Fatalf("unexpected error: %s", err)
	2043  				}
	2044  				if !reflect.DeepEqual(records, expected) {
	2045  					t.Error("Unexpected record set")
	2046  				}
	2047  				records, err = LookupNS("golang.org")
	2048  				if err.Error() != expectedErr.Error() {
	2049  					t.Fatalf("unexpected error: %s", err)
	2050  				}
	2051  				if !reflect.DeepEqual(records, expected) {
	2052  					t.Error("Unexpected record set")
	2053  				}
	2054  			},
	2055  		},
	2056  		{
	2057  			name: "Addr",
	2058  			f: func(t *testing.T) {
	2059  				expected := []string{"good.golang.org."}
	2060  				expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
	2061  				records, err := r.LookupAddr(context.Background(), "192.0.2.42")
	2062  				if err.Error() != expectedErr.Error() {
	2063  					t.Fatalf("unexpected error: %s", err)
	2064  				}
	2065  				if !reflect.DeepEqual(records, expected) {
	2066  					t.Error("Unexpected record set")
	2067  				}
	2068  				records, err = LookupAddr("192.0.2.42")
	2069  				if err.Error() != expectedErr.Error() {
	2070  					t.Fatalf("unexpected error: %s", err)
	2071  				}
	2072  				if !reflect.DeepEqual(records, expected) {
	2073  					t.Error("Unexpected record set")
	2074  				}
	2075  			},
	2076  		},
	2077  	}
	2078  
	2079  	for _, tc := range tests {
	2080  		t.Run(tc.name, tc.f)
	2081  	}
	2082  
	2083  }
	2084  
	2085  func TestNullMX(t *testing.T) {
	2086  	fake := fakeDNSServer{
	2087  		rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) {
	2088  			r := dnsmessage.Message{
	2089  				Header: dnsmessage.Header{
	2090  					ID:			 q.Header.ID,
	2091  					Response: true,
	2092  					RCode:		dnsmessage.RCodeSuccess,
	2093  				},
	2094  				Questions: q.Questions,
	2095  				Answers: []dnsmessage.Resource{
	2096  					{
	2097  						Header: dnsmessage.ResourceHeader{
	2098  							Name:	q.Questions[0].Name,
	2099  							Type:	dnsmessage.TypeMX,
	2100  							Class: dnsmessage.ClassINET,
	2101  						},
	2102  						Body: &dnsmessage.MXResource{
	2103  							MX: dnsmessage.MustNewName("."),
	2104  						},
	2105  					},
	2106  				},
	2107  			}
	2108  			return r, nil
	2109  		},
	2110  	}
	2111  	r := Resolver{PreferGo: true, Dial: fake.DialContext}
	2112  	rrset, err := r.LookupMX(context.Background(), "golang.org")
	2113  	if err != nil {
	2114  		t.Fatalf("LookupMX: %v", err)
	2115  	}
	2116  	if want := []*MX{&MX{Host: "."}}; !reflect.DeepEqual(rrset, want) {
	2117  		records := []string{}
	2118  		for _, rr := range rrset {
	2119  			records = append(records, fmt.Sprintf("%v", rr))
	2120  		}
	2121  		t.Errorf("records = [%v]; want [%v]", strings.Join(records, " "), want[0])
	2122  	}
	2123  }
	2124  

View as plain text