util.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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. "errors"
  9. "net"
  10. "net/url"
  11. "strconv"
  12. "strings"
  13. "github.com/syncthing/syncthing/lib/nat"
  14. "github.com/syncthing/syncthing/lib/osutil"
  15. )
  16. func fixupPort(uri *url.URL, defaultPort int) *url.URL {
  17. copyURI := *uri
  18. host, port, err := net.SplitHostPort(uri.Host)
  19. e := &net.AddrError{}
  20. if errors.As(err, &e) && strings.Contains(e.Err, "missing port") {
  21. // addr is of the form "1.2.3.4" or "[fe80::1]"
  22. host = uri.Host
  23. if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
  24. // net.JoinHostPort will add the brackets again
  25. host = host[1 : len(host)-1]
  26. }
  27. copyURI.Host = net.JoinHostPort(host, strconv.Itoa(defaultPort))
  28. } else if err == nil && port == "" {
  29. // addr is on the form "1.2.3.4:" or "[fe80::1]:"
  30. copyURI.Host = net.JoinHostPort(host, strconv.Itoa(defaultPort))
  31. }
  32. return &copyURI
  33. }
  34. func getURLsForAllAdaptersIfUnspecified(network string, uri *url.URL) []*url.URL {
  35. ip, port, err := resolve(network, uri.Host)
  36. // Failed to resolve
  37. if err != nil || port == 0 {
  38. return nil
  39. }
  40. // Not an unspecified address, so no point of substituting with local
  41. // interface addresses as it's listening on a specific adapter anyway.
  42. if len(ip) != 0 && !ip.IsUnspecified() {
  43. return nil
  44. }
  45. hostPorts := getHostPortsForAllAdapters(port)
  46. addrs := make([]*url.URL, 0, len(hostPorts))
  47. for _, hostPort := range hostPorts {
  48. newUri := *uri
  49. newUri.Host = hostPort
  50. addrs = append(addrs, &newUri)
  51. }
  52. return addrs
  53. }
  54. func getHostPortsForAllAdapters(port int) []string {
  55. nets, err := osutil.GetInterfaceAddrs(true)
  56. if err != nil {
  57. // Ignore failure.
  58. return nil
  59. }
  60. hostPorts := make([]string, 0, len(nets))
  61. portStr := strconv.Itoa(port)
  62. for _, network := range nets {
  63. // Only accept IPv4 link-local unicast and the private ranges defined in RFC 1918 and RFC 4193
  64. // IPv6 link-local addresses require an interface identifier to work correctly
  65. if (network.IP.To4() != nil && network.IP.IsLinkLocalUnicast()) || network.IP.IsPrivate() {
  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 maybeReplacePort(uri *url.URL, laddr net.Addr) *url.URL {
  95. if laddr == nil {
  96. return uri
  97. }
  98. host, portStr, err := net.SplitHostPort(uri.Host)
  99. if err != nil {
  100. return uri
  101. }
  102. port, err := strconv.Atoi(portStr)
  103. if err != nil {
  104. return uri
  105. }
  106. if port != 0 {
  107. return uri
  108. }
  109. _, lportStr, err := net.SplitHostPort(laddr.String())
  110. if err != nil {
  111. return uri
  112. }
  113. uriCopy := *uri
  114. uriCopy.Host = net.JoinHostPort(host, lportStr)
  115. return &uriCopy
  116. }
  117. func portMappingURIs(mapping *nat.Mapping, listener_uri url.URL) []*url.URL {
  118. var uris []*url.URL
  119. if mapping != nil {
  120. addrs := mapping.ExternalAddresses()
  121. for _, addr := range addrs {
  122. uri := listener_uri
  123. // Does net.JoinHostPort internally
  124. uri.Host = addr.String()
  125. uris = append(uris, &uri)
  126. // For every address with a specified IP, add one without an IP,
  127. // just in case the specified IP is still internal (router behind DMZ).
  128. if len(addr.IP) != 0 && !addr.IP.IsUnspecified() {
  129. zeroUri := listener_uri
  130. addr.IP = nil
  131. zeroUri.Host = addr.String()
  132. uris = append(uris, &zeroUri)
  133. }
  134. }
  135. }
  136. return uris
  137. }