mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
Using the Go stdlib APIs to detect IP Address of a device
This commit is contained in:
@@ -10,7 +10,6 @@ import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -46,10 +45,10 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node)
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, i := range intfs {
|
||||
if (i.Flags&net.FlagUp != 0) && (i.Flags&(net.FlagLoopback|net.FlagPointToPoint) == 0) {
|
||||
if ip := f.ipAddress(i.Name); ip != "" {
|
||||
defaultDevice = i.Name
|
||||
for _, intf := range intfs {
|
||||
if f.isDeviceEnabled(&intf) && f.isDeviceLoopBackOrPointToPoint(&intf) && f.deviceHasIpAddress(&intf) {
|
||||
if ip, err := f.ipAddress(&intf); err == nil {
|
||||
defaultDevice = intf.Name
|
||||
node.Attributes["network.ip-address"] = ip
|
||||
newNetwork.IP = ip
|
||||
newNetwork.CIDR = newNetwork.IP + "/32"
|
||||
@@ -150,99 +149,32 @@ func (f *NetworkFingerprint) linkSpeedEthtool(path, device string) int {
|
||||
return mbs
|
||||
}
|
||||
|
||||
// ipAddress returns the first IPv4 address on the configured default interface
|
||||
// Tries Golang native functions and falls back onto ifconfig
|
||||
func (f *NetworkFingerprint) ipAddress(device string) string {
|
||||
if ip, err := f.nativeIpAddress(device); err == nil {
|
||||
return ip
|
||||
func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) {
|
||||
var (
|
||||
addrs []net.Addr
|
||||
err error
|
||||
)
|
||||
if addrs, err = intf.Addrs(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.ifConfig(device)
|
||||
if len(addrs) == 0 {
|
||||
return "", errors.New(fmt.Sprintf("Interface %s has no IP address", intf.Name))
|
||||
}
|
||||
return addrs[0].String(), nil
|
||||
}
|
||||
|
||||
func (f *NetworkFingerprint) nativeIpAddress(device string) (string, error) {
|
||||
// Find IP address on configured interface
|
||||
var ip string
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", errors.New("could not retrieve interface list")
|
||||
}
|
||||
|
||||
// TODO: should we handle IPv6 here? How do we determine precedence?
|
||||
for _, i := range ifaces {
|
||||
if i.Name != device {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
return "", errors.New("could not retrieve interface IP addresses")
|
||||
}
|
||||
|
||||
for _, a := range addrs {
|
||||
switch v := a.(type) {
|
||||
case *net.IPNet:
|
||||
if v.IP.To4() != nil {
|
||||
ip = v.IP.String()
|
||||
}
|
||||
case *net.IPAddr:
|
||||
if v.IP.To4() != nil {
|
||||
ip = v.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if net.ParseIP(ip) == nil {
|
||||
return "", errors.New(fmt.Sprintf("could not parse IP address `%s`", ip))
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {
|
||||
return intf.Flags&net.FlagUp != 0
|
||||
}
|
||||
|
||||
// ifConfig returns the IP Address for this node according to ifConfig, for the
|
||||
// specified device.
|
||||
func (f *NetworkFingerprint) ifConfig(device string) string {
|
||||
ifConfigPath, _ := exec.LookPath("ifconfig")
|
||||
if ifConfigPath == "" {
|
||||
f.logger.Println("[WARN] fingerprint.network: ifconfig not found")
|
||||
return ""
|
||||
func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
|
||||
if addrs, err := intf.Addrs(); err == nil {
|
||||
return len(addrs) > 0
|
||||
}
|
||||
|
||||
outBytes, err := exec.Command(ifConfigPath, device).Output()
|
||||
if err != nil {
|
||||
f.logger.Printf("[WARN] fingerprint.network: Error calling ifconfig (%s %s): %v", ifConfigPath, device, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
// Parse out the IP address returned from ifconfig for this device
|
||||
// Tested on Ubuntu, the matching part of ifconfig output for eth0 is like
|
||||
// so:
|
||||
// inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
|
||||
// For OS X and en0, we have:
|
||||
// inet 192.168.0.7 netmask 0xffffff00 broadcast 192.168.0.255
|
||||
output := strings.TrimSpace(string(outBytes))
|
||||
|
||||
// re is a regular expression, which can vary based on the OS
|
||||
var re *regexp.Regexp
|
||||
|
||||
if "darwin" == runtime.GOOS {
|
||||
re = regexp.MustCompile("inet [0-9].+")
|
||||
} else {
|
||||
re = regexp.MustCompile("inet addr:[0-9].+")
|
||||
}
|
||||
args := strings.Split(re.FindString(output), " ")
|
||||
|
||||
var ip string
|
||||
if len(args) > 1 {
|
||||
ip = strings.TrimPrefix(args[1], "addr:")
|
||||
}
|
||||
|
||||
// validate what we've sliced out is a valid IP
|
||||
if net.ParseIP(ip) == nil {
|
||||
f.logger.Printf("[WARN] fingerprint.network: Unable to parse IP in output of '%s %s'", ifConfigPath, device)
|
||||
return ""
|
||||
}
|
||||
|
||||
return ip
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
|
||||
return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) == 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user