From eadac39ea778a471a61a7272ab191bd356e523ac Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 7 Aug 2026 16:04:20 -0400 Subject: [PATCH] Add NativeConfigDisabled flag to skip raw interface configuration on Darwin --- network/interface.go | 8 ++++++++ network/route.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/network/interface.go b/network/interface.go index 6b196d4..f33ec40 100644 --- a/network/interface.go +++ b/network/interface.go @@ -115,6 +115,10 @@ func FindUnusedUTUN() (string, error) { } func configureDarwin(interfaceName string, ip net.IP, ipNet *net.IPNet) error { + if NativeConfigDisabled { + return nil + } + logger.Info("Configuring darwin interface: %s", interfaceName) prefix, _ := ipNet.Mask.Size() @@ -246,6 +250,10 @@ func removeLinuxAddress(interfaceName string, ip net.IP, ipNet *net.IPNet) error } func removeDarwinAddress(interfaceName string, ip net.IP, ipNet *net.IPNet) error { + if NativeConfigDisabled { + return nil + } + prefix, _ := ipNet.Mask.Size() ipStr := fmt.Sprintf("%s/%d", ip.String(), prefix) diff --git a/network/route.go b/network/route.go index bc5905a..7081bdf 100644 --- a/network/route.go +++ b/network/route.go @@ -32,6 +32,20 @@ const VPNRouteMetric = 9999 // this to true (e.g. from a config value) before routes are added. var PreferLocalRoutes = false +// NativeConfigDisabled, when true, skips the raw `ifconfig`/`route` subprocess +// calls this package otherwise makes on darwin (configureDarwin, +// removeDarwinAddress, DarwinAddRouteWithSource, DarwinRemoveRoute) while still +// populating the JSON-facing NetworkSettings state. This must be set when the +// TUN device's addresses/routes are instead owned by an external mechanism +// that reconciles them independently - namely Apple's NetworkExtension +// (NEPacketTunnelProvider.setTunnelNetworkSettings), which is the sole +// sanctioned way to configure that virtual interface. Running our own +// ifconfig/route commands in addition to NE applying its own settings was +// observed to install two competing routes to the same destination (one via +// NE's gatewayAddress-based route, one via our own `-ifa` route), so the two +// mechanisms must be mutually exclusive rather than layered. +var NativeConfigDisabled = false + // DarwinAddRoute adds a route via the BSD routing table. Unlike Linux/Windows, // BSD's routing table has no per-route metric - preference between an // overlapping local route and this VPN route is instead resolved by @@ -54,6 +68,9 @@ func DarwinAddRouteWithSource(destination string, gateway string, interfaceName if runtime.GOOS != "darwin" { return nil } + if NativeConfigDisabled { + return nil + } var args []string @@ -87,6 +104,9 @@ func DarwinRemoveRoute(destination string) error { if runtime.GOOS != "darwin" { return nil } + if NativeConfigDisabled { + return nil + } cmd := exec.Command("route", "-q", "-n", "delete", "-inet", destination) logger.Info("Running command: %v", cmd)