mod interpret;
mod validate;
use std::fmt;
use std::fs;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::path::Path;
#[derive(Debug)]
pub enum AsmapError {
Io(std::io::Error),
Invalid,
}
impl fmt::Display for AsmapError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AsmapError::Io(e) => write!(f, "failed to read asmap file: {e}"),
AsmapError::Invalid => write!(f, "asmap data failed validation"),
}
}
}
impl std::error::Error for AsmapError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
AsmapError::Io(e) => Some(e),
AsmapError::Invalid => None,
}
}
}
impl From<std::io::Error> for AsmapError {
fn from(e: std::io::Error) -> Self {
AsmapError::Io(e)
}
}
#[derive(Debug)]
pub struct Asmap {
data: Vec<u8>,
}
impl Asmap {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, AsmapError> {
let data = fs::read(path)?;
Self::from_bytes(data)
}
pub fn from_bytes(data: Vec<u8>) -> Result<Self, AsmapError> {
if !validate::sanity_check(&data, 128) {
return Err(AsmapError::Invalid);
}
Ok(Asmap { data })
}
pub fn lookup(&self, addr: IpAddr) -> u32 {
let ip6 = match addr {
IpAddr::V4(v4) => v4.to_ipv6_mapped(),
IpAddr::V6(v6) => v6,
};
interpret::interpret(&self.data, &ip6.octets())
}
pub fn lookup_v4(&self, addr: Ipv4Addr) -> u32 {
self.lookup(IpAddr::V4(addr))
}
pub fn lookup_v6(&self, addr: Ipv6Addr) -> u32 {
self.lookup(IpAddr::V6(addr))
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
}