github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/cluster/listen_addr.go (about) 1 package cluster // import "github.com/Prakhar-Agarwal-byte/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 "", "", configError("could not parse listen address " + 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 146 func resolveDataPathAddr(dataPathAddr string) (string, error) { 147 if dataPathAddr == "" { 148 // dataPathAddr is not defined 149 return "", nil 150 } 151 // If a data path flag is specified try to resolve the IP address. 152 dataPathIP, err := resolveInputIPAddr(dataPathAddr, false) 153 if err != nil { 154 if err == errBadNetworkIdentifier { 155 err = errBadDataPathAddr 156 } 157 return "", err 158 } 159 return dataPathIP.String(), nil 160 } 161 162 func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) { 163 // Use a specific interface's IP address. 164 intf, err := net.InterfaceByName(specifiedInterface) 165 if err != nil { 166 return nil, errNoSuchInterface 167 } 168 169 addrs, err := intf.Addrs() 170 if err != nil { 171 return nil, err 172 } 173 174 var interfaceAddr4, interfaceAddr6 net.IP 175 176 for _, addr := range addrs { 177 ipAddr, ok := addr.(*net.IPNet) 178 179 if ok { 180 if ipAddr.IP.To4() != nil { 181 // IPv4 182 if interfaceAddr4 != nil { 183 return nil, configError(fmt.Sprintf("interface %s has more than one IPv4 address (%s and %s)", specifiedInterface, interfaceAddr4, ipAddr.IP)) 184 } 185 interfaceAddr4 = ipAddr.IP 186 } else { 187 // IPv6 188 if interfaceAddr6 != nil { 189 return nil, configError(fmt.Sprintf("interface %s has more than one IPv6 address (%s and %s)", specifiedInterface, interfaceAddr6, ipAddr.IP)) 190 } 191 interfaceAddr6 = ipAddr.IP 192 } 193 } 194 } 195 196 if interfaceAddr4 == nil && interfaceAddr6 == nil { 197 return nil, configError(fmt.Sprintf("interface %s has no usable IPv4 or IPv6 address", specifiedInterface)) 198 } 199 200 // In the case that there's exactly one IPv4 address 201 // and exactly one IPv6 address, favor IPv4 over IPv6. 202 if interfaceAddr4 != nil { 203 return interfaceAddr4, nil 204 } 205 return interfaceAddr6, nil 206 } 207 208 // resolveInputIPAddr tries to resolve the IP address from the string passed as input 209 // - tries to match the string as an interface name, if so returns the IP address associated with it 210 // - on failure of previous step tries to parse the string as an IP address itself 211 // if succeeds returns the IP address 212 func resolveInputIPAddr(input string, isUnspecifiedValid bool) (net.IP, error) { 213 // Try to see if it is an interface name 214 interfaceAddr, err := resolveInterfaceAddr(input) 215 if err == nil { 216 return interfaceAddr, nil 217 } 218 // String matched interface but there is a potential ambiguity to be resolved 219 if err != errNoSuchInterface { 220 return nil, err 221 } 222 223 // String is not an interface check if it is a valid IP 224 if ip := net.ParseIP(input); ip != nil && (isUnspecifiedValid || !ip.IsUnspecified()) { 225 return ip, nil 226 } 227 228 // Not valid IP found 229 return nil, errBadNetworkIdentifier 230 } 231 232 func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) { 233 // Use the system's only IP address, or fail if there are 234 // multiple addresses to choose from. Skip interfaces which 235 // are managed by docker via subnet check. 236 interfaces, err := net.Interfaces() 237 if err != nil { 238 return nil, err 239 } 240 241 var systemAddr net.IP 242 var systemInterface string 243 244 // List Docker-managed subnets 245 v4Subnets, v6Subnets := c.config.NetworkSubnetsProvider.Subnets() 246 247 ifaceLoop: 248 for _, intf := range interfaces { 249 // Skip inactive interfaces and loopback interfaces 250 if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 { 251 continue 252 } 253 254 addrs, err := intf.Addrs() 255 if err != nil { 256 continue 257 } 258 259 var interfaceAddr4, interfaceAddr6 net.IP 260 261 for _, addr := range addrs { 262 ipAddr, ok := addr.(*net.IPNet) 263 264 // Skip loopback and link-local addresses 265 if !ok || !ipAddr.IP.IsGlobalUnicast() { 266 continue 267 } 268 269 if ipAddr.IP.To4() != nil { 270 // IPv4 271 272 // Ignore addresses in subnets that are managed by Docker. 273 for _, subnet := range v4Subnets { 274 if subnet.Contains(ipAddr.IP) { 275 continue ifaceLoop 276 } 277 } 278 279 if interfaceAddr4 != nil { 280 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr4, ipAddr.IP) 281 } 282 283 interfaceAddr4 = ipAddr.IP 284 } else { 285 // IPv6 286 287 // Ignore addresses in subnets that are managed by Docker. 288 for _, subnet := range v6Subnets { 289 if subnet.Contains(ipAddr.IP) { 290 continue ifaceLoop 291 } 292 } 293 294 if interfaceAddr6 != nil { 295 return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr6, ipAddr.IP) 296 } 297 298 interfaceAddr6 = ipAddr.IP 299 } 300 } 301 302 // In the case that this interface has exactly one IPv4 address 303 // and exactly one IPv6 address, favor IPv4 over IPv6. 304 if interfaceAddr4 != nil { 305 if systemAddr != nil { 306 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr4) 307 } 308 systemAddr = interfaceAddr4 309 systemInterface = intf.Name 310 } else if interfaceAddr6 != nil { 311 if systemAddr != nil { 312 return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr6) 313 } 314 systemAddr = interfaceAddr6 315 systemInterface = intf.Name 316 } 317 } 318 319 if systemAddr == nil { 320 return nil, errNoIP 321 } 322 323 return systemAddr, nil 324 } 325 326 func listSystemIPs() []net.IP { 327 interfaces, err := net.Interfaces() 328 if err != nil { 329 return nil 330 } 331 332 var systemAddrs []net.IP 333 334 for _, intf := range interfaces { 335 addrs, err := intf.Addrs() 336 if err != nil { 337 continue 338 } 339 340 for _, addr := range addrs { 341 ipAddr, ok := addr.(*net.IPNet) 342 343 if ok { 344 systemAddrs = append(systemAddrs, ipAddr.IP) 345 } 346 } 347 } 348 349 return systemAddrs 350 } 351 352 func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error { 353 if interfaceA == interfaceB { 354 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)) 355 } 356 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)) 357 }