net/dns: handle systemd-resolved with DNSStubListener=no

Updates #11342

Signed-off-by: Andrew Dunham <andrew@du.nham.ca>
Change-Id: I5c368972b97970141ac0d6c96a19c874137c6523
This commit is contained in:
Andrew Dunham 2024-07-02 17:20:23 -04:00
parent 012933635b
commit 82a1d318ce
4 changed files with 45 additions and 4 deletions

View File

@ -495,6 +495,7 @@ type wholeFileFS interface {
ReadFile(name string) ([]byte, error) ReadFile(name string) ([]byte, error)
Remove(name string) error Remove(name string) error
Rename(oldName, newName string) error Rename(oldName, newName string) error
Readlink(name string) (string, error)
Stat(name string) (isRegular bool, err error) Stat(name string) (isRegular bool, err error)
Truncate(name string) error Truncate(name string) error
WriteFile(name string, contents []byte, perm os.FileMode) error WriteFile(name string, contents []byte, perm os.FileMode) error
@ -519,6 +520,10 @@ func (fs directFS) Stat(name string) (isRegular bool, err error) {
return fi.Mode().IsRegular(), nil return fi.Mode().IsRegular(), nil
} }
func (fs directFS) Readlink(name string) (string, error) {
return os.Readlink(fs.path(name))
}
func (fs directFS) Chmod(name string, mode os.FileMode) error { func (fs directFS) Chmod(name string, mode os.FileMode) error {
return os.Chmod(fs.path(name), mode) return os.Chmod(fs.path(name), mode)
} }

View File

@ -137,16 +137,35 @@ func dnsMode(logf logger.Logf, health *health.Tracker, env newOSConfigEnv) (ret
case "systemd-resolved": case "systemd-resolved":
dbg("rc", "resolved") dbg("rc", "resolved")
// If systemd-resolved says that the we don't have a stub resolver, but
// /etc/resolv.conf is symlinked to /run/systemd/resolve/resolv.conf,
// then systemd-resolved is managing DNS but the logic in
// resolvedIsActuallyResolver will not detect it.
//
// Check for this case and return early if we find it. See:
// https://github.com/tailscale/tailscale/issues/11342
var isResolvedNoStub bool
mode, err := env.dbusReadString("org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", "DNSStubListener")
if err == nil && mode == "no" {
target, err := env.fs.Readlink("/etc/resolv.conf")
if err == nil && target == "/run/systemd/resolve/resolv.conf" {
dbg("resolved", "no-stub")
isResolvedNoStub = true
}
}
// Some systems, for reasons known only to them, have a // Some systems, for reasons known only to them, have a
// resolv.conf that has the word "systemd-resolved" in its // resolv.conf that has the word "systemd-resolved" in its
// header, but doesn't actually point to resolved. We mustn't // header, but doesn't actually point to resolved. We mustn't
// try to program resolved in that case. // try to program resolved in that case.
// https://github.com/tailscale/tailscale/issues/2136 // https://github.com/tailscale/tailscale/issues/2136
if !isResolvedNoStub {
if err := resolvedIsActuallyResolver(logf, env, dbg, bs); err != nil { if err := resolvedIsActuallyResolver(logf, env, dbg, bs); err != nil {
logf("dns: resolvedIsActuallyResolver error: %v", err) logf("dns: resolvedIsActuallyResolver error: %v", err)
dbg("resolved", "not-in-use") dbg("resolved", "not-in-use")
return "direct", nil return "direct", nil
} }
}
if err := env.dbusPing("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/DnsManager"); err != nil { if err := env.dbusPing("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/DnsManager"); err != nil {
dbg("nm", "no") dbg("nm", "no")
return "systemd-resolved", nil return "systemd-resolved", nil

View File

@ -313,6 +313,17 @@ func (m memFS) Stat(name string) (isRegular bool, err error) {
return false, nil return false, nil
} }
func (m memFS) Readlink(name string) (string, error) {
v, ok := m[name]
if !ok {
return "", fs.ErrNotExist
}
if s, ok := v.(string); ok {
return s, nil
}
panic("unexpected")
}
func (m memFS) Chmod(name string, mode os.FileMode) error { panic("TODO") } func (m memFS) Chmod(name string, mode os.FileMode) error { panic("TODO") }
func (m memFS) Rename(oldName, newName string) error { panic("TODO") } func (m memFS) Rename(oldName, newName string) error { panic("TODO") }
func (m memFS) Remove(name string) error { panic("TODO") } func (m memFS) Remove(name string) error { panic("TODO") }

View File

@ -159,6 +159,12 @@ func (fs wslFS) Stat(name string) (isRegular bool, err error) {
return true, nil return true, nil
} }
func (fs wslFS) Readlink(name string) (string, error) {
// As of 2024-07-01, this function is only used on Linux. We can return
// the original path and no error here.
return name, nil
}
func (fs wslFS) Chmod(name string, perm os.FileMode) error { func (fs wslFS) Chmod(name string, perm os.FileMode) error {
return wslRun(fs.cmd("chmod", "--", fmt.Sprintf("%04o", perm), name)) return wslRun(fs.cmd("chmod", "--", fmt.Sprintf("%04o", perm), name))
} }