Skip to content

Commit

Permalink
Merge pull request #26457 from aboch/auto
Browse files Browse the repository at this point in the history
Add fallback to resolveSystemAddr() in linux
  • Loading branch information
cpuguy83 authored Sep 10, 2016
2 parents cf58eb4 + c0b24c6 commit ebae43e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 93 deletions.
95 changes: 95 additions & 0 deletions daemon/cluster/listen_addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,101 @@ func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
return interfaceAddr6, nil
}

func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) {
// Use the system's only IP address, or fail if there are
// multiple addresses to choose from. Skip interfaces which
// are managed by docker via subnet check.
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
}

func listSystemIPs() []net.IP {
interfaces, err := net.Interfaces()
if err != nil {
Expand Down
17 changes: 15 additions & 2 deletions daemon/cluster/listen_addr_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ func (c *Cluster) resolveSystemAddr() (net.IP, error) {
return nil, err
}

var systemAddr net.IP
var systemInterface string
var (
systemAddr net.IP
systemInterface string
deviceFound bool
)

for _, intf := range interfaces {
// Skip non device or inactive interfaces
Expand All @@ -40,6 +43,9 @@ func (c *Cluster) resolveSystemAddr() (net.IP, error) {
continue
}

// At least one non-loopback device is found and it is administratively up
deviceFound = true

if ipAddr.To4() != nil {
if interfaceAddr4 != nil {
return nil, errMultipleIPs(intf.Attrs().Name, intf.Attrs().Name, interfaceAddr4, ipAddr)
Expand Down Expand Up @@ -71,6 +77,13 @@ func (c *Cluster) resolveSystemAddr() (net.IP, error) {
}

if systemAddr == nil {
if !deviceFound {
// If no non-loopback device type interface is found,
// fall back to the regular auto-detection mechanism.
// This is to cover the case where docker is running
// inside a container (eths are in fact veths).
return c.resolveSystemAddrViaSubnetCheck()
}
return nil, errNoIP
}

Expand Down
92 changes: 1 addition & 91 deletions daemon/cluster/listen_addr_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,95 +5,5 @@ 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
return c.resolveSystemAddrViaSubnetCheck()
}

0 comments on commit ebae43e

Please sign in to comment.