Commit 5fe1b35e authored by Matthew Dempsky's avatar Matthew Dempsky

net: ensure dnsConfig search list is rooted

Avoids some extra work and string concatenation at query time.

benchmark                                      old allocs     new allocs     delta
BenchmarkGoLookupIP-32                         154            150            -2.60%
BenchmarkGoLookupIPNoSuchHost-32               446            442            -0.90%
BenchmarkGoLookupIPWithBrokenNameServer-32     564            568            +0.71%

benchmark                                      old bytes     new bytes     delta
BenchmarkGoLookupIP-32                         10824         10704         -1.11%
BenchmarkGoLookupIPNoSuchHost-32               43140         42992         -0.34%
BenchmarkGoLookupIPWithBrokenNameServer-32     46616         46680         +0.14%

BenchmarkGoLookupIPWithBrokenNameServer's regression appears to be
because it's actually only performing 1 LookupIP call, so the extra
work done parsing the DNS config file doesn't amortize as well as for
BenchmarkGoLookupIP or BenchmarkGoLOokupIPNoSuchHost, which perform
2000+ LookupIP calls per run.

Update #15473.

Change-Id: I98c8072f2f39e2f2ccd6c55e9e9bd309f5ad68f8
Reviewed-on: https://go-review.googlesource.com/22571Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 4d9bda51
...@@ -361,23 +361,23 @@ func (conf *dnsConfig) nameList(name string) []string { ...@@ -361,23 +361,23 @@ func (conf *dnsConfig) nameList(name string) []string {
if rooted { if rooted {
return []string{name} return []string{name}
} }
hasNdots := count(name, '.') >= conf.ndots
name += "."
// Build list of search choices. // Build list of search choices.
names := make([]string, 0, 1+len(conf.search)) names := make([]string, 0, 1+len(conf.search))
// If name has enough dots, try unsuffixed first. // If name has enough dots, try unsuffixed first.
if count(name, '.') >= conf.ndots { if hasNdots {
names = append(names, name+".") names = append(names, name)
} }
// Try suffixes. // Try suffixes.
for _, suffix := range conf.search { for _, suffix := range conf.search {
suffixed := name + "." + suffix names = append(names, name+suffix)
if suffixed[len(suffixed)-1] != '.' {
suffixed += "."
}
names = append(names, suffixed)
} }
// Try unsuffixed, if not tried first above. // Try unsuffixed, if not tried first above.
if count(name, '.') < conf.ndots { if !hasNdots {
names = append(names, name+".") names = append(names, name)
} }
return names return names
} }
......
...@@ -20,7 +20,7 @@ var ( ...@@ -20,7 +20,7 @@ var (
type dnsConfig struct { type dnsConfig struct {
servers []string // server addresses (in host:port form) to use servers []string // server addresses (in host:port form) to use
search []string // suffixes to append to local name search []string // rooted suffixes to append to local name
ndots int // number of dots in name to trigger absolute lookup ndots int // number of dots in name to trigger absolute lookup
timeout time.Duration // wait before giving up on a query, including retries timeout time.Duration // wait before giving up on a query, including retries
attempts int // lost packets before giving up on server attempts int // lost packets before giving up on server
...@@ -78,13 +78,13 @@ func dnsReadConfig(filename string) *dnsConfig { ...@@ -78,13 +78,13 @@ func dnsReadConfig(filename string) *dnsConfig {
case "domain": // set search path to just this domain case "domain": // set search path to just this domain
if len(f) > 1 { if len(f) > 1 {
conf.search = []string{f[1]} conf.search = []string{ensureRooted(f[1])}
} }
case "search": // set search path to given servers case "search": // set search path to given servers
conf.search = make([]string, len(f)-1) conf.search = make([]string, len(f)-1)
for i := 0; i < len(conf.search); i++ { for i := 0; i < len(conf.search); i++ {
conf.search[i] = f[i+1] conf.search[i] = ensureRooted(f[i+1])
} }
case "options": // magic options case "options": // magic options
...@@ -141,7 +141,7 @@ func dnsDefaultSearch() []string { ...@@ -141,7 +141,7 @@ func dnsDefaultSearch() []string {
return nil return nil
} }
if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 { if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 {
return []string{hn[i+1:]} return []string{ensureRooted(hn[i+1:])}
} }
return nil return nil
} }
...@@ -149,3 +149,10 @@ func dnsDefaultSearch() []string { ...@@ -149,3 +149,10 @@ func dnsDefaultSearch() []string {
func hasPrefix(s, prefix string) bool { func hasPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && s[:len(prefix)] == prefix return len(s) >= len(prefix) && s[:len(prefix)] == prefix
} }
func ensureRooted(s string) string {
if len(s) > 0 && s[len(s)-1] == '.' {
return s
}
return s + "."
}
...@@ -22,7 +22,7 @@ var dnsReadConfigTests = []struct { ...@@ -22,7 +22,7 @@ var dnsReadConfigTests = []struct {
name: "testdata/resolv.conf", name: "testdata/resolv.conf",
want: &dnsConfig{ want: &dnsConfig{
servers: []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"}, servers: []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
search: []string{"localdomain"}, search: []string{"localdomain."},
ndots: 5, ndots: 5,
timeout: 10 * time.Second, timeout: 10 * time.Second,
attempts: 3, attempts: 3,
...@@ -34,7 +34,7 @@ var dnsReadConfigTests = []struct { ...@@ -34,7 +34,7 @@ var dnsReadConfigTests = []struct {
name: "testdata/domain-resolv.conf", name: "testdata/domain-resolv.conf",
want: &dnsConfig{ want: &dnsConfig{
servers: []string{"8.8.8.8:53"}, servers: []string{"8.8.8.8:53"},
search: []string{"localdomain"}, search: []string{"localdomain."},
ndots: 1, ndots: 1,
timeout: 5 * time.Second, timeout: 5 * time.Second,
attempts: 2, attempts: 2,
...@@ -44,7 +44,7 @@ var dnsReadConfigTests = []struct { ...@@ -44,7 +44,7 @@ var dnsReadConfigTests = []struct {
name: "testdata/search-resolv.conf", name: "testdata/search-resolv.conf",
want: &dnsConfig{ want: &dnsConfig{
servers: []string{"8.8.8.8:53"}, servers: []string{"8.8.8.8:53"},
search: []string{"test", "invalid"}, search: []string{"test.", "invalid."},
ndots: 1, ndots: 1,
timeout: 5 * time.Second, timeout: 5 * time.Second,
attempts: 2, attempts: 2,
...@@ -57,7 +57,7 @@ var dnsReadConfigTests = []struct { ...@@ -57,7 +57,7 @@ var dnsReadConfigTests = []struct {
ndots: 1, ndots: 1,
timeout: 5 * time.Second, timeout: 5 * time.Second,
attempts: 2, attempts: 2,
search: []string{"domain.local"}, search: []string{"domain.local."},
}, },
}, },
{ {
...@@ -105,7 +105,7 @@ func TestDNSReadMissingFile(t *testing.T) { ...@@ -105,7 +105,7 @@ func TestDNSReadMissingFile(t *testing.T) {
ndots: 1, ndots: 1,
timeout: 5 * time.Second, timeout: 5 * time.Second,
attempts: 2, attempts: 2,
search: []string{"domain.local"}, search: []string{"domain.local."},
} }
if !reflect.DeepEqual(conf, want) { if !reflect.DeepEqual(conf, want) {
t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want) t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
...@@ -119,11 +119,11 @@ var dnsDefaultSearchTests = []struct { ...@@ -119,11 +119,11 @@ var dnsDefaultSearchTests = []struct {
}{ }{
{ {
name: "host.long.domain.local", name: "host.long.domain.local",
want: []string{"long.domain.local"}, want: []string{"long.domain.local."},
}, },
{ {
name: "host.local", name: "host.local",
want: []string{"local"}, want: []string{"local."},
}, },
{ {
name: "host", name: "host",
......
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