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)
Remove(name string) error
Rename(oldName, newName string) error
Readlink(name string) (string, error)
Stat(name string) (isRegular bool, err error)
Truncate(name string) 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
}
func (fs directFS) Readlink(name string) (string, error) {
return os.Readlink(fs.path(name))
}
func (fs directFS) Chmod(name string, mode os.FileMode) error {
return os.Chmod(fs.path(name), mode)
}

View File

@ -137,15 +137,34 @@ func dnsMode(logf logger.Logf, health *health.Tracker, env newOSConfigEnv) (ret
case "systemd-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
// resolv.conf that has the word "systemd-resolved" in its
// header, but doesn't actually point to resolved. We mustn't
// try to program resolved in that case.
// https://github.com/tailscale/tailscale/issues/2136
if err := resolvedIsActuallyResolver(logf, env, dbg, bs); err != nil {
logf("dns: resolvedIsActuallyResolver error: %v", err)
dbg("resolved", "not-in-use")
return "direct", nil
if !isResolvedNoStub {
if err := resolvedIsActuallyResolver(logf, env, dbg, bs); err != nil {
logf("dns: resolvedIsActuallyResolver error: %v", err)
dbg("resolved", "not-in-use")
return "direct", nil
}
}
if err := env.dbusPing("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/DnsManager"); err != nil {
dbg("nm", "no")

View File

@ -313,6 +313,17 @@ func (m memFS) Stat(name string) (isRegular bool, err error) {
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) Rename(oldName, newName 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
}
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 {
return wslRun(fs.cmd("chmod", "--", fmt.Sprintf("%04o", perm), name))
}