Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support "ip route get" as fallback on linux systems #17

Merged
merged 1 commit into from Apr 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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