1. package host
    2. import (
    3. "fmt"
    4. "net"
    5. "strconv"
    6. )
    7. // ExtractHostPort from address
    8. func ExtractHostPort(addr string) (host string, port uint64, err error) {
    9. var ports string
    10. host, ports, err = net.SplitHostPort(addr)
    11. if err != nil {
    12. return
    13. }
    14. port, err = strconv.ParseUint(ports, 10, 16) //nolint:gomnd
    15. if err != nil {
    16. return
    17. }
    18. return
    19. }
    20. func isValidIP(addr string) bool {
    21. ip := net.ParseIP(addr)
    22. return ip.IsGlobalUnicast() && !ip.IsInterfaceLocalMulticast()
    23. }
    24. // Port return a real port.
    25. func Port(lis net.Listener) (int, bool) {
    26. if addr, ok := lis.Addr().(*net.TCPAddr); ok {
    27. return addr.Port, true
    28. }
    29. return 0, false
    30. }
    31. // Extract returns a private addr and port.
    32. func Extract(hostPort string, lis net.Listener) (string, error) {
    33. addr, port, err := net.SplitHostPort(hostPort)
    34. if err != nil && lis == nil {
    35. return "", err
    36. }
    37. if lis != nil {
    38. if p, ok := Port(lis); ok {
    39. port = strconv.Itoa(p)
    40. } else {
    41. return "", fmt.Errorf("failed to extract port: %v", lis.Addr())
    42. }
    43. }
    44. if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]" && addr != "::") {
    45. return net.JoinHostPort(addr, port), nil
    46. }
    47. ifaces, err := net.Interfaces()
    48. if err != nil {
    49. return "", err
    50. }
    51. lowest := int(^uint(0) >> 1)
    52. var result net.IP
    53. for _, iface := range ifaces {
    54. if (iface.Flags & net.FlagUp) == 0 {
    55. continue
    56. }
    57. if iface.Index < lowest || result == nil {
    58. lowest = iface.Index
    59. } else if result != nil {
    60. continue
    61. }
    62. addrs, err := iface.Addrs()
    63. if err != nil {
    64. continue
    65. }
    66. for _, rawAddr := range addrs {
    67. var ip net.IP
    68. switch addr := rawAddr.(type) {
    69. case *net.IPAddr:
    70. ip = addr.IP
    71. case *net.IPNet:
    72. ip = addr.IP
    73. default:
    74. continue
    75. }
    76. if isValidIP(ip.String()) {
    77. result = ip
    78. }
    79. }
    80. }
    81. if result != nil {
    82. return net.JoinHostPort(result.String(), port), nil
    83. }
    84. return "", nil
    85. }