fix(utils): handle IPv6 zones and hex ranges (#3019)

* fix(utils): handle low-risk TODO range parsing

* fix(utils): address scoped IPv6 and range review
This commit is contained in:
安正超
2026-05-20 11:56:14 +08:00
committed by GitHub
parent e929814edc
commit cde53ca6ad
2 changed files with 91 additions and 10 deletions
+37 -2
View File
@@ -110,9 +110,35 @@ pub fn reset_dns_resolver() {
/// helper for validating if the provided arg is an ip address.
pub fn is_socket_addr(addr: &str) -> bool {
// TODO IPv6 zone information?
addr.parse::<SocketAddr>().is_ok() || addr.parse::<IpAddr>().is_ok() || is_ipv6_addr_with_zone(addr)
}
addr.parse::<SocketAddr>().is_ok() || addr.parse::<IpAddr>().is_ok()
fn is_ipv6_addr_with_zone(addr: &str) -> bool {
let Some(zone_start) = addr.find('%') else {
return false;
};
if addr.starts_with('[') {
let Some(end_bracket) = addr[zone_start..].find(']').map(|pos| zone_start + pos) else {
return false;
};
let zone = &addr[zone_start + 1..end_bracket];
return zone_start > 1
&& is_valid_ipv6_zone(zone)
&& addr[end_bracket..].starts_with("]:")
&& addr[1..zone_start].parse::<Ipv6Addr>().is_ok()
&& addr[end_bracket + 2..].parse::<u16>().is_ok();
}
let zone = &addr[zone_start + 1..];
zone_start > 0 && is_valid_ipv6_zone(zone) && addr[..zone_start].parse::<Ipv6Addr>().is_ok()
}
fn is_valid_ipv6_zone(zone: &str) -> bool {
!zone.is_empty()
&& zone
.bytes()
.all(|ch| matches!(ch, b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~'))
}
/// checks if server_addr is valid and local host.
@@ -708,4 +734,13 @@ mod test {
};
assert_eq!(host_zero_port.to_string(), "example.com:0");
}
#[test]
fn test_is_socket_addr_accepts_ipv6_zone_identifier() {
assert!(is_socket_addr("fe80::1%en0"));
assert!(is_socket_addr("[fe80::1%en0]:9000"));
assert!(!is_socket_addr("fe80::1%en0:9000"));
assert!(!is_socket_addr("fe80::1%en0 "));
assert!(!is_socket_addr("fe80::1%\t"));
}
}