diff --git a/daemon/cluster/listen_addr.go b/daemon/cluster/listen_addr.go index 94bc45f904..4b53a3cac0 100644 --- a/daemon/cluster/listen_addr.go +++ b/daemon/cluster/listen_addr.go @@ -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 { diff --git a/daemon/cluster/listen_addr_linux.go b/daemon/cluster/listen_addr_linux.go index 58cac0f964..3d4f239bda 100644 --- a/daemon/cluster/listen_addr_linux.go +++ b/daemon/cluster/listen_addr_linux.go @@ -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 @@ -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) @@ -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 } diff --git a/daemon/cluster/listen_addr_others.go b/daemon/cluster/listen_addr_others.go index 87803559a8..ebf7daea24 100644 --- a/daemon/cluster/listen_addr_others.go +++ b/daemon/cluster/listen_addr_others.go @@ -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() }