You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.2 KiB

4 years ago
  1. package net2
  2. import (
  3. "fmt"
  4. "log"
  5. "net"
  6. "os"
  7. "strings"
  8. "sync"
  9. )
  10. var myHostname string
  11. var myHostnameOnce sync.Once
  12. // Like os.Hostname but caches first successful result, making it cheap to call it
  13. // over and over.
  14. // It will also crash whole process if fetching Hostname fails!
  15. func MyHostname() string {
  16. myHostnameOnce.Do(func() {
  17. var err error
  18. myHostname, err = os.Hostname()
  19. if err != nil {
  20. log.Fatal(err)
  21. }
  22. })
  23. return myHostname
  24. }
  25. var myIp4 *net.IPAddr
  26. var myIp4Once sync.Once
  27. // Resolves `MyHostname()` to an Ip4 address. Caches first successful result, making it
  28. // cheap to call it over and over.
  29. // It will also crash whole process if resolving the IP fails!
  30. func MyIp4() *net.IPAddr {
  31. myIp4Once.Do(func() {
  32. var err error
  33. myIp4, err = net.ResolveIPAddr("ip4", MyHostname())
  34. if err != nil {
  35. log.Fatal(err)
  36. }
  37. })
  38. return myIp4
  39. }
  40. var myIp6 *net.IPAddr
  41. var myIp6Once sync.Once
  42. // Resolves `MyHostname()` to an Ip6 address. Caches first successful result, making it
  43. // cheap to call it over and over.
  44. // It will also crash whole process if resolving the IP fails!
  45. func MyIp6() *net.IPAddr {
  46. myIp6Once.Do(func() {
  47. var err error
  48. myIp6, err = net.ResolveIPAddr("ip6", MyHostname())
  49. if err != nil {
  50. log.Fatal(err)
  51. }
  52. })
  53. return myIp6
  54. }
  55. // This returns the list of local ip addresses which other hosts can connect
  56. // to (NOTE: Loopback ip is ignored).
  57. // Also resolves Hostname to an address and adds it to the list too, so
  58. // IPs from /etc/hosts can work too.
  59. func GetLocalIPs() ([]*net.IP, error) {
  60. hostname, err := os.Hostname()
  61. if err != nil {
  62. return nil, fmt.Errorf("Failed to lookup hostname: %v", err)
  63. }
  64. // Resolves IP Address from Hostname, this way overrides in /etc/hosts
  65. // can work too for IP resolution.
  66. ipInfo, err := net.ResolveIPAddr("ip4", hostname)
  67. if err != nil {
  68. return nil, fmt.Errorf("Failed to resolve ip: %v", err)
  69. }
  70. ips := []*net.IP{&ipInfo.IP}
  71. // TODO(zviad): Is rest of the code really necessary?
  72. addrs, err := net.InterfaceAddrs()
  73. if err != nil {
  74. return nil, fmt.Errorf("Failed to get interface addresses: %v", err)
  75. }
  76. for _, addr := range addrs {
  77. ipnet, ok := addr.(*net.IPNet)
  78. if !ok {
  79. continue
  80. }
  81. if ipnet.IP.IsLoopback() {
  82. continue
  83. }
  84. ips = append(ips, &ipnet.IP)
  85. }
  86. return ips, nil
  87. }
  88. var localhostIPNets []*net.IPNet
  89. func init() {
  90. for _, mask := range []string{"127.0.0.1/8", "::1/128"} {
  91. _, ipnet, err := net.ParseCIDR(mask)
  92. if err != nil {
  93. panic(err)
  94. }
  95. localhostIPNets = append(localhostIPNets, ipnet)
  96. }
  97. }
  98. func IsLocalhostIp(ipStr string) bool {
  99. ip := net.ParseIP(ipStr)
  100. if ip == nil {
  101. return false
  102. }
  103. for _, ipnet := range localhostIPNets {
  104. if ipnet.Contains(ip) {
  105. return true
  106. }
  107. }
  108. return false
  109. }
  110. // Given a host string, return true if the host is an ip (v4/v6) localhost.
  111. func IsLocalhost(host string) bool {
  112. return IsLocalhostIp(host) ||
  113. host == "localhost" ||
  114. host == "ip6-localhost" ||
  115. host == "ipv6-localhost"
  116. }
  117. // Resolves hostnames in addresses to actual IP4 addresses. Skips all invalid addresses
  118. // and all addresses that can't be resolved.
  119. // `addrs` are assumed to be of form: ["<hostname>:<port>", ...]
  120. // Returns an error in addition to resolved addresses if not all resolutions succeed.
  121. func ResolveIP4s(addrs []string) ([]string, error) {
  122. resolvedAddrs := make([]string, 0, len(addrs))
  123. var lastErr error
  124. for _, server := range addrs {
  125. hostPort := strings.Split(server, ":")
  126. if len(hostPort) != 2 {
  127. lastErr = fmt.Errorf("Skipping invalid address: %s", server)
  128. continue
  129. }
  130. ip, err := net.ResolveIPAddr("ip4", hostPort[0])
  131. if err != nil {
  132. lastErr = err
  133. continue
  134. }
  135. resolvedAddrs = append(resolvedAddrs, ip.IP.String()+":"+hostPort[1])
  136. }
  137. return resolvedAddrs, lastErr
  138. }
  139. func LookupValidAddrs() (map[string]bool, error) {
  140. hostName, err := os.Hostname()
  141. if err != nil {
  142. return nil, err
  143. }
  144. addrs, err := net.LookupHost(hostName)
  145. if err != nil {
  146. return nil, err
  147. }
  148. validAddrs := make(map[string]bool)
  149. validAddrs[hostName] = true
  150. for _, addr := range addrs {
  151. validAddrs[addr] = true
  152. }
  153. // Special case localhost/127.0.0.1 so that this works on devVMs. It should
  154. // have no affect in production.
  155. validAddrs["127.0.0.1"] = true
  156. validAddrs["localhost"] = true
  157. return validAddrs, nil
  158. }