mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-12 09:33:23 +00:00
nostr: ignore stale traversal for active peers
Skip BootstrapEvent::Established and BootstrapEvent::Failed dispatch in poll_nostr_discovery for peers that are already connected or actively handshaking. Without these guards, stale traversal events arriving after a peer connected through a different path would either attempt to adopt a redundant socket against the live connection (Established) or poison the per-peer failure-state cooldown and trigger redundant retraversal via schedule_retry / try_peer_addresses (Failed). The four guard sites use a new is_connecting_to_peer helper extracted from the existing closure inside initiate_peer_connection; the helper checks for an in-flight outbound handshake state. adopt_established_traversal gains a defense-in-depth check returning PeerAlreadyExists when called against an already-promoted peer, so the invariant holds if a future caller bypasses the outer dispatch guard. Side benefit: narrows a cooldown-poisoning vector previously available to an attacker injecting stale failure events for an active peer. Test coverage for the new behavior: - test_try_peer_addresses_skips_connected_peer - test_try_peer_addresses_skips_connecting_peer - test_nostr_traversal_failure_skips_connected_peer (Failed-arm event injection) - test_nostr_traversal_established_skips_connected_peer (Established-arm event injection, mirror of the Failed test) - test_adopted_traversal_skips_already_connected_peer (adopt_established_traversal defense-in-depth) CHANGELOG entry under [Unreleased] / Fixed. Closes #87
This commit is contained in:
committed by
Johnathan Corgan
parent
ab1e248ff4
commit
87d1af0269
@@ -117,6 +117,51 @@ async fn test_failed_adopted_traversal_cleans_up_transport() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_adopted_traversal_skips_already_connected_peer() {
|
||||
let mut node = make_node();
|
||||
let (packet_tx, packet_rx) = packet_channel(64);
|
||||
node.packet_tx = Some(packet_tx);
|
||||
node.packet_rx = Some(packet_rx);
|
||||
node.state = NodeState::Running;
|
||||
|
||||
let transport_id = TransportId::new(1);
|
||||
let link_id = LinkId::new(1);
|
||||
let (conn, peer_identity) = make_completed_connection(&mut node, link_id, transport_id, 1_000);
|
||||
let peer_node_addr = *peer_identity.node_addr();
|
||||
node.add_connection(conn).unwrap();
|
||||
node.promote_connection(link_id, peer_identity, 2_000)
|
||||
.unwrap();
|
||||
|
||||
let link_count = node.link_count();
|
||||
let transport_count = node.transport_count();
|
||||
|
||||
let adopted_socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||
let handoff = EstablishedTraversal::new(
|
||||
"sess-stale",
|
||||
peer_identity.npub(),
|
||||
"127.0.0.1:9".parse().unwrap(),
|
||||
adopted_socket,
|
||||
)
|
||||
.with_transport_name("nostr-stale");
|
||||
|
||||
let result = node.adopt_established_traversal(handoff).await;
|
||||
assert!(
|
||||
matches!(result, Err(NodeError::PeerAlreadyExists(addr)) if addr == peer_node_addr),
|
||||
"stale traversal handoff should be ignored once the peer is already active"
|
||||
);
|
||||
assert_eq!(
|
||||
node.link_count(),
|
||||
link_count,
|
||||
"ignored traversal must not create a duplicate link"
|
||||
);
|
||||
assert_eq!(
|
||||
node.transport_count(),
|
||||
transport_count,
|
||||
"ignored traversal must not leak an adopted transport"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_third_peer_can_handshake_via_adopted_transport_socket() {
|
||||
let mut node_a = make_node(); // Existing traversal peer (Alice)
|
||||
|
||||
Reference in New Issue
Block a user