github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/net/lookup_test.go (about)

     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  package net
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"runtime"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
    17  	switch host {
    18  	case "localhost":
    19  		return []IPAddr{
    20  			{IP: IPv4(127, 0, 0, 1)},
    21  			{IP: IPv6loopback},
    22  		}, nil
    23  	default:
    24  		return fn(host)
    25  	}
    26  }
    27  
    28  // The Lookup APIs use various sources such as local database, DNS or
    29  // mDNS, and may use platform-dependent DNS stub resolver if possible.
    30  // The APIs accept any of forms for a query; host name in various
    31  // encodings, UTF-8 encoded net name, domain name, FQDN or absolute
    32  // FQDN, but the result would be one of the forms and it depends on
    33  // the circumstances.
    34  
    35  var lookupGoogleSRVTests = []struct {
    36  	service, proto, name string
    37  	cname, target        string
    38  }{
    39  	{
    40  		"xmpp-server", "tcp", "google.com",
    41  		"google.com.", "google.com.",
    42  	},
    43  	{
    44  		"xmpp-server", "tcp", "google.com.",
    45  		"google.com.", "google.com.",
    46  	},
    47  
    48  	// non-standard back door
    49  	{
    50  		"", "", "_xmpp-server._tcp.google.com",
    51  		"google.com.", "google.com.",
    52  	},
    53  	{
    54  		"", "", "_xmpp-server._tcp.google.com.",
    55  		"google.com.", "google.com.",
    56  	},
    57  }
    58  
    59  func TestLookupGoogleSRV(t *testing.T) {
    60  	if testing.Short() || !*testExternal {
    61  		t.Skip("avoid external network")
    62  	}
    63  	if !supportsIPv4 || !*testIPv4 {
    64  		t.Skip("IPv4 is required")
    65  	}
    66  
    67  	for _, tt := range lookupGoogleSRVTests {
    68  		cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
    69  		if err != nil {
    70  			t.Fatal(err)
    71  		}
    72  		if len(srvs) == 0 {
    73  			t.Error("got no record")
    74  		}
    75  		if !strings.HasSuffix(cname, tt.cname) {
    76  			t.Errorf("got %s; want %s", cname, tt.cname)
    77  		}
    78  		for _, srv := range srvs {
    79  			if !strings.HasSuffix(srv.Target, tt.target) {
    80  				t.Errorf("got %v; want a record containing %s", srv, tt.target)
    81  			}
    82  		}
    83  	}
    84  }
    85  
    86  var lookupGmailMXTests = []struct {
    87  	name, host string
    88  }{
    89  	{"gmail.com", "google.com."},
    90  	{"gmail.com.", "google.com."},
    91  }
    92  
    93  func TestLookupGmailMX(t *testing.T) {
    94  	if testing.Short() || !*testExternal {
    95  		t.Skip("avoid external network")
    96  	}
    97  	if !supportsIPv4 || !*testIPv4 {
    98  		t.Skip("IPv4 is required")
    99  	}
   100  
   101  	for _, tt := range lookupGmailMXTests {
   102  		mxs, err := LookupMX(tt.name)
   103  		if err != nil {
   104  			t.Fatal(err)
   105  		}
   106  		if len(mxs) == 0 {
   107  			t.Error("got no record")
   108  		}
   109  		for _, mx := range mxs {
   110  			if !strings.HasSuffix(mx.Host, tt.host) {
   111  				t.Errorf("got %v; want a record containing %s", mx, tt.host)
   112  			}
   113  		}
   114  	}
   115  }
   116  
   117  var lookupGmailNSTests = []struct {
   118  	name, host string
   119  }{
   120  	{"gmail.com", "google.com."},
   121  	{"gmail.com.", "google.com."},
   122  }
   123  
   124  func TestLookupGmailNS(t *testing.T) {
   125  	if testing.Short() || !*testExternal {
   126  		t.Skip("avoid external network")
   127  	}
   128  	if !supportsIPv4 || !*testIPv4 {
   129  		t.Skip("IPv4 is required")
   130  	}
   131  
   132  	for _, tt := range lookupGmailNSTests {
   133  		nss, err := LookupNS(tt.name)
   134  		if err != nil {
   135  			t.Fatal(err)
   136  		}
   137  		if len(nss) == 0 {
   138  			t.Error("got no record")
   139  		}
   140  		for _, ns := range nss {
   141  			if !strings.HasSuffix(ns.Host, tt.host) {
   142  				t.Errorf("got %v; want a record containing %s", ns, tt.host)
   143  			}
   144  		}
   145  	}
   146  }
   147  
   148  var lookupGmailTXTTests = []struct {
   149  	name, txt, host string
   150  }{
   151  	{"gmail.com", "spf", "google.com"},
   152  	{"gmail.com.", "spf", "google.com"},
   153  }
   154  
   155  func TestLookupGmailTXT(t *testing.T) {
   156  	if testing.Short() || !*testExternal {
   157  		t.Skip("avoid external network")
   158  	}
   159  	if !supportsIPv4 || !*testIPv4 {
   160  		t.Skip("IPv4 is required")
   161  	}
   162  
   163  	for _, tt := range lookupGmailTXTTests {
   164  		txts, err := LookupTXT(tt.name)
   165  		if err != nil {
   166  			t.Fatal(err)
   167  		}
   168  		if len(txts) == 0 {
   169  			t.Error("got no record")
   170  		}
   171  		for _, txt := range txts {
   172  			if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
   173  				t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
   174  			}
   175  		}
   176  	}
   177  }
   178  
   179  var lookupGooglePublicDNSAddrTests = []struct {
   180  	addr, name string
   181  }{
   182  	{"8.8.8.8", ".google.com."},
   183  	{"8.8.4.4", ".google.com."},
   184  
   185  	{"2001:4860:4860::8888", ".google.com."},
   186  	{"2001:4860:4860::8844", ".google.com."},
   187  }
   188  
   189  func TestLookupGooglePublicDNSAddr(t *testing.T) {
   190  	if testing.Short() || !*testExternal {
   191  		t.Skip("avoid external network")
   192  	}
   193  	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
   194  		t.Skip("both IPv4 and IPv6 are required")
   195  	}
   196  
   197  	for _, tt := range lookupGooglePublicDNSAddrTests {
   198  		names, err := LookupAddr(tt.addr)
   199  		if err != nil {
   200  			t.Fatal(err)
   201  		}
   202  		if len(names) == 0 {
   203  			t.Error("got no record")
   204  		}
   205  		for _, name := range names {
   206  			if !strings.HasSuffix(name, tt.name) {
   207  				t.Errorf("got %s; want a record containing %s", name, tt.name)
   208  			}
   209  		}
   210  	}
   211  }
   212  
   213  func TestLookupIPv6LinkLocalAddr(t *testing.T) {
   214  	if !supportsIPv6 {
   215  		t.Skip("IPv6 is required")
   216  	}
   217  
   218  	addrs, err := LookupHost("localhost")
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	found := false
   223  	for _, addr := range addrs {
   224  		if addr == "fe80::1%lo0" {
   225  			found = true
   226  			break
   227  		}
   228  	}
   229  	if !found {
   230  		t.Skipf("not supported on %s", runtime.GOOS)
   231  	}
   232  	if _, err := LookupAddr("fe80::1%lo0"); err != nil {
   233  		t.Error(err)
   234  	}
   235  }
   236  
   237  var lookupIANACNAMETests = []struct {
   238  	name, cname string
   239  }{
   240  	{"www.iana.org", "icann.org."},
   241  	{"www.iana.org.", "icann.org."},
   242  }
   243  
   244  func TestLookupIANACNAME(t *testing.T) {
   245  	if testing.Short() || !*testExternal {
   246  		t.Skip("avoid external network")
   247  	}
   248  	if !supportsIPv4 || !*testIPv4 {
   249  		t.Skip("IPv4 is required")
   250  	}
   251  
   252  	for _, tt := range lookupIANACNAMETests {
   253  		cname, err := LookupCNAME(tt.name)
   254  		if err != nil {
   255  			t.Fatal(err)
   256  		}
   257  		if !strings.HasSuffix(cname, tt.cname) {
   258  			t.Errorf("got %s; want a record containing %s", cname, tt.cname)
   259  		}
   260  	}
   261  }
   262  
   263  var lookupGoogleHostTests = []struct {
   264  	name string
   265  }{
   266  	{"google.com"},
   267  	{"google.com."},
   268  }
   269  
   270  func TestLookupGoogleHost(t *testing.T) {
   271  	if testing.Short() || !*testExternal {
   272  		t.Skip("avoid external network")
   273  	}
   274  	if !supportsIPv4 || !*testIPv4 {
   275  		t.Skip("IPv4 is required")
   276  	}
   277  
   278  	for _, tt := range lookupGoogleHostTests {
   279  		addrs, err := LookupHost(tt.name)
   280  		if err != nil {
   281  			t.Fatal(err)
   282  		}
   283  		if len(addrs) == 0 {
   284  			t.Error("got no record")
   285  		}
   286  		for _, addr := range addrs {
   287  			if ParseIP(addr) == nil {
   288  				t.Errorf("got %q; want a literal IP address", addr)
   289  			}
   290  		}
   291  	}
   292  }
   293  
   294  var lookupGoogleIPTests = []struct {
   295  	name string
   296  }{
   297  	{"google.com"},
   298  	{"google.com."},
   299  }
   300  
   301  func TestLookupGoogleIP(t *testing.T) {
   302  	if testing.Short() || !*testExternal {
   303  		t.Skip("avoid external network")
   304  	}
   305  	if !supportsIPv4 || !*testIPv4 {
   306  		t.Skip("IPv4 is required")
   307  	}
   308  
   309  	for _, tt := range lookupGoogleIPTests {
   310  		ips, err := LookupIP(tt.name)
   311  		if err != nil {
   312  			t.Fatal(err)
   313  		}
   314  		if len(ips) == 0 {
   315  			t.Error("got no record")
   316  		}
   317  		for _, ip := range ips {
   318  			if ip.To4() == nil && ip.To16() == nil {
   319  				t.Errorf("got %v; want an IP address", ip)
   320  			}
   321  		}
   322  	}
   323  }
   324  
   325  var revAddrTests = []struct {
   326  	Addr      string
   327  	Reverse   string
   328  	ErrPrefix string
   329  }{
   330  	{"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
   331  	{"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
   332  	{"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
   333  	{"::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.", ""},
   334  	{"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.", ""},
   335  	{"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.", ""},
   336  	{"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.", ""},
   337  	{"1.2.3", "", "unrecognized address"},
   338  	{"1.2.3.4.5", "", "unrecognized address"},
   339  	{"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
   340  	{"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
   341  }
   342  
   343  func TestReverseAddress(t *testing.T) {
   344  	for i, tt := range revAddrTests {
   345  		a, err := reverseaddr(tt.Addr)
   346  		if len(tt.ErrPrefix) > 0 && err == nil {
   347  			t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
   348  			continue
   349  		}
   350  		if len(tt.ErrPrefix) == 0 && err != nil {
   351  			t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
   352  		}
   353  		if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
   354  			t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
   355  		}
   356  		if a != tt.Reverse {
   357  			t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
   358  		}
   359  	}
   360  }
   361  
   362  func TestLookupIPDeadline(t *testing.T) {
   363  	if !*testDNSFlood {
   364  		t.Skip("test disabled; use -dnsflood to enable")
   365  	}
   366  
   367  	const N = 5000
   368  	const timeout = 3 * time.Second
   369  	c := make(chan error, 2*N)
   370  	for i := 0; i < N; i++ {
   371  		name := fmt.Sprintf("%d.net-test.golang.org", i)
   372  		go func() {
   373  			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
   374  			c <- err
   375  		}()
   376  		go func() {
   377  			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
   378  			c <- err
   379  		}()
   380  	}
   381  	qstats := struct {
   382  		succeeded, failed         int
   383  		timeout, temporary, other int
   384  		unknown                   int
   385  	}{}
   386  	deadline := time.After(timeout + time.Second)
   387  	for i := 0; i < 2*N; i++ {
   388  		select {
   389  		case <-deadline:
   390  			t.Fatal("deadline exceeded")
   391  		case err := <-c:
   392  			switch err := err.(type) {
   393  			case nil:
   394  				qstats.succeeded++
   395  			case Error:
   396  				qstats.failed++
   397  				if err.Timeout() {
   398  					qstats.timeout++
   399  				}
   400  				if err.Temporary() {
   401  					qstats.temporary++
   402  				}
   403  				if !err.Timeout() && !err.Temporary() {
   404  					qstats.other++
   405  				}
   406  			default:
   407  				qstats.failed++
   408  				qstats.unknown++
   409  			}
   410  		}
   411  	}
   412  
   413  	// A high volume of DNS queries for sub-domain of golang.org
   414  	// would be coordinated by authoritative or recursive server,
   415  	// or stub resolver which implements query-response rate
   416  	// limitation, so we can expect some query successes and more
   417  	// failures including timeout, temporary and other here.
   418  	// As a rule, unknown must not be shown but it might possibly
   419  	// happen due to issue 4856 for now.
   420  	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)
   421  }
   422  
   423  func TestLookupDotsWithLocalSource(t *testing.T) {
   424  	if !supportsIPv4 {
   425  		t.Skip("IPv4 is required")
   426  	}
   427  
   428  	for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
   429  		fixup := fn()
   430  		if fixup == nil {
   431  			continue
   432  		}
   433  		names, err := LookupAddr("127.0.0.1")
   434  		fixup()
   435  		if err != nil {
   436  			t.Errorf("#%d: %v", i, err)
   437  			continue
   438  		}
   439  		for _, name := range names {
   440  			if !strings.HasSuffix(name, ".") {
   441  				t.Errorf("#%d: got %s; want name ending with trailing dot", i, name)
   442  			}
   443  		}
   444  	}
   445  }
   446  
   447  func TestLookupDotsWithRemoteSource(t *testing.T) {
   448  	if testing.Short() || !*testExternal {
   449  		t.Skipf("skipping external network test")
   450  	}
   451  
   452  	if fixup := forceGoDNS(); fixup != nil {
   453  		testDots(t, "go")
   454  		fixup()
   455  	}
   456  	if fixup := forceCgoDNS(); fixup != nil {
   457  		testDots(t, "cgo")
   458  		fixup()
   459  	}
   460  }
   461  
   462  func testDots(t *testing.T, mode string) {
   463  	names, err := LookupAddr("8.8.8.8") // Google dns server
   464  	if err != nil {
   465  		t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
   466  	} else {
   467  		for _, name := range names {
   468  			if !strings.HasSuffix(name, ".google.com.") {
   469  				t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
   470  				break
   471  			}
   472  		}
   473  	}
   474  
   475  	cname, err := LookupCNAME("www.mit.edu")
   476  	if err != nil || !strings.HasSuffix(cname, ".") {
   477  		t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode)
   478  	}
   479  
   480  	mxs, err := LookupMX("google.com")
   481  	if err != nil {
   482  		t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
   483  	} else {
   484  		for _, mx := range mxs {
   485  			if !strings.HasSuffix(mx.Host, ".google.com.") {
   486  				t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
   487  				break
   488  			}
   489  		}
   490  	}
   491  
   492  	nss, err := LookupNS("google.com")
   493  	if err != nil {
   494  		t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
   495  	} else {
   496  		for _, ns := range nss {
   497  			if !strings.HasSuffix(ns.Host, ".google.com.") {
   498  				t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
   499  				break
   500  			}
   501  		}
   502  	}
   503  
   504  	cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
   505  	if err != nil {
   506  		t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
   507  	} else {
   508  		if !strings.HasSuffix(cname, ".google.com.") {
   509  			t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
   510  		}
   511  		for _, srv := range srvs {
   512  			if !strings.HasSuffix(srv.Target, ".google.com.") {
   513  				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)
   514  				break
   515  			}
   516  		}
   517  	}
   518  }
   519  
   520  func mxString(mxs []*MX) string {
   521  	var buf bytes.Buffer
   522  	sep := ""
   523  	fmt.Fprintf(&buf, "[")
   524  	for _, mx := range mxs {
   525  		fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
   526  		sep = " "
   527  	}
   528  	fmt.Fprintf(&buf, "]")
   529  	return buf.String()
   530  }
   531  
   532  func nsString(nss []*NS) string {
   533  	var buf bytes.Buffer
   534  	sep := ""
   535  	fmt.Fprintf(&buf, "[")
   536  	for _, ns := range nss {
   537  		fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
   538  		sep = " "
   539  	}
   540  	fmt.Fprintf(&buf, "]")
   541  	return buf.String()
   542  }
   543  
   544  func srvString(srvs []*SRV) string {
   545  	var buf bytes.Buffer
   546  	sep := ""
   547  	fmt.Fprintf(&buf, "[")
   548  	for _, srv := range srvs {
   549  		fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
   550  		sep = " "
   551  	}
   552  	fmt.Fprintf(&buf, "]")
   553  	return buf.String()
   554  }
   555  
   556  var lookupPortTests = []struct {
   557  	network string
   558  	name    string
   559  	port    int
   560  	ok      bool
   561  }{
   562  	{"tcp", "0", 0, true},
   563  	{"tcp", "echo", 7, true},
   564  	{"tcp", "discard", 9, true},
   565  	{"tcp", "systat", 11, true},
   566  	{"tcp", "daytime", 13, true},
   567  	{"tcp", "chargen", 19, true},
   568  	{"tcp", "ftp-data", 20, true},
   569  	{"tcp", "ftp", 21, true},
   570  	{"tcp", "telnet", 23, true},
   571  	{"tcp", "smtp", 25, true},
   572  	{"tcp", "time", 37, true},
   573  	{"tcp", "domain", 53, true},
   574  	{"tcp", "finger", 79, true},
   575  	{"tcp", "42", 42, true},
   576  
   577  	{"udp", "0", 0, true},
   578  	{"udp", "echo", 7, true},
   579  	{"udp", "tftp", 69, true},
   580  	{"udp", "bootpc", 68, true},
   581  	{"udp", "bootps", 67, true},
   582  	{"udp", "domain", 53, true},
   583  	{"udp", "ntp", 123, true},
   584  	{"udp", "snmp", 161, true},
   585  	{"udp", "syslog", 514, true},
   586  	{"udp", "42", 42, true},
   587  
   588  	{"--badnet--", "zzz", 0, false},
   589  	{"tcp", "--badport--", 0, false},
   590  	{"tcp", "-1", 0, false},
   591  	{"tcp", "65536", 0, false},
   592  	{"udp", "-1", 0, false},
   593  	{"udp", "65536", 0, false},
   594  }
   595  
   596  func TestLookupPort(t *testing.T) {
   597  	switch runtime.GOOS {
   598  	case "nacl":
   599  		t.Skipf("not supported on %s", runtime.GOOS)
   600  	}
   601  
   602  	for _, tt := range lookupPortTests {
   603  		if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
   604  			t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port)
   605  		}
   606  	}
   607  }