use crate::dns::DnsCache;
use crate::{
DnsError, Error, MessageAuthenticator,
dns::{NoCache, Parameters},
};
use std::{fmt::Display, net::IpAddr, sync::Arc};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct IprevOutput {
pub result: IprevResult,
pub ptr: Option<Arc<[Box<str>]>>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum IprevResult {
Pass,
Fail(crate::Error),
TempError(crate::Error),
PermError(crate::Error),
None,
}
impl MessageAuthenticator {
pub async fn verify_iprev<'x, C>(
&self,
params: impl Into<Parameters<'x, IpAddr, C>>,
) -> IprevOutput
where
C: DnsCache + 'x,
{
let params = params.into();
match self.ptr_lookup(params.input, params.ptr_cache()).await {
Ok(ptr) => {
let mut last_err = None;
for host in ptr.records.iter().take(2) {
match ¶ms.input {
IpAddr::V4(ip) => match self.ipv4_lookup(host, params.ipv4_cache()).await {
Ok(ips) => {
if ips.records.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: Some(ptr.records.clone()),
};
}
}
Err(err) => {
last_err = err.into();
}
},
IpAddr::V6(ip) => match self.ipv6_lookup(host, params.ipv6_cache()).await {
Ok(ips) => {
if ips.records.iter().any(|cip| cip == ip) {
return IprevOutput {
result: IprevResult::Pass,
ptr: Some(ptr.records.clone()),
};
}
}
Err(err) => {
last_err = err.into();
}
},
}
}
IprevOutput {
result: if let Some(err) = last_err {
err.into()
} else {
IprevResult::Fail(Error::NotAligned)
},
ptr: Some(ptr.records.clone()),
}
}
Err(err) => IprevOutput {
result: err.into(),
ptr: None,
},
}
}
}
impl From<IpAddr> for Parameters<'_, IpAddr, NoCache> {
fn from(params: IpAddr) -> Self {
Parameters::new(params)
}
}
impl IprevOutput {
pub fn result(&self) -> &IprevResult {
&self.result
}
}
impl From<Error> for IprevResult {
fn from(err: Error) -> Self {
if matches!(&err, Error::Dns(DnsError::Resolver(_))) {
IprevResult::TempError(err)
} else {
IprevResult::PermError(err)
}
}
}
impl Display for IprevResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IprevResult::Pass => f.write_str("pass"),
IprevResult::Fail(err) => write!(f, "fail; {err}"),
IprevResult::TempError(err) => write!(f, "temp error; {err}"),
IprevResult::PermError(err) => write!(f, "perm error; {err}"),
IprevResult::None => f.write_str("none"),
}
}
}