iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 7c72b1f8f7679ef4aff2558d62a5696c41b961e1
parent 295859f9c8c8aa7e3603d8d34e2b7edddaa7b76f
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Tue, 28 Jul 2026 00:17:17 +0200

Ignore private peer discovery addresses

Diffstat:
MCargo.lock | 2+-
MCargo.toml | 2+-
Msrc/adapters/p2p.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -502,7 +502,7 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "iuna" -version = "0.1.5" +version = "0.1.6" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iuna" -version = "0.1.5" +version = "0.1.6" edition = "2024" license = "Apache-2.0" diff --git a/src/adapters/p2p.rs b/src/adapters/p2p.rs @@ -1,7 +1,7 @@ use std::{ collections::{BTreeMap, BTreeSet}, io::ErrorKind, - net::SocketAddr, + net::{IpAddr, SocketAddr}, sync::{ Arc, Mutex as StdMutex, atomic::{AtomicU64, Ordering}, @@ -1067,7 +1067,9 @@ async fn apply_peer_list( let mut peerbook = network.inner.peers.lock().await; for address in peers { let peer = normalize_advertised_peer(&address, remote_addr)?; - if !is_self_peer_address(&peer, network.inner.listen_addr) { + if is_self_peer_address(&peer, network.inner.listen_addr) { + P2pMetricsCounters::inc(&network.inner.metrics.self_peer_skips); + } else if peer_list_address_is_discoverable(&peer, remote_addr)? { peerbook.add_peer(peer); } else { P2pMetricsCounters::inc(&network.inner.metrics.self_peer_skips); @@ -1799,6 +1801,44 @@ fn normalize_advertised_peer(address: &str, remote_addr: SocketAddr) -> Result<S Ok(reachable_advertised_addr(advertised_addr, remote_addr).to_string()) } +fn peer_list_address_is_discoverable(address: &str, remote_addr: SocketAddr) -> Result<bool> { + let candidate = address + .parse::<SocketAddr>() + .with_context(|| format!("invalid peer-list address {address}"))?; + if candidate.ip().is_loopback() { + return Ok(remote_addr.ip().is_loopback()); + } + Ok(ip_is_publicly_discoverable(candidate.ip())) +} + +fn ip_is_publicly_discoverable(ip: IpAddr) -> bool { + match ip { + IpAddr::V4(ip) => { + let [a, b, c, d] = ip.octets(); + !(a == 0 + || a == 10 + || a == 127 + || (a == 100 && (64..=127).contains(&b)) + || (a == 169 && b == 254) + || (a == 172 && (16..=31).contains(&b)) + || (a == 192 && b == 168) + || (a == 192 && b == 0 && c == 2) + || (a == 198 && b == 51 && c == 100) + || (a == 203 && b == 0 && c == 113) + || a >= 224 + || [a, b, c, d] == [255, 255, 255, 255]) + } + IpAddr::V6(ip) => { + let segments = ip.segments(); + !(ip.is_unspecified() + || ip.is_loopback() + || (segments[0] & 0xfe00) == 0xfc00 + || (segments[0] & 0xffc0) == 0xfe80 + || (segments[0] & 0xff00) == 0xff00) + } + } +} + fn is_self_peer_address(address: &str, listen_addr: SocketAddr) -> bool { address .parse::<SocketAddr>() @@ -2672,6 +2712,39 @@ mod tests { } #[tokio::test] + async fn peer_list_ignores_private_ephemeral_addresses() { + let alice = Wallet::from_seed("px-private-ephemeral-alice"); + let allocations = allocations(std::slice::from_ref(&alice), 1_000); + let node = Arc::new(tokio::sync::Mutex::new(node("alice", alice, allocations))); + let peers = Arc::new(tokio::sync::Mutex::new(PeerBook::default())); + let network = super::GossipNetwork { + inner: Arc::new(super::GossipNetworkInner { + node, + peers: Arc::clone(&peers), + listen_addr: "0.0.0.0:9444".parse().unwrap(), + sessions: tokio::sync::Mutex::new(BTreeMap::new()), + tx_delivery: tokio::sync::Mutex::new(BTreeMap::new()), + metrics: super::P2pMetricsCounters::default(), + }), + }; + + super::apply_peer_list( + &network, + "142.132.164.59:9444".parse().unwrap(), + vec![ + "10.42.1.1:10091".to_string(), + "142.132.164.59:9444".to_string(), + ], + ) + .await + .unwrap(); + + let addresses = peers.lock().await.addresses(); + assert!(!addresses.contains(&"10.42.1.1:10091".to_string())); + assert!(addresses.contains(&"142.132.164.59:9444".to_string())); + } + + #[tokio::test] async fn peer_list_ignores_loopback_alias_for_unspecified_self() { let alice = Wallet::from_seed("px-self-alias-alice"); let allocations = allocations(std::slice::from_ref(&alice), 1_000);