github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/cluster/listen_addr.go (about) 1 package cluster // import "github.com/demonoid81/moby/daemon/cluster" 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 ) 8 9 const ( 10 errNoSuchInterface configError = "no such interface" 11 errNoIP configError = "could not find the system's IP address" 12 errMustSpecifyListenAddr configError = "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 errBadNetworkIdentifier configError = "must specify a valid IP address or interface name" 14 errBadListenAddr configError = "listen address must be an IP address or network interface (with optional port number)" 15 errBadAdvertiseAddr configError = "advertise address must be a non-zero IP address or network interface (with optional port number)" 16 errBadDataPathAddr configError = "data path address must be a non-zero IP address or network interface (without a port number)" 17 errBadDefaultAdvertiseAddr configError = "default advertise address must be a non-zero IP address or network interface (without a port number)" 18 ) 19 20 func resolveListenAddr(specifiedAddr string) (string, string, error) { 21 specifiedHost, specifiedPort, err := net.SplitHostPort(specifiedAddr) 22 if err != nil { 23 return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr) 24 } 25 // Does the host component match any of the interface names on the 26 // system? If so, use the address from that interface. 27 specifiedIP, err := resolveInputIPAddr(specifiedHost, true) 28 if err != nil { 29 if err == errBadNetworkIdentifier { 30 err = errBadListenAddr 31 } 32 return "", "", err 33 } 34 35 return specifiedIP.String(), specifiedPort, nil 36 } 37 38 func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) { 39 // Approach: 40 // - If an advertise address is specified, use that. Resolve the 41 // interface's address if an interface was specified in 42 // advertiseAddr. Fill in the port from listenAddrPort if necessary. 43 // - If DefaultAdvertiseAddr is not empty, use that with the port from 44 // listenAddrPort. Resolve the interface's address from 45 // if an interface name was specified in DefaultAdvertiseAddr. 46 // - Otherwise, try to autodetect the system's address. Use the port in 47 // listenAddrPort with this address if autodetection succeeds. 48 49 if advertiseAddr != "" { 50 advertiseHost, advertisePort, err := net.SplitHostPort(advertiseAddr) 51 if err != nil { 52 // Not a host:port specification 53 advertiseHost = advertiseAddr 54 advertisePort = listenAddrPort 55 } 56 // Does the host component match any of the interface names on the 57 // system? If so, use the address from that interface. 58 advertiseIP, err := resolveInputIPAddr(advertiseHost, false) 59 if err != nil { 60 if err == errBadNetworkIdentifier { 61 err = errBadAdvertiseAddr 62 } 63 return "", "", err 64 } 65 66 return advertiseIP.String(), advertisePort, nil 67 } 68 69 if c.config.DefaultAdvertiseAddr != "" { 70 // Does the default advertise address component match any of the 71 // interface names on the system? If so, use the address from 72 // that interface. 73 defaultAdvertiseIP, err := resolveInputIPAddr(c.config.DefaultAdvertiseAddr, false) 74 if err != nil { 75 if err == errBadNetworkIdentifier { 76 err = errBadDefaultAdvertiseAddr 77 } 78 return "", "", err 79 } 80 81 return defaultAdvertiseIP.String(), listenAddrPort, nil 82 } 83 84 systemAddr, err := c.resolveSystemAddr() 85 if err != nil { 86 return "", "", err 87 } 88 return systemAddr.String(), listenAddrPort, nil 89 } 90 91 // validateDefaultAddrPool validates default address pool 92 // it also strips white space from the string before validation 93 func validateDefaultAddrPool(defaultAddrPool []string, size uint32) error { 94 if defaultAddrPool == nil { 95 // defaultAddrPool is not defined 96 return nil 97 } 98 // if size is not set, then we use default value 24 99 if size == 0 { 100 size = 24 101 } 102 // We allow max value as 29. We can have 8 IP addresses for max value 29 103 // If we allow 30, then we will get only 4 IP addresses. But with latest 104 // libnetwork LB scale implementation, we use total of 4 IP addresses for internal use. 105 // Hence keeping 29 as max value, we will have 8 IP addresses. This will be 106 // smallest subnet that can be used in overlay network. 107 if size > 29 { 108 return fmt.Errorf("subnet size is out of range: %d", size) 109 } 110 for i := range defaultAddrPool { 111 // trim leading and trailing white spaces 112 defaultAddrPool[i] = strings.TrimSpace(defaultAddrPool[i]) 113 _, b, err := net.ParseCIDR(defaultAddrPool[i]) 114 if err != nil { 115 return fmt.Errorf("invalid base pool %s: %v", defaultAddrPool[i], err) 116 } 117 ones, _ := b.Mask.Size() 118 if size < uint32(ones) { 119 return fmt.Errorf("invalid CIDR: %q. Subnet size is too small for pool: %d", defaultAddrPool[i], size) 120 } 121 } 122 123 return nil 124 } 125 126 // getDataPathPort validates vxlan udp port (data path port) number. 127 // if no port is set, the default (4789) is returned 128 // valid port numbers are between 1024 and 49151 129 func getDataPathPort(portNum uint32) (uint32, error) { 130 // if the value comes as 0 by any reason we set it to default value 4789 131 if portNum == 0 { 132 portNum = 4789 133 return portNum, nil 134 } 135 // IANA procedures for each range in detail 136 // The Well Known Ports, aka the System Ports, from 0-1023 137 // The Registered Ports, aka the User Ports, from 1024-49151 138 // The Dynamic Ports, aka the Private Ports, from 49152-65535 139 // So we can allow range between 1024 to 49151 140 if portNum < 1024 || portNum > 49151 { 141 return 0, fmt.Errorf("Datapath port number is not in valid range (1024-49151) : %d", portNum) 142 } 143 return portNum, nil 144 } 145 func resolveDataPathAddr(dataPathAddr string) (string, error) { 146 if dataPathAddr == "" { 147 // dataPathAddr is not defined 148 return "", nil 149 } 150 // If a data path flag is specified try to resolve the IP address. 151 dataPathIP, err := resolveInputIPAddr(dataPathAddr, false) 152 if err != nil { 153 if err == errBadNetworkIdentifier { 154 err = errBadDataPathAddr 155 } 156 return "", err 157 } 158 return dataPathIP.String(), nil 159 } 160 161 func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) { 162 // Use a specific interface's IP address. 163 intf, err := net.InterfaceByName(specifiedInterface) 164 if err != nil { 165 return nil, errNoSuchInterface 166 } 167 168 addrs, err := intf.Addrs() 169 if err != nil { 170 return nil, err 171 } 172 173 var interfaceAddr4, interfaceAddr6 net.IP 174 175 for _, addr := range addrs { 176 ipAddr, ok := addr.(*net.IPNet) 177 178 if ok { 179 if ipAddr.IP.To4() != nil { 180 // IPv4 181 if interfaceAddr4 != nil { 182 return nil, configError(fmt.Sprintf("interface %s has more than one IPv4 address (%s and %s)", specifiedInterface, interfaceAddr4, ipAddr.IP)) 183 } 184 interfaceAddr4 = ipAddr.IP 185 } else { 186 // IPv6 187 if interfaceAddr6 != nil { 188 return nil, configError(fmt.Sprintf("interface %s has more than one IPv6 address (%s and %s)", specifiedInterface, interfaceAddr6, ipAddr.IP)) 189 } 190 interfaceAddr6 = ipAddr.IP 191 } 192 } 193 } 194 195 if interfaceAddr4 == nil && interfaceAddr6 == nil { 196 return nil, configError(fmt.Sprintf("interface %s has no usable IPv4 or IPv6 address", specifiedInterface)) 197 } 198 199 // In the case that there's exactly one IPv4 address 200 // and exactly one IPv6 address, favor IPv4 over IPv6. 201 if interfaceAddr4 != nil { 202 return interfaceAddr4, nil 203 } 204 return interfaceAddr6, nil 205 } 206 207 // resolveInputIPAddr tries to resolve the IP address from the string passed as input 208 // - tries to match the string as an interface name, if so returns the IP address associated with it 209 // - on failure of previous step tries to parse the string as an IP address itself 210 // if succeeds returns the IP address 211 func resolveInputIPAddr(input string, isUnspecifiedValid bool) (net.IP, error) { 212 // Try to see if it is an interface name 213 interfaceAddr, err := resolveInterfaceAddr(input) 214 if err == nil { 215 return interfaceAddr, nil 216 } 217 // String matched interface but there is a potential ambiguity to be resolved 218 if err != errNoSuchInterface { 219 return nil, err 220 } 221 222 // String is not an interface check if it is a valid IP 223 if ip := net.ParseIP(input); ip != nil && (isUnspecifiedValid || !ip.IsUnspecified()) { 224 return ip, nil 225 } 226 227 // Not valid IP found 228 return nil, errBadNetworkIdentifier 229 } 230 231 func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) { 232 // Use the system's only IP address, or fail if there are 233 // multiple addresses to choose from. Skip interfaces which 234 // are managed by docker via subnet check. 235 interfaces, err := net.Interfaces() 236 if err != nil { 237 return nil, err 238 } 239 240 var systemAddr net.IP 241 var systemInterface string 242 243 // List Docker-managed subnets 244 v4Subnets, v6Subnets := c.config.NetworkSubnetsProvider.Subnets() 245 246 ifaceLoop: 247 for _, intf := range interfaces { 248 // Skip inactive interfaces and loopback interfaces 249 if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 { 250 continue 251 } 252 253 addrs, err := intf.Addrs() 254 if err != nil { 255 continue 256 } 257 258 var interfaceAddr4, interfaceAddr6 net.IP 259 260 for _, addr := range addrs { 261 ipAddr, ok := addr.(*net.IPNet) 262 263 // Skip loopback and link-local addresses 264 if !ok || !ipAddr.IP.IsGlobalUnicast() { 265 continue 266 } 267 268 if ipAddr.IP.To4() != nil { 269 // IPv4 270 271 // Ignore addresses in subnets that are managed by Docker. 272 for _, subnet := range v4Subnets { 273 if subnet.Contains(ipAddr.IP) { 274 continue ifaceLoop 275 } 276 } 277 278 if interfaceAddr4 != nil { 279 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr4, ipAddr.IP) 280 } 281 282 interfaceAddr4 = ipAddr.IP 283 } else { 284 // IPv6 285 286 // Ignore addresses in subnets that are managed by Docker. 287 for _, subnet := range v6Subnets { 288 if subnet.Contains(ipAddr.IP) { 289 continue ifaceLoop 290 } 291 } 292 293 if interfaceAddr6 != nil { 294 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr6, ipAddr.IP) 295 } 296 297 interfaceAddr6 = ipAddr.IP 298 } 299 } 300 301 // In the case that this interface has exactly one IPv4 address 302 // and exactly one IPv6 address, favor IPv4 over IPv6. 303 if interfaceAddr4 != nil { 304 if systemAddr != nil { 305 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr4) 306 } 307 systemAddr = interfaceAddr4 308 systemInterface = intf.Name 309 } else if interfaceAddr6 != nil { 310 if systemAddr != nil { 311 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr6) 312 } 313 systemAddr = interfaceAddr6 314 systemInterface = intf.Name 315 } 316 } 317 318 if systemAddr == nil { 319 return nil, errNoIP 320 } 321 322 return systemAddr, nil 323 } 324 325 func listSystemIPs() []net.IP { 326 interfaces, err := net.Interfaces() 327 if err != nil { 328 return nil 329 } 330 331 var systemAddrs []net.IP 332 333 for _, intf := range interfaces { 334 addrs, err := intf.Addrs() 335 if err != nil { 336 continue 337 } 338 339 for _, addr := range addrs { 340 ipAddr, ok := addr.(*net.IPNet) 341 342 if ok { 343 systemAddrs = append(systemAddrs, ipAddr.IP) 344 } 345 } 346 } 347 348 return systemAddrs 349 } 350 351 func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error { 352 if interfaceA == interfaceB { 353 return configError(fmt.Sprintf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", interfaceA, addrA, addrB)) 354 } 355 return configError(fmt.Sprintf("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)) 356 }