only add metric if provided through PreferLocalRoutes

This commit is contained in:
Owen
2026-07-18 17:29:27 -04:00
parent 8d582b4ea5
commit 6610655376
2 changed files with 38 additions and 16 deletions

View File

@@ -23,6 +23,15 @@ import (
// routing table at add-time.
const VPNRouteMetric = 9999
// PreferLocalRoutes controls whether routes added by AddRoutes are given the
// explicit high VPNRouteMetric priority, so that an overlapping local/
// connected route always takes precedence over the VPN route to the same
// destination. Defaults to false (routes are added with the OS default
// metric/priority, matching behavior prior to the introduction of
// VPNRouteMetric); callers that want local routes to win opt in by setting
// this to true (e.g. from a config value) before routes are added.
var PreferLocalRoutes = 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
@@ -83,12 +92,15 @@ func LinuxAddRoute(destination string, gateway string, interfaceName string) err
return fmt.Errorf("invalid destination address: %v", err)
}
// Create route. Priority is set explicitly (rather than left at the
// default of 0) so that this route never outranks a local/connected
// route to the same destination - see VPNRouteMetric.
// Create route. When PreferLocalRoutes is enabled, Priority is set
// explicitly (rather than left at the default of 0) so that this route
// never outranks a local/connected route to the same destination - see
// VPNRouteMetric.
route := &netlink.Route{
Dst: ipNet,
Priority: VPNRouteMetric,
Dst: ipNet,
}
if PreferLocalRoutes {
route.Priority = VPNRouteMetric
}
if gateway != "" {
@@ -135,8 +147,10 @@ func LinuxRemoveRoute(destination string, interfaceName string) error {
// a local/native route to the same destination on a different
// interface (or with a different metric) must never be touched.
route := &netlink.Route{
Dst: ipNet,
Priority: VPNRouteMetric,
Dst: ipNet,
}
if PreferLocalRoutes {
route.Priority = VPNRouteMetric
}
if interfaceName != "" {

View File

@@ -84,11 +84,15 @@ func WindowsAddRoute(destination string, gateway string, interfaceName string) e
return fmt.Errorf("either gateway or interface must be specified")
}
// Add the route using winipcfg. Metric is set explicitly (rather than a
// low value like 1, which would nearly always outrank local routes) so
// that an overlapping local/connected route is preferred over this VPN
// route - see VPNRouteMetric.
err = luid.AddRoute(prefix, nextHop, VPNRouteMetric)
// Add the route using winipcfg. When PreferLocalRoutes is enabled,
// metric is set explicitly (rather than a low value like 1, which would
// nearly always outrank local routes) so that an overlapping local/
// connected route is preferred over this VPN route - see VPNRouteMetric.
var metric uint32
if PreferLocalRoutes {
metric = VPNRouteMetric
}
err = luid.AddRoute(prefix, nextHop, metric)
if err != nil {
return fmt.Errorf("failed to add route: %v", err)
}
@@ -152,15 +156,19 @@ func WindowsRemoveRoute(destination string, interfaceName string) error {
}
// Find and delete matching route. When we know which interface we added
// the route on, only delete the entry on that interface with our
// VPNRouteMetric so we never remove an unrelated local/native route to
// the same destination.
// the route on, only delete the entry on that interface with the metric
// we added it with (see PreferLocalRoutes) so we never remove an
// unrelated local/native route to the same destination.
var wantMetric uint32
if PreferLocalRoutes {
wantMetric = VPNRouteMetric
}
for _, route := range routes {
routePrefix := route.DestinationPrefix.Prefix()
if routePrefix != prefix {
continue
}
if haveLuid && (route.InterfaceLUID != luid || route.Metric != VPNRouteMetric) {
if haveLuid && (route.InterfaceLUID != luid || route.Metric != wantMetric) {
continue
}
logger.Info("Removing route to %s on interface %s", destination, interfaceName)