listen_addr.go 9.1 KB

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