#![allow(clippy::from_over_into)] use crate::common::expr::Expr; use memchr::memchr; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; use std::fmt::Debug; use std::net::IpAddr; use std::net::Ipv4Addr; use std::net::Ipv6Addr; use std::str::FromStr; pub const BITMASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; pub const BITCOUNT: u8 = 128; pub type Addr = IpAddr; #[derive(Debug)] pub enum Error { InvalidAddr(String), InvalidBlock(String), InvalidMaskLength(String), InvalidNibblesCount(usize), MaskLengthTooLarge(u8), } #[derive(Copy, Clone, Eq)] pub struct Block { pub addr: u128, pub mlen: u8, } pub type Meta = HashMap; impl Block { fn new(addr: IpAddr, mlen: u8) -> Self { let (ipv6_addr, ipv6_mlen) = match addr { IpAddr::V4(addr) => { assert!(mlen <= 32); (addr.to_ipv6_mapped(), mlen + 96) } IpAddr::V6(addr) => { assert!(mlen <= 128); (addr, mlen) } }; let segments = ipv6_addr.segments(); let addr_bits = ((segments[0] as u128) << 112) | ((segments[1] as u128) << 96) | ((segments[2] as u128) << 80) | ((segments[3] as u128) << 64) | ((segments[4] as u128) << 48) | ((segments[5] as u128) << 32) | ((segments[6] as u128) << 16) | (segments[7] as u128); Self { addr: addr_bits, mlen: ipv6_mlen, } } pub fn from_bytestring(bytestring: &[u8]) -> Result { match memchr(b'/', bytestring) { Some(pos) => { let addr = IpAddr::parse_ascii(&bytestring[0..pos]).map_err(|_| { Error::InvalidAddr( std::str::from_utf8(&bytestring[0..pos]) .unwrap() .to_string(), ) })?; let mut mlen = 0; for (i, byte) in bytestring[pos + 1..bytestring.len()] .iter() .rev() .enumerate() { if *byte < 48 || *byte > 57 { return Err(Error::InvalidBlock("Invalid1".to_string())); } mlen += (byte - 48) * 10u8.pow(i as u32); } Ok(Self::new(addr, mlen)) } None => Err(Error::InvalidBlock( std::str::from_utf8(bytestring).unwrap().to_string(), )), } } fn addr(&self) -> IpAddr { addr_from_bits(self.addr) } pub fn start(&self) -> IpAddr { let mask = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff ^ ((1 << (128 - self.mlen)) - 1); addr_from_bits(self.addr & mask) } pub fn end(&self) -> IpAddr { let mask = !(0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff ^ ((1 << (128 - self.mlen)) - 1)); addr_from_bits(self.addr | mask) } pub fn size(&self) -> u128 { 2u128.pow(128 - self.mlen as u32) } } fn addr_from_bits(bits: u128) -> IpAddr { if bits & 0xffff_ffff_ffff_ffff_ffff_ffff_0000_0000 == 0xffff_0000_0000 { IpAddr::V4(Ipv4Addr::from((bits & 0xff_ff_ff_ff) as u32)) } else { IpAddr::V6(Ipv6Addr::from(bits)) } } impl FromStr for Block { type Err = Error; fn from_str(s: &str) -> Result { let parts: Vec<&str> = s.splitn(2, '/').collect(); if parts.len() < 2 { return Err(Error::InvalidBlock(s.to_string())); } let addr = IpAddr::from_str(parts[0]).map_err(|_| Error::InvalidAddr(parts[0].to_string()))?; let mlen = parts[1] .parse::() .map_err(|_| Error::InvalidMaskLength(parts[1].to_string()))?; Ok(Self::new(addr, mlen)) } } impl fmt::Display for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let addr = self.addr(); let mlen = if addr.is_ipv4() { self.mlen - 96 } else { self.mlen }; write!(f, "{}/{}", addr, mlen) } } impl fmt::Debug for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let addr = self.addr(); let mlen = if addr.is_ipv4() { self.mlen - 96 } else { self.mlen }; write!(f, "{}/{}", addr, mlen) } } impl Ord for Block { fn cmp(&self, other: &Self) -> Ordering { (self.addr >> (BITCOUNT - self.mlen) as usize) .cmp(&(other.addr >> ((BITCOUNT - other.mlen) % 32) as usize)) } } impl PartialEq for Block { fn eq(&self, other: &Self) -> bool { self.addr == other.addr && self.mlen == other.mlen } } impl PartialOrd for Block { fn partial_cmp(&self, other: &Self) -> Option { Some( (self.addr >> (BITCOUNT - self.mlen) as usize) .cmp(&(other.addr >> ((BITCOUNT - other.mlen) % 32) as usize)), ) } } impl Into> for Block { fn into(self) -> Vec { (&self).into() } } impl Into> for &Block { fn into(self) -> Vec { self.to_string().into() } }