use std::net::{IpAddr, SocketAddr};
pub(crate) fn canonical(addr: SocketAddr) -> SocketAddr {
SocketAddr::new(addr.ip().to_canonical(), addr.port())
}
pub(crate) fn to_family(dst: SocketAddr, socket_is_v6: bool) -> SocketAddr {
match (socket_is_v6, dst.ip()) {
(true, IpAddr::V4(ip)) => SocketAddr::new(IpAddr::V6(ip.to_ipv6_mapped()), dst.port()),
_ => dst,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn canonical_unmaps_v4_mapped_peers() {
let mapped: SocketAddr = "[::ffff:1.2.3.4]:5000".parse().unwrap();
assert_eq!(canonical(mapped), "1.2.3.4:5000".parse().unwrap());
}
#[test]
fn canonical_passes_through_native_addresses() {
let v4: SocketAddr = "1.2.3.4:5000".parse().unwrap();
let v6: SocketAddr = "[2001:db8::1]:5000".parse().unwrap();
assert_eq!(canonical(v4), v4);
assert_eq!(canonical(v6), v6);
}
#[test]
fn to_family_remaps_v4_for_a_dual_stack_socket() {
let v4: SocketAddr = "1.2.3.4:5000".parse().unwrap();
assert_eq!(to_family(v4, true), "[::ffff:1.2.3.4]:5000".parse().unwrap());
}
#[test]
fn to_family_leaves_matching_families_alone() {
let v4: SocketAddr = "1.2.3.4:5000".parse().unwrap();
let v6: SocketAddr = "[2001:db8::1]:5000".parse().unwrap();
assert_eq!(to_family(v4, false), v4);
assert_eq!(to_family(v6, true), v6);
}
#[test]
fn canonical_and_to_family_round_trip() {
let mapped: SocketAddr = "[::ffff:1.2.3.4]:5000".parse().unwrap();
assert_eq!(to_family(canonical(mapped), true), mapped);
}
}