2025-05-21 23:32:45 -04:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
|
2025-05-21 23:52:29 -04:00
|
|
|
/// How many bytes should be taken as the prefix (from the begining of the address).
|
2025-06-22 03:02:44 -04:00
|
|
|
pub(crate) const IPV6_PREFIX_BYTES: usize = 16;
|
2025-05-21 23:32:45 -04:00
|
|
|
|
|
|
|
/// The protocol of a [`RemoteAddr`].
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum AddrProto {
|
|
|
|
IPV4,
|
|
|
|
IPV6,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A representation of a remote IP address.
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RemoteAddr(pub SocketAddr, pub AddrProto);
|
|
|
|
|
|
|
|
impl From<&str> for RemoteAddr {
|
|
|
|
fn from(value: &str) -> Self {
|
|
|
|
if value.len() >= 16 {
|
|
|
|
// ipv6 (16 bytes; 128 bits)
|
|
|
|
if !(value.starts_with("[") | value.contains("]:1000")) {
|
|
|
|
Self(format!("[{value}]:1000").parse().unwrap(), AddrProto::IPV6)
|
|
|
|
} else {
|
|
|
|
Self(value.parse().unwrap(), AddrProto::IPV6)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// ipv4 (4 bytes; 32 bits)
|
2025-05-22 00:29:00 -04:00
|
|
|
if !value.contains(":1000") {
|
|
|
|
Self(
|
|
|
|
format!("{value}:1000")
|
|
|
|
.parse()
|
|
|
|
.unwrap_or("0.0.0.0:1000".parse().unwrap()),
|
|
|
|
AddrProto::IPV4,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Self(
|
|
|
|
value.parse().unwrap_or("0.0.0.0:1000".parse().unwrap()),
|
|
|
|
AddrProto::IPV4,
|
|
|
|
)
|
|
|
|
}
|
2025-05-21 23:32:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RemoteAddr {
|
|
|
|
/// Get the address' prefix (returns the entire address for IPV4 addresses).
|
|
|
|
///
|
|
|
|
/// Operates on the IP address **without** colon characters.
|
|
|
|
pub fn prefix(&self, chop: Option<usize>) -> String {
|
|
|
|
if self.1 == AddrProto::IPV4 {
|
|
|
|
return self.0.to_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're adding 2 bytes to the chop bytes because we also
|
|
|
|
// need to remove 2 colons
|
|
|
|
let as_string = self.ipv6_inner();
|
|
|
|
(&as_string[0..(match chop {
|
|
|
|
Some(c) => c,
|
|
|
|
None => IPV6_PREFIX_BYTES,
|
|
|
|
} + (IPV6_PREFIX_BYTES / 4))])
|
|
|
|
.to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// [`Self::prefix`], but it returns another [`RemoteAddr`].
|
|
|
|
pub fn to_prefix(self, chop: Option<usize>) -> Self {
|
|
|
|
Self::from(self.prefix(chop).as_str())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the innter content from the address (as ipv6).
|
|
|
|
pub fn ipv6_inner(&self) -> String {
|
|
|
|
self.0.to_string().replace("[", "").replace("]:1000", "")
|
|
|
|
}
|
|
|
|
}
|