Location (URL)
https://doc.rust-lang.org/std/net/enum.IpAddr.html
https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
Summary
There has been past discussion about whether Rust should support IPv4-mapped IPv6 addresses, and I don't want to raise that issue again. But the current behaviour has some footguns that I think should be documented better.
For example, I think it's reasonable to write a function such as:
/// Ensure that we don't make TCP connections to loopback addresses.
fn connect_if_not_loopback(s: SocketAddr) -> std::io::Result<Option<TcpStream>> {
if s.ip().is_loopback() {
return Ok(None);
}
Ok(Some(TcpStream::connect(s)?))
}
and it would be reasonable to expect that it would prevent connections to loopback addresses. And there isn't anything in IpAddr that would suggest otherwise.
But since Ipv6Addr::is_loopback() does not handle IPv4-mapped IPv6 addresses, this code is broken, and may lead to security issues in code where the author wasn't knowledgeable of IPv4-mapped IPv6 addresses.
For example:
let localhost = IpAddr::V6(Ipv4Addr::LOCALHOST.to_ipv6_mapped());
// We expect this to return `None`, but it connects to the loopback address and returns `Some`.
// This assertion panics.
assert!(connect_if_not_loopback(SocketAddr::new(localhost, 9000)).unwrap().is_none());
The correct code (AFAIK) should use s.ip().to_canonical().is_loopback(), but this isn't clear from the documentation. And this isn't an issue for just is_loopback(), but also other methods like is_unspecified() and the various nightly methods.
There is some top-level documentation in Ipv6Addr, but it doesn't mention to_canonical() at all and is easy to miss.
So I think it would be helpful (and remove a footgun) for IpAddr and Ipv6Addr if the helper is_foo() methods had a sentence explaining that they don't handle IPv4-mapped IPv6 addresses, and linked to a paragraph for how to handle them properly.
Location (URL)
https://doc.rust-lang.org/std/net/enum.IpAddr.html
https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
Summary
There has been past discussion about whether Rust should support IPv4-mapped IPv6 addresses, and I don't want to raise that issue again. But the current behaviour has some footguns that I think should be documented better.
For example, I think it's reasonable to write a function such as:
and it would be reasonable to expect that it would prevent connections to loopback addresses. And there isn't anything in
IpAddrthat would suggest otherwise.But since
Ipv6Addr::is_loopback()does not handle IPv4-mapped IPv6 addresses, this code is broken, and may lead to security issues in code where the author wasn't knowledgeable of IPv4-mapped IPv6 addresses.For example:
The correct code (AFAIK) should use
s.ip().to_canonical().is_loopback(), but this isn't clear from the documentation. And this isn't an issue for justis_loopback(), but also other methods likeis_unspecified()and the various nightly methods.There is some top-level documentation in
Ipv6Addr, but it doesn't mentionto_canonical()at all and is easy to miss.So I think it would be helpful (and remove a footgun) for
IpAddrandIpv6Addrif the helperis_foo()methods had a sentence explaining that they don't handle IPv4-mapped IPv6 addresses, and linked to a paragraph for how to handle them properly.