github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/cluster/listen_addr.go (about)

     1  package cluster
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  )
     7  
     8  const (
     9  	errNoSuchInterface         configError = "no such interface"
    10  	errNoIP                    configError = "could not find the system's IP address"
    11  	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"
    12  	errBadNetworkIdentifier    configError = "must specify a valid IP address or interface name"
    13  	errBadListenAddr           configError = "listen address must be an IP address or network interface (with optional port number)"
    14  	errBadAdvertiseAddr        configError = "advertise address must be a non-zero IP address or network interface (with optional port number)"
    15  	errBadDataPathAddr         configError = "data path address must be a non-zero IP address or network interface (without a port number)"
    16  	errBadDefaultAdvertiseAddr configError = "default advertise address must be a non-zero IP address or network interface (without a port number)"
    17  )
    18  
    19  func resolveListenAddr(specifiedAddr string) (string, string, error) {
    20  	specifiedHost, specifiedPort, err := net.SplitHostPort(specifiedAddr)
    21  	if err != nil {
    22  		return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr)
    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  	specifiedIP, err := resolveInputIPAddr(specifiedHost, true)
    27  	if err != nil {
    28  		if err == errBadNetworkIdentifier {
    29  			err = errBadListenAddr
    30  		}
    31  		return "", "", err
    32  	}
    33  
    34  	return specifiedIP.String(), specifiedPort, nil
    35  }
    36  
    37  func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) {
    38  	// Approach:
    39  	// - If an advertise address is specified, use that. Resolve the
    40  	//   interface's address if an interface was specified in
    41  	//   advertiseAddr. Fill in the port from listenAddrPort if necessary.
    42  	// - If DefaultAdvertiseAddr is not empty, use that with the port from
    43  	//   listenAddrPort. Resolve the interface's address from
    44  	//   if an interface name was specified in DefaultAdvertiseAddr.
    45  	// - Otherwise, try to autodetect the system's address. Use the port in
    46  	//   listenAddrPort with this address if autodetection succeeds.
    47  
    48  	if advertiseAddr != "" {
    49  		advertiseHost, advertisePort, err := net.SplitHostPort(advertiseAddr)
    50  		if err != nil {
    51  			// Not a host:port specification
    52  			advertiseHost = advertiseAddr
    53  			advertisePort = listenAddrPort
    54  		}
    55  		// Does the host component match any of the interface names on the
    56  		// system? If so, use the address from that interface.
    57  		advertiseIP, err := resolveInputIPAddr(advertiseHost, false)
    58  		if err != nil {
    59  			if err == errBadNetworkIdentifier {
    60  				err = errBadAdvertiseAddr
    61  			}
    62  			return "", "", err
    63  		}
    64  
    65  		return advertiseIP.String(), advertisePort, nil
    66  	}
    67  
    68  	if c.config.DefaultAdvertiseAddr != "" {
    69  		// Does the default advertise address component match any of the
    70  		// interface names on the system? If so, use the address from
    71  		// that interface.
    72  		defaultAdvertiseIP, err := resolveInputIPAddr(c.config.DefaultAdvertiseAddr, false)
    73  		if err != nil {
    74  			if err == errBadNetworkIdentifier {
    75  				err = errBadDefaultAdvertiseAddr
    76  			}
    77  			return "", "", err
    78  		}
    79  
    80  		return defaultAdvertiseIP.String(), listenAddrPort, nil
    81  	}
    82  
    83  	systemAddr, err := c.resolveSystemAddr()
    84  	if err != nil {
    85  		return "", "", err
    86  	}
    87  	return systemAddr.String(), listenAddrPort, nil
    88  }
    89  
    90  func resolveDataPathAddr(dataPathAddr string) (string, error) {
    91  	if dataPathAddr == "" {
    92  		// dataPathAddr is not defined
    93  		return "", nil
    94  	}
    95  	// If a data path flag is specified try to resolve the IP address.
    96  	dataPathIP, err := resolveInputIPAddr(dataPathAddr, false)
    97  	if err != nil {
    98  		if err == errBadNetworkIdentifier {
    99  			err = errBadDataPathAddr
   100  		}
   101  		return "", err
   102  	}
   103  	return dataPathIP.String(), 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, configError(fmt.Sprintf("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, configError(fmt.Sprintf("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, configError(fmt.Sprintf("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  // resolveInputIPAddr tries to resolve the IP address from the string passed as input
   153  // - tries to match the string as an interface name, if so returns the IP address associated with it
   154  // - on failure of previous step tries to parse the string as an IP address itself
   155  //	 if succeeds returns the IP address
   156  func resolveInputIPAddr(input string, isUnspecifiedValid bool) (net.IP, error) {
   157  	// Try to see if it is an interface name
   158  	interfaceAddr, err := resolveInterfaceAddr(input)
   159  	if err == nil {
   160  		return interfaceAddr, nil
   161  	}
   162  	// String matched interface but there is a potential ambiguity to be resolved
   163  	if err != errNoSuchInterface {
   164  		return nil, err
   165  	}
   166  
   167  	// String is not an interface check if it is a valid IP
   168  	if ip := net.ParseIP(input); ip != nil && (isUnspecifiedValid || !ip.IsUnspecified()) {
   169  		return ip, nil
   170  	}
   171  
   172  	// Not valid IP found
   173  	return nil, errBadNetworkIdentifier
   174  }
   175  
   176  func (c *Cluster) resolveSystemAddrViaSubnetCheck() (net.IP, error) {
   177  	// Use the system's only IP address, or fail if there are
   178  	// multiple addresses to choose from. Skip interfaces which
   179  	// are managed by docker via subnet check.
   180  	interfaces, err := net.Interfaces()
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	var systemAddr net.IP
   186  	var systemInterface string
   187  
   188  	// List Docker-managed subnets
   189  	v4Subnets, v6Subnets := c.config.NetworkSubnetsProvider.Subnets()
   190  
   191  ifaceLoop:
   192  	for _, intf := range interfaces {
   193  		// Skip inactive interfaces and loopback interfaces
   194  		if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 {
   195  			continue
   196  		}
   197  
   198  		addrs, err := intf.Addrs()
   199  		if err != nil {
   200  			continue
   201  		}
   202  
   203  		var interfaceAddr4, interfaceAddr6 net.IP
   204  
   205  		for _, addr := range addrs {
   206  			ipAddr, ok := addr.(*net.IPNet)
   207  
   208  			// Skip loopback and link-local addresses
   209  			if !ok || !ipAddr.IP.IsGlobalUnicast() {
   210  				continue
   211  			}
   212  
   213  			if ipAddr.IP.To4() != nil {
   214  				// IPv4
   215  
   216  				// Ignore addresses in subnets that are managed by Docker.
   217  				for _, subnet := range v4Subnets {
   218  					if subnet.Contains(ipAddr.IP) {
   219  						continue ifaceLoop
   220  					}
   221  				}
   222  
   223  				if interfaceAddr4 != nil {
   224  					return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr4, ipAddr.IP)
   225  				}
   226  
   227  				interfaceAddr4 = ipAddr.IP
   228  			} else {
   229  				// IPv6
   230  
   231  				// Ignore addresses in subnets that are managed by Docker.
   232  				for _, subnet := range v6Subnets {
   233  					if subnet.Contains(ipAddr.IP) {
   234  						continue ifaceLoop
   235  					}
   236  				}
   237  
   238  				if interfaceAddr6 != nil {
   239  					return nil, errMultipleIPs(intf.Name, intf.Name, interfaceAddr6, ipAddr.IP)
   240  				}
   241  
   242  				interfaceAddr6 = ipAddr.IP
   243  			}
   244  		}
   245  
   246  		// In the case that this interface has exactly one IPv4 address
   247  		// and exactly one IPv6 address, favor IPv4 over IPv6.
   248  		if interfaceAddr4 != nil {
   249  			if systemAddr != nil {
   250  				return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr4)
   251  			}
   252  			systemAddr = interfaceAddr4
   253  			systemInterface = intf.Name
   254  		} else if interfaceAddr6 != nil {
   255  			if systemAddr != nil {
   256  				return nil, errMultipleIPs(systemInterface, intf.Name, systemAddr, interfaceAddr6)
   257  			}
   258  			systemAddr = interfaceAddr6
   259  			systemInterface = intf.Name
   260  		}
   261  	}
   262  
   263  	if systemAddr == nil {
   264  		return nil, errNoIP
   265  	}
   266  
   267  	return systemAddr, nil
   268  }
   269  
   270  func listSystemIPs() []net.IP {
   271  	interfaces, err := net.Interfaces()
   272  	if err != nil {
   273  		return nil
   274  	}
   275  
   276  	var systemAddrs []net.IP
   277  
   278  	for _, intf := range interfaces {
   279  		addrs, err := intf.Addrs()
   280  		if err != nil {
   281  			continue
   282  		}
   283  
   284  		for _, addr := range addrs {
   285  			ipAddr, ok := addr.(*net.IPNet)
   286  
   287  			if ok {
   288  				systemAddrs = append(systemAddrs, ipAddr.IP)
   289  			}
   290  		}
   291  	}
   292  
   293  	return systemAddrs
   294  }
   295  
   296  func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error {
   297  	if interfaceA == interfaceB {
   298  		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))
   299  	}
   300  	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))
   301  }