1use std::net::IpAddr;
25use std::sync::Arc;
26
27use crate::a_sync::interface::MutexedCaches;
28use crate::a_sync::network::SocketTaps;
29use crate::a_sync::CachesController;
30use crate::common::RecordSOA;
31use crate::error::*;
32
33use super::query::QDns;
34use super::DnsRdata;
35use super::QType;
36use super::{QuerySetup, ResolveConfig};
37
38pub async
53fn resolve_fqdn<C, LOC, TAP, MC>(
54 fqdn: C,
55 custom_resolv: Option<Arc<ResolveConfig>>,
56 cache: Arc<CachesController<MC>>
57) -> CDnsResult<Vec<IpAddr>>
58where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
59{
60 let dns =
62 QDns::<LOC, TAP, MC>::make_a_aaaa_request(custom_resolv, fqdn.as_ref(),
63 QuerySetup::default(), cache).await?;
64
65 let res = dns.query().await;
67
68 let mut iplist: Vec<IpAddr> = vec![];
70
71 let recs = res.get_result()?;
72
73 for dnsr in recs.into_iter()
74 {
75 for resp in dnsr.into_iter()
76 {
77 match resp.borrow_rdata()
78 {
79 DnsRdata::A(ip) =>
80 iplist.push(IpAddr::from(ip.ip)),
81 DnsRdata::AAAA( ip ) =>
82 iplist.push(IpAddr::from(ip.ip)),
83 _ => continue,
84 }
85 }
86 }
87
88 return Ok(iplist);
89}
90
91pub async
107fn resolve_mx<C, LOC, TAP, MC>(
108 fqdn: C,
109 custom_resolv: Option<Arc<ResolveConfig>>,
110 cache: Arc<CachesController<MC>>
111) -> CDnsResult<Vec<String>>
112where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
113{
114 let mut dns_req =
115 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
116
117 dns_req.add_request(QType::MX, fqdn.as_ref());
118
119 let res = dns_req.query().await;
121
122 let mut mxlist: Vec<(u16, String)> = Vec::new();
124
125 let recs = res.get_result()?;
126
127 for dnsr in recs.into_iter()
128 {
129 for resp in dnsr.into_iter()
130 {
131 match resp.borrow_rdata()
132 {
133 DnsRdata::MX(mx) =>
134 {
135 let idx = mxlist.binary_search_by_key(&mx.preference, |x| x.0).map_or_else(|v| v, |f| f);
139 mxlist.insert(idx, (mx.preference, mx.exchange));
140
141 },
161 _ => continue,
162 }
163 }
164 }
165
166 return Ok(mxlist.into_iter().map( |(_, ip)| ip).collect());
167}
168
169pub async
184fn resolve_soa<C, LOC, TAP, MC>(
185 fqdn: C,
186 custom_resolv: Option<Arc<ResolveConfig>>,
187 cache: Arc<CachesController<MC>>
188) -> CDnsResult<Vec<RecordSOA>>
189where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
190{
191 let mut dns_req =
192 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
193
194 dns_req.add_request(QType::SOA, fqdn.as_ref());
195
196 let res = dns_req.query().await;
198
199 let mut soa_list: Vec<RecordSOA> = Vec::new();
200
201 let recs = res.get_result()?;
202
203 for dnsr in recs.into_iter()
204 {
205 for resp in dnsr.into_iter()
206 {
207 match resp.borrow_rdata()
208 {
209 DnsRdata::SOA(soa) =>
210 soa_list.push(soa),
211 _ => continue,
212 }
213 }
214 }
215
216 return Ok(soa_list);
217}
218
219pub async
234fn resolve_reverse<C, LOC, TAP, MC>(
235 ipaddr: C,
236 custom_resolv: Option<Arc<ResolveConfig>>,
237 cache: Arc<CachesController<MC>>
238) -> CDnsResult<Vec<String>>
239where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
240{
241 let mut dns_req =
242 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
243
244 dns_req.add_request(QType::PTR, ipaddr.as_ref());
245
246 let res = dns_req.query().await;
248
249 let recs = res.get_result()?;
250
251 let mut ptr_list: Vec<String> = Vec::new();
252
253 for dnsr in recs.into_iter()
254 {
255 for resp in dnsr.into_iter()
256 {
257 match resp.borrow_rdata()
258 {
259 DnsRdata::PTR(ptr) =>
260 ptr_list.push(ptr.fqdn),
261 _ => continue,
262 }
263 }
264 }
265
266 return Ok(ptr_list);
267}
268
269#[cfg(feature = "use_async_tokio")]
270#[cfg(test)]
271mod tests
272{
273 use std::sync::Arc;
274
275 use crate::a_sync::{request::{resolve_fqdn, resolve_mx, resolve_reverse}, SocketBase, CachesController, TokioInterf};
276
277 #[tokio::test]
278 async fn test_mx_resolve()
279 {
280 let cache = Arc::new(CachesController::new().await.unwrap());
281
282 let mx_doms = resolve_mx::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
283
284 assert_eq!(mx_doms.is_err(), false);
285
286 let mx_doms = mx_doms.unwrap();
287
288 let mut index = 0;
289 for di in mx_doms
290 {
291 match index
292 {
293 0 => assert_eq!(di.as_str(), "mail.protonmail.ch"),
294 1 => assert_eq!(di.as_str(), "mailsec.protonmail.ch"),
295 _ => panic!("test is required to be modified")
296 }
297
298 index += 1;
299
300 println!("{}", di);
301 }
302
303 }
304
305
306 #[tokio::test]
307 async fn test_a_aaaa_resolve()
308 {
309 let cache = Arc::new(CachesController::new().await.unwrap());
310
311 let a_aaaa = resolve_fqdn::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
312
313 assert_eq!(a_aaaa.is_ok(), true);
314
315 let a_aaaa = a_aaaa.unwrap();
316
317 for di in a_aaaa
318 {
319 println!("{}", di);
320 }
321
322 }
323
324 #[tokio::test]
325 async fn test_ptr_resolve_fail()
326 {
327 let cache = Arc::new(CachesController::new().await.unwrap());
328
329 let ptr = resolve_reverse::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
330
331 assert_eq!(ptr.is_ok(), true);
332
333 let ptr = ptr.unwrap();
334
335 assert_eq!(ptr.len(), 0);
336
337 }
338}