diff --git a/Cargo.lock b/Cargo.lock index 622f6ae0e..83cd5b921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,7 +1505,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdev" -version = "0.3.16" +version = "0.3.17" dependencies = [ "anyhow", "axum", @@ -1635,7 +1635,7 @@ dependencies = [ [[package]] name = "freenet" -version = "0.1.38" +version = "0.1.39" dependencies = [ "aes-gcm", "ahash", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index f387d8476..c8c2ecb1d 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "freenet" -version = "0.1.38" +version = "0.1.39" edition = "2021" rust-version = "1.80" publish = true diff --git a/crates/core/src/ring/connection_manager.rs b/crates/core/src/ring/connection_manager.rs index 2ffadb5e2..8ba4bfb31 100644 --- a/crates/core/src/ring/connection_manager.rs +++ b/crates/core/src/ring/connection_manager.rs @@ -148,13 +148,25 @@ impl ConnectionManager { /// Will panic if the node checking for this condition has no location assigned. pub fn should_accept(&self, location: Location, peer_id: &PeerId) -> bool { // Don't accept connections from ourselves + // Primary check: compare full PeerId (address-based equality) if let Some(own_id) = self.get_peer_key() { if &own_id == peer_id { - tracing::warn!(%peer_id, "should_accept: rejecting self-connection attempt"); + tracing::warn!(%peer_id, "should_accept: rejecting self-connection attempt (address match)"); return false; } } + // Secondary check: compare pub_key directly + // This catches self-connections even when peer_key is not yet set, + // which can happen early in initialization. Same pub_key means same node. + if *self.pub_key == peer_id.pub_key { + tracing::warn!( + %peer_id, + "should_accept: rejecting self-connection attempt (pub_key match)" + ); + return false; + } + tracing::info!("Checking if should accept connection"); let open = self.connection_count(); let reserved_before = self.pending_reservations.read().len(); @@ -725,4 +737,44 @@ mod tests { "should_accept must accept connection from different peer" ); } + + #[test] + fn rejects_self_connection_by_pubkey_when_peer_key_not_set() { + // Create a keypair for our node + let keypair = TransportKeypair::new(); + + // Create connection manager WITHOUT peer_id set (simulating early initialization) + let cm = ConnectionManager::init( + Rate::new_per_second(1_000_000.0), + Rate::new_per_second(1_000_000.0), + 1, + 10, + 7, + ( + keypair.public().clone(), + None, // peer_id is None - simulating early initialization + AtomicU64::new(u64::from_le_bytes(0.5f64.to_le_bytes())), + ), + false, + 10, + Duration::from_secs(60), + ); + + // Verify the connection manager does NOT have peer_key set + assert_eq!(cm.get_peer_key(), None); + + // Create a PeerId with our pub_key but a different address + // This simulates a scenario where we receive a connection request + // that somehow references our own pub_key + let self_like_addr: SocketAddr = "127.0.0.1:9999".parse().unwrap(); + let self_like_peer_id = PeerId::new(self_like_addr, keypair.public().clone()); + + // Attempt to accept - should be rejected because pub_key matches + let location = Location::new(0.5); + let accepted = cm.should_accept(location, &self_like_peer_id); + assert!( + !accepted, + "should_accept must reject self-connection by pub_key even when peer_key is not set" + ); + } } diff --git a/crates/fdev/Cargo.toml b/crates/fdev/Cargo.toml index c434dd744..449e3e301 100644 --- a/crates/fdev/Cargo.toml +++ b/crates/fdev/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fdev" -version = "0.3.16" +version = "0.3.17" edition = "2021" rust-version = "1.80" publish = true @@ -39,7 +39,7 @@ reqwest = { version = "0.12", features = ["json"] } http = "1.4" # internal -freenet = { path = "../core", version = "0.1.38" } +freenet = { path = "../core", version = "0.1.39" } freenet-stdlib = { workspace = true } [features]