diff --git a/gateway_parsers.go b/gateway_parsers.go index b075ade..7bf1bc6 100644 --- a/gateway_parsers.go +++ b/gateway_parsers.go @@ -14,6 +14,7 @@ import ( "slices" "strconv" "strings" + "unicode" ) const ( @@ -146,6 +147,28 @@ func parseToWindowsRouteStruct(output []byte) ([]windowsRouteStruct, error) { break } fields := strings.Fields(inputLine) + // Some Windows commands are localized, so we need to handle the fields in a logical way. + // Baiscally, fields that start with a number will be treated as-is, but consecutive fields + // that start with a letter will be combined into a single field. + { + var logicalFields []string + for f := 0; f < len(fields); f++ { + field := fields[f] + if len(field) > 0 && unicode.IsLetter(rune(field[0])) { + for f+1 < len(fields) { + nextField := fields[f+1] + if len(nextField) > 0 && unicode.IsLetter(rune(nextField[0])) { + field += " " + nextField + f++ + } else { + break + } + } + } + logicalFields = append(logicalFields, field) + } + fields = logicalFields + } if len(fields) < 5 || !ipRegex.MatchString(fields[0]) { return nil, &ErrCantParse{} } @@ -263,7 +286,8 @@ func parseWindowsGatewayIPs(output []byte) ([]net.IP, error) { result := make([]net.IP, 0, len(parsedOutputs)) for _, parsedOutput := range parsedOutputs { - if strings.EqualFold(parsedOutput.Gateway, "On-link") { + // Skip "On-link" gateways (these will start with a letter; not all languages will print "On-link"). + if len(parsedOutput.Gateway) > 0 && unicode.IsLetter(rune(parsedOutput.Gateway[0])) { continue } ip := net.ParseIP(parsedOutput.Gateway) @@ -272,6 +296,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..ed5a412 100644 --- a/gateway_test.go +++ b/gateway_test.go @@ -50,12 +50,13 @@ func TestParseWindows(t *testing.T) { testcases := []ipTestCase{ {windows, true, "10.88.88.2", nil}, {windowsLocalized, true, "10.88.88.2", nil}, + {windowsLocalized2, true, "192.168.100.1", nil}, {windowsMultipleGateways, true, "10.21.38.1", nil}, {randomData, false, "", &ErrCantParse{}}, {windowsNoRoute, false, "", &ErrNoGateway{}}, {windowsNoDefaultRoute, false, "", &ErrNoGateway{}}, {windowsBadRoute1, false, "", &ErrCantParse{}}, - {windowsBadRoute2, false, "", &ErrCantParse{}}, + {windowsBadRoute2, false, "", &ErrNoGateway{}}, } t.Run("parseWindowsGatewayIPs", func(t *testing.T) { diff --git a/route-tables/windows.txt b/route-tables/windows.txt index 8abc235..117fbcd 100644 --- a/route-tables/windows.txt +++ b/route-tables/windows.txt @@ -8,12 +8,12 @@ IPv4 Route Table Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 10.88.88.2 10.88.88.149 10 - 0.0.0.0 128.0.0.0 On-link 192.168.0.1 5 127.0.0.0 255.0.0.0 On-link 127.0.0.1 331 127.0.0.1 255.255.255.255 On-link 127.0.0.1 331 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 - 192.168.0.0 255.255.255.0 On-link 192.168.0.52 291 - 192.168.0.52 255.255.255.255 On-link 192.168.0.52 291 - 192.168.0.255 255.255.255.255 On-link 192.168.0.52 291 =========================================================================== Persistent Routes: + Network Address Netmask Gateway Address Metric + 0.0.0.0 0.0.0.0 10.88.88.2 Default + 192.168.1.255 255.255.255.255 10.88.88.2 1 +--------------------------------------------------------------------------- diff --git a/route-tables/windowsLocalized2.txt b/route-tables/windowsLocalized2.txt new file mode 100644 index 0000000..aa788af --- /dev/null +++ b/route-tables/windowsLocalized2.txt @@ -0,0 +1,28 @@ +=========================================================================== +ILista de interfaces +29...........................SGNAutobahn Tunnel +11...........................SGN Tunnel +18...01 02 03 04 05 60 ......Microsoft Wi-Fi Direct Virtual Adapter + 4...01 02 03 04 05 61 ......Microsoft Wi-Fi Direct Virtual Adapter #2 +10...01 02 03 04 05 62 ......MediaTek Wi-Fi 6E MT7902 Wireless LAN Card +14...01 02 03 04 05 63 ......Bluetooth Device (Personal Area Network) + 1...........................Software Loopback Interface 1 +=========================================================================== + +IPv4 Tabla de enrutamiento +=========================================================================== +Rutas activas: +Destino de red Máscara de red Puerta de enlace Interfaz Métrica + 0.0.0.0 0.0.0.0 192.168.100.1 192.168.100.80 35 + 0.0.0.0 192.0.0.0 En vínculo 123.45.0.10 250 +=========================================================================== +Rutas persistentes: + Ninguno + +IPv6 Tabla de enrutamiento +=========================================================================== +Rutas activas: + Ninguno +Rutas persistentes: + Ninguno + diff --git a/test_route_tables.go b/test_route_tables.go index 80435da..ea625f1 100644 --- a/test_route_tables.go +++ b/test_route_tables.go @@ -15,11 +15,12 @@ const ( netBSD = "netBSD" randomData = "randomData" solarisBadRoute = "solarisBadRoute" + solarisNoInterface = "solarisNoInterface" solarisNoRoute = "solarisNoRoute" solaris = "solaris" - solarisNoInterface = "solarisNoInterface" windowsBadRoute1 = "windowsBadRoute1" windowsBadRoute2 = "windowsBadRoute2" + windowsLocalized2 = "windowsLocalized2" windowsLocalized = "windowsLocalized" windowsMultipleGateways = "windowsMultipleGateways" windowsNoDefaultRoute = "windowsNoDefaultRoute" @@ -196,6 +197,21 @@ Routing Table: IPv6 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 `), + solarisNoInterface: []byte(` +Routing Table: IPv4 + Destination Gateway Flags Ref Use Interface +-------------------- -------------------- ----- ----- ---------- --------- +default 172.16.32.1 UG 49 681748414 +127.0.0.1 127.0.0.1 UH 2 52832 lo0 +172.16.32.0 172.16.32.17 U 5 1450483 net0 + +Routing Table: IPv6 + Destination/Mask Gateway Flags Ref Use If +--------------------------- --------------------------- ----- --- ------- ----- +::1 ::1 UH 2 966 lo0 +fe80::/10 fe80::aabb:ccdd:1234:2 U 5 77620 net0 +default fe80::aabb:ccdd:1234:1 UG 3 4092447`), + solarisNoRoute: []byte(` Routing Table: IPv4 Destination Gateway Flags Ref Use Interface @@ -225,22 +241,6 @@ Routing Table: IPv6 ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 -`), - - solarisNoInterface: []byte(` -Routing Table: IPv4 - Destination Gateway Flags Ref Use Interface --------------------- -------------------- ----- ----- ---------- --------- -default 172.16.32.1 UG 49 681748414 -127.0.0.1 127.0.0.1 UH 2 52832 lo0 -172.16.32.0 172.16.32.17 U 5 1450483 net0 - -Routing Table: IPv6 - Destination/Mask Gateway Flags Ref Use If ---------------------------- --------------------------- ----- --- ------- ----- -::1 ::1 UH 2 966 lo0 -fe80::/10 fe80::aabb:ccdd:1234:2 U 5 77620 net0 -default fe80::aabb:ccdd:1234:1 UG 3 4092447 `), windowsBadRoute1: []byte(` @@ -269,6 +269,37 @@ Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 foo 10.88.88.149 10 =========================================================================== Persistent Routes: +`), + + windowsLocalized2: []byte(` +=========================================================================== +ILista de interfaces +29...........................SGNAutobahn Tunnel +11...........................SGN Tunnel +18...01 02 03 04 05 60 ......Microsoft Wi-Fi Direct Virtual Adapter + 4...01 02 03 04 05 61 ......Microsoft Wi-Fi Direct Virtual Adapter #2 +10...01 02 03 04 05 62 ......MediaTek Wi-Fi 6E MT7902 Wireless LAN Card +14...01 02 03 04 05 63 ......Bluetooth Device (Personal Area Network) + 1...........................Software Loopback Interface 1 +=========================================================================== + +IPv4 Tabla de enrutamiento +=========================================================================== +Rutas activas: +Destino de red Máscara de red Puerta de enlace Interfaz Métrica + 0.0.0.0 0.0.0.0 192.168.100.1 192.168.100.80 35 + 0.0.0.0 192.0.0.0 En vínculo 123.45.0.10 250 +=========================================================================== +Rutas persistentes: + Ninguno + +IPv6 Tabla de enrutamiento +=========================================================================== +Rutas activas: + Ninguno +Rutas persistentes: + Ninguno + `), windowsLocalized: []byte(` @@ -359,5 +390,9 @@ Network Destination Netmask Gateway Interface Metric 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 =========================================================================== Persistent Routes: + Network Address Netmask Gateway Address Metric + 0.0.0.0 0.0.0.0 10.88.88.2 Default + 192.168.1.255 255.255.255.255 10.88.88.2 1 +--------------------------------------------------------------------------- `), }