Black Lives Matter. Support the Equal Justice Initiative.

Source file src/net/lookup_test.go

Documentation: net

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

View as plain text