util.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 e, ok := err.(*net.AddrError); ok && strings.Contains(e.Err, "missing port") {
  18. // addr is of 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 accept IPv4 link-local unicast and the private ranges defined in RFC 1918 and RFC 4193
  61. // IPv6 link-local addresses require an interface identifier to work correctly
  62. if (network.IP.To4() != nil && network.IP.IsLinkLocalUnicast()) || network.IP.IsPrivate() {
  63. hostPorts = append(hostPorts, net.JoinHostPort(network.IP.String(), portStr))
  64. }
  65. }
  66. return hostPorts
  67. }
  68. func resolve(network, hostPort string) (net.IP, int, error) {
  69. switch network {
  70. case "tcp", "tcp4", "tcp6":
  71. if addr, err := net.ResolveTCPAddr(network, hostPort); err != nil {
  72. return net.IPv4zero, 0, err
  73. } else {
  74. return addr.IP, addr.Port, nil
  75. }
  76. case "udp", "udp4", "udp6":
  77. if addr, err := net.ResolveUDPAddr(network, hostPort); err != nil {
  78. return net.IPv4zero, 0, err
  79. } else {
  80. return addr.IP, addr.Port, nil
  81. }
  82. case "ip", "ip4", "ip6":
  83. if addr, err := net.ResolveIPAddr(network, hostPort); err != nil {
  84. return net.IPv4zero, 0, err
  85. } else {
  86. return addr.IP, 0, nil
  87. }
  88. }
  89. return net.IPv4zero, 0, net.UnknownNetworkError(network)
  90. }
  91. func maybeReplacePort(uri *url.URL, laddr net.Addr) *url.URL {
  92. if laddr == nil {
  93. return uri
  94. }
  95. host, portStr, err := net.SplitHostPort(uri.Host)
  96. if err != nil {
  97. return uri
  98. }
  99. port, err := strconv.Atoi(portStr)
  100. if err != nil {
  101. return uri
  102. }
  103. if port != 0 {
  104. return uri
  105. }
  106. _, lportStr, err := net.SplitHostPort(laddr.String())
  107. if err != nil {
  108. return uri
  109. }
  110. uriCopy := *uri
  111. uriCopy.Host = net.JoinHostPort(host, lportStr)
  112. return &uriCopy
  113. }