From 6dc3d6f7872d46d3df95f662a9052985e800391e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 23 Jul 2023 09:41:27 -0700 Subject: [PATCH] net/dns: make directManager use /tmp/resolv.conf on gokrazy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Appliances built using https://gokrazy.org/ have a read-only root file system, including /etc/resolv.conf, which is a symlink to /tmp/resolv.conf. The system’s dhcp client overwrites /tmp/resolv.conf instead, so we need to use this path in Tailscale, too. Fixes #8689 Updates gokrazy/gokrazy#209 Co-authored-by: Michael Stapelberg Signed-off-by: Brad Fitzpatrick --- net/dns/direct.go | 55 +++++++++++++++++++++++----------------- net/dns/direct_linux.go | 2 +- net/dns/manager_linux.go | 2 +- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/net/dns/direct.go b/net/dns/direct.go index 0cae70d0e..b2947108e 100644 --- a/net/dns/direct.go +++ b/net/dns/direct.go @@ -28,8 +28,8 @@ import ( ) const ( - backupConf = "/etc/resolv.pre-tailscale-backup.conf" - resolvConf = "/etc/resolv.conf" + defaultBackupConf = "/etc/resolv.pre-tailscale-backup.conf" + defaultResolvConf = "/etc/resolv.conf" ) // writeResolvConf writes DNS configuration in resolv.conf format to the given writer. @@ -132,6 +132,9 @@ type directManager struct { // but is better than having non-functioning DNS. renameBroken bool + resolvConf string // usually "/etc/resolv.conf" + backupConf string // usually "/etc/resolv.pre-tailscale-backup.conf" + ctx context.Context // valid until Close ctxClose context.CancelFunc // closes ctx @@ -147,10 +150,16 @@ func newDirectManager(logf logger.Logf) *directManager { func newDirectManagerOnFS(logf logger.Logf, fs wholeFileFS) *directManager { ctx, cancel := context.WithCancel(context.Background()) m := &directManager{ - logf: logf, - fs: fs, - ctx: ctx, - ctxClose: cancel, + logf: logf, + fs: fs, + ctx: ctx, + ctxClose: cancel, + resolvConf: defaultResolvConf, + backupConf: defaultBackupConf, + } + if distro.Get() == distro.Gokrazy { + m.resolvConf = "/tmp/resolv.conf" + m.backupConf = "/tmp/resolv.pre-tailscale-backup.conf" } go m.runFileWatcher() return m @@ -167,7 +176,7 @@ func (m *directManager) readResolvFile(path string) (OSConfig, error) { // ownedByTailscale reports whether /etc/resolv.conf seems to be a // tailscale-managed file. func (m *directManager) ownedByTailscale() (bool, error) { - isRegular, err := m.fs.Stat(resolvConf) + isRegular, err := m.fs.Stat(m.resolvConf) if err != nil { if os.IsNotExist(err) { return false, nil @@ -177,7 +186,7 @@ func (m *directManager) ownedByTailscale() (bool, error) { if !isRegular { return false, nil } - bs, err := m.fs.ReadFile(resolvConf) + bs, err := m.fs.ReadFile(m.resolvConf) if err != nil { return false, err } @@ -190,11 +199,11 @@ func (m *directManager) ownedByTailscale() (bool, error) { // backupConfig creates or updates a backup of /etc/resolv.conf, if // resolv.conf does not currently contain a Tailscale-managed config. func (m *directManager) backupConfig() error { - if _, err := m.fs.Stat(resolvConf); err != nil { + if _, err := m.fs.Stat(m.resolvConf); err != nil { if os.IsNotExist(err) { // No resolv.conf, nothing to back up. Also get rid of any // existing backup file, to avoid restoring something old. - m.fs.Remove(backupConf) + m.fs.Remove(m.backupConf) return nil } return err @@ -208,11 +217,11 @@ func (m *directManager) backupConfig() error { return nil } - return m.rename(resolvConf, backupConf) + return m.rename(m.resolvConf, m.backupConf) } func (m *directManager) restoreBackup() (restored bool, err error) { - if _, err := m.fs.Stat(backupConf); err != nil { + if _, err := m.fs.Stat(m.backupConf); err != nil { if os.IsNotExist(err) { // No backup, nothing we can do. return false, nil @@ -223,7 +232,7 @@ func (m *directManager) restoreBackup() (restored bool, err error) { if err != nil { return false, err } - _, err = m.fs.Stat(resolvConf) + _, err = m.fs.Stat(m.resolvConf) if err != nil && !os.IsNotExist(err) { return false, err } @@ -232,12 +241,12 @@ func (m *directManager) restoreBackup() (restored bool, err error) { if resolvConfExists && !owned { // There's already a non-tailscale config in place, get rid of // our backup. - m.fs.Remove(backupConf) + m.fs.Remove(m.backupConf) return false, nil } // We own resolv.conf, and a backup exists. - if err := m.rename(backupConf, resolvConf); err != nil { + if err := m.rename(m.backupConf, m.resolvConf); err != nil { return false, err } @@ -307,7 +316,7 @@ func (m *directManager) checkForFileTrample() { return } - cur, err := m.fs.ReadFile(resolvConf) + cur, err := m.fs.ReadFile(m.resolvConf) if err != nil { m.logf("trample: read error: %v", err) return @@ -365,7 +374,7 @@ func (m *directManager) SetDNS(config OSConfig) (err error) { buf := new(bytes.Buffer) writeResolvConf(buf, config.Nameservers, config.SearchDomains) - if err := m.atomicWriteFile(m.fs, resolvConf, buf.Bytes(), 0644); err != nil { + if err := m.atomicWriteFile(m.fs, m.resolvConf, buf.Bytes(), 0644); err != nil { return err } @@ -414,9 +423,9 @@ func (m *directManager) GetBaseConfig() (OSConfig, error) { if err != nil { return OSConfig{}, err } - fileToRead := resolvConf + fileToRead := m.resolvConf if owned { - fileToRead = backupConf + fileToRead = m.backupConf } return m.readResolvFile(fileToRead) @@ -429,7 +438,7 @@ func (m *directManager) Close() error { // things. Clean it up if it's still there. m.fs.Remove("/etc/resolv.tailscale.conf") - if _, err := m.fs.Stat(backupConf); err != nil { + if _, err := m.fs.Stat(m.backupConf); err != nil { if os.IsNotExist(err) { // No backup, nothing we can do. return nil @@ -440,7 +449,7 @@ func (m *directManager) Close() error { if err != nil { return err } - _, err = m.fs.Stat(resolvConf) + _, err = m.fs.Stat(m.resolvConf) if err != nil && !os.IsNotExist(err) { return err } @@ -449,12 +458,12 @@ func (m *directManager) Close() error { if resolvConfExists && !owned { // There's already a non-tailscale config in place, get rid of // our backup. - m.fs.Remove(backupConf) + m.fs.Remove(m.backupConf) return nil } // We own resolv.conf, and a backup exists. - if err := m.rename(backupConf, resolvConf); err != nil { + if err := m.rename(m.backupConf, m.resolvConf); err != nil { return err } diff --git a/net/dns/direct_linux.go b/net/dns/direct_linux.go index 4a388c47b..82d348909 100644 --- a/net/dns/direct_linux.go +++ b/net/dns/direct_linux.go @@ -43,7 +43,7 @@ func (m *directManager) runFileWatcher() { } var match bool for _, ev := range events { - if ev.Name == resolvConf { + if ev.Name == m.resolvConf { match = true break } diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go index 642fe99c5..0be7a4dec 100644 --- a/net/dns/manager_linux.go +++ b/net/dns/manager_linux.go @@ -121,7 +121,7 @@ func dnsMode(logf logger.Logf, env newOSConfigEnv) (ret string, err error) { dbg("resolved-ping", "yes") } - bs, err := env.fs.ReadFile(resolvConf) + bs, err := env.fs.ReadFile(defaultResolvConf) if os.IsNotExist(err) { dbg("rc", "missing") return "direct", nil