From c567cc04e7d4d3e81ef00f74e122378853fe5463 Mon Sep 17 00:00:00 2001 From: Marcus B Spencer Date: Fri, 6 Mar 2026 14:51:15 -0600 Subject: [PATCH] Return `ErrNoGateway` when all default routes have an `On-link` gateway Fixes a bug where if all routes to `0.0.0.0` have an `On-link` gateway, the `parseWindowsGatewayIPs` function would return a blank slice with no error, rather than `ErrNoGateway`. This also causes a panic in `DiscoverGateway`, when `ips[0]` is accessed (ref https://github.com/syncthing/syncthing/issues/10593). --- gateway_parsers.go | 3 + gateway_test.go | 2 + route-tables/windowsOnLinkDefaultRoute.txt | 26 ++++++++ test_route_tables.go | 76 +++++++++++++++------- 4 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 route-tables/windowsOnLinkDefaultRoute.txt diff --git a/gateway_parsers.go b/gateway_parsers.go index b075ade..4e34b24 100644 --- a/gateway_parsers.go +++ b/gateway_parsers.go @@ -272,6 +272,9 @@ func parseWindowsGatewayIPs(output []byte) ([]net.IP, error) { } result = append(result, ip) } + if len(result) == 0 { + return nil, &ErrNoGateway{} + } return result, nil } diff --git a/gateway_test.go b/gateway_test.go index cbf2185..7f015a7 100644 --- a/gateway_test.go +++ b/gateway_test.go @@ -54,6 +54,7 @@ func TestParseWindows(t *testing.T) { {randomData, false, "", &ErrCantParse{}}, {windowsNoRoute, false, "", &ErrNoGateway{}}, {windowsNoDefaultRoute, false, "", &ErrNoGateway{}}, + {windowsOnLinkDefaultRoute, false, "", &ErrNoGateway{}}, {windowsBadRoute1, false, "", &ErrCantParse{}}, {windowsBadRoute2, false, "", &ErrCantParse{}}, } @@ -71,6 +72,7 @@ func TestParseWindows(t *testing.T) { {randomData, false, "", &ErrCantParse{}}, {windowsNoRoute, false, "", &ErrNoGateway{}}, {windowsNoDefaultRoute, false, "", &ErrNoGateway{}}, + {windowsOnLinkDefaultRoute, true, "192.0.2.5", nil}, {windowsBadRoute1, false, "", &ErrCantParse{}}, {windowsBadRoute2, true, "10.88.88.149", nil}, } diff --git a/route-tables/windowsOnLinkDefaultRoute.txt b/route-tables/windowsOnLinkDefaultRoute.txt new file mode 100644 index 0000000..a606904 --- /dev/null +++ b/route-tables/windowsOnLinkDefaultRoute.txt @@ -0,0 +1,26 @@ +=========================================================================== +Interface List + 43..........................._Common_na_vpn + 50...00 42 42 42 42 42 ......Hyper-V Virtual Ethernet Adapter + 13...42 42 42 42 42 42 ......Intel(R) Wi-Fi otters #2 + 10...42 42 42 42 42 48 ......Intel(R) Wi-Fi otters #5 + 12...42 42 42 42 42 42 ......Intel(R) Wi-Fi otters + 8...42 42 42 42 42 40 ......Bluetooth Device (Personal Area Network) + 1...........................Software Loopback Interface 1 +=========================================================================== + +IPv4 Route Table +=========================================================================== +Active Routes: +Network Destination Netmask Gateway Interface Metric + 0.0.0.0 0.0.0.0 On-link 192.0.2.5 1 +=========================================================================== +Persistent Routes: + None + +IPv6 Route Table +=========================================================================== +Active Routes: + None +Persistent Routes: + None diff --git a/test_route_tables.go b/test_route_tables.go index 80435da..162e144 100644 --- a/test_route_tables.go +++ b/test_route_tables.go @@ -2,29 +2,30 @@ package gateway const ( - darwinBadRoute = "darwinBadRoute" - darwinNoRoute = "darwinNoRoute" - darwin = "darwin" - freeBSDBadRoute = "freeBSDBadRoute" - freeBSDNoRoute = "freeBSDNoRoute" - freeBSD = "freeBSD" - linuxNoRoute = "linuxNoRoute" - linux = "linux" - netBSDBadRoute = "netBSDBadRoute" - netBSDNoRoute = "netBSDNoRoute" - netBSD = "netBSD" - randomData = "randomData" - solarisBadRoute = "solarisBadRoute" - solarisNoRoute = "solarisNoRoute" - solaris = "solaris" - solarisNoInterface = "solarisNoInterface" - windowsBadRoute1 = "windowsBadRoute1" - windowsBadRoute2 = "windowsBadRoute2" - windowsLocalized = "windowsLocalized" - windowsMultipleGateways = "windowsMultipleGateways" - windowsNoDefaultRoute = "windowsNoDefaultRoute" - windowsNoRoute = "windowsNoRoute" - windows = "windows" + darwinBadRoute = "darwinBadRoute" + darwinNoRoute = "darwinNoRoute" + darwin = "darwin" + freeBSDBadRoute = "freeBSDBadRoute" + freeBSDNoRoute = "freeBSDNoRoute" + freeBSD = "freeBSD" + linuxNoRoute = "linuxNoRoute" + linux = "linux" + netBSDBadRoute = "netBSDBadRoute" + netBSDNoRoute = "netBSDNoRoute" + netBSD = "netBSD" + randomData = "randomData" + solarisBadRoute = "solarisBadRoute" + solarisNoInterface = "solarisNoInterface" + solarisNoRoute = "solarisNoRoute" + solaris = "solaris" + windowsBadRoute1 = "windowsBadRoute1" + windowsBadRoute2 = "windowsBadRoute2" + windowsLocalized = "windowsLocalized" + windowsMultipleGateways = "windowsMultipleGateways" + windowsNoDefaultRoute = "windowsNoDefaultRoute" + windowsNoRoute = "windowsNoRoute" + windowsOnLinkDefaultRoute = "windowsOnLinkDefaultRoute" + windows = "windows" ) var routeTables = map[string][]byte{ @@ -343,6 +344,35 @@ IPv4 Route Table Active Routes: `), + windowsOnLinkDefaultRoute: []byte(` +=========================================================================== +Interface List + 43..........................._Common_na_vpn + 50...00 42 42 42 42 42 ......Hyper-V Virtual Ethernet Adapter + 13...42 42 42 42 42 42 ......Intel(R) Wi-Fi otters #2 + 10...42 42 42 42 42 48 ......Intel(R) Wi-Fi otters #5 + 12...42 42 42 42 42 42 ......Intel(R) Wi-Fi otters + 8...42 42 42 42 42 40 ......Bluetooth Device (Personal Area Network) + 1...........................Software Loopback Interface 1 +=========================================================================== + +IPv4 Route Table +=========================================================================== +Active Routes: +Network Destination Netmask Gateway Interface Metric + 0.0.0.0 0.0.0.0 On-link 192.0.2.5 1 +=========================================================================== +Persistent Routes: + None + +IPv6 Route Table +=========================================================================== +Active Routes: + None +Persistent Routes: + None +`), + windows: []byte(` =========================================================================== Interface List