From 9a2dbb6b23005630fe2c282cb1375460b5165309 Mon Sep 17 00:00:00 2001 From: Shawn Hartsock Date: Mon, 13 Jul 2026 18:40:22 -0400 Subject: [PATCH] =?UTF-8?q?WIP(bus):=20candidate=20dial-back=20loopback=20?= =?UTF-8?q?augmentation=20for=20link-local=20IPv6=20(issue=20#61,=20UNVERI?= =?UTF-8?q?FIED=20=E2=80=94=20do=20not=20merge)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent-mesh-bus/src/bus.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/agent-mesh-bus/src/bus.rs b/agent-mesh-bus/src/bus.rs index 0f046bb..a9940d4 100644 --- a/agent-mesh-bus/src/bus.rs +++ b/agent-mesh-bus/src/bus.rs @@ -604,7 +604,22 @@ async fn dial_reply_peer( ) -> Result { if let Some((pubkey, addr)) = reverse { if Fingerprint::of_bytes(pubkey.as_bytes()) == peer_fp { - match endpoint.dial(pubkey, [addr]).await { + // CANDIDATE (unverified — see issue #61): augment the dial-back with + // loopback at the source port, mirroring `dial_peer`, so a same-host + // quiet-bind client is reachable when its source is a scopeless + // link-local IPv6. Passed the isolated `quiet_client` test but was + // racy in the full serial suite; the scope_id-preserving fix is + // likely more correct. Left for the transport owner. + let mut dial_addrs = vec![addr]; + for lo in [ + SocketAddr::new(std::net::Ipv4Addr::LOCALHOST.into(), addr.port()), + SocketAddr::new(std::net::Ipv6Addr::LOCALHOST.into(), addr.port()), + ] { + if !dial_addrs.contains(&lo) { + dial_addrs.push(lo); + } + } + match endpoint.dial(pubkey, dial_addrs).await { Ok(conn) => return Ok(conn), Err(e) => tracing::debug!( peer = %peer_fp.short(),