mirror of
https://github.com/kemko/nomad.git
synced 2026-01-09 03:45:41 +03:00
Merge pull request #2536 from hashicorp/f-ipv6-fingerprint
Support IPv6 addresses during fingerprinting
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
IMPROVEMENTS:
|
||||
* driver/docker: Allow setting container IP with user defined networks
|
||||
[GH-2535]
|
||||
* client: Fingerprint all routable addresses on an interface including IPv6
|
||||
addresses [GH-2536]
|
||||
|
||||
BUG FIXES:
|
||||
* server: Reject non-TLS clients when TLS enabled [GH-2525]
|
||||
|
||||
@@ -66,12 +66,12 @@ type Port struct {
|
||||
// NetworkResource is used to describe required network
|
||||
// resources of a given task.
|
||||
type NetworkResource struct {
|
||||
Public bool
|
||||
Device string
|
||||
CIDR string
|
||||
ReservedPorts []Port
|
||||
DynamicPorts []Port
|
||||
IP string
|
||||
MBits *int
|
||||
ReservedPorts []Port
|
||||
DynamicPorts []Port
|
||||
}
|
||||
|
||||
func (n *NetworkResource) Canonicalize() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package fingerprint
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
@@ -56,10 +55,11 @@ func NewNetworkFingerprint(logger *log.Logger) Fingerprint {
|
||||
}
|
||||
|
||||
func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
|
||||
// newNetwork is populated and addded to the Nodes resources
|
||||
newNetwork := &structs.NetworkResource{}
|
||||
var ip string
|
||||
if node.Resources == nil {
|
||||
node.Resources = &structs.Resources{}
|
||||
}
|
||||
|
||||
// Find the named interface
|
||||
intf, err := f.findInterface(cfg.NetworkInterface)
|
||||
switch {
|
||||
case err != nil:
|
||||
@@ -69,52 +69,57 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if ip, err = f.ipAddress(intf); err != nil {
|
||||
return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err)
|
||||
}
|
||||
|
||||
newNetwork.Device = intf.Name
|
||||
node.Attributes["unique.network.ip-address"] = ip
|
||||
newNetwork.IP = ip
|
||||
newNetwork.CIDR = newNetwork.IP + "/32"
|
||||
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip)
|
||||
|
||||
// Record the throughput of the interface
|
||||
var mbits int
|
||||
throughput := f.linkSpeed(intf.Name)
|
||||
if cfg.NetworkSpeed != 0 {
|
||||
newNetwork.MBits = cfg.NetworkSpeed
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", newNetwork.MBits)
|
||||
mbits = cfg.NetworkSpeed
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", mbits)
|
||||
} else if throughput != 0 {
|
||||
newNetwork.MBits = throughput
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits)
|
||||
mbits = throughput
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, mbits)
|
||||
} else {
|
||||
newNetwork.MBits = defaultNetworkSpeed
|
||||
mbits = defaultNetworkSpeed
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: link speed could not be detected and no speed specified by user. Defaulting to %d", defaultNetworkSpeed)
|
||||
}
|
||||
|
||||
if node.Resources == nil {
|
||||
node.Resources = &structs.Resources{}
|
||||
// Create the network resources from the interface
|
||||
nwResources, err := f.createNetworkResources(mbits, intf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
node.Resources.Networks = append(node.Resources.Networks, newNetwork)
|
||||
// Add the network resources to the node
|
||||
node.Resources.Networks = nwResources
|
||||
for _, nwResource := range nwResources {
|
||||
f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP: %v", intf.Name, nwResource.IP)
|
||||
}
|
||||
|
||||
// Deprecated, setting the first IP as unique IP for the node
|
||||
if len(nwResources) > 0 {
|
||||
node.Attributes["unique.network.ip-address"] = nwResources[0].IP
|
||||
}
|
||||
|
||||
// return true, because we have a network connection
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Gets the ipv4 addr for a network interface
|
||||
func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) {
|
||||
var addrs []net.Addr
|
||||
var err error
|
||||
|
||||
if addrs, err = f.interfaceDetector.Addrs(intf); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
return "", errors.New(fmt.Sprintf("Interface %s has no IP address", intf.Name))
|
||||
// createNetworkResources creates network resources for every IP
|
||||
func (f *NetworkFingerprint) createNetworkResources(throughput int, intf *net.Interface) ([]*structs.NetworkResource, error) {
|
||||
// Find the interface with the name
|
||||
addrs, err := f.interfaceDetector.Addrs(intf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nwResources := make([]*structs.NetworkResource, 0)
|
||||
for _, addr := range addrs {
|
||||
// Create a new network resource
|
||||
newNetwork := &structs.NetworkResource{
|
||||
Device: intf.Name,
|
||||
MBits: throughput,
|
||||
}
|
||||
|
||||
// Find the IP Addr and the CIDR from the Address
|
||||
var ip net.IP
|
||||
switch v := (addr).(type) {
|
||||
case *net.IPNet:
|
||||
@@ -122,13 +127,21 @@ func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) {
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return ip.String(), nil
|
||||
|
||||
// If the ip is link-local then we ignore it
|
||||
if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
|
||||
continue
|
||||
}
|
||||
newNetwork.IP = ip.String()
|
||||
if ip.To4() != nil {
|
||||
newNetwork.CIDR = newNetwork.IP + "/32"
|
||||
} else {
|
||||
newNetwork.CIDR = newNetwork.IP + "/128"
|
||||
}
|
||||
|
||||
nwResources = append(nwResources, newNetwork)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Couldn't parse IP address for interface %s", intf.Name)
|
||||
|
||||
return nwResources, nil
|
||||
}
|
||||
|
||||
// Checks if the device is marked UP by the operator
|
||||
@@ -138,8 +151,8 @@ func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {
|
||||
|
||||
// Checks if the device has any IP address configured
|
||||
func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
|
||||
_, err := f.ipAddress(intf)
|
||||
return err == nil
|
||||
addrs, err := f.interfaceDetector.Addrs(intf)
|
||||
return err == nil && len(addrs) != 0
|
||||
}
|
||||
|
||||
func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
|
||||
|
||||
@@ -126,8 +126,9 @@ func (n *NetworkInterfaceDetectorMultipleInterfaces) Addrs(intf *net.Interface)
|
||||
|
||||
if intf.Name == "eth0" {
|
||||
_, ipnet1, _ := net.ParseCIDR("100.64.0.11/10")
|
||||
_, ipnet2, _ := net.ParseCIDR("2005:DB6::/48")
|
||||
return []net.Addr{ipnet1, ipnet2}, nil
|
||||
_, ipnet2, _ := net.ParseCIDR("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64")
|
||||
ipAddr, _ := net.ResolveIPAddr("ip6", "fe80::140c:9579:8037:f565")
|
||||
return []net.Addr{ipnet1, ipnet2, ipAddr}, nil
|
||||
}
|
||||
|
||||
if intf.Name == "eth1" {
|
||||
@@ -307,4 +308,16 @@ func TestNetworkFingerPrint_excludelo_down_interfaces(t *testing.T) {
|
||||
if net.MBits == 0 {
|
||||
t.Fatal("Expected Network Resource to have a non-zero bandwith")
|
||||
}
|
||||
|
||||
// Test the CIDR of the IPs
|
||||
if node.Resources.Networks[0].CIDR != "100.64.0.0/32" {
|
||||
t.Fatalf("bad CIDR: %v", node.Resources.Networks[0].CIDR)
|
||||
}
|
||||
if node.Resources.Networks[1].CIDR != "2001:db8:85a3::/128" {
|
||||
t.Fatalf("bad CIDR: %v", node.Resources.Networks[1].CIDR)
|
||||
}
|
||||
// Ensure that the link local address isn't fingerprinted
|
||||
if len(node.Resources.Networks) != 2 {
|
||||
t.Fatalf("bad number of IPs %v", len(node.Resources.Networks))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ client {
|
||||
|
||||
- `network_interface` `(string: "lo | lo0")` - Specifies the name of the
|
||||
interface to force network fingerprinting on. This defaults to the loopback
|
||||
interface.
|
||||
interface. All addresses on the interface are fingerprinted except the ones
|
||||
which are scoped local for IPv6. The scheduler is going to pick one of the
|
||||
many addresses which have been fingerprinted.
|
||||
|
||||
- `network_speed` `(int: 0)` - Specifies an override for the network link speed.
|
||||
This value, if set, overrides any detected or defaulted link speed. Most
|
||||
|
||||
Reference in New Issue
Block a user