Commit f3901357 authored by Alex A Skinner's avatar Alex A Skinner Committed by Brad Fitzpatrick

net: make go DNS use localhost if resolv.conf is missing or empty

Per resolv.conf man page, "If this file does not exist, only the name
server on the local machine will be queried."

This behavior also occurs if file is present but unreadable,
or if no nameservers are listed.

Fixes #10566

Change-Id: Id5716da0eae534d5ebfafea111bbc657f302e307
Reviewed-on: https://go-review.googlesource.com/9380
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 7556948e
...@@ -68,9 +68,9 @@ func initConfVal() { ...@@ -68,9 +68,9 @@ func initConfVal() {
confVal.nss = parseNSSConfFile("/etc/nsswitch.conf") confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
} }
if resolv, err := dnsReadConfig("/etc/resolv.conf"); err == nil { confVal.resolv = dnsReadConfig("/etc/resolv.conf")
confVal.resolv = resolv if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
} else if !os.IsNotExist(err.(*DNSConfigError).Err) { !os.IsPermission(confVal.resolv.err) {
// If we can't read the resolv.conf file, assume it // If we can't read the resolv.conf file, assume it
// had something important in it and defer to cgo. // had something important in it and defer to cgo.
// libc's resolver might then fail too, but at least // libc's resolver might then fail too, but at least
...@@ -85,7 +85,7 @@ func initConfVal() { ...@@ -85,7 +85,7 @@ func initConfVal() {
// hostLookupOrder determines which strategy to use to resolve hostname. // hostLookupOrder determines which strategy to use to resolve hostname.
func (c *conf) hostLookupOrder(hostname string) hostLookupOrder { func (c *conf) hostLookupOrder(hostname string) hostLookupOrder {
if c.forceCgoLookupHost { if c.forceCgoLookupHost || c.resolv.unknownOpt {
return hostLookupCgo return hostLookupCgo
} }
if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 { if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
...@@ -100,7 +100,7 @@ func (c *conf) hostLookupOrder(hostname string) hostLookupOrder { ...@@ -100,7 +100,7 @@ func (c *conf) hostLookupOrder(hostname string) hostLookupOrder {
// OpenBSD's resolv.conf manpage says that a non-existent // OpenBSD's resolv.conf manpage says that a non-existent
// resolv.conf means "lookup" defaults to only "files", // resolv.conf means "lookup" defaults to only "files",
// without DNS lookups. // without DNS lookups.
if c.resolv == nil { if os.IsNotExist(c.resolv.err) {
return hostLookupFiles return hostLookupFiles
} }
lookup := c.resolv.lookup lookup := c.resolv.lookup
...@@ -135,9 +135,6 @@ func (c *conf) hostLookupOrder(hostname string) hostLookupOrder { ...@@ -135,9 +135,6 @@ func (c *conf) hostLookupOrder(hostname string) hostLookupOrder {
return hostLookupCgo return hostLookupCgo
} }
} }
if c.resolv != nil && c.resolv.unknownOpt {
return hostLookupCgo
}
hasDot := byteIndex(hostname, '.') != -1 hasDot := byteIndex(hostname, '.') != -1
......
...@@ -19,6 +19,15 @@ type nssHostTest struct { ...@@ -19,6 +19,15 @@ type nssHostTest struct {
func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) } func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) }
// represents a dnsConfig returned by parsing a nonexistent resolv.conf
var defaultResolvConf = &dnsConfig{
servers: defaultNS,
ndots: 1,
timeout: 5,
attempts: 2,
err: os.ErrNotExist,
}
func TestConfHostLookupOrder(t *testing.T) { func TestConfHostLookupOrder(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
...@@ -31,6 +40,7 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -31,6 +40,7 @@ func TestConfHostLookupOrder(t *testing.T) {
c: &conf{ c: &conf{
forceCgoLookupHost: true, forceCgoLookupHost: true,
nss: nssStr("foo: bar"), nss: nssStr("foo: bar"),
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"foo.local", hostLookupCgo}, {"foo.local", hostLookupCgo},
...@@ -40,7 +50,8 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -40,7 +50,8 @@ func TestConfHostLookupOrder(t *testing.T) {
{ {
name: "ubuntu_trusty_avahi", name: "ubuntu_trusty_avahi",
c: &conf{ c: &conf{
nss: nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"), nss: nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"),
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"foo.local", hostLookupCgo}, {"foo.local", hostLookupCgo},
...@@ -53,8 +64,9 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -53,8 +64,9 @@ func TestConfHostLookupOrder(t *testing.T) {
{ {
name: "freebsdlinux_no_resolv_conf", name: "freebsdlinux_no_resolv_conf",
c: &conf{ c: &conf{
goos: "freebsd", goos: "freebsd",
nss: nssStr("foo: bar"), nss: nssStr("foo: bar"),
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}}, hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
}, },
...@@ -62,15 +74,17 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -62,15 +74,17 @@ func TestConfHostLookupOrder(t *testing.T) {
{ {
name: "openbsd_no_resolv_conf", name: "openbsd_no_resolv_conf",
c: &conf{ c: &conf{
goos: "openbsd", goos: "openbsd",
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{{"google.com", hostLookupFiles}}, hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
}, },
{ {
name: "solaris_no_nsswitch", name: "solaris_no_nsswitch",
c: &conf{ c: &conf{
goos: "solaris", goos: "solaris",
nss: &nssConf{err: os.ErrNotExist}, nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
}, },
...@@ -138,14 +152,18 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -138,14 +152,18 @@ func TestConfHostLookupOrder(t *testing.T) {
{ {
name: "linux_no_nsswitch.conf", name: "linux_no_nsswitch.conf",
c: &conf{ c: &conf{
goos: "linux", goos: "linux",
nss: &nssConf{err: os.ErrNotExist}, nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
}, },
hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}}, hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
}, },
{ {
name: "files_mdns_dns", name: "files_mdns_dns",
c: &conf{nss: nssStr("hosts: files mdns dns")}, c: &conf{
nss: nssStr("hosts: files mdns dns"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupFilesDNS}, {"x.com", hostLookupFilesDNS},
{"x.local", hostLookupCgo}, {"x.local", hostLookupCgo},
...@@ -153,7 +171,10 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -153,7 +171,10 @@ func TestConfHostLookupOrder(t *testing.T) {
}, },
{ {
name: "dns_special_hostnames", name: "dns_special_hostnames",
c: &conf{nss: nssStr("hosts: dns")}, c: &conf{
nss: nssStr("hosts: dns"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupDNS}, {"x.com", hostLookupDNS},
{"x\\.com", hostLookupCgo}, // punt on weird glibc escape {"x\\.com", hostLookupCgo}, // punt on weird glibc escape
...@@ -164,6 +185,7 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -164,6 +185,7 @@ func TestConfHostLookupOrder(t *testing.T) {
name: "mdns_allow", name: "mdns_allow",
c: &conf{ c: &conf{
nss: nssStr("hosts: files mdns dns"), nss: nssStr("hosts: files mdns dns"),
resolv: defaultResolvConf,
hasMDNSAllow: true, hasMDNSAllow: true,
}, },
hostTests: []nssHostTest{ hostTests: []nssHostTest{
...@@ -173,7 +195,10 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -173,7 +195,10 @@ func TestConfHostLookupOrder(t *testing.T) {
}, },
{ {
name: "files_dns", name: "files_dns",
c: &conf{nss: nssStr("hosts: files dns")}, c: &conf{
nss: nssStr("hosts: files dns"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupFilesDNS}, {"x.com", hostLookupFilesDNS},
{"x", hostLookupFilesDNS}, {"x", hostLookupFilesDNS},
...@@ -182,7 +207,10 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -182,7 +207,10 @@ func TestConfHostLookupOrder(t *testing.T) {
}, },
{ {
name: "dns_files", name: "dns_files",
c: &conf{nss: nssStr("hosts: dns files")}, c: &conf{
nss: nssStr("hosts: dns files"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupDNSFiles}, {"x.com", hostLookupDNSFiles},
{"x", hostLookupDNSFiles}, {"x", hostLookupDNSFiles},
...@@ -191,14 +219,20 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -191,14 +219,20 @@ func TestConfHostLookupOrder(t *testing.T) {
}, },
{ {
name: "something_custom", name: "something_custom",
c: &conf{nss: nssStr("hosts: dns files something_custom")}, c: &conf{
nss: nssStr("hosts: dns files something_custom"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupCgo}, {"x.com", hostLookupCgo},
}, },
}, },
{ {
name: "myhostname", name: "myhostname",
c: &conf{nss: nssStr("hosts: files dns myhostname")}, c: &conf{
nss: nssStr("hosts: files dns myhostname"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupFilesDNS}, {"x.com", hostLookupFilesDNS},
{"somehostname", hostLookupCgo}, {"somehostname", hostLookupCgo},
...@@ -206,7 +240,10 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -206,7 +240,10 @@ func TestConfHostLookupOrder(t *testing.T) {
}, },
{ {
name: "ubuntu14.04.02", name: "ubuntu14.04.02",
c: &conf{nss: nssStr("hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4")}, c: &conf{
nss: nssStr("hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupFilesDNS}, {"x.com", hostLookupFilesDNS},
{"somehostname", hostLookupCgo}, {"somehostname", hostLookupCgo},
...@@ -218,7 +255,10 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -218,7 +255,10 @@ func TestConfHostLookupOrder(t *testing.T) {
// files. // files.
{ {
name: "debian_squeeze", name: "debian_squeeze",
c: &conf{nss: nssStr("hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]")}, c: &conf{
nss: nssStr("hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"),
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{ hostTests: []nssHostTest{
{"x.com", hostLookupDNSFiles}, {"x.com", hostLookupDNSFiles},
{"somehostname", hostLookupDNSFiles}, {"somehostname", hostLookupDNSFiles},
...@@ -228,7 +268,7 @@ func TestConfHostLookupOrder(t *testing.T) { ...@@ -228,7 +268,7 @@ func TestConfHostLookupOrder(t *testing.T) {
name: "resolv.conf-unknown", name: "resolv.conf-unknown",
c: &conf{ c: &conf{
nss: nssStr("foo: bar"), nss: nssStr("foo: bar"),
resolv: &dnsConfig{unknownOpt: true}, resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
}, },
hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
}, },
......
...@@ -216,10 +216,10 @@ func convertRR_AAAA(records []dnsRR) []IP { ...@@ -216,10 +216,10 @@ func convertRR_AAAA(records []dnsRR) []IP {
var cfg struct { var cfg struct {
ch chan struct{} ch chan struct{}
mu sync.RWMutex // protects dnsConfig and dnserr mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig dnsConfig *dnsConfig
dnserr error
} }
var onceLoadConfig sync.Once var onceLoadConfig sync.Once
// Assume dns config file is /etc/resolv.conf here // Assume dns config file is /etc/resolv.conf here
...@@ -230,12 +230,12 @@ func loadDefaultConfig() { ...@@ -230,12 +230,12 @@ func loadDefaultConfig() {
func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) { func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
var mtime time.Time var mtime time.Time
cfg.ch = make(chan struct{}, 1) cfg.ch = make(chan struct{}, 1)
if fi, err := os.Stat(resolvConfPath); err != nil { if fi, err := os.Stat(resolvConfPath); err == nil {
cfg.dnserr = err
} else {
mtime = fi.ModTime() mtime = fi.ModTime()
cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
} }
cfg.dnsConfig = dnsReadConfig(resolvConfPath)
go func() { go func() {
for { for {
time.Sleep(reloadTime) time.Sleep(reloadTime)
...@@ -258,14 +258,11 @@ func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan cha ...@@ -258,14 +258,11 @@ func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan cha
} }
mtime = m mtime = m
// In case of error, we keep the previous config // In case of error, we keep the previous config
ncfg, err := dnsReadConfig(resolvConfPath) if ncfg := dnsReadConfig(resolvConfPath); ncfg.err == nil {
if err != nil || len(ncfg.servers) == 0 { cfg.mu.Lock()
continue cfg.dnsConfig = ncfg
cfg.mu.Unlock()
} }
cfg.mu.Lock()
cfg.dnsConfig = ncfg
cfg.dnserr = nil
cfg.mu.Unlock()
} }
}() }()
} }
...@@ -284,10 +281,6 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) { ...@@ -284,10 +281,6 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
cfg.mu.RLock() cfg.mu.RLock()
defer cfg.mu.RUnlock() defer cfg.mu.RUnlock()
if cfg.dnserr != nil || cfg.dnsConfig == nil {
err = cfg.dnserr
return
}
// If name is rooted (trailing dot) or has enough dots, // If name is rooted (trailing dot) or has enough dots,
// try it by itself first. // try it by itself first.
rooted := len(name) > 0 && name[len(name)-1] == '.' rooted := len(name) > 0 && name[len(name)-1] == '.'
......
...@@ -171,23 +171,26 @@ func TestReloadResolvConfFail(t *testing.T) { ...@@ -171,23 +171,26 @@ func TestReloadResolvConfFail(t *testing.T) {
r := newResolvConfTest(t) r := newResolvConfTest(t)
defer r.Close() defer r.Close()
// resolv.conf.tmp does not exist yet
r.Start() r.Start()
if _, err := goLookupIP("golang.org"); err == nil {
t.Fatal("goLookupIP(missing) succeeded")
}
r.SetConf("nameserver 8.8.8.8") r.SetConf("nameserver 8.8.8.8")
if _, err := goLookupIP("golang.org"); err != nil { if _, err := goLookupIP("golang.org"); err != nil {
t.Fatalf("goLookupIP(missing; good) failed: %v", err) t.Fatalf("goLookupIP(missing; good) failed: %v", err)
} }
// Using a bad resolv.conf while we had a good // Using an empty resolv.conf should use localhost as servers
// one before should not update the config
r.SetConf("") r.SetConf("")
if _, err := goLookupIP("golang.org"); err != nil {
t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err) if len(cfg.dnsConfig.servers) != len(defaultNS) {
t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
} }
for i := range cfg.dnsConfig.servers {
if cfg.dnsConfig.servers[i] != defaultNS[i] {
t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
}
}
} }
func TestReloadResolvConfChange(t *testing.T) { func TestReloadResolvConfChange(t *testing.T) {
...@@ -198,19 +201,25 @@ func TestReloadResolvConfChange(t *testing.T) { ...@@ -198,19 +201,25 @@ func TestReloadResolvConfChange(t *testing.T) {
r := newResolvConfTest(t) r := newResolvConfTest(t)
defer r.Close() defer r.Close()
r.SetConf("nameserver 8.8.8.8")
r.Start() r.Start()
r.SetConf("nameserver 8.8.8.8")
if _, err := goLookupIP("golang.org"); err != nil { if _, err := goLookupIP("golang.org"); err != nil {
t.Fatalf("goLookupIP(good) failed: %v", err) t.Fatalf("goLookupIP(good) failed: %v", err)
} }
r.WantServers([]string{"8.8.8.8"}) r.WantServers([]string{"8.8.8.8"})
// Using a bad resolv.conf when we had a good one // Using an empty resolv.conf should use localhost as servers
// before should not update the config
r.SetConf("") r.SetConf("")
if _, err := goLookupIP("golang.org"); err != nil {
t.Fatalf("goLookupIP(good; bad) failed: %v", err) if len(cfg.dnsConfig.servers) != len(defaultNS) {
t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
}
for i := range cfg.dnsConfig.servers {
if cfg.dnsConfig.servers[i] != defaultNS[i] {
t.Fatalf("goLookupIP(missing; good; bad) failed: servers=%v, want: %v", cfg.dnsConfig.servers, defaultNS)
}
} }
// A new good config should get picked up // A new good config should get picked up
...@@ -238,9 +247,7 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { ...@@ -238,9 +247,7 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
testHookUninstaller.Do(func() { uninstallTestHooks() }) testHookUninstaller.Do(func() { uninstallTestHooks() })
onceLoadConfig.Do(loadDefaultConfig) onceLoadConfig.Do(loadDefaultConfig)
if cfg.dnserr != nil || cfg.dnsConfig == nil {
b.Fatalf("loadConfig failed: %v", cfg.dnserr)
}
// This looks ugly but it's safe as long as benchmarks are run // This looks ugly but it's safe as long as benchmarks are run
// sequentially in package testing. // sequentially in package testing.
orig := cfg.dnsConfig orig := cfg.dnsConfig
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
package net package net
var defaultNS = []string{"127.0.0.1", "::1"}
type dnsConfig struct { type dnsConfig struct {
servers []string // servers to use servers []string // servers to use
search []string // suffixes to append to local name search []string // suffixes to append to local name
...@@ -17,22 +19,25 @@ type dnsConfig struct { ...@@ -17,22 +19,25 @@ type dnsConfig struct {
rotate bool // round robin among servers rotate bool // round robin among servers
unknownOpt bool // anything unknown was encountered unknownOpt bool // anything unknown was encountered
lookup []string // OpenBSD top-level database "lookup" order lookup []string // OpenBSD top-level database "lookup" order
err error // any error that occurs during open of resolv.conf
} }
// See resolv.conf(5) on a Linux machine. // See resolv.conf(5) on a Linux machine.
// TODO(rsc): Supposed to call uname() and chop the beginning // TODO(rsc): Supposed to call uname() and chop the beginning
// of the host name to get the default search domain. // of the host name to get the default search domain.
func dnsReadConfig(filename string) (*dnsConfig, error) { func dnsReadConfig(filename string) *dnsConfig {
file, err := open(filename)
if err != nil {
return nil, &DNSConfigError{err}
}
defer file.close()
conf := &dnsConfig{ conf := &dnsConfig{
ndots: 1, ndots: 1,
timeout: 5, timeout: 5,
attempts: 2, attempts: 2,
} }
file, err := open(filename)
if err != nil {
conf.servers = defaultNS
conf.err = err
return conf
}
defer file.close()
for line, ok := file.readLine(); ok; line, ok = file.readLine() { for line, ok := file.readLine(); ok; line, ok = file.readLine() {
if len(line) > 0 && (line[0] == ';' || line[0] == '#') { if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
// comment. // comment.
...@@ -104,7 +109,10 @@ func dnsReadConfig(filename string) (*dnsConfig, error) { ...@@ -104,7 +109,10 @@ func dnsReadConfig(filename string) (*dnsConfig, error) {
conf.unknownOpt = true conf.unknownOpt = true
} }
} }
return conf, nil if len(conf.servers) == 0 {
conf.servers = defaultNS
}
return conf
} }
func hasPrefix(s, prefix string) bool { func hasPrefix(s, prefix string) bool {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package net package net
import ( import (
"os"
"reflect" "reflect"
"testing" "testing"
) )
...@@ -50,6 +51,7 @@ var dnsReadConfigTests = []struct { ...@@ -50,6 +51,7 @@ var dnsReadConfigTests = []struct {
{ {
name: "testdata/empty-resolv.conf", name: "testdata/empty-resolv.conf",
want: &dnsConfig{ want: &dnsConfig{
servers: defaultNS,
ndots: 1, ndots: 1,
timeout: 5, timeout: 5,
attempts: 2, attempts: 2,
...@@ -70,12 +72,29 @@ var dnsReadConfigTests = []struct { ...@@ -70,12 +72,29 @@ var dnsReadConfigTests = []struct {
func TestDNSReadConfig(t *testing.T) { func TestDNSReadConfig(t *testing.T) {
for _, tt := range dnsReadConfigTests { for _, tt := range dnsReadConfigTests {
conf, err := dnsReadConfig(tt.name) conf := dnsReadConfig(tt.name)
if err != nil { if conf.err != nil {
t.Fatal(err) t.Fatal(conf.err)
} }
if !reflect.DeepEqual(conf, tt.want) { if !reflect.DeepEqual(conf, tt.want) {
t.Errorf("%s:\n got: %+v\nwant: %+v", tt.name, conf, tt.want) t.Errorf("%s:\n got: %+v\nwant: %+v", tt.name, conf, tt.want)
} }
} }
} }
func TestDNSReadMissingFile(t *testing.T) {
conf := dnsReadConfig("a-nonexistent-file")
if !os.IsNotExist(conf.err) {
t.Errorf("Missing resolv.conf:\n got: %v\nwant: %v", conf.err, os.ErrNotExist)
}
conf.err = nil
want := &dnsConfig{
servers: defaultNS,
ndots: 1,
timeout: 5,
attempts: 2,
}
if !reflect.DeepEqual(conf, want) {
t.Errorf("Missing resolv.conf:\n got: %+v\nwant: %+v", conf, want)
}
}
...@@ -62,9 +62,6 @@ second: ...@@ -62,9 +62,6 @@ second:
switch err := nestedErr.(type) { switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
return nil return nil
case *DNSConfigError:
nestedErr = err.Err
goto third
case *os.SyscallError: case *os.SyscallError:
nestedErr = err.Err nestedErr = err.Err
goto third goto third
...@@ -293,9 +290,6 @@ second: ...@@ -293,9 +290,6 @@ second:
switch err := nestedErr.(type) { switch err := nestedErr.(type) {
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
return nil return nil
case *DNSConfigError:
nestedErr = err.Err
goto third
case *os.SyscallError: case *os.SyscallError:
nestedErr = err.Err nestedErr = err.Err
goto third goto third
......
...@@ -435,6 +435,7 @@ func (e InvalidAddrError) Timeout() bool { return false } ...@@ -435,6 +435,7 @@ func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false } func (e InvalidAddrError) Temporary() bool { return false }
// DNSConfigError represents an error reading the machine's DNS configuration. // DNSConfigError represents an error reading the machine's DNS configuration.
// (No longer used; kept for compatibility.)
type DNSConfigError struct { type DNSConfigError struct {
Err error Err error
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment