util.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package connections
  7. import (
  8. "net"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "github.com/syncthing/syncthing/lib/osutil"
  13. )
  14. func fixupPort(uri *url.URL, defaultPort int) *url.URL {
  15. copyURI := *uri
  16. host, port, err := net.SplitHostPort(uri.Host)
  17. if err != nil && strings.Contains(err.Error(), "missing port") {
  18. // addr is on the form "1.2.3.4" or "[fe80::1]"
  19. host = uri.Host
  20. if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
  21. // net.JoinHostPort will add the brackets again
  22. host = host[1 : len(host)-1]
  23. }
  24. copyURI.Host = net.JoinHostPort(host, strconv.Itoa(defaultPort))
  25. } else if err == nil && port == "" {
  26. // addr is on the form "1.2.3.4:" or "[fe80::1]:"
  27. copyURI.Host = net.JoinHostPort(host, strconv.Itoa(defaultPort))
  28. }
  29. return &copyURI
  30. }
  31. func getURLsForAllAdaptersIfUnspecified(network string, uri *url.URL) []*url.URL {
  32. ip, port, err := resolve(network, uri.Host)
  33. // Failed to resolve
  34. if err != nil || port == 0 {
  35. return nil
  36. }
  37. // Not an unspecified address, so no point of substituting with local
  38. // interface addresses as it's listening on a specific adapter anyway.
  39. if len(ip) != 0 && !ip.IsUnspecified() {
  40. return nil
  41. }
  42. hostPorts := getHostPortsForAllAdapters(port)
  43. addrs := make([]*url.URL, 0, len(hostPorts))
  44. for _, hostPort := range hostPorts {
  45. newUri := *uri
  46. newUri.Host = hostPort
  47. addrs = append(addrs, &newUri)
  48. }
  49. return addrs
  50. }
  51. func getHostPortsForAllAdapters(port int) []string {
  52. nets, err := osutil.GetLans()
  53. if err != nil {
  54. // Ignore failure.
  55. return nil
  56. }
  57. hostPorts := make([]string, 0, len(nets))
  58. portStr := strconv.Itoa(port)
  59. for _, network := range nets {
  60. // Only IPv4 addresses, as v6 link local require an interface identifiers to work correctly
  61. // And non link local in theory are globally routable anyway.
  62. if network.IP.To4() == nil {
  63. continue
  64. }
  65. if network.IP.IsLinkLocalUnicast() || (isV4Local(network.IP) && network.IP.IsGlobalUnicast()) {
  66. hostPorts = append(hostPorts, net.JoinHostPort(network.IP.String(), portStr))
  67. }
  68. }
  69. return hostPorts
  70. }
  71. func resolve(network, hostPort string) (net.IP, int, error) {
  72. switch network {
  73. case "tcp", "tcp4", "tcp6":
  74. if addr, err := net.ResolveTCPAddr(network, hostPort); err != nil {
  75. return net.IPv4zero, 0, err
  76. } else {
  77. return addr.IP, addr.Port, nil
  78. }
  79. case "udp", "udp4", "udp6":
  80. if addr, err := net.ResolveUDPAddr(network, hostPort); err != nil {
  81. return net.IPv4zero, 0, err
  82. } else {
  83. return addr.IP, addr.Port, nil
  84. }
  85. case "ip", "ip4", "ip6":
  86. if addr, err := net.ResolveIPAddr(network, hostPort); err != nil {
  87. return net.IPv4zero, 0, err
  88. } else {
  89. return addr.IP, 0, nil
  90. }
  91. }
  92. return net.IPv4zero, 0, net.UnknownNetworkError(network)
  93. }
  94. func isV4Local(ip net.IP) bool {
  95. // See https://go-review.googlesource.com/c/go/+/162998/
  96. // We only take the V4 part of that.
  97. if ip4 := ip.To4(); ip4 != nil {
  98. return ip4[0] == 10 ||
  99. (ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
  100. (ip4[0] == 192 && ip4[1] == 168)
  101. }
  102. return false
  103. }