use std::time::Duration;
pub const MAX_CNAME_CHAIN_DEPTH: usize = 12;
pub const RESOLVER_TIMEOUT: Duration = Duration::from_secs(8);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CnameHop {
pub query: String,
pub target: String,
}
#[derive(Debug, Clone, Default)]
pub struct DnsProbe {
pub chain: Vec<CnameHop>,
pub first_a: Option<std::net::IpAddr>,
pub final_ptr: Option<String>,
pub asn: Option<AsnInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AsnInfo {
pub number: u32,
pub name: String,
}
impl DnsProbe {
pub fn all_hosts(&self) -> Vec<&str> {
self.tagged_hosts().into_iter().map(|(_, h)| h).collect()
}
pub fn tagged_hosts(&self) -> Vec<(&'static str, &str)> {
let mut out: Vec<(&'static str, &str)> = Vec::with_capacity(self.chain.len() + 3);
for hop in &self.chain {
out.push(("cname", hop.query.as_str()));
}
if let Some(last) = self.chain.last() {
out.push(("cname", last.target.as_str()));
}
if let Some(ref ptr) = self.final_ptr {
out.push(("ptr", ptr.as_str()));
}
if let Some(ref asn) = self.asn {
out.push(("asn", asn.name.as_str()));
}
out
}
}
#[derive(Debug, Clone, Copy)]
pub enum DnsProbeError {
ResolverInitFailed,
Timeout,
NoRecords,
DepthExceeded,
Io,
}
impl std::fmt::Display for DnsProbeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ResolverInitFailed => write!(f, "DNS resolver init failed"),
Self::Timeout => write!(f, "DNS lookup timed out"),
Self::NoRecords => write!(f, "no DNS records returned"),
Self::DepthExceeded => {
write!(f, "CNAME chain depth exceeded {MAX_CNAME_CHAIN_DEPTH}")
}
Self::Io => write!(f, "DNS resolver I/O error"),
}
}
}
impl std::error::Error for DnsProbeError {}