use std::net::IpAddr;
use std::sync::Arc;
use crate::a_sync::interface::MutexedCaches;
use crate::a_sync::network::SocketTaps;
use crate::a_sync::CachesController;
use crate::common::RecordSOA;
use crate::error::*;
use super::query::QDns;
use super::DnsRdata;
use super::QType;
use super::{QuerySetup, ResolveConfig};
pub async
fn resolve_fqdn<C, LOC, TAP, MC>(
fqdn: C,
custom_resolv: Option<Arc<ResolveConfig>>,
cache: Arc<CachesController<MC>>
) -> CDnsResult<Vec<IpAddr>>
where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
{
let dns =
QDns::<LOC, TAP, MC>::make_a_aaaa_request(custom_resolv, fqdn.as_ref(),
QuerySetup::default(), cache).await?;
let res = dns.query().await;
let mut iplist: Vec<IpAddr> = vec![];
let recs = res.get_result()?;
for dnsr in recs.into_iter()
{
for resp in dnsr.into_iter()
{
match resp.borrow_rdata()
{
DnsRdata::A(ip) =>
iplist.push(IpAddr::from(ip.ip)),
DnsRdata::AAAA( ip ) =>
iplist.push(IpAddr::from(ip.ip)),
_ => continue,
}
}
}
return Ok(iplist);
}
pub async
fn resolve_mx<C, LOC, TAP, MC>(
fqdn: C,
custom_resolv: Option<Arc<ResolveConfig>>,
cache: Arc<CachesController<MC>>
) -> CDnsResult<Vec<String>>
where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
{
let mut dns_req =
QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
dns_req.add_request(QType::MX, fqdn.as_ref());
let res = dns_req.query().await;
let mut mxlist: Vec<(u16, String)> = Vec::new();
let recs = res.get_result()?;
for dnsr in recs.into_iter()
{
for resp in dnsr.into_iter()
{
match resp.borrow_rdata()
{
DnsRdata::MX(mx) =>
{
let idx = mxlist.binary_search_by_key(&mx.preference, |x| x.0).map_or_else(|v| v, |f| f);
mxlist.insert(idx, (mx.preference, mx.exchange));
},
_ => continue,
}
}
}
return Ok(mxlist.into_iter().map( |(_, ip)| ip).collect());
}
pub async
fn resolve_soa<C, LOC, TAP, MC>(
fqdn: C,
custom_resolv: Option<Arc<ResolveConfig>>,
cache: Arc<CachesController<MC>>
) -> CDnsResult<Vec<RecordSOA>>
where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
{
let mut dns_req =
QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
dns_req.add_request(QType::SOA, fqdn.as_ref());
let res = dns_req.query().await;
let mut soa_list: Vec<RecordSOA> = Vec::new();
let recs = res.get_result()?;
for dnsr in recs.into_iter()
{
for resp in dnsr.into_iter()
{
match resp.borrow_rdata()
{
DnsRdata::SOA(soa) =>
soa_list.push(soa),
_ => continue,
}
}
}
return Ok(soa_list);
}
pub async
fn resolve_reverse<C, LOC, TAP, MC>(
ipaddr: C,
custom_resolv: Option<Arc<ResolveConfig>>,
cache: Arc<CachesController<MC>>
) -> CDnsResult<Vec<String>>
where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
{
let mut dns_req =
QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
dns_req.add_request(QType::PTR, ipaddr.as_ref());
let res = dns_req.query().await;
let recs = res.get_result()?;
let mut ptr_list: Vec<String> = Vec::new();
for dnsr in recs.into_iter()
{
for resp in dnsr.into_iter()
{
match resp.borrow_rdata()
{
DnsRdata::PTR(ptr) =>
ptr_list.push(ptr.fqdn),
_ => continue,
}
}
}
return Ok(ptr_list);
}
#[cfg(feature = "use_async_tokio")]
#[cfg(test)]
mod tests
{
use std::sync::Arc;
use crate::a_sync::{request::{resolve_fqdn, resolve_mx, resolve_reverse}, SocketBase, CachesController, TokioInterf};
#[tokio::test]
async fn test_mx_resolve()
{
let cache = Arc::new(CachesController::new().await.unwrap());
let mx_doms = resolve_mx::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
assert_eq!(mx_doms.is_err(), false);
let mx_doms = mx_doms.unwrap();
let mut index = 0;
for di in mx_doms
{
match index
{
0 => assert_eq!(di.as_str(), "mail.protonmail.ch"),
1 => assert_eq!(di.as_str(), "mailsec.protonmail.ch"),
_ => panic!("test is required to be modified")
}
index += 1;
println!("{}", di);
}
}
#[tokio::test]
async fn test_a_aaaa_resolve()
{
let cache = Arc::new(CachesController::new().await.unwrap());
let a_aaaa = resolve_fqdn::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
assert_eq!(a_aaaa.is_ok(), true);
let a_aaaa = a_aaaa.unwrap();
for di in a_aaaa
{
println!("{}", di);
}
}
#[tokio::test]
async fn test_ptr_resolve_fail()
{
let cache = Arc::new(CachesController::new().await.unwrap());
let ptr = resolve_reverse::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
assert_eq!(ptr.is_ok(), true);
let ptr = ptr.unwrap();
assert_eq!(ptr.len(), 0);
}
}