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

net: fix race in (*resolverConfig).tryUpdate

Fixes #14072.

Change-Id: Ie31caa06690ac621906fc5acd34da2efa4e2049f
Reviewed-on: https://go-review.googlesource.com/18860Reviewed-by: default avatarMikio Hara <mikioh.mikioh@gmail.com>
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
parent 315f4c70
...@@ -229,7 +229,6 @@ type resolverConfig struct { ...@@ -229,7 +229,6 @@ type resolverConfig struct {
// time to recheck resolv.conf. // time to recheck resolv.conf.
ch chan struct{} // guards lastChecked and modTime ch chan struct{} // guards lastChecked and modTime
lastChecked time.Time // last time resolv.conf was checked lastChecked time.Time // last time resolv.conf was checked
modTime time.Time // time of resolv.conf modification
mu sync.RWMutex // protects dnsConfig mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
...@@ -239,16 +238,12 @@ var resolvConf resolverConfig ...@@ -239,16 +238,12 @@ var resolvConf resolverConfig
// init initializes conf and is only called via conf.initOnce. // init initializes conf and is only called via conf.initOnce.
func (conf *resolverConfig) init() { func (conf *resolverConfig) init() {
// Set dnsConfig, modTime, and lastChecked so we don't parse // Set dnsConfig and lastChecked so we don't parse
// resolv.conf twice the first time. // resolv.conf twice the first time.
conf.dnsConfig = systemConf().resolv conf.dnsConfig = systemConf().resolv
if conf.dnsConfig == nil { if conf.dnsConfig == nil {
conf.dnsConfig = dnsReadConfig("/etc/resolv.conf") conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
} }
if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
conf.modTime = fi.ModTime()
}
conf.lastChecked = time.Now() conf.lastChecked = time.Now()
// Prepare ch so that only one update of resolverConfig may // Prepare ch so that only one update of resolverConfig may
...@@ -274,17 +269,12 @@ func (conf *resolverConfig) tryUpdate(name string) { ...@@ -274,17 +269,12 @@ func (conf *resolverConfig) tryUpdate(name string) {
} }
conf.lastChecked = now conf.lastChecked = now
var mtime time.Time
if fi, err := os.Stat(name); err == nil { if fi, err := os.Stat(name); err == nil {
if fi.ModTime().Equal(conf.modTime) { mtime = fi.ModTime()
return }
} if mtime.Equal(conf.dnsConfig.mtime) {
conf.modTime = fi.ModTime() return
} else {
// If modTime wasn't set prior, assume nothing has changed.
if conf.modTime.IsZero() {
return
}
conf.modTime = time.Time{}
} }
dnsConf := dnsReadConfig(name) dnsConf := dnsReadConfig(name)
......
...@@ -8,18 +8,21 @@ ...@@ -8,18 +8,21 @@
package net package net
import "time"
var defaultNS = []string{"127.0.0.1", "::1"} 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
ndots int // number of dots in name to trigger absolute lookup ndots int // number of dots in name to trigger absolute lookup
timeout int // seconds before giving up on packet timeout int // seconds before giving up on packet
attempts int // lost packets before giving up on server attempts int // lost packets before giving up on server
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 err error // any error that occurs during open of resolv.conf
mtime time.Time // time of resolv.conf modification
} }
// See resolv.conf(5) on a Linux machine. // See resolv.conf(5) on a Linux machine.
...@@ -38,6 +41,13 @@ func dnsReadConfig(filename string) *dnsConfig { ...@@ -38,6 +41,13 @@ func dnsReadConfig(filename string) *dnsConfig {
return conf return conf
} }
defer file.close() defer file.close()
if fi, err := file.file.Stat(); err == nil {
conf.mtime = fi.ModTime()
} else {
conf.servers = defaultNS
conf.err = err
return conf
}
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.
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"os" "os"
"reflect" "reflect"
"testing" "testing"
"time"
) )
var dnsReadConfigTests = []struct { var dnsReadConfigTests = []struct {
...@@ -76,6 +77,7 @@ func TestDNSReadConfig(t *testing.T) { ...@@ -76,6 +77,7 @@ func TestDNSReadConfig(t *testing.T) {
if conf.err != nil { if conf.err != nil {
t.Fatal(conf.err) t.Fatal(conf.err)
} }
conf.mtime = time.Time{}
if !reflect.DeepEqual(conf, tt.want) { if !reflect.DeepEqual(conf, tt.want) {
t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want) t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
} }
......
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