add: ban ipv6 addresses by prefix

assumes all ipv6 addresses have 64-bit prefix (8 bytes at the start + 2 bytes for colons)
This commit is contained in:
trisua 2025-05-21 23:32:45 -04:00
parent 2b91422d18
commit d7e800fcb4
6 changed files with 128 additions and 4 deletions

View file

@ -0,0 +1,61 @@
use std::net::SocketAddr;
/// How many bytes should be chopped off the end of an IPV6 address to get its prefix.
pub(crate) const IPV6_PREFIX_BYTES: usize = 8;
/// 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)
Self(value.parse().unwrap(), AddrProto::IPV4)
}
}
}
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", "")
}
}

View file

@ -1,3 +1,4 @@
pub mod addr;
pub mod auth;
pub mod communities;
pub mod communities_permissions;