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.
This commit is contained in:
Red Bear OS
2026-07-26 16:56:28 +09:00
parent b887d2b450
commit 20d805ed37
+24 -11
View File
@@ -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::<u16>()
.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::<u16>().unwrap_or(0);
IpListenEndpoint { addr: host, port }
}