github.com/gdevillele/moby@v1.13.0/daemon/cluster/listen_addr.go (about) 1 package cluster 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 ) 8 9 var ( 10 errNoSuchInterface = errors.New("no such interface") 11 errNoIP = errors.New("could not find the system's IP address") 12 errMustSpecifyListenAddr = errors.New("must specify a listening address because the address to advertise is not recognized as a system address, and a system's IP address to use could not be uniquely identified") 13 errBadListenAddr = errors.New("listen address must be an IP address or network interface (with optional port number)") 14 errBadAdvertiseAddr = errors.New("advertise address must be a non-zero IP address or network interface (with optional port number)") 15 errBadDefaultAdvertiseAddr = errors.New("default advertise address must be a non-zero IP address or network interface (without a port number)") 16 ) 17 18 func resolveListenAddr(specifiedAddr string) (string, string, error) { 19 specifiedHost, specifiedPort, err := net.SplitHostPort(specifiedAddr) 20 if err != nil { 21 return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr) 22 } 23 24 // Does the host component match any of the interface names on the 25 // system? If so, use the address from that interface. 26 interfaceAddr, err := resolveInterfaceAddr(specifiedHost) 27 if err == nil { 28 return interfaceAddr.String(), specifiedPort, nil 29 } 30 if err != errNoSuchInterface { 31 return "", "", err 32 } 33 34 // If it's not an interface, it must be an IP (for now) 35 if net.ParseIP(specifiedHost) == nil { 36 return "", "", errBadListenAddr 37 } 38 39 return specifiedHost, specifiedPort, nil 40 } 41 42 func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) { 43 // Approach: 44 // - If an advertise address is specified, use that. Resolve the 45 // interface's address if an interface was specified in 46 // advertiseAddr. Fill in the port from listenAddrPort if necessary. 47 // - If DefaultAdvertiseAddr is not empty, use that with the port from 48 // listenAddrPort. Resolve the interface's address from 49 // if an interface name was specified in DefaultAdvertiseAddr. 50 // - Otherwise, try to autodetect the system's address. Use the port in 51 // listenAddrPort with this address if autodetection succeeds. 52 53 if advertiseAddr != "" { 54 advertiseHost, advertisePort, err := net.SplitHostPort(advertiseAddr) 55 if err != nil { 56 // Not a host:port specification 57 advertiseHost = advertiseAddr 58 advertisePort = listenAddrPort 59 } 60 61 // Does the host component match any of the interface names on the 62 // system? If so, use the address from that interface. 63 interfaceAddr, err := resolveInterfaceAddr(advertiseHost) 64 if err == nil { 65 return interfaceAddr.String(), advertisePort, nil 66 } 67 if err != errNoSuchInterface { 68 return "", "", err 69 } 70 71 // If it's not an interface, it must be an IP (for now) 72 if ip := net.ParseIP(advertiseHost); ip == nil || ip.IsUnspecified() { 73 return "", "", errBadAdvertiseAddr 74 } 75 76 return advertiseHost, advertisePort, nil 77 } 78 79 if c.config.DefaultAdvertiseAddr != "" { 80 // Does the default advertise address component match any of the 81 // interface names on the system? If so, use the address from 82 // that interface. 83 interfaceAddr, err := resolveInterfaceAddr(c.config.DefaultAdvertiseAddr) 84 if err == nil { 85 return interfaceAddr.String(), listenAddrPort, nil 86 } 87 if err != errNoSuchInterface { 88 return "", "", err 89 } 90 91 // If it's not an interface, it must be an IP (for now) 92 if ip := net.ParseIP(c.config.DefaultAdvertiseAddr); ip == nil || ip.IsUnspecified() { 93 return "", "", errBadDefaultAdvertiseAddr 94 } 95 96 return c.config.DefaultAdvertiseAddr, listenAddrPort, nil 97 } 98 99 systemAddr, err := c.resolveSystemAddr() 100 if err != nil { 101 return "", "", err 102 } 103 return systemAddr.String(), listenAddrPort, nil 104 } 105 106 func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) { 107 // Use a specific interface's IP address. 108 intf, err := net.InterfaceByName(specifiedInterface) 109 if err != nil { 110 return nil, errNoSuchInterface 111 } 112 113 addrs, err := intf.Addrs() 114 if err != nil { 115 return nil, err 116 } 117 118 var interfaceAddr4, interfaceAddr6 net.IP 119 120 for _, addr := range addrs { 121 ipAddr, ok := addr.(*net.IPNet) 122 123 if ok { 124 if ipAddr.IP.To4() != nil { 125 // IPv4 126 if interfaceAddr4 != nil { 127 return nil, fmt.Errorf("interface %s has more than one IPv4 address (%s and %s)", specifiedInterface, interfaceAddr4, ipAddr.IP) 128 } 129 interfaceAddr4 = ipAddr.IP 130 } else { 131 // IPv6 132 if interfaceAddr6 != nil { 133 return nil, fmt.Errorf("interface %s has more than one IPv6 address (%s and %s)", specifiedInterface, interfaceAddr6, ipAddr.IP) 134 } 135 interfaceAddr6 = ipAddr.IP 136 } 137 } 138 } 139 140 if interfaceAddr4 == nil && interfaceAddr6 == nil { 141 return nil, fmt.Errorf("interface %s has no usable IPv4 or IPv6 address", specifiedInterface) 142 } 143 144 // In the case that there's exactly one IPv4 address 145 // and exactly one IPv6 address, favor IPv4 over IPv6. 146 if interfaceAddr4 != nil { 147 return interfaceAddr4, nil 148 } 149 return interfaceAddr6, nil 150 } 151 152 func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) { 153 // Use the system's only IP address, or fail if there are 154 // multiple addresses to choose from. Skip interfaces which 155 // are managed by docker via subnet check. 156 interfaces, err := net.Interfaces() 157 if err != nil { 158 return nil, err 159 } 160 161 var systemAddr net.IP 162 var systemInterface string 163 164 // List Docker-managed subnets 165 v4Subnets := c.config.NetworkSubnetsProvider.V4Subnets() 166 v6Subnets := c.config.NetworkSubnetsProvider.V6Subnets() 167 168 ifaceLoop: 169 for _, intf := range interfaces { 170 // Skip inactive interfaces and loopback interfaces 171 if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 { 172 continue 173 } 174 175 addrs, err := intf.Addrs() 176 if err != nil { 177 continue 178 } 179 180 var interfaceAddr4, interfaceAddr6 net.IP 181 182 for _, addr := range addrs { 183 ipAddr, ok := addr.(*net.IPNet) 184 185 // Skip loopback and link-local addresses 186 if !ok || !ipAddr.IP.IsGlobalUnicast() { 187 continue 188 } 189 190 if ipAddr.IP.To4() != nil { 191 // IPv4 192 193 // Ignore addresses in subnets that are managed by Docker. 194 for _, subnet := range v4Subnets { 195 if subnet.Contains(ipAddr.IP) { 196 continue ifaceLoop 197 } 198 } 199 200 if interfaceAddr4 != nil { 201 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr4, ipAddr.IP) 202 } 203 204 interfaceAddr4 = ipAddr.IP 205 } else { 206 // IPv6 207 208 // Ignore addresses in subnets that are managed by Docker. 209 for _, subnet := range v6Subnets { 210 if subnet.Contains(ipAddr.IP) { 211 continue ifaceLoop 212 } 213 } 214 215 if interfaceAddr6 != nil { 216 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr6, ipAddr.IP) 217 } 218 219 interfaceAddr6 = ipAddr.IP 220 } 221 } 222 223 // In the case that this interface has exactly one IPv4 address 224 // and exactly one IPv6 address, favor IPv4 over IPv6. 225 if interfaceAddr4 != nil { 226 if systemAddr != nil { 227 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr4) 228 } 229 systemAddr = interfaceAddr4 230 systemInterface = intf.Name 231 } else if interfaceAddr6 != nil { 232 if systemAddr != nil { 233 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr6) 234 } 235 systemAddr = interfaceAddr6 236 systemInterface = intf.Name 237 } 238 } 239 240 if systemAddr == nil { 241 return nil, errNoIP 242 } 243 244 return systemAddr, nil 245 } 246 247 func listSystemIPs() []net.IP { 248 interfaces, err := net.Interfaces() 249 if err != nil { 250 return nil 251 } 252 253 var systemAddrs []net.IP 254 255 for _, intf := range interfaces { 256 addrs, err := intf.Addrs() 257 if err != nil { 258 continue 259 } 260 261 for _, addr := range addrs { 262 ipAddr, ok := addr.(*net.IPNet) 263 264 if ok { 265 systemAddrs = append(systemAddrs, ipAddr.IP) 266 } 267 } 268 } 269 270 return systemAddrs 271 } 272 273 func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error { 274 if interfaceA == interfaceB { 275 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) 276 } 277 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) 278 }