From 12c17e344db0db725f7cd38d2581428c0971e19d Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Tue, 1 Apr 2025 01:09:39 +0200 Subject: [PATCH] p2p/nat: addAnyPortMapping should have the same semantics over clients With UPnP IGD v2 it was random only if specified was unavailable. With UPnP IGD v1 it was disregarding the external port. Signed-off-by: Csaba Kiraly --- p2p/nat/natupnp.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/p2p/nat/natupnp.go b/p2p/nat/natupnp.go index af285de18b..59322bd813 100644 --- a/p2p/nat/natupnp.go +++ b/p2p/nat/natupnp.go @@ -111,13 +111,20 @@ func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, li return uint16(extport), err } +// addAnyPortMapping tries to add a port mapping with the specified external port. +// If the external port is already in use, it will try to assign another port. func (n *upnp) addAnyPortMapping(protocol string, extport, intport int, ip net.IP, desc string, lifetimeS uint32) (uint16, error) { if client, ok := n.client.(*internetgateway2.WANIPConnection2); ok { return client.AddAnyPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) } - // It will retry with a random port number if the client does - // not support AddAnyPortMapping. - var err error + // For IGDv1 and v1 services we should first try to add with extport. + err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) + if err == nil { + return uint16(extport), nil + } + + // If above fails, we retry with a random port. + // We retry several times because of possible port conflicts. for i := 0; i < 3; i++ { extport = n.randomPort() err := n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS)