diff --git a/gateway_common.go b/gateway_common.go index 74cc7b2..441ea62 100644 --- a/gateway_common.go +++ b/gateway_common.go @@ -39,7 +39,7 @@ func parseWindowsRoutePrint(output []byte) (net.IP, error) { return nil, errNoGateway } -func parseLinuxIPRoute(output []byte) (net.IP, error) { +func parseLinuxIPRouteShow(output []byte) (net.IP, error) { // Linux '/usr/bin/ip route show' format looks like this: // default via 192.168.178.1 dev wlp3s0 metric 303 // 192.168.178.0/24 dev wlp3s0 proto kernel scope link src 192.168.178.76 metric 303 @@ -57,6 +57,23 @@ func parseLinuxIPRoute(output []byte) (net.IP, error) { return nil, errNoGateway } +func parseLinuxIPRouteGet(output []byte) (net.IP, error) { + // Linux '/usr/bin/ip route get 8.8.8.8' format looks like this: + // 8.8.8.8 via 10.0.1.1 dev eth0 src 10.0.1.36 uid 2000 + lines := strings.Split(string(output), "\n") + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) >= 2 && fields[1] == "via" { + ip := net.ParseIP(fields[2]) + if ip != nil { + return ip, nil + } + } + } + + return nil, errNoGateway +} + func parseLinuxRoute(output []byte) (net.IP, error) { // Linux route out format is always like this: // Kernel IP routing table diff --git a/gateway_linux.go b/gateway_linux.go index 788f5d8..ede4ed6 100644 --- a/gateway_linux.go +++ b/gateway_linux.go @@ -8,19 +8,32 @@ import ( func DiscoverGateway() (ip net.IP, err error) { ip, err = discoverGatewayUsingRoute() if err != nil { - ip, err = discoverGatewayUsingIp() + ip, err = discoverGatewayUsingIpRouteShow() + } + if err != nil { + ip, err = discoveryGatewayUsingIpRouteGet() } return } -func discoverGatewayUsingIp() (net.IP, error) { +func discoverGatewayUsingIpRouteShow() (net.IP, error) { routeCmd := exec.Command("ip", "route", "show") output, err := routeCmd.CombinedOutput() if err != nil { return nil, err } - return parseLinuxIPRoute(output) + return parseLinuxIPRouteShow(output) +} + +func discoverGatewayUsingIpRouteGet() (net.IP, error) { + routeCmd := exec.Command("ip", "route", "get", "8.8.8.8") + output, err := routeCmd.CombinedOutput() + if err != nil { + return nil, err + } + + return parseLinuxIPRouteGet(output) } func discoverGatewayUsingRoute() (net.IP, error) { diff --git a/gateway_test.go b/gateway_test.go index ba5dc0e..7c081b8 100644 --- a/gateway_test.go +++ b/gateway_test.go @@ -59,7 +59,7 @@ Persistent Routes: test(t, testcases, parseWindowsRoutePrint) } -func TestParseLinuxIPRoutePrint(t *testing.T) { +func TestParseLinuxIPRouteShow(t *testing.T) { correctData := []byte(` default via 192.168.178.1 dev wlp3s0 metric 303 192.168.178.0/24 dev wlp3s0 proto kernel scope link src 192.168.178.76 metric 303 @@ -85,7 +85,40 @@ default via foo dev wlp3s0 metric 303 {badRoute, false, ""}, } - test(t, testcases, parseLinuxIPRoute) + test(t, testcases, parseLinuxIPRouteShow) +} + +func TestParseLinuxIPRouteGet(t *testing.T) { + correctData := []byte(` +8.8.8.8 via 10.0.1.1 dev eth0 src 10.0.1.36 uid 2000 + cache`) + randomData := []byte(` +test +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna +aliqua. Ut enim ad minim veniam, quis nostrud exercitation +`) + noRoute := []byte(` +broadcast 255.255.255.255 dev eth0 src 10.0.1.36 uid 2000 + cache +`) + badRoute := []byte(` +local 0.0.0.0 dev lo src 127.0.0.1 uid 2000 + cache +`) + errorRoute := []byte(` +RTNETLINK answers: Invalid argument +`) + + testcases := []testcase{ + {correctData, true, "10.0.1.1"}, + {randomData, false, ""}, + {noRoute, false, ""}, + {badRoute, false, ""}, + {errorRoute, false, ""}, + } + + test(t, testcases, parseLinuxIPRouteGet) } func TestParseLinuxRoutePrint(t *testing.T) { @@ -108,6 +141,11 @@ Destination Gateway Genmask Flags Metric Ref Use Iface Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 foo 0.0.0.0 UG 0 0 0 eth0 +`) + missingRoute := []byte(` +Kernel IP routing table +Destination Gateway Genmask Flags Metric Ref Use Iface +10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 `) testcases := []testcase{ @@ -115,6 +153,7 @@ Destination Gateway Genmask Flags Metric Ref Use Iface {randomData, false, ""}, {noRoute, false, ""}, {badRoute, false, ""}, + {missingRoute, false, ""}, } test(t, testcases, parseLinuxRoute)