61 lines
1.7 KiB
Rust
61 lines
1.7 KiB
Rust
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
|
|
/// Trait to convert an IP address to its canonical form
|
|
pub trait ToCanonical {
|
|
fn to_canonical(&self) -> Self;
|
|
}
|
|
|
|
impl ToCanonical for SocketAddr {
|
|
fn to_canonical(&self) -> Self {
|
|
match self {
|
|
SocketAddr::V4(_) => *self,
|
|
SocketAddr::V6(v6) => match v6.ip().to_ipv4() {
|
|
Some(mapped) => {
|
|
if mapped == Ipv4Addr::new(0, 0, 0, 1) {
|
|
*self
|
|
} else {
|
|
SocketAddr::new(IpAddr::V4(mapped), self.port())
|
|
}
|
|
}
|
|
None => *self,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use std::net::Ipv6Addr;
|
|
#[test]
|
|
fn ipv4_loopback_to_canonical() {
|
|
let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
|
|
assert_eq!(socket.to_canonical(), socket);
|
|
}
|
|
#[test]
|
|
fn ipv6_loopback_to_canonical() {
|
|
let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 8080);
|
|
assert_eq!(socket.to_canonical(), socket);
|
|
}
|
|
#[test]
|
|
fn ipv4_to_canonical() {
|
|
let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080);
|
|
assert_eq!(socket.to_canonical(), socket);
|
|
}
|
|
#[test]
|
|
fn ipv6_to_canonical() {
|
|
let socket = SocketAddr::new(
|
|
IpAddr::V6(Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0xdead, 0xbeef)),
|
|
8080,
|
|
);
|
|
assert_eq!(socket.to_canonical(), socket);
|
|
}
|
|
#[test]
|
|
fn ipv4_mapped_to_ipv6_to_canonical() {
|
|
let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff)), 8080);
|
|
assert_eq!(
|
|
socket.to_canonical(),
|
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 10, 2, 255)), 8080)
|
|
);
|
|
}
|
|
}
|