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  }