From bb04a36c1d5082c89794d11be6e006398695b39b Mon Sep 17 00:00:00 2001 From: Jonathan Nobels Date: Wed, 2 Apr 2025 12:21:59 -0400 Subject: [PATCH] net/netns, version: enable interface binding for loopback addrs on sandboxed macos fixes tailscale/corp#27506 The bootstrapDNS code is unable to resolve log and derp endpoints when if the forward dns is a local loopback addr while the tunnel is running. Sandboxed macos requires that we bind to loopback addresses explicitly. tailscaled on mac must not. Signed-off-by: Jonathan Nobels --- net/netns/netns_darwin.go | 6 ++++-- version/prop.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/net/netns/netns_darwin.go b/net/netns/netns_darwin.go index ac5e89d76..794b9b864 100644 --- a/net/netns/netns_darwin.go +++ b/net/netns/netns_darwin.go @@ -21,6 +21,7 @@ import ( "tailscale.com/net/netmon" "tailscale.com/net/tsaddr" "tailscale.com/types/logger" + "tailscale.com/version" ) func control(logf logger.Logf, netMon *netmon.Monitor) func(network, address string, c syscall.RawConn) error { @@ -38,8 +39,9 @@ var errInterfaceStateInvalid = errors.New("interface state invalid") // It's intentionally the same signature as net.Dialer.Control // and net.ListenConfig.Control. func controlLogf(logf logger.Logf, netMon *netmon.Monitor, network, address string, c syscall.RawConn) error { - if isLocalhost(address) { - // Don't bind to an interface for localhost connections. + // Don't bind to an interface for localhost connections for tailscaled. We must still bind for + // the network extension variants. + if version.IsMacOSTailscaled() && isLocalhost(address) { return nil } diff --git a/version/prop.go b/version/prop.go index 9327e6fe6..a3d15b1d5 100644 --- a/version/prop.go +++ b/version/prop.go @@ -147,6 +147,20 @@ func IsAppleTV() bool { }) } +var isMacOSTailscaled lazy.SyncValue[bool] + +// IsMacOSTailscaled reports whether this binary is the tailscaled daemon running on macos +func IsMacOSTailscaled() bool { + // This rules out iOS and tvOS + if runtime.GOOS != "darwin" { + return false + } + return isMacOSTailscaled.Get(func() bool { + // A darwin client that is not sandboxed macOS is tailscaled + return !IsSandboxedMacOS() + }) +} + var isWindowsGUI lazy.SyncValue[bool] // IsWindowsGUI reports whether the current process is the Windows GUI.