-
-
Notifications
You must be signed in to change notification settings - Fork 107
fix: handle NAT address in subscribe and seeding operations #2193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Adds NAT address handling to subscribe/seeding operations: - Subscribers with PeerAddr::Unknown have their address filled in by gateway - Gateway observes real UDP source address and updates subscriber address - SeedingManager tracks subscriber addresses properly - live_tx tests updated for new address model - In-memory testing infrastructure updated for PeerAddr Supersedes PRs #2172, #2174, #2175 (which had changes requested). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements NAT address handling for subscribe and seeding operations, allowing peers behind NAT to properly participate in the network by having gateways fill in their external addresses based on observed UDP source addresses.
Key Changes:
- Gateway-based address observation using new
ObservedAddrtype for NAT peers - Updated
SeedingManagerandRingto accept optional upstream addresses for subscriber registration - Improved connection maintenance with concurrent transaction tracking via
active_transaction_count()
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/freenet-macros/src/codegen.rs | Moved port release timing to just before binding to minimize race window |
| crates/core/src/transport/mod.rs | Added ObservedAddr newtype wrapper for transport-layer observed addresses |
| crates/core/src/test_utils.rs | Removed outdated race condition documentation comments |
| crates/core/src/ring/seeding.rs | Added upstream_addr parameter to add_subscriber for NAT address handling |
| crates/core/src/ring/mod.rs | Updated add_subscriber signature and improved connection maintenance with concurrent connection limits |
| crates/core/src/ring/live_tx.rs | Replaced still_alive with active_transaction_count method with comprehensive tests |
| crates/core/src/operations/update.rs | Updated add_subscriber call to pass None for upstream address |
| crates/core/src/operations/subscribe.rs | Implemented NAT address filling from source_addr before subscriber registration |
| crates/core/src/operations/get.rs | Converted expect() panics to graceful error handling with proper logging |
| crates/core/src/operations/connect.rs | Improved variable naming and added error handling for missing upstream addresses |
| crates/core/src/node/testing_impl/in_memory.rs | Updated test infrastructure for new add_subscriber signature |
| crates/core/src/node/network_bridge/p2p_protoc.rs | Removed OutboundMessageWithTarget variant, simplified to use message-based routing |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let Some(upstream) = source_addr else { | ||
| tracing::warn!( | ||
| tx = %self.id, | ||
| "ConnectResponse has no upstream - was this locally initiated?" | ||
| ); | ||
| // No upstream to route through - this shouldn't happen for relayed connections | ||
| return Ok(store_operation_state(&mut self)); | ||
| }; |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The source_addr is already validated at lines 817-821 and stored in upstream_addr. The check at line 889 will always succeed because we've already ensured source_addr is Some. This redundant check should be removed, and upstream_addr should be used directly instead of re-checking source_addr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - same issue as the other comment. Since source_addr is validated at line 817, this check is redundant.
Will use upstream_addr directly in both places.
[AI-assisted - Claude]
| let Some(upstream) = source_addr else { | ||
| tracing::warn!( | ||
| tx = %self.id, | ||
| "ObservedAddress message has no upstream - was this locally initiated?" | ||
| ); | ||
| // No upstream to route through - this shouldn't happen for relayed connections | ||
| return Ok(OperationResult { | ||
| return_msg: None, | ||
| target_addr: None, | ||
| state: Some(OpEnum::Connect(Box::new(self))), | ||
| }); | ||
| }; |
Copilot
AI
Dec 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The source_addr is already validated at lines 817-821 and stored in upstream_addr. The check at line 833 will always succeed because we've already ensured source_addr is Some. This redundant check should be removed, and upstream_addr should be used directly instead of re-checking source_addr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid point. source_addr is validated at line 817 with ok_or_else()?, so by the time we reach this code, it's guaranteed to be Some. The subsequent check is indeed redundant.
Will simplify to use upstream_addr directly here.
[AI-assisted - Claude]
|
@claude Please do a detailed review, both high level and detail |
|
Claude finished @sanity's task —— View job Detailed Code Review of PR #2193I've completed a comprehensive review of the NAT address handling implementation. Here are my findings organized by category: High-Level Architecture Review✅ Strengths
|
Address Copilot review feedback: after validating source_addr at the start of the ConnectMsg::Request match arm, subsequent checks are redundant. Use upstream_addr directly instead of re-checking source_addr. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Response to Claude bot reviewThanks for the detailed review! Here's my analysis: Already addressed
Clarification on "passing None to add_subscriber"The review flagged multiple places passing // Lines 414-426: Address is filled BEFORE add_subscriber call
let mut subscriber = subscriber.clone();
if subscriber.peer_addr.is_unknown() {
if let Some(addr) = source_addr {
subscriber.set_addr(addr); // Address filled here
}
}
// ...
// Line 464: subscriber now has correct address, no override needed
op_manager.ring.add_subscriber(key, subscriber.clone(), None)The Suggestions deferred to follow-up issues
[AI-assisted - Claude] |
Answers to Review Questions1. Is there a reason
|
iduartgomez
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR looks good for the most part. I think we can add more type safety around what addresses we are using, but this is a good start, we can merge and improve later.
crates/core/src/ring/mod.rs
Outdated
| } | ||
|
|
||
| // Acquire new connections up to MAX_CONCURRENT_CONNECTIONS limit | ||
| let active_count = live_tx_tracker.active_transaction_count(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in here we are counting all transactions, shouldn't we just count live connection transactions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! Fixed in 46e30d6.
Added active_connect_transaction_count() to LiveTransactionTracker that filters to only TransactionType::Connect transactions. The MAX_CONCURRENT_CONNECTIONS limit now correctly limits only connection acquisition attempts, not all operations (Get/Put/Subscribe/Update).
[AI-assisted - Claude]
…imit Address review feedback: active_transaction_count() was counting all transaction types (Get/Put/Subscribe/Update/Connect), but MAX_CONCURRENT_CONNECTIONS should only limit concurrent connection acquisition attempts. Added filtered method active_connect_transaction_count() that only counts Connect transactions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Problem
Peers behind NAT don't know their own external address. When they subscribe to contracts or act as seeders, the protocol needs to properly handle this "unknown address" case.
This is a follow-up to PR #2191 (now merged) which added the
PeerAddrenum and wire protocol cleanup.This Solution
Adds NAT address handling to subscribe/seeding operations:
PeerAddr::Unknownhave their address filled in by gatewaySeedingManagertracks subscriber addresses properlylive_txtests updated for new address modelTesting
Related
[AI-assisted - Claude]