Fixes #7403. Tested by enabling UPnP on the router, and checking on the router page that the external ports of the UDP mappings match what is shown in the logs and the internal ports matching the QUIC listening port.
This commit is contained in:
@@ -49,9 +49,11 @@ type quicListener struct {
|
||||
registry *registry.Registry
|
||||
lanChecker *lanChecker
|
||||
|
||||
address *url.URL
|
||||
laddr net.Addr
|
||||
mut sync.Mutex
|
||||
address *url.URL
|
||||
natService *nat.Service
|
||||
mapping *nat.Mapping
|
||||
laddr net.Addr
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func (t *quicListener) OnNATTypeChanged(natType stun.NATType) {
|
||||
@@ -126,7 +128,24 @@ func (t *quicListener) serve(ctx context.Context) error {
|
||||
l.Infof("QUIC listener (%v) starting", udpConn.LocalAddr())
|
||||
defer l.Infof("QUIC listener (%v) shutting down", udpConn.LocalAddr())
|
||||
|
||||
var ipVersion nat.IPVersion
|
||||
switch t.uri.Scheme {
|
||||
case "quic4":
|
||||
ipVersion = nat.IPv4Only
|
||||
case "quic6":
|
||||
ipVersion = nat.IPv6Only
|
||||
default:
|
||||
ipVersion = nat.IPvAny
|
||||
}
|
||||
mapping := t.natService.NewMapping(nat.UDP, ipVersion, udpAddr.IP, udpAddr.Port)
|
||||
mapping.OnChanged(func() {
|
||||
t.notifyAddressesChanged(t)
|
||||
})
|
||||
// Should be called after t.mapping is nil'ed out.
|
||||
defer t.natService.RemoveMapping(mapping)
|
||||
|
||||
t.mut.Lock()
|
||||
t.mapping = mapping
|
||||
t.laddr = udpConn.LocalAddr()
|
||||
t.mut.Unlock()
|
||||
defer func() {
|
||||
@@ -196,6 +215,9 @@ func (t *quicListener) WANAddresses() []*url.URL {
|
||||
if t.address != nil {
|
||||
uris = append(uris, t.address)
|
||||
}
|
||||
|
||||
uris = append(uris, portMappingURIs(t.mapping, *t.uri)...)
|
||||
|
||||
t.mut.Unlock()
|
||||
return uris
|
||||
}
|
||||
@@ -232,12 +254,13 @@ func (*quicListenerFactory) Valid(config.Configuration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, _ *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
|
||||
func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service, registry *registry.Registry, lanChecker *lanChecker) genericListener {
|
||||
l := &quicListener{
|
||||
uri: fixupPort(uri, config.DefaultQUICPort),
|
||||
cfg: cfg,
|
||||
tlsCfg: tlsCfg,
|
||||
conns: conns,
|
||||
natService: natService,
|
||||
factory: f,
|
||||
registry: registry,
|
||||
lanChecker: lanChecker,
|
||||
|
||||
@@ -175,24 +175,9 @@ func (t *tcpListener) WANAddresses() []*url.URL {
|
||||
uris := []*url.URL{
|
||||
maybeReplacePort(t.uri, t.laddr),
|
||||
}
|
||||
if t.mapping != nil {
|
||||
addrs := t.mapping.ExternalAddresses()
|
||||
for _, addr := range addrs {
|
||||
uri := *t.uri
|
||||
// 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() {
|
||||
zeroUri := *t.uri
|
||||
addr.IP = nil
|
||||
zeroUri.Host = addr.String()
|
||||
uris = append(uris, &zeroUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
uris = append(uris, portMappingURIs(t.mapping, *t.uri)...)
|
||||
|
||||
t.mut.RUnlock()
|
||||
|
||||
// If we support ReusePort, add an unspecified zero port address, which will be resolved by the discovery server
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/nat"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
)
|
||||
|
||||
@@ -130,3 +131,27 @@ func maybeReplacePort(uri *url.URL, laddr net.Addr) *url.URL {
|
||||
uriCopy.Host = net.JoinHostPort(host, lportStr)
|
||||
return &uriCopy
|
||||
}
|
||||
|
||||
func portMappingURIs(mapping *nat.Mapping, listener_uri url.URL) []*url.URL {
|
||||
var uris []*url.URL
|
||||
if mapping != nil {
|
||||
addrs := mapping.ExternalAddresses()
|
||||
for _, addr := range addrs {
|
||||
uri := listener_uri
|
||||
// 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() {
|
||||
zeroUri := listener_uri
|
||||
addr.IP = nil
|
||||
zeroUri.Host = addr.String()
|
||||
uris = append(uris, &zeroUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uris
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user