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

View as plain text