summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Dunham <andrew@du.nham.ca>2024-07-02 17:20:23 -0400
committerAndrew Dunham <andrew@du.nham.ca>2024-07-02 17:45:59 -0400
commit82a1d318ce73b8be9452f1eb5232b8da21f9d33d (patch)
treec4cc20fd855875f6cb7be8f29795580c5050fc83
parent012933635b43ac41c8ff4340213bdae9abd6d059 (diff)
downloadtailscale-andrew/net-dns-systemd-no-stub.tar.xz
tailscale-andrew/net-dns-systemd-no-stub.zip
net/dns: handle systemd-resolved with DNSStubListener=noandrew/net-dns-systemd-no-stub
Updates #11342 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I5c368972b97970141ac0d6c96a19c874137c6523
-rw-r--r--net/dns/direct.go5
-rw-r--r--net/dns/manager_linux.go27
-rw-r--r--net/dns/manager_linux_test.go11
-rw-r--r--net/dns/wsl_windows.go6
4 files changed, 45 insertions, 4 deletions
diff --git a/net/dns/direct.go b/net/dns/direct.go
index aaff18fcb..1a31fd496 100644
--- a/net/dns/direct.go
+++ b/net/dns/direct.go
@@ -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)
}
diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go
index 3ba3022b6..a0cb41cea 100644
--- a/net/dns/manager_linux.go
+++ b/net/dns/manager_linux.go
@@ -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")
diff --git a/net/dns/manager_linux_test.go b/net/dns/manager_linux_test.go
index 605344c06..58b39b34c 100644
--- a/net/dns/manager_linux_test.go
+++ b/net/dns/manager_linux_test.go
@@ -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") }
diff --git a/net/dns/wsl_windows.go b/net/dns/wsl_windows.go
index 8b0780f55..a7946a88e 100644
--- a/net/dns/wsl_windows.go
+++ b/net/dns/wsl_windows.go
@@ -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))
}