1mod interpret;
2mod validate;
3
4use std::fmt;
5use std::fs;
6use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
7use std::path::Path;
8
9#[derive(Debug)]
11pub enum AsmapError {
12 Io(std::io::Error),
13 Invalid,
14}
15
16impl fmt::Display for AsmapError {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 match self {
19 AsmapError::Io(e) => write!(f, "failed to read asmap file: {e}"),
20 AsmapError::Invalid => write!(f, "asmap data failed validation"),
21 }
22 }
23}
24
25impl std::error::Error for AsmapError {
26 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
27 match self {
28 AsmapError::Io(e) => Some(e),
29 AsmapError::Invalid => None,
30 }
31 }
32}
33
34impl From<std::io::Error> for AsmapError {
35 fn from(e: std::io::Error) -> Self {
36 AsmapError::Io(e)
37 }
38}
39
40#[derive(Debug)]
56pub struct Asmap {
57 data: Vec<u8>,
58}
59
60impl Asmap {
61 pub fn from_file(path: impl AsRef<Path>) -> Result<Self, AsmapError> {
63 let data = fs::read(path)?;
64 Self::from_bytes(data)
65 }
66
67 pub fn from_bytes(data: Vec<u8>) -> Result<Self, AsmapError> {
69 if !validate::sanity_check(&data, 128) {
70 return Err(AsmapError::Invalid);
71 }
72 Ok(Asmap { data })
73 }
74
75 pub fn lookup(&self, addr: IpAddr) -> u32 {
77 let ip6 = match addr {
78 IpAddr::V4(v4) => v4.to_ipv6_mapped(),
79 IpAddr::V6(v6) => v6,
80 };
81 interpret::interpret(&self.data, &ip6.octets())
82 }
83
84 pub fn lookup_v4(&self, addr: Ipv4Addr) -> u32 {
86 self.lookup(IpAddr::V4(addr))
87 }
88
89 pub fn lookup_v6(&self, addr: Ipv6Addr) -> u32 {
91 self.lookup(IpAddr::V6(addr))
92 }
93
94 pub fn as_bytes(&self) -> &[u8] {
96 &self.data
97 }
98}