github.com/dpiddy/docker@v1.12.2-rc1/daemon/cluster/listen_addr.go (about) 1 package cluster 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 ) 8 9 var ( 10 errNoSuchInterface = errors.New("no such interface") 11 errNoIP = errors.New("could not find the system's IP address") 12 errMustSpecifyListenAddr = errors.New("must specify a listening address because the address to advertise is not recognized as a system address") 13 errBadListenAddr = errors.New("listen address must be an IP address or network interface (with optional port number)") 14 errBadAdvertiseAddr = errors.New("advertise address must be an IP address or network interface (with optional port number)") 15 errBadDefaultAdvertiseAddr = errors.New("default advertise address must be an IP address or network interface (without a port number)") 16 ) 17 18 func resolveListenAddr(specifiedAddr string) (string, string, error) { 19 specifiedHost, specifiedPort, err := net.SplitHostPort(specifiedAddr) 20 if err != nil { 21 return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr) 22 } 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 interfaceAddr, err := resolveInterfaceAddr(specifiedHost) 27 if err == nil { 28 return interfaceAddr.String(), specifiedPort, nil 29 } 30 if err != errNoSuchInterface { 31 return "", "", err 32 } 33 34 // If it's not an interface, it must be an IP (for now) 35 if net.ParseIP(specifiedHost) == nil { 36 return "", "", errBadListenAddr 37 } 38 39 return specifiedHost, specifiedPort, nil 40 } 41 42 func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) { 43 // Approach: 44 // - If an advertise address is specified, use that. Resolve the 45 // interface's address if an interface was specified in 46 // advertiseAddr. Fill in the port from listenAddrPort if necessary. 47 // - If DefaultAdvertiseAddr is not empty, use that with the port from 48 // listenAddrPort. Resolve the interface's address from 49 // if an interface name was specified in DefaultAdvertiseAddr. 50 // - Otherwise, try to autodetect the system's address. Use the port in 51 // listenAddrPort with this address if autodetection succeeds. 52 53 if advertiseAddr != "" { 54 advertiseHost, advertisePort, err := net.SplitHostPort(advertiseAddr) 55 if err != nil { 56 // Not a host:port specification 57 advertiseHost = advertiseAddr 58 advertisePort = listenAddrPort 59 } 60 61 // Does the host component match any of the interface names on the 62 // system? If so, use the address from that interface. 63 interfaceAddr, err := resolveInterfaceAddr(advertiseHost) 64 if err == nil { 65 return interfaceAddr.String(), advertisePort, nil 66 } 67 if err != errNoSuchInterface { 68 return "", "", err 69 } 70 71 // If it's not an interface, it must be an IP (for now) 72 if net.ParseIP(advertiseHost) == nil { 73 return "", "", errBadAdvertiseAddr 74 } 75 76 return advertiseHost, advertisePort, nil 77 } 78 79 if c.config.DefaultAdvertiseAddr != "" { 80 // Does the default advertise address component match any of the 81 // interface names on the system? If so, use the address from 82 // that interface. 83 interfaceAddr, err := resolveInterfaceAddr(c.config.DefaultAdvertiseAddr) 84 if err == nil { 85 return interfaceAddr.String(), listenAddrPort, nil 86 } 87 if err != errNoSuchInterface { 88 return "", "", err 89 } 90 91 // If it's not an interface, it must be an IP (for now) 92 if net.ParseIP(c.config.DefaultAdvertiseAddr) == nil { 93 return "", "", errBadDefaultAdvertiseAddr 94 } 95 96 return c.config.DefaultAdvertiseAddr, listenAddrPort, nil 97 } 98 99 systemAddr, err := c.resolveSystemAddr() 100 if err != nil { 101 return "", "", err 102 } 103 return systemAddr.String(), listenAddrPort, 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, fmt.Errorf("interface %s has more than one IPv4 address", specifiedInterface) 128 } 129 interfaceAddr4 = ipAddr.IP 130 } else { 131 // IPv6 132 if interfaceAddr6 != nil { 133 return nil, fmt.Errorf("interface %s has more than one IPv6 address", specifiedInterface) 134 } 135 interfaceAddr6 = ipAddr.IP 136 } 137 } 138 } 139 140 if interfaceAddr4 == nil && interfaceAddr6 == nil { 141 return nil, fmt.Errorf("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 func (c *Cluster) resolveSystemAddr() (net.IP, error) { 153 // Use the system's only IP address, or fail if there are 154 // multiple addresses to choose from. 155 interfaces, err := net.Interfaces() 156 if err != nil { 157 return nil, err 158 } 159 160 var systemAddr net.IP 161 var systemInterface net.Interface 162 163 // List Docker-managed subnets 164 v4Subnets := c.config.NetworkSubnetsProvider.V4Subnets() 165 v6Subnets := c.config.NetworkSubnetsProvider.V6Subnets() 166 167 ifaceLoop: 168 for _, intf := range interfaces { 169 // Skip inactive interfaces and loopback interfaces 170 if (intf.Flags&net.FlagUp == 0) || (intf.Flags&net.FlagLoopback) != 0 { 171 continue 172 } 173 174 addrs, err := intf.Addrs() 175 if err != nil { 176 continue 177 } 178 179 var interfaceAddr4, interfaceAddr6 net.IP 180 181 for _, addr := range addrs { 182 ipAddr, ok := addr.(*net.IPNet) 183 184 // Skip loopback and link-local addresses 185 if !ok || !ipAddr.IP.IsGlobalUnicast() { 186 continue 187 } 188 189 if ipAddr.IP.To4() != nil { 190 // IPv4 191 192 // Ignore addresses in subnets that are managed by Docker. 193 for _, subnet := range v4Subnets { 194 if subnet.Contains(ipAddr.IP) { 195 continue ifaceLoop 196 } 197 } 198 199 if interfaceAddr4 != nil { 200 return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", intf.Name, interfaceAddr4, ipAddr.IP) 201 } 202 203 interfaceAddr4 = ipAddr.IP 204 } else { 205 // IPv6 206 207 // Ignore addresses in subnets that are managed by Docker. 208 for _, subnet := range v6Subnets { 209 if subnet.Contains(ipAddr.IP) { 210 continue ifaceLoop 211 } 212 } 213 214 if interfaceAddr6 != nil { 215 return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", intf.Name, interfaceAddr6, ipAddr.IP) 216 } 217 218 interfaceAddr6 = ipAddr.IP 219 } 220 } 221 222 // In the case that this interface has exactly one IPv4 address 223 // and exactly one IPv6 address, favor IPv4 over IPv6. 224 if interfaceAddr4 != nil { 225 if systemAddr != nil { 226 return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on different interfaces (%s on %s and %s on %s)", systemAddr, systemInterface.Name, interfaceAddr4, intf.Name) 227 } 228 systemAddr = interfaceAddr4 229 systemInterface = intf 230 } else if interfaceAddr6 != nil { 231 if systemAddr != nil { 232 return nil, fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on different interfaces (%s on %s and %s on %s)", systemAddr, systemInterface.Name, interfaceAddr6, intf.Name) 233 } 234 systemAddr = interfaceAddr6 235 systemInterface = intf 236 } 237 } 238 239 if systemAddr == nil { 240 return nil, errNoIP 241 } 242 243 return systemAddr, nil 244 } 245 246 func listSystemIPs() []net.IP { 247 interfaces, err := net.Interfaces() 248 if err != nil { 249 return nil 250 } 251 252 var systemAddrs []net.IP 253 254 for _, intf := range interfaces { 255 addrs, err := intf.Addrs() 256 if err != nil { 257 continue 258 } 259 260 for _, addr := range addrs { 261 ipAddr, ok := addr.(*net.IPNet) 262 263 if ok { 264 systemAddrs = append(systemAddrs, ipAddr.IP) 265 } 266 } 267 } 268 269 return systemAddrs 270 }