fix: self-healing NAT mappings with request deduplication#3367
Merged
fix: self-healing NAT mappings with request deduplication#3367
Conversation
3 tasks
3 tasks
Member
Author
|
@MarcoPolo @sukunrt I've resolved the conflicts (d4ac0de) caused by the grand log refactor that landed in master. Would it be possible to review this bugfix and ship in the next go-libp2p? 🙏 |
Collaborator
|
Yep! I'll take a look this week :)
|
MarcoPolo
reviewed
Sep 3, 2025
MarcoPolo
approved these changes
Sep 3, 2025
Collaborator
MarcoPolo
left a comment
There was a problem hiding this comment.
minor nits. Looks good. Thanks for this and for testing it!
5f61fa8 to
d59d597
Compare
Collaborator
|
I’ll deal with the conflicts and merge tomorrow |
Router restarts can cause UPnP/NAT-PMP services to change their listening ports, leading to connection refused errors. This fix implements automatic NAT rediscovery when consecutive connection failures are detected, restoring all existing port mappings on the new NAT instance. See #3224 (comment) for details on the router behavior that motivated this fix.
d59d597 to
c916a49
Compare
Multiple libp2p transports can share the same port (TCP, QUIC, WebTransport, WebRTC-direct), causing duplicate AddMapping calls for the same protocol/port combination. This fix adds deduplication in NAT.AddMapping to prevent redundant NAT device operations and reduce log spam.
c916a49 to
ff8b509
Compare
Contributor
|
Is self-healing NAT a planned feature for Rust? Happy to begin working on a port if there's interest. |
|
@jxs might be able to comment on how self-healing NAT fits into rust-libp2p plans. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR makes NAT port mappings self-healing after router restarts.
It also adds bunch of tests and eliminates duplicate mapping requests that occur on node start.
Changes
1. Automatic NAT recovery after router restart
Router restarts can cause UPnP (SOAP) services to change their listening ports, leading to "connection refused" errors that permanently break port mappings.
This is the problem described in #3224 (comment) (cc @sukunrt @MarcoPolo)
We had Kubo users impacted this since forever, impacting their ability to provide data:
This PR implements automatic NAT rediscovery that detects consecutive connection failures, triggers rediscovery after 3 failures, and restores all existing port mappings on the new NAT instance.
FWIW I've tested it extensively in my own LAN – see "Demo" at the end.
IIUC this
2. Port mapping deduplication
This is something I've discovered while testing (1), so also fixed it in this PR.
Multiple libp2p transports sharing the same port (TCP, QUIC, WebTransport, WebRTC-direct) were causing duplicate NAT mapping requests. The fix adds deduplication in
NAT.AddMapping()that checks if mapping already exists before making NAT API calls.In case of Kubo IPFS node:
Demo
The following log shows automatic NAT recovery in action. The router's UPnP service (miniupnpd) restarts and changes its SOAP/HTTP endpoint from port 45251 to a different port, causing "connection refused" errors. After 3 consecutive failures, go-libp2p automatically rediscovers the NAT and restores all mappings:
Key moments in the log:
Without this fix, the connection refused errors would continue indefinitely, requiring manual daemon restart.