1use std::net::IpAddr;
17use std::sync::Arc;
18
19use crate::a_sync::interface::MutexedCaches;
20use crate::a_sync::network::SocketTaps;
21use crate::a_sync::CachesController;
22use crate::common::RecordSOA;
23use crate::error::*;
24
25use super::query::QDns;
26use super::DnsRdata;
27use super::QType;
28use super::{QuerySetup, ResolveConfig};
29
30pub async
45fn resolve_fqdn<C, LOC, TAP, MC>(
46 fqdn: C,
47 custom_resolv: Option<Arc<ResolveConfig>>,
48 cache: Arc<CachesController<MC>>
49) -> CDnsResult<Vec<IpAddr>>
50where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
51{
52 let dns =
54 QDns::<LOC, TAP, MC>::make_a_aaaa_request(custom_resolv, fqdn.as_ref(),
55 QuerySetup::default(), cache).await?;
56
57 let res = dns.query().await;
59
60 let mut iplist: Vec<IpAddr> = vec![];
62
63 let recs = res.get_result()?;
64
65 for dnsr in recs.into_iter()
66 {
67 for resp in dnsr.into_iter()
68 {
69 match resp.borrow_rdata()
70 {
71 DnsRdata::A(ip) =>
72 iplist.push(IpAddr::from(ip.ip)),
73 DnsRdata::AAAA( ip ) =>
74 iplist.push(IpAddr::from(ip.ip)),
75 _ => continue,
76 }
77 }
78 }
79
80 return Ok(iplist);
81}
82
83pub async
99fn resolve_mx<C, LOC, TAP, MC>(
100 fqdn: C,
101 custom_resolv: Option<Arc<ResolveConfig>>,
102 cache: Arc<CachesController<MC>>
103) -> CDnsResult<Vec<String>>
104where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
105{
106 let mut dns_req =
107 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
108
109 dns_req.add_request(QType::MX, fqdn.as_ref());
110
111 let res = dns_req.query().await;
113
114 let mut mxlist: Vec<(u16, String)> = Vec::new();
116
117 let recs = res.get_result()?;
118
119 for dnsr in recs.into_iter()
120 {
121 for resp in dnsr.into_iter()
122 {
123 match resp.borrow_rdata()
124 {
125 DnsRdata::MX(mx) =>
126 {
127 let idx = mxlist.binary_search_by_key(&mx.preference, |x| x.0).map_or_else(|v| v, |f| f);
131 mxlist.insert(idx, (mx.preference, mx.exchange));
132
133 },
153 _ => continue,
154 }
155 }
156 }
157
158 return Ok(mxlist.into_iter().map( |(_, ip)| ip).collect());
159}
160
161pub async
176fn resolve_soa<C, LOC, TAP, MC>(
177 fqdn: C,
178 custom_resolv: Option<Arc<ResolveConfig>>,
179 cache: Arc<CachesController<MC>>
180) -> CDnsResult<Vec<RecordSOA>>
181where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
182{
183 let mut dns_req =
184 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
185
186 dns_req.add_request(QType::SOA, fqdn.as_ref());
187
188 let res = dns_req.query().await;
190
191 let mut soa_list: Vec<RecordSOA> = Vec::new();
192
193 let recs = res.get_result()?;
194
195 for dnsr in recs.into_iter()
196 {
197 for resp in dnsr.into_iter()
198 {
199 match resp.borrow_rdata()
200 {
201 DnsRdata::SOA(soa) =>
202 soa_list.push(soa),
203 _ => continue,
204 }
205 }
206 }
207
208 return Ok(soa_list);
209}
210
211pub async
226fn resolve_reverse<C, LOC, TAP, MC>(
227 ipaddr: C,
228 custom_resolv: Option<Arc<ResolveConfig>>,
229 cache: Arc<CachesController<MC>>
230) -> CDnsResult<Vec<String>>
231where C: AsRef<str>, TAP: SocketTaps<LOC>, MC: MutexedCaches, LOC: Send + Sync
232{
233 let mut dns_req =
234 QDns::<LOC, TAP, MC>::make_empty(custom_resolv, QuerySetup::default(), cache).await?;
235
236 dns_req.add_request(QType::PTR, ipaddr.as_ref());
237
238 let res = dns_req.query().await;
240
241 let recs = res.get_result()?;
242
243 let mut ptr_list: Vec<String> = Vec::new();
244
245 for dnsr in recs.into_iter()
246 {
247 for resp in dnsr.into_iter()
248 {
249 match resp.borrow_rdata()
250 {
251 DnsRdata::PTR(ptr) =>
252 ptr_list.push(ptr.fqdn),
253 _ => continue,
254 }
255 }
256 }
257
258 return Ok(ptr_list);
259}
260
261#[cfg(feature = "use_async_tokio")]
262#[cfg(test)]
263mod tests
264{
265 use std::sync::Arc;
266
267 use crate::a_sync::{request::{resolve_fqdn, resolve_mx, resolve_reverse}, SocketBase, CachesController, TokioInterf};
268
269 #[tokio::test]
270 async fn test_mx_resolve()
271 {
272 let cache = Arc::new(CachesController::new().await.unwrap());
273
274 let mx_doms = resolve_mx::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
275
276 assert_eq!(mx_doms.is_err(), false);
277
278 let mx_doms = mx_doms.unwrap();
279
280 let mut index = 0;
281 for di in mx_doms
282 {
283 match index
284 {
285 0 => assert_eq!(di.as_str(), "mail.protonmail.ch"),
286 1 => assert_eq!(di.as_str(), "mailsec.protonmail.ch"),
287 _ => panic!("test is required to be modified")
288 }
289
290 index += 1;
291
292 println!("{}", di);
293 }
294
295 }
296
297
298 #[tokio::test]
299 async fn test_a_aaaa_resolve()
300 {
301 let cache = Arc::new(CachesController::new().await.unwrap());
302
303 let a_aaaa = resolve_fqdn::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
304
305 assert_eq!(a_aaaa.is_ok(), true);
306
307 let a_aaaa = a_aaaa.unwrap();
308
309 for di in a_aaaa
310 {
311 println!("{}", di);
312 }
313
314 }
315
316 #[tokio::test]
317 async fn test_ptr_resolve_fail()
318 {
319 let cache = Arc::new(CachesController::new().await.unwrap());
320
321 let ptr = resolve_reverse::<_, SocketBase, SocketBase, TokioInterf>("protonmail.com", None, cache).await;
322
323 assert_eq!(ptr.is_ok(), true);
324
325 let ptr = ptr.unwrap();
326
327 assert_eq!(ptr.len(), 0);
328
329 }
330}