Skip to content

Commit

Permalink
Merge pull request #17 from tmm1/android
Browse files Browse the repository at this point in the history
support "ip route get" as fallback on linux systems
  • Loading branch information
jackpal committed Apr 7, 2018
2 parents 05005e5 + 25e5c05 commit cbcf4e3
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 6 deletions.
19 changes: 18 additions & 1 deletion gateway_common.go
Expand Up @@ -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
Expand All @@ -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
Expand Down
19 changes: 16 additions & 3 deletions gateway_linux.go
Expand Up @@ -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 = discoverGatewayUsingIpRouteGet()
}
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) {
Expand Down
43 changes: 41 additions & 2 deletions gateway_test.go
Expand Up @@ -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
Expand All @@ -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 <local,brd>
`)
badRoute := []byte(`
local 0.0.0.0 dev lo src 127.0.0.1 uid 2000
cache <local>
`)
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) {
Expand All @@ -108,13 +141,19 @@ 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{
{correctData, true, "192.168.1.1"},
{randomData, false, ""},
{noRoute, false, ""},
{badRoute, false, ""},
{missingRoute, false, ""},
}

test(t, testcases, parseLinuxRoute)
Expand Down

0 comments on commit cbcf4e3

Please sign in to comment.