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 <jonathan@tailscale.com>
This commit is contained in:
Jonathan Nobels 2025-04-02 12:21:59 -04:00
parent 6d117d64a2
commit bb04a36c1d
2 changed files with 18 additions and 2 deletions

View File

@ -21,6 +21,7 @@ import (
"tailscale.com/net/netmon" "tailscale.com/net/netmon"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/version"
) )
func control(logf logger.Logf, netMon *netmon.Monitor) func(network, address string, c syscall.RawConn) error { 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 // It's intentionally the same signature as net.Dialer.Control
// and net.ListenConfig.Control. // and net.ListenConfig.Control.
func controlLogf(logf logger.Logf, netMon *netmon.Monitor, network, address string, c syscall.RawConn) error { 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 for tailscaled. We must still bind for
// Don't bind to an interface for localhost connections. // the network extension variants.
if version.IsMacOSTailscaled() && isLocalhost(address) {
return nil return nil
} }

View File

@ -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] var isWindowsGUI lazy.SyncValue[bool]
// IsWindowsGUI reports whether the current process is the Windows GUI. // IsWindowsGUI reports whether the current process is the Windows GUI.