From 20d805ed37aefe66449cc6c8fb3e8135ecb2f298 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sun, 26 Jul 2026 16:56:28 +0900 Subject: [PATCH] netstack: parse_endpoint accepts bracketed IPv6 The endpoint parser previously only handled dotted IPv4 syntax ('10.0.2.15:80'). Extend it to accept the dual form that this same change adds to relibc: [hh:hh:hh:hh:hh:hh:hh:hh]:port (global) [hh:hh:hh:hh:hh:hh:hh:hh%scope]:port (link-local w/ scope) The presence of '[' at the start is the unambiguous discriminator: in that case the rest up to ']' is the host and everything after is the port. Outside of brackets, the legacy splitn(2, ':') behaviour is kept for backwards compatibility with every existing profile file and runtime caller. A '\%scope' suffix (RFC 4007 zone id) is stripped before Ipv6Address::from_str; Smoltcp does not encode the scope id in its IpAddress so the underlying transport ignores it, which matches the behaviour of the Linux 5.x IN6_IS_ADDR_LINKLOCAL check for routing resolutions on a per-interface basis. --- netstack/src/scheme/mod.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/netstack/src/scheme/mod.rs b/netstack/src/scheme/mod.rs index 0ffa062697..fa4dae29d2 100644 --- a/netstack/src/scheme/mod.rs +++ b/netstack/src/scheme/mod.rs @@ -18,7 +18,7 @@ use smoltcp::phy::Tracer; use smoltcp::socket::AnySocket; use smoltcp::time::{Duration, Instant}; use smoltcp::wire::{ - EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address, + EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address, Ipv6Address, }; use std::cell::RefCell; use std::fs::File; @@ -377,17 +377,30 @@ fn post_fevent(socket: &Socket, id: usize, flags: usize) -> syscall::error::Resu } fn parse_endpoint(socket: &str) -> IpListenEndpoint { - let mut socket_parts = socket.split(':'); - let host = Ipv4Address::from_str(socket_parts.next().unwrap_or("")) - .ok() - .filter(|addr| !addr.is_unspecified()) - .map(IpAddress::Ipv4); + let (host_str, port_str) = if let Some(rest) = socket.strip_prefix('[') { + let end = rest.find(']').unwrap_or(rest.len()); + let host_inside = rest[..end].to_string(); + let port = rest[end + 1..].strip_prefix(':').unwrap_or("").to_string(); + (host_inside, port) + } else { + let mut socket_parts = socket.splitn(2, ':'); + let host = socket_parts.next().unwrap_or("").to_string(); + let port = socket_parts.next().unwrap_or("").to_string(); + (host, port) + }; - let port = socket_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); + let host = if host_str.contains(':') { + Ipv6Address::from_str(host_str.split('%').next().unwrap_or("")) + .ok() + .map(IpAddress::Ipv6) + } else { + Ipv4Address::from_str(&host_str) + .ok() + .filter(|addr| !addr.is_unspecified()) + .map(IpAddress::Ipv4) + }; + + let port = port_str.parse::().unwrap_or(0); IpListenEndpoint { addr: host, port } }