While writing some networking code and making it IPv6 ready I encountered some odd behavior in the standard library.
If I bind my server so 0.0.0.0 or [::1] and telnet/curl from localhost, I can easily tell whether the connection came from a local user or not by using the is_loopback
call on IpAddr
, Ipv4Addr
or Ipv6Addr
.
Once I bind my server to [::] to work on IPv4 AND IPv6 at the same time and then query it via v4 to 127.0.0.1 the is_loopback
call returns false.
I then have to manually try conversion of the Ipv6Addr
into an Ipv4Addr
and perform a second check with is_loopback
.
In my opinion, this behavior should either be clearly documented in the standard library or better yet should happen automatically (at least in IpAddr
) since an ipv6 encapsulated ipv4 loopback address is still a perfectly valid loopback address.
The current documentation in Ipv6Addr
states that it is a check for [::1] but a clear statement that IPv4 in IPv6 loopback addresses are not covered might help. I also guess that having the current minimal checks in both variants (v4 and v6) makes sense but the general is_loopback
in IpAddr
itself could provide the convenient conversion as it covers v4 and v6 anyways.
use std::net::{Ipv4Addr, Ipv6Addr};
fn main() {
let ipv4 = Ipv4Addr::new(127, 0, 0, 1);
let ipv6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1);
let v4_in_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1);
println!("{} is loopback? {} ", ipv4, ipv4.is_loopback());
println!("{} is loopback? {} ", ipv6, ipv6.is_loopback());
println!("{} is loopback? {} ", v4_in_v6, v4_in_v6.is_loopback());
println!("{} is loopback? {} ", v4_in_v6, v4_in_v6.to_ipv4().unwrap().is_loopback());
}
Output:
127.0.0.1 is loopback? true
::1 is loopback? true
::ffff:127.0.0.1 is loopback? false
::ffff:127.0.0.1 is loopback? true
Is this forum the right place for this discussion or should I have used the internals forum or just open an issue in github?