diff --git a/GNUmakefile b/GNUmakefile index f3dfd24cf..0f3ae1661 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -55,7 +55,7 @@ doc:: world:: @set -e; \ - for os in solaris darwin freebsd linux windows; do \ + for os in solaris darwin freebsd linux windows android; do \ for arch in amd64; do \ printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \ env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \ diff --git a/cmd/sockaddr/GNUmakefile b/cmd/sockaddr/GNUmakefile index 6d0039ae5..646ad085d 100644 --- a/cmd/sockaddr/GNUmakefile +++ b/cmd/sockaddr/GNUmakefile @@ -26,4 +26,4 @@ test:: $(BIN) .PHONY: world world:: mkdir -p bin - gox -os="solaris darwin freebsd linux windows" -arch="386 amd64 arm" -output="bin/sockaddr_{{.OS}}_{{.Arch}}" . + gox -os="solaris darwin freebsd linux windows android" -arch="386 amd64 arm" -output="bin/sockaddr_{{.OS}}_{{.Arch}}" . diff --git a/ifaddrs.go b/ifaddrs.go index 2a706c34e..80f61bef6 100644 --- a/ifaddrs.go +++ b/ifaddrs.go @@ -1197,23 +1197,46 @@ func parseDefaultIfNameFromRoute(routeOut string) (string, error) { // parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for // Linux. func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) { + parsedLines := parseIfNameFromIPCmd(routeOut) + for _, parsedLine := range parsedLines { + if parsedLine[0] == "default" && + parsedLine[1] == "via" && + parsedLine[3] == "dev" { + ifName := strings.TrimSpace(parsedLine[4]) + return ifName, nil + } + } + + return "", errors.New("No default interface found") +} + +// parseDefaultIfNameFromIPCmdAndroid parses the default interface from ip(8) for +// Android. +func parseDefaultIfNameFromIPCmdAndroid(routeOut string) (string, error) { + parsedLines := parseIfNameFromIPCmd(routeOut) + if (len(parsedLines) > 0) { + ifName := strings.TrimSpace(parsedLines[0][4]) + return ifName, nil + } + + return "", errors.New("No default interface found") +} + + +// parseIfNameFromIPCmd parses interfaces from ip(8) for +// Linux. +func parseIfNameFromIPCmd(routeOut string) [][]string { lines := strings.Split(routeOut, "\n") re := whitespaceRE.Copy() + parsedLines := make([][]string, 0, len(lines)) for _, line := range lines { kvs := re.Split(line, -1) if len(kvs) < 5 { continue } - - if kvs[0] == "default" && - kvs[1] == "via" && - kvs[3] == "dev" { - ifName := strings.TrimSpace(kvs[4]) - return ifName, nil - } + parsedLines = append(parsedLines, kvs) } - - return "", errors.New("No default interface found") + return parsedLines } // parseDefaultIfNameWindows parses the default interface from `netstat -rn` and diff --git a/route_info_android.go b/route_info_android.go new file mode 100644 index 000000000..9885915a6 --- /dev/null +++ b/route_info_android.go @@ -0,0 +1,34 @@ +package sockaddr + +import ( + "errors" + "os/exec" +) + +type routeInfo struct { + cmds map[string][]string +} + +// NewRouteInfo returns a Android-specific implementation of the RouteInfo +// interface. +func NewRouteInfo() (routeInfo, error) { + return routeInfo{ + cmds: map[string][]string{"ip": {"/system/bin/ip", "route", "get", "8.8.8.8"}}, + }, nil +} + +// GetDefaultInterfaceName returns the interface name attached to the default +// route on the default interface. +func (ri routeInfo) GetDefaultInterfaceName() (string, error) { + out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() + if err != nil { + return "", err + } + + + var ifName string + if ifName, err = parseDefaultIfNameFromIPCmdAndroid(string(out)); err != nil { + return "", errors.New("No default interface found") + } + return ifName, nil +} diff --git a/route_info_linux.go b/route_info_linux.go index c2ec91eaf..b62ce6ecb 100644 --- a/route_info_linux.go +++ b/route_info_linux.go @@ -1,3 +1,5 @@ +// +build !android + package sockaddr import (