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 }