localip.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright (c) 2017 Uber Technologies, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package utils
  15. import (
  16. "errors"
  17. "net"
  18. )
  19. // This code is borrowed from https://github.com/uber/tchannel-go/blob/dev/localip.go
  20. // scoreAddr scores how likely the given addr is to be a remote address and returns the
  21. // IP to use when listening. Any address which receives a negative score should not be used.
  22. // Scores are calculated as:
  23. // -1 for any unknown IP addresses.
  24. // +300 for IPv4 addresses
  25. // +100 for non-local addresses, extra +100 for "up" interaces.
  26. func scoreAddr(iface net.Interface, addr net.Addr) (int, net.IP) {
  27. var ip net.IP
  28. if netAddr, ok := addr.(*net.IPNet); ok {
  29. ip = netAddr.IP
  30. } else if netIP, ok := addr.(*net.IPAddr); ok {
  31. ip = netIP.IP
  32. } else {
  33. return -1, nil
  34. }
  35. var score int
  36. if ip.To4() != nil {
  37. score += 300
  38. }
  39. if iface.Flags&net.FlagLoopback == 0 && !ip.IsLoopback() {
  40. score += 100
  41. if iface.Flags&net.FlagUp != 0 {
  42. score += 100
  43. }
  44. }
  45. return score, ip
  46. }
  47. // HostIP tries to find an IP that can be used by other machines to reach this machine.
  48. func HostIP() (net.IP, error) {
  49. interfaces, err := net.Interfaces()
  50. if err != nil {
  51. return nil, err
  52. }
  53. bestScore := -1
  54. var bestIP net.IP
  55. // Select the highest scoring IP as the best IP.
  56. for _, iface := range interfaces {
  57. addrs, err := iface.Addrs()
  58. if err != nil {
  59. // Skip this interface if there is an error.
  60. continue
  61. }
  62. for _, addr := range addrs {
  63. score, ip := scoreAddr(iface, addr)
  64. if score > bestScore {
  65. bestScore = score
  66. bestIP = ip
  67. }
  68. }
  69. }
  70. if bestScore == -1 {
  71. return nil, errors.New("no addresses to listen on")
  72. }
  73. return bestIP, nil
  74. }