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:
+24
-11
@@ -18,7 +18,7 @@ use smoltcp::phy::Tracer;
|
|||||||
use smoltcp::socket::AnySocket;
|
use smoltcp::socket::AnySocket;
|
||||||
use smoltcp::time::{Duration, Instant};
|
use smoltcp::time::{Duration, Instant};
|
||||||
use smoltcp::wire::{
|
use smoltcp::wire::{
|
||||||
EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address,
|
EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address, Ipv6Address,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fs::File;
|
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 {
|
fn parse_endpoint(socket: &str) -> IpListenEndpoint {
|
||||||
let mut socket_parts = socket.split(':');
|
let (host_str, port_str) = if let Some(rest) = socket.strip_prefix('[') {
|
||||||
let host = Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
|
let end = rest.find(']').unwrap_or(rest.len());
|
||||||
.ok()
|
let host_inside = rest[..end].to_string();
|
||||||
.filter(|addr| !addr.is_unspecified())
|
let port = rest[end + 1..].strip_prefix(':').unwrap_or("").to_string();
|
||||||
.map(IpAddress::Ipv4);
|
(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
|
let host = if host_str.contains(':') {
|
||||||
.next()
|
Ipv6Address::from_str(host_str.split('%').next().unwrap_or(""))
|
||||||
.unwrap_or("")
|
.ok()
|
||||||
.parse::<u16>()
|
.map(IpAddress::Ipv6)
|
||||||
.unwrap_or(0);
|
} 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 }
|
IpListenEndpoint { addr: host, port }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user