From ccb80ac79b5ef74dd710f3b5f2e546555154cfa2 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Fri, 5 Jun 2026 17:41:24 +0400 Subject: [PATCH] Announce the mapped external UDP port instead of the discovery port --- storage/nat.nim | 8 +++++++- storage/storage.nim | 5 ++--- tests/storage/testnat.nim | 25 +++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/storage/nat.nim b/storage/nat.nim index 4a709ab6..e9769011 100644 --- a/storage/nat.nim +++ b/storage/nat.nim @@ -140,7 +140,10 @@ proc announcePeerInfoAddrs*(discovery: Discovery, peerInfo: PeerInfo, udpPort: P discovery.updateRecordsAndSpr(addrs, udpPort = udpPort) proc setupPeerInfoObserver*( - switch: Switch, autonat: AutonatV2Service, discovery: Discovery, udpPort: Port + switch: Switch, + autonat: AutonatV2Service, + discovery: Discovery, + natMapper: NatPortMapper, ): PeerInfoObserver = ## AutoNAT's address mapper resolves peerInfo.addrs into public addresses ## once the node is Reachable; peerInfo.update() then notifies observers. @@ -150,6 +153,9 @@ proc setupPeerInfoObserver*( addrs = peerInfo.addrs, reachability = autonat.networkReachability if autonat.networkReachability != NetworkReachability.Reachable: return + # When a NAT mapping is active, announce its external UDP port: the router + # may have assigned a different port than the requested discoveryPort. + let udpPort = natMapper.activeUdpPort.get(natMapper.discoveryPort) announcePeerInfoAddrs(discovery, peerInfo, udpPort) switch.peerInfo.addObserver(observer) diff --git a/storage/storage.nim b/storage/storage.nim index 79b098da..18a5270f 100644 --- a/storage/storage.nim +++ b/storage/storage.nim @@ -490,9 +490,8 @@ proc new*( if natRouter.isSome: natRouter.get.natMapper = natMapper - peerInfoObserver = some( - setupPeerInfoObserver(switch, autonatService.get, discovery, config.discoveryPort) - ) + peerInfoObserver = + some(setupPeerInfoObserver(switch, autonatService.get, discovery, natMapper.get)) autonatService.get.setStatusAndConfidenceHandler( proc( diff --git a/tests/storage/testnat.nim b/tests/storage/testnat.nim index a64fa0f3..8dd87b1e 100644 --- a/tests/storage/testnat.nim +++ b/tests/storage/testnat.nim @@ -135,7 +135,9 @@ asyncchecksuite "NAT - handleNatStatus": test "peerInfo observer announces addresses when Reachable": let autonat = AutonatV2Service.new(Rng.instance()) - discard setupPeerInfoObserver(sw, autonat, disc, discoveryPort) + discard setupPeerInfoObserver( + sw, autonat, disc, NatPortMapper(discoveryPort: discoveryPort) + ) autonat.networkReachability = Reachable sw.peerInfo.listenAddrs.add( @@ -145,9 +147,28 @@ asyncchecksuite "NAT - handleNatStatus": check disc.announceAddrs == sw.peerInfo.addrs + test "peerInfo observer announces the mapped external UDP port when a mapping is active": + let autonat = AutonatV2Service.new(Rng.instance()) + let mapper = + NatPortMapper(discoveryPort: discoveryPort, activeUdpPort: some(Port(40001))) + discard setupPeerInfoObserver(sw, autonat, disc, mapper) + autonat.networkReachability = Reachable + + sw.peerInfo.listenAddrs.add( + MultiAddress.init("/ip4/1.2.3.4/tcp/9999").expect("valid") + ) + await sw.peerInfo.update() + + let sprAddrs = disc.getSpr().data.addresses.mapIt(it.address) + check MultiAddress.init("/ip4/1.2.3.4/udp/40001").expect("valid") in sprAddrs + check MultiAddress.init("/ip4/1.2.3.4/udp/" & $discoveryPort).expect("valid") notin + sprAddrs + test "peerInfo observer does not announce when the node is not Reachable": let autonat = AutonatV2Service.new(Rng.instance()) - discard setupPeerInfoObserver(sw, autonat, disc, discoveryPort) + discard setupPeerInfoObserver( + sw, autonat, disc, NatPortMapper(discoveryPort: discoveryPort) + ) autonat.networkReachability = NotReachable sw.peerInfo.listenAddrs.add(