Skip to content

Instantly share code, notes, and snippets.

@sub-mod
Created March 4, 2015 21:02
Show Gist options
  • Save sub-mod/cc43acdac7087372d454 to your computer and use it in GitHub Desktop.
Save sub-mod/cc43acdac7087372d454 to your computer and use it in GitHub Desktop.
get_ip_kube.go
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