From ffb13d67917665d0073b464c31fd216e6f3ae631 Mon Sep 17 00:00:00 2001 From: Scott Reimers Date: Sun, 19 Apr 2026 17:37:33 -0400 Subject: [PATCH] Our Info: display peer-observed external address Store the external address reported by peers via your_observed_addr in initial exchange. Display it in Our Info panel with NAT classification. Replaces reliance on iroh's pkarr/STUN for external address discovery while keeping clear_address_lookup() (no dns.iroh.link publishing). Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/core/src/connection.rs | 21 ++++++++++++++++++++- crates/tauri-app/src/lib.rs | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/crates/core/src/connection.rs b/crates/core/src/connection.rs index d01ddf2..bfb0090 100644 --- a/crates/core/src/connection.rs +++ b/crates/core/src/connection.rs @@ -613,6 +613,8 @@ pub struct ConnectionManager { activity_log: Arc>, /// UPnP external address (prepended to self-reported addresses in anchor registration) upnp_external_addr: Option, + /// External address as observed by peers (from initial exchange your_observed_addr) + pub observed_external_addr: std::sync::Mutex>, /// Stable bind address (from --bind flag), used for anchor advertised address bind_addr: Option, /// Our detected NAT type (from STUN probing on startup) @@ -684,6 +686,7 @@ impl ConnectionManager { recovery_tx: None, activity_log, upnp_external_addr, + observed_external_addr: std::sync::Mutex::new(None), bind_addr, nat_type, nat_mapping, @@ -1597,9 +1600,12 @@ impl ConnectionManager { } } - // Log observed address (STUN-like feedback) + // Store observed address (STUN-like feedback from peer) if let Some(ref observed) = their_payload.your_observed_addr { info!(observed_addr = %observed, reporter = hex::encode(remote_node_id), "Peer reports our address as"); + if let Ok(addr) = observed.parse::() { + *self.observed_external_addr.lock().unwrap() = Some(addr); + } } // Store peer's NAT type @@ -6709,6 +6715,9 @@ pub enum ConnCommand { GetUpnpExternalAddr { reply: oneshot::Sender>, }, + GetObservedExternalAddr { + reply: oneshot::Sender>, + }, TouchSessionIfExists { peer: NodeId, }, @@ -7204,6 +7213,12 @@ impl ConnHandle { rx.await.ok().flatten() } + pub async fn observed_external_addr(&self) -> Option { + let (tx, rx) = oneshot::channel(); + let _ = self.tx.send(ConnCommand::GetObservedExternalAddr { reply: tx }).await; + rx.await.ok().flatten() + } + /// Touch session last_active (fire-and-forget, no-op if not a session peer). pub fn touch_session_if_exists(&self, peer: &NodeId) { let _ = self.tx.try_send(ConnCommand::TouchSessionIfExists { peer: *peer }); @@ -8119,6 +8134,10 @@ impl ConnectionActor { let cm = self.cm.lock().await; let _ = reply.send(cm.upnp_external_addr); } + ConnCommand::GetObservedExternalAddr { reply } => { + let cm = self.cm.lock().await; + let _ = reply.send(*cm.observed_external_addr.lock().unwrap()); + } ConnCommand::TouchSessionIfExists { peer } => { let mut cm = self.cm.lock().await; if let Some(session) = cm.sessions.get_mut(&peer) { diff --git a/crates/tauri-app/src/lib.rs b/crates/tauri-app/src/lib.rs index 5268ac8..7211c90 100644 --- a/crates/tauri-app/src/lib.rs +++ b/crates/tauri-app/src/lib.rs @@ -1870,7 +1870,7 @@ async fn get_our_info(state: State<'_, AppNode>) -> Result { } } - // Add iroh-discovered addresses not already listed (STUN-observed externals) + // Add iroh-discovered addresses not already listed for sock in net.endpoint_addr().ip_addrs() { if sock.ip().is_loopback() || sock.ip().is_unspecified() { continue; } let s = sock.to_string(); @@ -1885,6 +1885,19 @@ async fn get_our_info(state: State<'_, AppNode>) -> Result { }); } + // Add peer-observed external address (from anchor's your_observed_addr) + if let Some(observed) = net.conn_handle().observed_external_addr().await { + let s = observed.to_string(); + if !addresses.iter().any(|a| a.addr == s) { + let family = if observed.ip().is_ipv4() { "IPv4" } else { "IPv6" }; + addresses.insert(0, AddressInfoDto { + addr: s, + family: family.to_string(), + status: classify_addr(&observed, &nat_type, has_upnp, bind_addr.is_some(), true), + }); + } + } + Ok(OurInfoDto { node_id: hex::encode(net.node_id_bytes()), addresses,