Created
March 4, 2015 21:02
-
-
Save sub-mod/cc43acdac7087372d454 to your computer and use it in GitHub Desktop.
get_ip_kube.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"encoding/hex" | |
"fmt" | |
"io" | |
"net" | |
"os" | |
"strings" | |
) | |
func main() { | |
hostIP, err := ChooseHostInterface() | |
if err != nil { | |
fmt.Printf("Failed to select a host interface: %v", err) | |
} | |
fmt.Println(" IP = ", hostIP) | |
} | |
type Route struct { | |
Interface string | |
Destination net.IP | |
Gateway net.IP | |
// TODO: add more fields here if needed | |
} | |
func getRoutes(input io.Reader) ([]Route, error) { | |
routes := []Route{} | |
scanner := bufio.NewReader(input) | |
for { | |
line, err := scanner.ReadString('\n') | |
if strings.HasPrefix(line, "Iface") { | |
continue | |
} | |
if err == io.EOF { | |
break | |
} | |
fields := strings.Fields(line) | |
if len(fields) < 11 { | |
return nil, fmt.Errorf("Incorrect number of fields (expected at least 11, got %d): %s", len(fields), line) | |
} | |
routes = append(routes, Route{}) | |
route := &routes[len(routes)-1] | |
route.Interface = fields[0] | |
ip, err := parseIP(fields[1]) | |
if err != nil { | |
return nil, fmt.Errorf("Unable to Parse IP: %s", fields[1]) | |
} | |
route.Destination = ip | |
ip, err = parseIP(fields[2]) | |
if err != nil { | |
return nil, fmt.Errorf("Unable to Parse IP: %s", fields[2]) | |
} | |
route.Gateway = ip | |
} | |
return routes, nil | |
} | |
func parseIP(str string) (net.IP, error) { | |
bytes, err := hex.DecodeString(str) | |
if err != nil { | |
return nil, err | |
} | |
if len(bytes) != net.IPv4len { | |
return nil, fmt.Errorf("only IPv4 is supported") | |
} | |
bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0] | |
return net.IP(bytes), nil | |
} | |
func getFinalIP(addrs []net.Addr) (net.IP, error) { | |
if len(addrs) > 0 { | |
for i := range addrs { | |
fmt.Printf("Checking addr %s.\n", addrs[i].String()) | |
ip, _, err := net.ParseCIDR(addrs[i].String()) | |
if err != nil { | |
return nil, err | |
} | |
//Only IPv4 | |
if ip.To4() != nil { | |
if !ip.IsLoopback() { | |
fmt.Printf("IP found %v\n", ip) | |
return ip, nil | |
} else { | |
fmt.Printf("Loopback found %v\n", ip) | |
} | |
} else { | |
fmt.Printf("%v is not a valid IPv4 address\n", ip) | |
} | |
} | |
} | |
return nil, nil | |
} | |
func isInterfaceUp(intf *net.Interface) bool { | |
if intf.Flags&net.FlagUp != 0 { | |
fmt.Printf("Interface %v is up\n", intf.Name) | |
return true | |
} | |
return false | |
} | |
func getIPFromIntferace(intf *net.Interface, fngetAddrs getInterfaceAdddrsType) (net.IP, error) { | |
if isInterfaceUp(intf) { | |
addrs, err := fngetAddrs(intf) | |
if err != nil { | |
return nil, err | |
} | |
fmt.Printf("Interface %q has %d addresses :%v.\n", intf.Name, len(addrs), addrs) | |
finalIP, err := getFinalIP(addrs) | |
if err != nil { | |
fmt.Printf("Can't get IP from addresses of interface %q: %v\n", intf.Name, err) | |
return nil, err | |
} | |
if finalIP != nil { | |
fmt.Printf("valid IPv4 address for interface %q found as %v.\n", intf.Name, finalIP) | |
return finalIP, nil | |
} | |
} | |
return nil, nil | |
} | |
func ChooseHostInterface() (net.IP, error) { | |
var finalIP net.IP | |
inFile, err := os.Open("/proc/net/route") | |
if err != nil { | |
return nil, err | |
} | |
defer inFile.Close() | |
routes, err := getRoutes(inFile) | |
if err != nil { | |
fmt.Printf("getRoutes, %v\n", err) | |
return nil, err | |
} | |
finalIP, err = ChooseHostInterfaceFromRoute(routes, getInterface, getAddrs) | |
if err != nil { | |
return nil, err | |
} | |
return finalIP, err | |
} | |
func getInterface(intfName string) (*net.Interface, error) { | |
intf, err := net.InterfaceByName(intfName) | |
if err != nil { | |
fmt.Printf("Can't find an interface named %q: %v\n", intfName, err) | |
return nil, err | |
} | |
return intf, nil | |
} | |
func getAddrs(intf *net.Interface) ([]net.Addr, error) { | |
addrs, err := intf.Addrs() | |
if err != nil { | |
fmt.Printf("Can't get addresses for interface %q: %v\n", intf.Name, err) | |
return nil, err | |
} | |
return addrs, nil | |
} | |
type getInterfaceType func(string) (*net.Interface, error) | |
type getInterfaceAdddrsType func(*net.Interface) ([]net.Addr, error) | |
func ChooseHostInterfaceFromRoute(routes []Route, fngetInterface getInterfaceType, fngetAddrs getInterfaceAdddrsType) (net.IP, error) { | |
zero := net.IP{0, 0, 0, 0} | |
var finalIP net.IP | |
for i := range routes { | |
//find interface with gateway | |
if routes[i].Destination.Equal(zero) { | |
fmt.Printf("Default route transits interface %q\n", routes[i].Interface) | |
intf, err := fngetInterface(routes[i].Interface) | |
if err != nil { | |
return nil, err | |
} | |
finalIP, err := getIPFromIntferace(intf, fngetAddrs) | |
if err != nil { | |
return nil, err | |
} | |
if finalIP != nil { | |
fmt.Printf("Choosing IP %v \n", finalIP) | |
return finalIP, nil | |
} | |
} | |
} | |
if finalIP == nil { | |
return nil, fmt.Errorf("Unable to select an IP.") | |
} | |
return nil, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment