Source file src/net/conf_test.go

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build unix
     6  
     7  package net
     8  
     9  import (
    10  	"io/fs"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  type nssHostTest struct {
    17  	host      string
    18  	localhost string
    19  	want      hostLookupOrder
    20  }
    21  
    22  func nssStr(t *testing.T, s string) *nssConf {
    23  	f, err := os.CreateTemp(t.TempDir(), "nss")
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  	if _, err := f.WriteString(s); err != nil {
    28  		t.Fatal(err)
    29  	}
    30  	if err := f.Close(); err != nil {
    31  		t.Fatal(err)
    32  	}
    33  	return parseNSSConfFile(f.Name())
    34  }
    35  
    36  // represents a dnsConfig returned by parsing a nonexistent resolv.conf
    37  var defaultResolvConf = &dnsConfig{
    38  	servers:  defaultNS,
    39  	ndots:    1,
    40  	timeout:  5,
    41  	attempts: 2,
    42  	err:      fs.ErrNotExist,
    43  }
    44  
    45  func TestConfHostLookupOrder(t *testing.T) {
    46  	// These tests are written for a system with cgo available,
    47  	// without using the netgo tag.
    48  	if netGoBuildTag {
    49  		t.Skip("skipping test because net package built with netgo tag")
    50  	}
    51  	if !cgoAvailable {
    52  		t.Skip("skipping test because cgo resolver not available")
    53  	}
    54  
    55  	tests := []struct {
    56  		name      string
    57  		c         *conf
    58  		nss       *nssConf
    59  		resolver  *Resolver
    60  		resolv    *dnsConfig
    61  		hostTests []nssHostTest
    62  	}{
    63  		{
    64  			name: "force",
    65  			c: &conf{
    66  				preferCgo: true,
    67  				netCgo:    true,
    68  			},
    69  			resolv: defaultResolvConf,
    70  			nss:    nssStr(t, "foo: bar"),
    71  			hostTests: []nssHostTest{
    72  				{"foo.local", "myhostname", hostLookupCgo},
    73  				{"google.com", "myhostname", hostLookupCgo},
    74  			},
    75  		},
    76  		{
    77  			name: "netgo_dns_before_files",
    78  			c: &conf{
    79  				netGo: true,
    80  			},
    81  			resolv: defaultResolvConf,
    82  			nss:    nssStr(t, "hosts: dns files"),
    83  			hostTests: []nssHostTest{
    84  				{"x.com", "myhostname", hostLookupDNSFiles},
    85  			},
    86  		},
    87  		{
    88  			name: "netgo_fallback_on_cgo",
    89  			c: &conf{
    90  				netGo: true,
    91  			},
    92  			resolv: defaultResolvConf,
    93  			nss:    nssStr(t, "hosts: dns files something_custom"),
    94  			hostTests: []nssHostTest{
    95  				{"x.com", "myhostname", hostLookupDNSFiles},
    96  			},
    97  		},
    98  		{
    99  			name: "ubuntu_trusty_avahi",
   100  			c: &conf{
   101  				mdnsTest: mdnsAssumeDoesNotExist,
   102  			},
   103  			resolv: defaultResolvConf,
   104  			nss:    nssStr(t, "hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"),
   105  			hostTests: []nssHostTest{
   106  				{"foo.local", "myhostname", hostLookupCgo},
   107  				{"foo.local.", "myhostname", hostLookupCgo},
   108  				{"foo.LOCAL", "myhostname", hostLookupCgo},
   109  				{"foo.LOCAL.", "myhostname", hostLookupCgo},
   110  				{"google.com", "myhostname", hostLookupFilesDNS},
   111  			},
   112  		},
   113  		{
   114  			name: "freebsdlinux_no_resolv_conf",
   115  			c: &conf{
   116  				goos: "freebsd",
   117  			},
   118  			resolv:    defaultResolvConf,
   119  			nss:       nssStr(t, "foo: bar"),
   120  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
   121  		},
   122  		// On OpenBSD, no resolv.conf means no DNS.
   123  		{
   124  			name: "openbsd_no_resolv_conf",
   125  			c: &conf{
   126  				goos: "openbsd",
   127  			},
   128  			resolv:    defaultResolvConf,
   129  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
   130  		},
   131  		{
   132  			name: "solaris_no_nsswitch",
   133  			c: &conf{
   134  				goos: "solaris",
   135  			},
   136  			resolv:    defaultResolvConf,
   137  			nss:       &nssConf{err: fs.ErrNotExist},
   138  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
   139  		},
   140  		{
   141  			name: "openbsd_lookup_bind_file",
   142  			c: &conf{
   143  				goos: "openbsd",
   144  			},
   145  			resolv: &dnsConfig{lookup: []string{"bind", "file"}},
   146  			hostTests: []nssHostTest{
   147  				{"google.com", "myhostname", hostLookupDNSFiles},
   148  				{"foo.local", "myhostname", hostLookupDNSFiles},
   149  			},
   150  		},
   151  		{
   152  			name: "openbsd_lookup_file_bind",
   153  			c: &conf{
   154  				goos: "openbsd",
   155  			},
   156  			resolv:    &dnsConfig{lookup: []string{"file", "bind"}},
   157  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
   158  		},
   159  		{
   160  			name: "openbsd_lookup_bind",
   161  			c: &conf{
   162  				goos: "openbsd",
   163  			},
   164  			resolv:    &dnsConfig{lookup: []string{"bind"}},
   165  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNS}},
   166  		},
   167  		{
   168  			name: "openbsd_lookup_file",
   169  			c: &conf{
   170  				goos: "openbsd",
   171  			},
   172  			resolv:    &dnsConfig{lookup: []string{"file"}},
   173  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
   174  		},
   175  		{
   176  			name: "openbsd_lookup_yp",
   177  			c: &conf{
   178  				goos: "openbsd",
   179  			},
   180  			resolv:    &dnsConfig{lookup: []string{"file", "bind", "yp"}},
   181  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
   182  		},
   183  		{
   184  			name: "openbsd_lookup_two",
   185  			c: &conf{
   186  				goos: "openbsd",
   187  			},
   188  			resolv:    &dnsConfig{lookup: []string{"file", "foo"}},
   189  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
   190  		},
   191  		{
   192  			name: "openbsd_lookup_empty",
   193  			c: &conf{
   194  				goos: "openbsd",
   195  			},
   196  			resolv:    &dnsConfig{lookup: nil},
   197  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}},
   198  		},
   199  		{
   200  			name: "linux_no_nsswitch.conf",
   201  			c: &conf{
   202  				goos: "linux",
   203  			},
   204  			resolv:    defaultResolvConf,
   205  			nss:       &nssConf{err: fs.ErrNotExist},
   206  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
   207  		},
   208  		{
   209  			name: "linux_empty_nsswitch.conf",
   210  			c: &conf{
   211  				goos: "linux",
   212  			},
   213  			resolv:    defaultResolvConf,
   214  			nss:       nssStr(t, ""),
   215  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
   216  		},
   217  		{
   218  			name: "files_mdns_dns",
   219  			c: &conf{
   220  				mdnsTest: mdnsAssumeDoesNotExist,
   221  			},
   222  			resolv: defaultResolvConf,
   223  			nss:    nssStr(t, "hosts: files mdns dns"),
   224  			hostTests: []nssHostTest{
   225  				{"x.com", "myhostname", hostLookupFilesDNS},
   226  				{"x.local", "myhostname", hostLookupCgo},
   227  			},
   228  		},
   229  		{
   230  			name:   "dns_special_hostnames",
   231  			c:      &conf{},
   232  			resolv: defaultResolvConf,
   233  			nss:    nssStr(t, "hosts: dns"),
   234  			hostTests: []nssHostTest{
   235  				{"x.com", "myhostname", hostLookupDNS},
   236  				{"x\\.com", "myhostname", hostLookupCgo},     // punt on weird glibc escape
   237  				{"foo.com%en0", "myhostname", hostLookupCgo}, // and IPv6 zones
   238  			},
   239  		},
   240  		{
   241  			name: "mdns_allow",
   242  			c: &conf{
   243  				mdnsTest: mdnsAssumeExists,
   244  			},
   245  			resolv: defaultResolvConf,
   246  			nss:    nssStr(t, "hosts: files mdns dns"),
   247  			hostTests: []nssHostTest{
   248  				{"x.com", "myhostname", hostLookupCgo},
   249  				{"x.local", "myhostname", hostLookupCgo},
   250  			},
   251  		},
   252  		{
   253  			name:   "files_dns",
   254  			c:      &conf{},
   255  			resolv: defaultResolvConf,
   256  			nss:    nssStr(t, "hosts: files dns"),
   257  			hostTests: []nssHostTest{
   258  				{"x.com", "myhostname", hostLookupFilesDNS},
   259  				{"x", "myhostname", hostLookupFilesDNS},
   260  				{"x.local", "myhostname", hostLookupCgo},
   261  			},
   262  		},
   263  		{
   264  			name:   "dns_files",
   265  			c:      &conf{},
   266  			resolv: defaultResolvConf,
   267  			nss:    nssStr(t, "hosts: dns files"),
   268  			hostTests: []nssHostTest{
   269  				{"x.com", "myhostname", hostLookupDNSFiles},
   270  				{"x", "myhostname", hostLookupDNSFiles},
   271  				{"x.local", "myhostname", hostLookupCgo},
   272  			},
   273  		},
   274  		{
   275  			name:   "something_custom",
   276  			c:      &conf{},
   277  			resolv: defaultResolvConf,
   278  			nss:    nssStr(t, "hosts: dns files something_custom"),
   279  			hostTests: []nssHostTest{
   280  				{"x.com", "myhostname", hostLookupCgo},
   281  			},
   282  		},
   283  		{
   284  			name:   "myhostname",
   285  			c:      &conf{},
   286  			resolv: defaultResolvConf,
   287  			nss:    nssStr(t, "hosts: files dns myhostname"),
   288  			hostTests: []nssHostTest{
   289  				{"x.com", "myhostname", hostLookupFilesDNS},
   290  				{"myhostname", "myhostname", hostLookupCgo},
   291  				{"myHostname", "myhostname", hostLookupCgo},
   292  				{"myhostname.dot", "myhostname.dot", hostLookupCgo},
   293  				{"myHostname.dot", "myhostname.dot", hostLookupCgo},
   294  				{"_gateway", "myhostname", hostLookupCgo},
   295  				{"_Gateway", "myhostname", hostLookupCgo},
   296  				{"_outbound", "myhostname", hostLookupCgo},
   297  				{"_Outbound", "myhostname", hostLookupCgo},
   298  				{"localhost", "myhostname", hostLookupCgo},
   299  				{"Localhost", "myhostname", hostLookupCgo},
   300  				{"anything.localhost", "myhostname", hostLookupCgo},
   301  				{"Anything.localhost", "myhostname", hostLookupCgo},
   302  				{"localhost.localdomain", "myhostname", hostLookupCgo},
   303  				{"Localhost.Localdomain", "myhostname", hostLookupCgo},
   304  				{"anything.localhost.localdomain", "myhostname", hostLookupCgo},
   305  				{"Anything.Localhost.Localdomain", "myhostname", hostLookupCgo},
   306  				{"somehostname", "myhostname", hostLookupFilesDNS},
   307  			},
   308  		},
   309  		{
   310  			name: "ubuntu14.04.02",
   311  			c: &conf{
   312  				mdnsTest: mdnsAssumeDoesNotExist,
   313  			},
   314  			resolv: defaultResolvConf,
   315  			nss:    nssStr(t, "hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"),
   316  			hostTests: []nssHostTest{
   317  				{"x.com", "myhostname", hostLookupFilesDNS},
   318  				{"somehostname", "myhostname", hostLookupFilesDNS},
   319  				{"myhostname", "myhostname", hostLookupCgo},
   320  			},
   321  		},
   322  		// Debian Squeeze is just "dns,files", but lists all
   323  		// the default criteria for dns, but then has a
   324  		// non-standard but redundant notfound=return for the
   325  		// files.
   326  		{
   327  			name:   "debian_squeeze",
   328  			c:      &conf{},
   329  			resolv: defaultResolvConf,
   330  			nss:    nssStr(t, "hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"),
   331  			hostTests: []nssHostTest{
   332  				{"x.com", "myhostname", hostLookupDNSFiles},
   333  				{"somehostname", "myhostname", hostLookupDNSFiles},
   334  			},
   335  		},
   336  		{
   337  			name:      "resolv.conf-unknown",
   338  			c:         &conf{},
   339  			resolv:    &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
   340  			nss:       nssStr(t, "foo: bar"),
   341  			hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
   342  		},
   343  		// Issue 24393: make sure "Resolver.PreferGo = true" acts like netgo.
   344  		{
   345  			name:     "resolver-prefergo",
   346  			resolver: &Resolver{PreferGo: true},
   347  			c: &conf{
   348  				preferCgo: true,
   349  				netCgo:    true,
   350  			},
   351  			resolv: defaultResolvConf,
   352  			nss:    nssStr(t, ""),
   353  			hostTests: []nssHostTest{
   354  				{"localhost", "myhostname", hostLookupFilesDNS},
   355  			},
   356  		},
   357  		{
   358  			name:     "unknown-source",
   359  			resolver: &Resolver{PreferGo: true},
   360  			c:        &conf{},
   361  			resolv:   defaultResolvConf,
   362  			nss:      nssStr(t, "hosts: resolve files"),
   363  			hostTests: []nssHostTest{
   364  				{"x.com", "myhostname", hostLookupDNSFiles},
   365  			},
   366  		},
   367  		{
   368  			name:     "dns-among-unknown-sources",
   369  			resolver: &Resolver{PreferGo: true},
   370  			c:        &conf{},
   371  			resolv:   defaultResolvConf,
   372  			nss:      nssStr(t, "hosts: mymachines files dns"),
   373  			hostTests: []nssHostTest{
   374  				{"x.com", "myhostname", hostLookupFilesDNS},
   375  			},
   376  		},
   377  		{
   378  			name:     "dns-among-unknown-sources-2",
   379  			resolver: &Resolver{PreferGo: true},
   380  			c:        &conf{},
   381  			resolv:   defaultResolvConf,
   382  			nss:      nssStr(t, "hosts: dns mymachines files"),
   383  			hostTests: []nssHostTest{
   384  				{"x.com", "myhostname", hostLookupDNSFiles},
   385  			},
   386  		},
   387  	}
   388  
   389  	origGetHostname := getHostname
   390  	defer func() { getHostname = origGetHostname }()
   391  	defer setSystemNSS(getSystemNSS(), 0)
   392  	conf, err := newResolvConfTest()
   393  	if err != nil {
   394  		t.Fatal(err)
   395  	}
   396  	defer conf.teardown()
   397  
   398  	for _, tt := range tests {
   399  		if !conf.forceUpdateConf(tt.resolv, time.Now().Add(time.Hour)) {
   400  			t.Errorf("%s: failed to change resolv config", tt.name)
   401  		}
   402  		for _, ht := range tt.hostTests {
   403  			getHostname = func() (string, error) { return ht.localhost, nil }
   404  			setSystemNSS(tt.nss, time.Hour)
   405  
   406  			gotOrder, _ := tt.c.hostLookupOrder(tt.resolver, ht.host)
   407  			if gotOrder != ht.want {
   408  				t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want)
   409  			}
   410  		}
   411  	}
   412  }
   413  
   414  func TestAddrLookupOrder(t *testing.T) {
   415  	// This test is written for a system with cgo available,
   416  	// without using the netgo tag.
   417  	if netGoBuildTag {
   418  		t.Skip("skipping test because net package built with netgo tag")
   419  	}
   420  	if !cgoAvailable {
   421  		t.Skip("skipping test because cgo resolver not available")
   422  	}
   423  
   424  	defer setSystemNSS(getSystemNSS(), 0)
   425  	c, err := newResolvConfTest()
   426  	if err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	defer c.teardown()
   430  
   431  	if !c.forceUpdateConf(defaultResolvConf, time.Now().Add(time.Hour)) {
   432  		t.Fatal("failed to change resolv config")
   433  	}
   434  
   435  	setSystemNSS(nssStr(t, "hosts: files myhostname dns"), time.Hour)
   436  	cnf := &conf{}
   437  	order, _ := cnf.addrLookupOrder(nil, "192.0.2.1")
   438  	if order != hostLookupCgo {
   439  		t.Errorf("addrLookupOrder returned: %v, want cgo", order)
   440  	}
   441  
   442  	setSystemNSS(nssStr(t, "hosts: files mdns4 dns"), time.Hour)
   443  	order, _ = cnf.addrLookupOrder(nil, "192.0.2.1")
   444  	if order != hostLookupCgo {
   445  		t.Errorf("addrLookupOrder returned: %v, want cgo", order)
   446  	}
   447  
   448  }
   449  
   450  func setSystemNSS(nss *nssConf, addDur time.Duration) {
   451  	nssConfig.mu.Lock()
   452  	nssConfig.nssConf = nss
   453  	nssConfig.mu.Unlock()
   454  	nssConfig.acquireSema()
   455  	nssConfig.lastChecked = time.Now().Add(addDur)
   456  	nssConfig.releaseSema()
   457  }
   458  
   459  func TestSystemConf(t *testing.T) {
   460  	systemConf()
   461  }
   462  

View as plain text