瀏覽代碼

lib/nat, lib/connections: Fix a few issues with NAT traversal

1. For the same internal port we ask for the same external port on all devices. This can be a problem if one device speaks over two protocols.
2. Always add a nil address even if we managed to get external address of the gateway, just because the gateway might be in DMZ behind another gateway.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3196
Audrius Butkevicius 9 年之前
父節點
當前提交
87701339fe
共有 2 個文件被更改,包括 20 次插入4 次删除
  1. 9 0
      lib/connections/tcp_listen.go
  2. 11 4
      lib/nat/service.go

+ 9 - 0
lib/connections/tcp_listen.go

@@ -137,6 +137,15 @@ func (t *tcpListener) WANAddresses() []*url.URL {
 			// Does net.JoinHostPort internally
 			uri.Host = addr.String()
 			uris = append(uris, &uri)
+
+			// For every address with a specified IP, add one without an IP,
+			// just in case the specified IP is still internal (router behind DMZ).
+			if len(addr.IP) != 0 && !addr.IP.IsUnspecified() {
+				uri = *t.uri
+				addr.IP = nil
+				uri.Host = addr.String()
+				uris = append(uris, &uri)
+			}
 		}
 	}
 	t.mut.RUnlock()

+ 11 - 4
lib/nat/service.go

@@ -8,6 +8,7 @@ package nat
 
 import (
 	"fmt"
+	"hash/fnv"
 	"math/rand"
 	"net"
 	stdsync "sync"
@@ -284,10 +285,10 @@ func (s *Service) tryNATDevice(natd Device, intPort, extPort int, leaseTime time
 	var err error
 	var port int
 
-	// Generate a predictable random which is based on device ID + local port
-	// number so that the ports we'd try to acquire for the mapping would always
-	// be the same.
-	predictableRand := rand.New(rand.NewSource(int64(s.id.Short()) + int64(intPort)))
+	// Generate a predictable random which is based on device ID + local port + hash of the device ID
+	// number so that the ports we'd try to acquire for the mapping would always be the same for the
+	// same device trying to get the same internal port.
+	predictableRand := rand.New(rand.NewSource(int64(s.id.Short()) + int64(intPort) + hash(natd.ID())))
 
 	if extPort != 0 {
 		// First try renewing our existing mapping, if we have one.
@@ -325,3 +326,9 @@ findIP:
 		Port: extPort,
 	}, nil
 }
+
+func hash(input string) int64 {
+	h := fnv.New64a()
+	h.Write([]byte(input))
+	return int64(h.Sum64())
+}