fix(identify): cross-protocol translation for shared-port transports#6277
Open
lthibault wants to merge 5 commits intolibp2p:masterfrom
Open
fix(identify): cross-protocol translation for shared-port transports#6277lthibault wants to merge 5 commits intolibp2p:masterfrom
lthibault wants to merge 5 commits intolibp2p:masterfrom
Conversation
Add PeerScoreParameters struct to expose granular breakdown of peer scores: - Individual contributions for P1-P7 score parameters - Slow peer penalty tracking - Final score field Add peer_score_params() public API method to retrieve detailed score breakdown. This enables external tooling and debugging to inspect individual components of the gossipsub peer scoring algorithm per the v1.1 spec.
…nsports When an outbound ephemeral TCP connection triggers identify, the observed address carries an ephemeral source port. The existing same-protocol translation guard correctly pairs TCP observations with TCP listen addresses and QUIC observations with QUIC listen addresses, but produces an empty result when the node has only a QUIC listener and receives a TCP observation (or vice versa). Previously the fallback unconditionally emitted the raw observed address — including its ephemeral port — as an external address candidate. AutoNAT then probes that ephemeral port, finds it closed, and incorrectly concludes the node is unreachable (NatStatus::Private). This is a real-world failure mode when TCP and QUIC share the same port (a common deployment pattern). In that case the observed IP is correct for both transports, so cross-protocol translation is valid: use the observed IP with the listen port, gated on the ports matching across the two addresses. Changes: - Add `port_of(addr)` helper to extract TCP/UDP port from a multiaddr. - When same-protocol translation yields nothing, attempt cross-protocol translation against listen addresses whose port matches the observed port. - Fall back to the raw observed address only when no listen addresses exist at all (pure dial-out nodes), preserving existing behaviour for that case.
…on fix - Bump version to 0.47.1 (0.47.0 is already released on crates.io) - Add changelog entry under 0.47.1 - Add unit tests for port_of() helper
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.
Description
When an outbound connection triggers identify, the behaviour attempts to translate
the observed address into a stable external address candidate by substituting the
observed IP into a matching listen address. The translation guard requires both
addresses to be the same transport type (TCP→TCP, QUICv1→QUICv1, etc.).
When no same-protocol listen address exists — e.g. a node whose only listener is
QUIC but whose outbound TCP connection causes an observe —
translated_addressesis empty and the fallback unconditionally emits the raw observed address as a
NewExternalAddrCandidate. The observed address carries the OS-assigned ephemeralsource port, not the node's listen port, so the emitted candidate is wrong.
AutoNAT then receives that ephemeral port as a dial-back target, finds it closed,
and can incorrectly conclude the node is unreachable (
NatStatus::Private).This scenario arises in any deployment where TCP and QUIC share a single listen
port (e.g. both on port 4001). In that case the observed IP is valid for all
transports on that port, and cross-protocol translation is correct.
Fix: when same-protocol translation yields nothing, attempt cross-protocol
translation against listen addresses whose port equals the observed port. Fall
back to the raw observed address only when no listen address exists at all
(pure dial-out nodes), which preserves existing behaviour for that case.
Notes & open questions
port_of(listen) == port_of(observed)) is what makescross-protocol translation safe. If TCP and QUIC use different ports, the gate
prevents a wrong candidate and the existing fallback applies unchanged.
list is empty, so the raw observed address is still emitted as before.
port_ofhelper extracts the firstTcporUdpport component from amultiaddr. It returns
Nonefor relay circuit addresses and other non-portaddress types, naturally excluding them from cross-protocol translation.
Change checklist