mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Only consider "device" interfaces in address autodetection on Linux
- This automatically rules out bridges and other non system created interfaces Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
93fea86d1d
commit
8f7d3a4380
3 changed files with 186 additions and 96 deletions
|
@ -124,13 +124,13 @@ func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
|
||||||
if ipAddr.IP.To4() != nil {
|
if ipAddr.IP.To4() != nil {
|
||||||
// IPv4
|
// IPv4
|
||||||
if interfaceAddr4 != nil {
|
if interfaceAddr4 != nil {
|
||||||
return nil, fmt.Errorf("interface %s has more than one IPv4 address", specifiedInterface)
|
return nil, fmt.Errorf("interface %s has more than one IPv4 address (%s and %s)", specifiedInterface, interfaceAddr4, ipAddr.IP)
|
||||||
}
|
}
|
||||||
interfaceAddr4 = ipAddr.IP
|
interfaceAddr4 = ipAddr.IP
|
||||||
} else {
|
} else {
|
||||||
// IPv6
|
// IPv6
|
||||||
if interfaceAddr6 != nil {
|
if interfaceAddr6 != nil {
|
||||||
return nil, fmt.Errorf("interface %s has more than one IPv6 address", specifiedInterface)
|
return nil, fmt.Errorf("interface %s has more than one IPv6 address (%s and %s)", specifiedInterface, interfaceAddr6, ipAddr.IP)
|
||||||
}
|
}
|
||||||
interfaceAddr6 = ipAddr.IP
|
interfaceAddr6 = ipAddr.IP
|
||||||
}
|
}
|
||||||
|
@ -149,100 +149,6 @@ func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
|
||||||
return interfaceAddr6, nil
|
return interfaceAddr6, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cluster) resolveSystemAddr() (net.IP, error) {
|
|
||||||
// Use the system's only IP address, or fail if there are
|
|
||||||
// multiple addresses to choose from.
|
|
||||||
interfaces, err := net.Interfaces()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var systemAddr net.IP
|
|
||||||
var systemInterface net.Interface
|
|
||||||
|
|
||||||
// List Docker-managed subnets
|
|
||||||
v4Subnets := c.config.NetworkSubnetsProvider.V4Subnets()
|
|
||||||
v6Subnets := c.config.NetworkSubnetsProvider.V6Subnets()
|
|
||||||
|
|
||||||
ifaceLoop:
|
|
||||||
for _, intf := range interfaces {
|
|
||||||
// Skip inactive interfaces and loopback interfaces
|
|
||||||
if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs, err := intf.Addrs()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var interfaceAddr4, interfaceAddr6 net.IP
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
ipAddr, ok := addr.(*net.IPNet)
|
|
||||||
|
|
||||||
// Skip loopback and link-local addresses
|
|
||||||
if !ok || !ipAddr.IP.IsGlobalUnicast() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ipAddr.IP.To4() != nil {
|
|
||||||
// IPv4
|
|
||||||
|
|
||||||
// Ignore addresses in subnets that are managed by Docker.
|
|
||||||
for _, subnet := range v4Subnets {
|
|
||||||
if subnet.Contains(ipAddr.IP) {
|
|
||||||
continue ifaceLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if interfaceAddr4 != nil {
|
|
||||||
return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", intf.Name, interfaceAddr4, ipAddr.IP)
|
|
||||||
}
|
|
||||||
|
|
||||||
interfaceAddr4 = ipAddr.IP
|
|
||||||
} else {
|
|
||||||
// IPv6
|
|
||||||
|
|
||||||
// Ignore addresses in subnets that are managed by Docker.
|
|
||||||
for _, subnet := range v6Subnets {
|
|
||||||
if subnet.Contains(ipAddr.IP) {
|
|
||||||
continue ifaceLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if interfaceAddr6 != nil {
|
|
||||||
return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", intf.Name, interfaceAddr6, ipAddr.IP)
|
|
||||||
}
|
|
||||||
|
|
||||||
interfaceAddr6 = ipAddr.IP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the case that this interface has exactly one IPv4 address
|
|
||||||
// and exactly one IPv6 address, favor IPv4 over IPv6.
|
|
||||||
if interfaceAddr4 != nil {
|
|
||||||
if systemAddr != nil {
|
|
||||||
return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on different interfaces (%s on %s and %s on %s)", systemAddr, systemInterface.Name, interfaceAddr4, intf.Name)
|
|
||||||
}
|
|
||||||
systemAddr = interfaceAddr4
|
|
||||||
systemInterface = intf
|
|
||||||
} else if interfaceAddr6 != nil {
|
|
||||||
if systemAddr != nil {
|
|
||||||
return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on different interfaces (%s on %s and %s on %s)", systemAddr, systemInterface.Name, interfaceAddr6, intf.Name)
|
|
||||||
}
|
|
||||||
systemAddr = interfaceAddr6
|
|
||||||
systemInterface = intf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if systemAddr == nil {
|
|
||||||
return nil, errNoIP
|
|
||||||
}
|
|
||||||
|
|
||||||
return systemAddr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func listSystemIPs() []net.IP {
|
func listSystemIPs() []net.IP {
|
||||||
interfaces, err := net.Interfaces()
|
interfaces, err := net.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -268,3 +174,10 @@ func listSystemIPs() []net.IP {
|
||||||
|
|
||||||
return systemAddrs
|
return systemAddrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error {
|
||||||
|
if interfaceA == interfaceB {
|
||||||
|
return fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", interfaceA, addrA, addrB)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on different interfaces (%s on %s and %s on %s)", addrA, interfaceA, addrB, interfaceB)
|
||||||
|
}
|
||||||
|
|
78
daemon/cluster/listen_addr_linux.go
Normal file
78
daemon/cluster/listen_addr_linux.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package cluster
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Cluster) resolveSystemAddr() (net.IP, error) {
|
||||||
|
// Use the system's only device IP address, or fail if there are
|
||||||
|
// multiple addresses to choose from.
|
||||||
|
interfaces, err := netlink.LinkList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var systemAddr net.IP
|
||||||
|
var systemInterface string
|
||||||
|
|
||||||
|
for _, intf := range interfaces {
|
||||||
|
// Skip non device or inactive interfaces
|
||||||
|
if intf.Type() != "device" || intf.Attrs().Flags&net.FlagUp == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := netlink.AddrList(intf, netlink.FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var interfaceAddr4, interfaceAddr6 net.IP
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipAddr := addr.IPNet.IP
|
||||||
|
|
||||||
|
// Skip loopback and link-local addresses
|
||||||
|
if !ipAddr.IsGlobalUnicast() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipAddr.To4() != nil {
|
||||||
|
if interfaceAddr4 != nil {
|
||||||
|
return nil, errMultipleIPs(intf.Attrs().Name, intf.Attrs().Name, interfaceAddr4, ipAddr)
|
||||||
|
}
|
||||||
|
interfaceAddr4 = ipAddr
|
||||||
|
} else {
|
||||||
|
if interfaceAddr6 != nil {
|
||||||
|
return nil, errMultipleIPs(intf.Attrs().Name, intf.Attrs().Name, interfaceAddr6, ipAddr)
|
||||||
|
}
|
||||||
|
interfaceAddr6 = ipAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case that this interface has exactly one IPv4 address
|
||||||
|
// and exactly one IPv6 address, favor IPv4 over IPv6.
|
||||||
|
if interfaceAddr4 != nil {
|
||||||
|
if systemAddr != nil {
|
||||||
|
return nil, errMultipleIPs(systemInterface, intf.Attrs().Name, systemAddr, interfaceAddr4)
|
||||||
|
}
|
||||||
|
systemAddr = interfaceAddr4
|
||||||
|
systemInterface = intf.Attrs().Name
|
||||||
|
} else if interfaceAddr6 != nil {
|
||||||
|
if systemAddr != nil {
|
||||||
|
return nil, errMultipleIPs(systemInterface, intf.Attrs().Name, systemAddr, interfaceAddr6)
|
||||||
|
}
|
||||||
|
systemAddr = interfaceAddr6
|
||||||
|
systemInterface = intf.Attrs().Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if systemAddr == nil {
|
||||||
|
return nil, errNoIP
|
||||||
|
}
|
||||||
|
|
||||||
|
return systemAddr, nil
|
||||||
|
}
|
99
daemon/cluster/listen_addr_others.go
Normal file
99
daemon/cluster/listen_addr_others.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package cluster
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
func (c *Cluster) resolveSystemAddr() (net.IP, error) {
|
||||||
|
// Use the system's only IP address, or fail if there are
|
||||||
|
// multiple addresses to choose from.
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var systemAddr net.IP
|
||||||
|
var systemInterface string
|
||||||
|
|
||||||
|
// List Docker-managed subnets
|
||||||
|
v4Subnets := c.config.NetworkSubnetsProvider.V4Subnets()
|
||||||
|
v6Subnets := c.config.NetworkSubnetsProvider.V6Subnets()
|
||||||
|
|
||||||
|
ifaceLoop:
|
||||||
|
for _, intf := range interfaces {
|
||||||
|
// Skip inactive interfaces and loopback interfaces
|
||||||
|
if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := intf.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var interfaceAddr4, interfaceAddr6 net.IP
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipAddr, ok := addr.(*net.IPNet)
|
||||||
|
|
||||||
|
// Skip loopback and link-local addresses
|
||||||
|
if !ok || !ipAddr.IP.IsGlobalUnicast() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipAddr.IP.To4() != nil {
|
||||||
|
// IPv4
|
||||||
|
|
||||||
|
// Ignore addresses in subnets that are managed by Docker.
|
||||||
|
for _, subnet := range v4Subnets {
|
||||||
|
if subnet.Contains(ipAddr.IP) {
|
||||||
|
continue ifaceLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if interfaceAddr4 != nil {
|
||||||
|
return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr4, ipAddr.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceAddr4 = ipAddr.IP
|
||||||
|
} else {
|
||||||
|
// IPv6
|
||||||
|
|
||||||
|
// Ignore addresses in subnets that are managed by Docker.
|
||||||
|
for _, subnet := range v6Subnets {
|
||||||
|
if subnet.Contains(ipAddr.IP) {
|
||||||
|
continue ifaceLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if interfaceAddr6 != nil {
|
||||||
|
return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr6, ipAddr.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceAddr6 = ipAddr.IP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case that this interface has exactly one IPv4 address
|
||||||
|
// and exactly one IPv6 address, favor IPv4 over IPv6.
|
||||||
|
if interfaceAddr4 != nil {
|
||||||
|
if systemAddr != nil {
|
||||||
|
return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr4)
|
||||||
|
}
|
||||||
|
systemAddr = interfaceAddr4
|
||||||
|
systemInterface = intf.Name
|
||||||
|
} else if interfaceAddr6 != nil {
|
||||||
|
if systemAddr != nil {
|
||||||
|
return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr6)
|
||||||
|
}
|
||||||
|
systemAddr = interfaceAddr6
|
||||||
|
systemInterface = intf.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if systemAddr == nil {
|
||||||
|
return nil, errNoIP
|
||||||
|
}
|
||||||
|
|
||||||
|
return systemAddr, nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue