PageRenderTime 31ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/daemon/cluster/listen_addr.go

https://gitlab.com/vectorci/docker-1
Go | 183 lines | 129 code | 29 blank | 25 comment | 56 complexity | 382c8a4d810982210a816ce1c3dc9478 MD5 | raw file
  1. package cluster
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. )
  7. var (
  8. errNoSuchInterface = errors.New("no such interface")
  9. errNoIP = errors.New("could not find the system's IP address")
  10. errMustSpecifyListenAddr = errors.New("must specify a listening address because the address to advertise is not recognized as a system address")
  11. errBadListenAddr = errors.New("listen address must be an IP address or network interface (with optional port number)")
  12. errBadAdvertiseAddr = errors.New("advertise address must be an IP address or network interface (with optional port number)")
  13. errBadDefaultAdvertiseAddr = errors.New("default advertise address must be an IP address or network interface (without a port number)")
  14. )
  15. func resolveListenAddr(specifiedAddr string) (string, string, error) {
  16. specifiedHost, specifiedPort, err := net.SplitHostPort(specifiedAddr)
  17. if err != nil {
  18. return "", "", fmt.Errorf("could not parse listen address %s", specifiedAddr)
  19. }
  20. // Does the host component match any of the interface names on the
  21. // system? If so, use the address from that interface.
  22. interfaceAddr, err := resolveInterfaceAddr(specifiedHost)
  23. if err == nil {
  24. return interfaceAddr.String(), specifiedPort, nil
  25. }
  26. if err != errNoSuchInterface {
  27. return "", "", err
  28. }
  29. // If it's not an interface, it must be an IP (for now)
  30. if net.ParseIP(specifiedHost) == nil {
  31. return "", "", errBadListenAddr
  32. }
  33. return specifiedHost, specifiedPort, nil
  34. }
  35. func (c *Cluster) resolveAdvertiseAddr(advertiseAddr, listenAddrPort string) (string, string, error) {
  36. // Approach:
  37. // - If an advertise address is specified, use that. Resolve the
  38. // interface's address if an interface was specified in
  39. // advertiseAddr. Fill in the port from listenAddrPort if necessary.
  40. // - If DefaultAdvertiseAddr is not empty, use that with the port from
  41. // listenAddrPort. Resolve the interface's address from
  42. // if an interface name was specified in DefaultAdvertiseAddr.
  43. // - Otherwise, try to autodetect the system's address. Use the port in
  44. // listenAddrPort with this address if autodetection succeeds.
  45. if advertiseAddr != "" {
  46. advertiseHost, advertisePort, err := net.SplitHostPort(advertiseAddr)
  47. if err != nil {
  48. // Not a host:port specification
  49. advertiseHost = advertiseAddr
  50. advertisePort = listenAddrPort
  51. }
  52. // Does the host component match any of the interface names on the
  53. // system? If so, use the address from that interface.
  54. interfaceAddr, err := resolveInterfaceAddr(advertiseHost)
  55. if err == nil {
  56. return interfaceAddr.String(), advertisePort, nil
  57. }
  58. if err != errNoSuchInterface {
  59. return "", "", err
  60. }
  61. // If it's not an interface, it must be an IP (for now)
  62. if net.ParseIP(advertiseHost) == nil {
  63. return "", "", errBadAdvertiseAddr
  64. }
  65. return advertiseHost, advertisePort, nil
  66. }
  67. if c.config.DefaultAdvertiseAddr != "" {
  68. // Does the default advertise address component match any of the
  69. // interface names on the system? If so, use the address from
  70. // that interface.
  71. interfaceAddr, err := resolveInterfaceAddr(c.config.DefaultAdvertiseAddr)
  72. if err == nil {
  73. return interfaceAddr.String(), listenAddrPort, nil
  74. }
  75. if err != errNoSuchInterface {
  76. return "", "", err
  77. }
  78. // If it's not an interface, it must be an IP (for now)
  79. if net.ParseIP(c.config.DefaultAdvertiseAddr) == nil {
  80. return "", "", errBadDefaultAdvertiseAddr
  81. }
  82. return c.config.DefaultAdvertiseAddr, listenAddrPort, nil
  83. }
  84. systemAddr, err := c.resolveSystemAddr()
  85. if err != nil {
  86. return "", "", err
  87. }
  88. return systemAddr.String(), listenAddrPort, nil
  89. }
  90. func resolveInterfaceAddr(specifiedInterface string) (net.IP, error) {
  91. // Use a specific interface's IP address.
  92. intf, err := net.InterfaceByName(specifiedInterface)
  93. if err != nil {
  94. return nil, errNoSuchInterface
  95. }
  96. addrs, err := intf.Addrs()
  97. if err != nil {
  98. return nil, err
  99. }
  100. var interfaceAddr4, interfaceAddr6 net.IP
  101. for _, addr := range addrs {
  102. ipAddr, ok := addr.(*net.IPNet)
  103. if ok {
  104. if ipAddr.IP.To4() != nil {
  105. // IPv4
  106. if interfaceAddr4 != nil {
  107. return nil, fmt.Errorf("interface %s has more than one IPv4 address (%s and %s)", specifiedInterface, interfaceAddr4, ipAddr.IP)
  108. }
  109. interfaceAddr4 = ipAddr.IP
  110. } else {
  111. // IPv6
  112. if interfaceAddr6 != nil {
  113. return nil, fmt.Errorf("interface %s has more than one IPv6 address (%s and %s)", specifiedInterface, interfaceAddr6, ipAddr.IP)
  114. }
  115. interfaceAddr6 = ipAddr.IP
  116. }
  117. }
  118. }
  119. if interfaceAddr4 == nil && interfaceAddr6 == nil {
  120. return nil, fmt.Errorf("interface %s has no usable IPv4 or IPv6 address", specifiedInterface)
  121. }
  122. // In the case that there's exactly one IPv4 address
  123. // and exactly one IPv6 address, favor IPv4 over IPv6.
  124. if interfaceAddr4 != nil {
  125. return interfaceAddr4, nil
  126. }
  127. return interfaceAddr6, nil
  128. }
  129. func listSystemIPs() []net.IP {
  130. interfaces, err := net.Interfaces()
  131. if err != nil {
  132. return nil
  133. }
  134. var systemAddrs []net.IP
  135. for _, intf := range interfaces {
  136. addrs, err := intf.Addrs()
  137. if err != nil {
  138. continue
  139. }
  140. for _, addr := range addrs {
  141. ipAddr, ok := addr.(*net.IPNet)
  142. if ok {
  143. systemAddrs = append(systemAddrs, ipAddr.IP)
  144. }
  145. }
  146. }
  147. return systemAddrs
  148. }
  149. func errMultipleIPs(interfaceA, interfaceB string, addrA, addrB net.IP) error {
  150. if interfaceA == interfaceB {
  151. return fmt.Errorf("could not choose an IP address to advertise since this system has multiple addresses on interface %s (%s and %s)", interfaceA, addrA, addrB)
  152. }
  153. return 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)", addrA, interfaceA, addrB, interfaceB)
  154. }