From 3ae4ac725bb5d73ba3b4f01a8b5921bb25b61bc1 Mon Sep 17 00:00:00 2001 From: Arjen <18398758+Origami74@users.noreply.github.com> Date: Thu, 2 Jul 2026 14:25:13 +0200 Subject: [PATCH] fix(transport/udp): preserve sin6_scope_id on receive sockaddr_to_socket_addr dropped the IPv6 scope id when converting an inbound source address, so a reply to a link-local peer (fe80::/10) had no interface scope and could not be routed. This stalled the Noise handshake reply (msg2) over a Wi-Fi Aware NDP interface, where every address is link-local: msg1 reached the peer (sent to a scoped address) but msg2 never routed back. Rebuild the SocketAddrV6 with sin6_scope_id; non-link-local sources carry scope 0 and are unaffected. --- src/transport/udp/socket.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/transport/udp/socket.rs b/src/transport/udp/socket.rs index 6ba77f9..810d6ae 100644 --- a/src/transport/udp/socket.rs +++ b/src/transport/udp/socket.rs @@ -606,7 +606,17 @@ mod platform { unsafe { &*(storage as *const _ as *const libc::sockaddr_in6) }; let ip = std::net::Ipv6Addr::from(addr.sin6_addr.s6_addr); let port = u16::from_be(addr.sin6_port); - Ok(SocketAddr::from((ip, port))) + // Preserve sin6_scope_id: a link-local source (fe80::/10) is + // only routable together with its interface scope, so dropping + // it here breaks replies to a link-local peer (e.g. a Wi-Fi + // Aware NDP interface). Non-link-local sources carry scope 0, + // for which SocketAddrV6 is identical to the unscoped form. + Ok(SocketAddr::V6(std::net::SocketAddrV6::new( + ip, + port, + 0, + addr.sin6_scope_id, + ))) } family => Err(std::io::Error::new( std::io::ErrorKind::InvalidData,