use ipnet::Ipv4Net;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{borrow::Borrow, fmt::Debug, net::Ipv4Addr};
#[cfg(feature = "tracing")]
use tracing::instrument;
const RFC6890: [Ipv4Net; 4] = [
match Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), 8) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 0), 8) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(192, 0, 0, 0), 24) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(255, 255, 255, 255), 32) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
];
const RFC1918: [Ipv4Net; 3] = [
match Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 0), 8) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(172, 16, 0, 0), 12) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(192, 168, 0, 0), 16) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
];
const RFC6598: [Ipv4Net; 1] =
[match Ipv4Net::new(Ipv4Addr::new(169, 254, 0, 0), 16) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
}];
const RFC3927: [Ipv4Net; 1] =
[match Ipv4Net::new(Ipv4Addr::new(100, 64, 0, 0), 10) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
}];
const RFC7526: [Ipv4Net; 1] =
[match Ipv4Net::new(Ipv4Addr::new(192, 88, 99, 0), 24) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
}];
const RFC2544: [Ipv4Net; 1] =
[match Ipv4Net::new(Ipv4Addr::new(198, 18, 0, 0), 15) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
}];
const RFC5737: [Ipv4Net; 2] = [
match Ipv4Net::new(Ipv4Addr::new(198, 51, 100, 0), 24) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(203, 0, 113, 0), 24) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
];
const RFC5771: [Ipv4Net; 2] = [
match Ipv4Net::new(Ipv4Addr::new(224, 18, 0, 0), 4) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
match Ipv4Net::new(Ipv4Addr::new(233, 252, 0, 0), 24) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
},
];
const RFC3232: [Ipv4Net; 1] =
[match Ipv4Net::new(Ipv4Addr::new(240, 0, 0, 0), 4) {
Ok(cidr) => cidr,
Err(_) => panic!("invalid cidr"),
}];
pub(crate) fn all() -> Vec<Box<dyn Warn>> {
vec![Box::new(Private), Box::new(LargeMask)]
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Warning(pub String);
impl From<String> for Warning {
fn from(value: String) -> Self {
Self(value)
}
}
impl Borrow<str> for Warning {
fn borrow(&self) -> &str {
&self.0
}
}
pub(crate) trait Warn: Debug {
fn check(&self, cidr: Ipv4Net) -> Option<Warning>;
}
#[derive(Clone, Debug, Default)]
pub(crate) struct Private;
impl Warn for Private {
#[cfg_attr(feature = "tracing", instrument(ret))]
fn check(&self, cidr: Ipv4Net) -> Option<Warning> {
for block in [
&RFC1918[..],
&RFC2544[..],
&RFC3232[..],
&RFC3927[..],
&RFC5737[..],
&RFC5771[..],
&RFC6598[..],
&RFC6890[..],
&RFC7526[..],
]
.concat()
{
if block.contains(&cidr) {
return Some(format!("RESERVED ADDRESS SPACE: {cidr} is in the {block} private address space").into());
}
}
None
}
}
#[derive(Clone, Debug, Default)]
pub(crate) struct LargeMask;
impl Warn for LargeMask {
#[cfg_attr(feature = "tracing", instrument(ret))]
fn check(&self, cidr: Ipv4Net) -> Option<Warning> {
if cidr.prefix_len() < 24 {
return Some(
format!(
"LARGE MASK: {cidr} contains {} hosts",
cidr.hosts().count()
)
.into(),
);
}
None
}
}