From 97ee3891f1187dfa8e6583cb6d2b4e1ca55d3d70 Mon Sep 17 00:00:00 2001
From: Denton Gentry <dgentry@tailscale.com>
Date: Sun, 15 Oct 2023 15:32:37 -0700
Subject: [PATCH] net/dns: use direct when NetworkManager has no
 systemd-resolved

Endeavour OS, at least, uses NetworkManager 1.44.2 and does
not use systemd-resolved behind the scenes at all. If we
find ourselves in that situation, return "direct" not
"systemd-resolved"

Fixes https://github.com/tailscale/tailscale/issues/9687

Signed-off-by: Denton Gentry <dgentry@tailscale.com>
---
 net/dns/manager_linux.go      |  7 +++++++
 net/dns/manager_linux_test.go | 12 ++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go
index 642fe99c5..75662d672 100644
--- a/net/dns/manager_linux.go
+++ b/net/dns/manager_linux.go
@@ -265,6 +265,13 @@ func dnsMode(logf logger.Logf, env newOSConfigEnv) (ret string, err error) {
 			dbg("nm-safe", "yes")
 			return "network-manager", nil
 		}
+		if err := env.nmIsUsingResolved(); err != nil {
+			// If systemd-resolved is not running at all, then we don't have any
+			// other choice: we take direct control of DNS.
+			dbg("nm-resolved", "no")
+			return "direct", nil
+		}
+
 		health.SetDNSManagerHealth(errors.New("systemd-resolved and NetworkManager are wired together incorrectly; MagicDNS will probably not work. For more info, see https://tailscale.com/s/resolved-nm"))
 		dbg("nm-safe", "no")
 		return "systemd-resolved", nil
diff --git a/net/dns/manager_linux_test.go b/net/dns/manager_linux_test.go
index c936d7b02..bbaa7ddc1 100644
--- a/net/dns/manager_linux_test.go
+++ b/net/dns/manager_linux_test.go
@@ -270,6 +270,18 @@ func TestLinuxDNSMode(t *testing.T) {
 			wantLog: "dns: [resolved-ping=yes rc=resolved resolved=file nm=no resolv-conf-mode=fortests ret=systemd-resolved]",
 			want:    "systemd-resolved",
 		},
+		{
+			// regression test for https://github.com/tailscale/tailscale/issues/9687
+			name: "networkmanager_endeavouros",
+			env: env(resolvDotConf(
+				"# Generated by NetworkManager",
+				"search example.com localdomain",
+				"nameserver 10.0.0.1"),
+				nmRunning("1.44.2", false)),
+			wantLog: "dns: resolvedIsActuallyResolver error: resolv.conf doesn't point to systemd-resolved; points to [10.0.0.1]\n" +
+				"dns: [rc=nm resolved=not-in-use ret=direct]",
+			want: "direct",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {