cdns_rs/a_sync/
query.rs

1/*-
2 * cdns-rs - a simple sync/async DNS query library
3 * 
4 * Copyright (C) 2020  Aleksandr Morozov
5 * 
6 * Copyright (C) 2025 Aleksandr Morozov
7 * 
8 * The syslog-rs crate can be redistributed and/or modified
9 * under the terms of either of the following licenses:
10 *
11 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
12 *                     
13 *   2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
14 */
15
16
17use std::collections::{BTreeSet, HashMap};
18use std::convert::TryFrom;
19use std::marker::PhantomData;
20use std::net::IpAddr;
21use std::sync::Arc;
22use std::time::Duration;
23use std::time::Instant;
24
25use async_recursion::async_recursion;
26
27
28use crate::a_sync::caches::CachesController;
29
30#[cfg(feature = "built_in_async")]
31use crate::a_sync::interface::MutexedCaches;
32#[cfg(not(feature = "built_in_async"))]
33use crate::a_sync::interface::MutexedCaches;
34
35#[cfg(feature = "built_in_async")]
36use crate::a_sync::{IoInterf, SocketBase};
37
38#[cfg(feature = "built_in_async")]
39use crate::a_sync::TokioInterf;
40
41use crate::a_sync::SocketTaps;
42use crate::cfg_resolv_parser::{ConfigEntryTls, ResolveConfEntry, ResolveConfigFamily};
43use crate::common::{CDdnsGlobals, DnsRequestAnswer, DnsRequestHeader};
44use crate::{error::*, DnsResponsePayload, QDnsQueryResult};
45use crate::query::QDnsQuery;
46use crate::{write_error, internal_error};
47use crate::query_private::QDnsReq;
48
49use super::network::{NetworkTapType, SocketTap};
50use super::{QDnsName, QType, QuerySetup, ResolveConfig};
51
52/// A main instance which contains all common logic. All requests for name/host 
53/// resolutions should be perfomed using this structure.
54/// 
55/// ```ignore
56/// let dns_req = 
57///     QDns::<SocketBase, SocketBase, IoInterf>::make_empty(Some(cust.clone()), QuerySetup::default(), cache.clone())
58///         .await
59///         .unwrap();
60///
61///  dns_req.add_request(QType::SOA, "protonmail.com");
62/// ```
63/// 
64/// This struct is for the `async` with the user provided interface to the
65/// async executor items like sockets, files, etc...
66/// 
67/// feature = "built_in_async" which s enabled by the feature `use_async_tokio`.
68/// 
69/// # Generics
70/// 
71/// * `LOC` - this generic do nothing and needed to overcome the problem
72///     of the foreign stucts and traits implemented outside of the crate.
73///     "only traits defined in the current crate can be implemented for types 
74///     defined outside of the crate". Usually is set to the same type as `TAP`.
75///     By default, it is preset to [SocketBase].
76/// 
77/// * `TAP` - a generic which should implement [SocketTaps] which will be used 
78///     by the crate. By default, it is pre set to [SocketBase].
79/// 
80/// * `MC` - a generic which should implement [MutexedCaches] which provides the
81///     file and mutex funtionality. By default, it is pre set to [TokioInterf].
82#[cfg(feature = "built_in_async")]
83#[derive(Clone, Debug)]
84pub struct QDns<LOC: Sync + Send = SocketBase, TAP: SocketTaps<LOC> = SocketBase, MC: MutexedCaches = IoInterf>
85{
86    /// An instance of the parser /etc/resolv.conf or custom config
87    resolvers: Arc<ResolveConfig>,
88
89    /// A pre-ordered list of the requests, if more than one
90    ordered_req_list: Vec<QDnsReq>,
91
92    /// Override options
93    opts: QuerySetup,
94
95    /// A cached config files.
96    cache: Arc<CachesController<MC>>,
97
98    /// TAP phantom
99    _tap: PhantomData<TAP>,
100
101    /// LOC phantom
102    _loc: PhantomData<LOC>
103}
104
105#[cfg(feature = "use_async_tokio")]
106impl QDns<SocketBase>
107{
108    /// Initializes new empty storage for requests.
109    /// 
110    /// In some cases it is good idea to combine different requests, because by default
111    /// all requests are performed in parallel. But in some cases it is bad idea.
112    /// 
113    /// # Arguments
114    /// 
115    /// * `resolvers` - an [Arc] [ResolveConfig] which contains configuration i.e nameservers
116    /// 
117    /// * `planned_reqs_len` - how many requests are planned
118    /// 
119    /// * `opts` - [QuerySetup] additional options or overrides. Use default() for default
120    ///     values.
121    /// 
122    /// * `cache` - a [Arc] to [CachesController] which should be prepared before calling 
123    ///     this function.
124    /// 
125    /// # Returns
126    /// 
127    /// A [CDnsResult] is returned ([Result] alias) where:
128    /// 
129    /// * [Result::Ok] is returned with the new instance.
130    /// 
131    /// * [Result::Err] is returned with error description. The error may happen during attempt 
132    ///     to read resolv config or obtain a cached verion.
133    #[inline]
134    pub async 
135    fn builtin_make_empty(resolvers: Option<Arc<ResolveConfig>>, opts: QuerySetup, cache: Arc<CachesController<TokioInterf>>) -> CDnsResult<QDns<SocketBase, SocketBase, TokioInterf>>
136    {
137        return QDns::<_>::make_empty(resolvers, opts, cache).await;
138    }
139
140    /// Adds a new request to current instance.
141    /// 
142    /// # Arguemnts
143    /// 
144    /// * `qtype` - a [QType] type of the request
145    /// 
146    /// * `req_name` - a [Into] [QDnsName] which is target. i.e 'localhost' or 'domain.tld'
147    #[inline]
148    pub 
149    fn buildin_add_request<R>(&mut self, qtype: QType, req_name: R) -> CDnsResult<()>
150    where
151        R: TryInto<QDnsName, Error = CDnsError>,
152    {
153        let qr = QDnsReq::new_into(req_name, qtype)?;
154
155        self.ordered_req_list.push(qr);
156
157        return Ok(());
158    }
159
160    /// This is helper which makes for you an A, AAAA query. The order of A and AAAA 
161    /// is defined in the [ResolveConfig].
162    /// 
163    /// Use this function directly. Do not use [QDns::make_empty]
164    /// 
165    /// # Arguments
166    /// 
167    /// * `resolvers` - an [Option] value [Arc] [ResolveConfig] which can be used to 
168    ///     override the system's `resolv.conf`
169    /// 
170    /// * `req_name` - a [Into] [QDnsName] which is target i.e 'localhost' or 'domain.tld'
171    /// 
172    /// * `opts` - [QuerySetup] additional options or overrides. Use default() for default
173    ///     values.
174    /// 
175    /// * `cache` - a [Arc] to [CachesController] which should be prepared before calling 
176    ///     this function.
177    /// 
178    /// # Returns
179    /// 
180    /// A [CDnsResult] is returned;
181    /// 
182    /// * [Result::Ok] - with Self as inner type
183    /// 
184    /// * [Result::Err] is returned with error description. The error may happen during attempt 
185    ///     to read resolv config or obtain a cached verion.
186    pub async 
187    fn buildin_make_a_aaaa_request<R: AsRef<str>>(resolvers_opt: Option<Arc<ResolveConfig>>, req_name: R, 
188        opts: QuerySetup, cache: Arc<CachesController<TokioInterf>>) -> CDnsResult<Self>
189    {
190        return QDns::<_>::make_a_aaaa_request(resolvers_opt, req_name, opts, cache).await;
191    }
192}
193
194/// A main instance which contains all common logic. All requests for name/host 
195/// resolutions should be perfomed using this structure.
196/// 
197/// ```ignore
198/// let dns_req = 
199///     QDns::<SocketBase, SocketBase, IoInterf>::make_empty(Some(cust.clone()), QuerySetup::default(), cache.clone())
200///         .await
201///         .unwrap();
202///
203///  dns_req.add_request(QType::SOA, "protonmail.com");
204/// ```
205/// 
206/// This struct is for the `async` with the user provided interface to the
207/// async executor items like sockets, files, etc...
208/// 
209/// feature = "built_in_async"
210/// 
211/// # Generics
212/// 
213/// * `LOC` - this generic do nothing and needed to overcome the problem
214///     of the foreign stucts and traits implemented outside of the crate.
215///     "only traits defined in the current crate can be implemented for types 
216///     defined outside of the crate". Usually is set to the same type as `TAP`.
217/// 
218/// * `TAP` - a generic which should implement [SocketTaps] which will be used 
219///     by the crate.
220/// 
221/// * `MC` - a generic which should implement [MutexedCaches] which provides the
222///     file and mutex funtionality.
223#[cfg(not(feature = "built_in_async"))]
224#[derive(Clone, Debug)]
225pub struct QDns<LOC: Sync + Send, TAP: SocketTaps<LOC>, MC: MutexedCaches>
226{
227    /// An instance of the parser /etc/resolv.conf or custom config
228    resolvers: Arc<ResolveConfig>,
229
230    /// A pre-ordered list of the requests, if more than one
231    ordered_req_list: Vec<QDnsReq>,
232
233    /// Override options
234    opts: QuerySetup,
235
236    /// A cached config files.
237    cache: Arc<CachesController<MC>>,
238
239    /// TAP phantom
240    _tap: PhantomData<TAP>,
241
242    /// LOC phantom
243    _loc: PhantomData<LOC>
244}
245
246impl<LOC: Sync + Send, TAP: SocketTaps<LOC>, MC: MutexedCaches> QDns<LOC, TAP, MC>
247{
248    /// Initializes new empty storage for requests.
249    /// 
250    /// # Arguments
251    /// 
252    /// * `resolvers` - an [Arc] [ResolveConfig] which contains configuration i.e nameservers
253    /// 
254    /// * `planned_reqs_len` - how many requests are planned
255    /// 
256    /// * `opts` - [QuerySetup] additional options or overrides. Use default() for default
257    ///     values.
258    /// 
259    /// * `cache` - a [Arc] to [CachesController] which should be prepared before calling 
260    ///     this function.
261    /// 
262    /// # Returns
263    /// 
264    /// A [CDnsResult] is returned ([Result] alias) where:
265    /// 
266    /// * [Result::Ok] is returned with the new instance.
267    /// 
268    /// * [Result::Err] is returned with error description. The error may happen during attempt 
269    ///     to read resolv config or obtain a cached verion.
270    pub async 
271    fn make_empty(resolvers: Option<Arc<ResolveConfig>>, opts: QuerySetup, cache: Arc<CachesController<MC>>) -> CDnsResult<QDns<LOC, TAP, MC>>
272    {
273        return Ok(
274            Self
275            {
276                resolvers: resolvers.unwrap_or(cache.clone_resolve_list().await?),
277                ordered_req_list: Vec::new(),
278                opts: opts,
279                cache: cache,
280                _tap: PhantomData,
281                _loc: PhantomData
282            }
283        );
284    }
285
286    /// Adds a new request to current instance.
287    /// 
288    /// # Arguemnts
289    /// 
290    /// * `qtype` - a [QType] type of the request
291    /// 
292    /// * `req_name` - a [Into] [QDnsName] which is target. i.e 'localhost' or 'domain.tld'
293    pub 
294    fn add_request<R>(&mut self, qtype: QType, req_name: R) -> CDnsResult<()>
295    where
296        R: TryInto<QDnsName, Error = CDnsError>
297    {
298        let qr = QDnsReq::new_into(req_name, qtype)?;
299
300        self.ordered_req_list.push(qr);
301
302        return Ok(());
303    }
304
305    /// This is helper which makes for you an A, AAAA query. The order of A and AAAA 
306    /// is defined in the [ResolveConfig].
307    /// 
308    /// Use this function directly. Do not use [QDns::make_empty]
309    /// 
310    /// # Arguments
311    /// 
312    /// * `resolvers` - an [Option] value [Arc] [ResolveConfig] which can be used to 
313    ///     override the system's `resolv.conf`
314    /// 
315    /// * `req_name` - a [Into] [QDnsName] which is target i.e 'localhost' or 'domain.tld'
316    /// 
317    /// * `opts` - [QuerySetup] additional options or overrides. Use default() for default
318    ///     values.
319    /// 
320    /// * `cache` - a [Arc] to [CachesController] which should be prepared before calling 
321    ///     this function.
322    /// 
323    /// # Returns
324    /// 
325    /// A [CDnsResult] is returned;
326    /// 
327    /// * [Result::Ok] - with Self as inner type
328    /// 
329    /// * [Result::Err] is returned with error description. The error may happen during attempt 
330    ///     to read resolv config or obtain a cached verion.
331    pub async 
332    fn make_a_aaaa_request<R: AsRef<str>>(resolvers_opt: Option<Arc<ResolveConfig>>, req_name_ref: R, 
333        opts: QuerySetup, cache: Arc<CachesController<MC>>) -> CDnsResult<Self>
334    {
335        let req_n = QDnsName::try_from(req_name_ref.as_ref())?;
336
337        let resolvers = resolvers_opt.unwrap_or(cache.clone_resolve_list().await?);
338
339        // store the A and AAAA depending on order
340        let reqs: Vec<QDnsReq> = 
341            match resolvers.family
342            {
343                ResolveConfigFamily::INET4_INET6 => 
344                {
345                    vec![
346                        QDnsReq::new(req_n.clone(), QType::A),
347                        QDnsReq::new(req_n, QType::AAAA),
348                    ]
349                },
350                ResolveConfigFamily::INET6_INET4 => 
351                {
352                    vec![
353                        QDnsReq::new(req_n.clone(), QType::AAAA),
354                        QDnsReq::new(req_n, QType::A),
355                    ]
356                },
357                ResolveConfigFamily::INET6 => 
358                {
359                    vec![
360                        QDnsReq::new(req_n, QType::AAAA),
361                    ]
362                },
363                ResolveConfigFamily::INET4 => 
364                {
365                    vec![
366                        QDnsReq::new(req_n, QType::A),
367                    ]
368                }
369                _ =>
370                {
371                    // set default
372                    vec![
373                        QDnsReq::new(req_n.clone(), QType::A),
374                        QDnsReq::new(req_n, QType::AAAA),
375                    ]
376                }
377            };
378
379        
380        
381        return Ok(
382            Self
383            {
384                resolvers: resolvers,
385                ordered_req_list: reqs,
386                opts: opts,
387                cache: cache,
388                _tap: PhantomData,
389                _loc: PhantomData
390            }
391        );
392    }
393
394    /// Runs the created query/ies consuming the instance.
395    /// 
396    /// # Returns
397    /// 
398    /// A [QDnsQueryResult] is returned. It contains a pairs of the request and
399    /// response result.
400    pub async 
401    fn query(mut self) -> QDnsQueryResult
402    {
403        // check if we need to measure time
404        let now = 
405            if self.opts.measure_time == true
406            {
407                Some(Instant::now())
408            }
409            else
410            {
411                None
412            };
413
414        // determine where to look firstly i.e file -> bind, bind -> file
415        // or bind only, or file only
416        if self.resolvers.lookup.is_file_first()
417        {
418            let mut query_res = 
419                match self.lookup_file(now.as_ref()).await
420                {
421                    Ok(file) => 
422                    {
423                        if file.is_empty() == false
424                        {
425                            // remove records which was resolved
426                            self.ordered_req_list.retain(|req| 
427                                {
428                                    return !file.contains_dnsreq(req);
429                                }
430                            );
431                        }
432
433                        file
434                    },
435                    Err(e) => 
436                    {
437                        write_error!(e);
438
439                        QDnsQueryResult::default()
440                    }
441                };
442
443
444            // if something left unresolved, try ask internet
445            if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_bind() == true
446            {
447                let res = self.process_request(now.as_ref()).await;
448                
449                query_res.extend(res);
450            }
451
452            return query_res;
453        }
454        else
455        {
456            let mut dns_res = self.process_request(now.as_ref()).await;
457            if dns_res.is_empty() == false
458            {
459                // remove records which was resolved
460                self.ordered_req_list.retain(|req| 
461                    {
462                        return !dns_res.contains_dnsreq(req);
463                    }
464                );
465            }
466
467
468
469            if self.ordered_req_list.is_empty() == false && self.resolvers.lookup.is_file() == true
470            {
471                match self.lookup_file(now.as_ref()).await
472                {
473                    Ok(res) => 
474                    {
475                        dns_res.extend(res);
476                    },
477                    Err(e) =>
478                    {
479                        write_error!(e);
480                    }
481                }
482            }
483
484            return dns_res;
485        }
486    }
487
488    /// Returns timeout
489    fn get_timeout(&self) -> Duration
490    {
491        if let Some(timeout) = self.opts.timeout
492        {
493            return Duration::from_secs(timeout as u64);
494        }
495        else
496        {
497            return Duration::from_secs(self.resolvers.timeout as u64);
498        }
499    }
500
501    /// Searches in /etc/hosts
502    async 
503    fn lookup_file(&mut self, now: Option<&Instant>) -> CDnsResult<QDnsQueryResult>
504    {
505        let mut dnsquries: QDnsQueryResult = QDnsQueryResult::default();
506
507        // check if the it is overriden
508        if self.opts.ign_hosts == false
509        {
510            let hlist = self.cache.clone_host_list().await?;
511
512            for req in self.ordered_req_list.iter()
513            {
514                match *req.get_type()
515                {
516                    QType::A | QType::AAAA => 
517                    {
518                        let req_name = String::from(req.get_req_name());
519
520                        let Some(host_name_ent) = hlist.search_by_fqdn(req.get_type(), req_name.as_str())
521                            else { continue };
522                        
523                        let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
524                            else { continue };
525                        
526                        // store to list
527                        dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now)));
528                    },
529                    QType::PTR => 
530                    {
531                        let Ok(ip) = IpAddr::try_from(req.get_req_name())
532                            else { continue };
533
534                        let Some(host_name_ent) = hlist.search_by_ip(&ip)
535                            else { continue };
536
537                        let Some(drp) = DnsResponsePayload::new_local(*req.get_type(), host_name_ent)
538                            else { continue };    
539
540                        dnsquries.push(req.clone(), Ok(QDnsQuery::from_local(drp, now))); 
541                    },
542                    _ => 
543                        continue,
544                }
545            }
546
547        }
548
549        return Ok(dnsquries);
550    }
551
552    /// Creates socket based on config and flag. If `force_tcp` is set then Tcp tap will
553    /// be created.
554    #[inline]
555    fn create_socket(&self, force_tcp: bool, resolver: Arc<ResolveConfEntry>) -> CDnsResult<Box<NetworkTapType<LOC>>>
556    {
557        if resolver.get_tls_type() != ConfigEntryTls::None
558        {
559            #[cfg(feature = "use_async_tokio_tls")]
560            return TAP::new_tls_socket(resolver, self.get_timeout());
561
562            #[cfg(not(feature = "use_async_tokio_tls"))]
563            internal_error!(CDnsErrorType::SocketNotSupported, "compiled without TLS support");
564        }
565        else if self.resolvers.option_flags.is_force_tcp() == true || force_tcp == true
566        {
567            return TAP::new_tcp_socket(resolver, self.get_timeout());
568        }
569        else
570        {
571            return TAP::new_udp_socket(resolver, self.get_timeout());
572        }
573    }
574
575    /// Quering all nameservers
576    async 
577    fn process_request(&mut self, now: Option<&Instant>) -> QDnsQueryResult
578    {
579        let mut responses: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
580
581        if self.resolvers.option_flags.is_no_parallel() == true
582        {
583            for req in self.ordered_req_list.iter()
584            {
585                let mut last_resp: Option<CDnsResult<QDnsQuery>> = None;
586
587                for resolver in self.resolvers.get_resolvers_iter()
588                {
589                    match self.query_exec_seq(now, resolver.clone(), req, None).await
590                    {
591                        Ok(resp) =>
592                        {
593                            if resp.should_check_next_ns() == true
594                            {
595                                last_resp = Some(Ok(resp));
596
597                                continue;
598                            }
599                            else
600                            {
601                                responses.push(req.clone(), Ok(resp));
602
603                                let _ = last_resp.take();
604
605                                break;
606                            }
607                        },
608                        Err(e) =>
609                        {
610                            if last_resp.is_none() == true
611                            {
612                                last_resp = Some(Err(e));
613                            }                      
614
615                            continue;
616                        }
617                    }
618                } // for
619
620                responses.push(req.clone(), last_resp.take().unwrap());
621            }// for
622        }
623        else
624        {
625           // let mut responses: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
626
627            for resolver in self.resolvers.get_resolvers_iter()
628            {
629                if self.ordered_req_list.is_empty() == true
630                {
631                    break;
632                }
633
634                match self.query_exec_pipelined(now, resolver.clone(), None).await
635                {
636                    Ok(resp) =>
637                    {
638                        for (qdns_res, qdns_que) in resp
639                        {
640                            if let Ok(ref resp) = qdns_que
641                            {
642                                if resp.should_check_next_ns() == false
643                                    {
644                                        self
645                                            .ordered_req_list
646                                            .retain(
647                                                |req_item|
648                                                req_item != &qdns_res
649                                            );
650                                    }
651                            }
652                            
653                            responses.push(qdns_res, qdns_que);
654                        }
655                    },
656                    Err(e) =>
657                    {
658                        write_error!(e);
659
660                        continue;
661                    }
662                }
663            }
664        }
665
666        return responses;
667    }
668
669    #[async_recursion]
670    async 
671    fn query_exec_pipelined(
672        &self, 
673        now: Option<&Instant>, 
674        resolver: Arc<ResolveConfEntry>,
675        requery: Option<HashMap<DnsRequestHeader<'async_recursion>, QDnsReq>>,
676    ) -> CDnsResult<QDnsQueryResult>
677    {
678        let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
679
680        let mut query_headers: HashMap<DnsRequestHeader, QDnsReq> = 
681            if let Some(requer) = requery
682            {
683                let pkts_ids = requer.iter().map(|q| q.0.get_id()).collect::<BTreeSet<u16>>();
684
685                // regenerate que ID and collect
686                requer
687                    .into_iter()
688                    .map(
689                        |(mut qrr, qdr)| 
690                        { 
691                            loop
692                            {
693                                qrr.regenerate_id(); 
694
695                                if pkts_ids.contains(&qrr.get_id()) == false
696                                {
697                                    break;
698                                }
699                            }
700                            (qrr, qdr)
701                        })
702                    .collect::<HashMap<DnsRequestHeader, QDnsReq>>()
703            }
704            else    
705            {
706                let mut pkts_ids: BTreeSet<u16> = BTreeSet::new();
707
708                // create que
709                self
710                    .ordered_req_list
711                    .iter()
712                    .map(
713                        |query| 
714                        {
715                            
716                            let mut drh_res = DnsRequestHeader::try_from(query);
717                            
718                            loop
719                            {
720                                if let Ok(ref mut drh) = drh_res
721                                {
722                                    if pkts_ids.contains(&drh.get_id()) == true
723                                    {
724                                        drh.regenerate_id();
725
726                                        continue;
727                                    }
728                                    else
729                                    {
730                                        pkts_ids.insert(drh.get_id());
731                                        break;
732                                    }
733                                }
734                                else
735                                {
736                                    break;
737                                }
738                            }
739
740                            drh_res.map(|dh| (dh, query.clone()))
741                        }
742                    )
743                    .collect::<CDnsResult<HashMap<DnsRequestHeader, QDnsReq>>>()?
744            };
745
746        // create socket and store
747        let mut tap = self.create_socket(force_tcp, resolver.clone())?;
748
749        tap.connect(CDdnsGlobals::get_tcp_conn_timeout()).await?;
750
751        // send everything
752        for qh in query_headers.iter()
753        {
754            let pkt = qh.0.to_bytes(tap.should_append_len())?;
755
756            tap.send(pkt.as_slice()).await?;
757        }
758
759        let mut resp: QDnsQueryResult = QDnsQueryResult::with_capacity(self.ordered_req_list.len());
760        let mut requery: HashMap<DnsRequestHeader, QDnsReq> = HashMap::new();
761        // poll socket
762        
763        loop
764        {
765            if query_headers.len() == 0
766            {
767                break;
768            }
769            
770            tap.poll_read().await?;
771
772            let ans = self.read_response(tap.as_mut()).await?;
773
774            let Some((query_header, qdnsreq)) = query_headers.remove_entry(&ans.req_header)
775                else
776                {
777                    internal_error!(CDnsErrorType::IoError, "can not find response with request: {}", ans.req_header);
778                };
779
780            ans.verify(&query_header)?;
781
782            // verified
783            let qdns_resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now);
784
785            if let Ok(ref qdns) = qdns_resp
786            {
787                if qdns.get_status().should_try_tcp() == true && force_tcp == false
788                {
789                    requery.insert(query_header, qdnsreq);
790                }
791                else
792                {
793                    resp.push(qdnsreq, qdns_resp);
794                }
795            }
796            else
797            {
798                resp.push(qdnsreq, qdns_resp);
799            }
800        }
801
802        if requery.is_empty() == false
803        {
804            let res = self.query_exec_pipelined(now, resolver, Some(requery)).await?;
805
806            resp.extend(res);
807        }
808        
809        return Ok(resp);   
810    }
811
812    /// Processes request/s for nameserver
813    #[async_recursion]
814    async 
815    fn query_exec_seq(
816        &self, 
817        now: Option<&Instant>, 
818        resolver: Arc<ResolveConfEntry>,
819        query: &QDnsReq,
820        requery: Option<DnsRequestHeader<'async_recursion>>,
821    ) -> CDnsResult<QDnsQuery>
822    {
823        let force_tcp = self.resolvers.option_flags.is_force_tcp() || requery.is_some();
824
825        // create socket and store
826        let mut tap = self.create_socket(force_tcp, resolver.clone())?;
827
828        let query_header = 
829            // form the list of reqests binded to taps
830            if let Some(mut requery) = requery
831            {
832                requery.regenerate_id();
833
834                requery
835            }
836            else
837            {
838                let drh_req = DnsRequestHeader::try_from(query)?;
839                
840                drh_req
841            };
842
843        let res = 
844            {
845                // open connection, with timeout because working in non parallel mode
846                tap.connect(CDdnsGlobals::get_tcp_conn_timeout()).await?;
847
848                // convert to byte packet (the error returned is global error i.e OOM)
849                let pkt = query_header.to_bytes(tap.should_append_len())?;
850
851                // send to DNS server, if error happens, then stop processing this server
852                tap.send(pkt.as_slice()).await?;
853
854                let ans = self.read_response(tap.as_mut()).await?;
855
856                ans.verify(&query_header)?;
857
858                // verified
859                let resp = QDnsQuery::from_response(tap.get_remote_addr(), ans, now)?;
860
861                Ok(resp)
862            };
863
864        if (res.is_ok() == true && res.as_ref().unwrap().status.should_try_tcp() == false) || 
865            (res.is_err() == true && force_tcp == true)
866        {
867            return res;
868        }
869        
870
871        return 
872            self.query_exec_seq(now, resolver.clone(), query, Some(query_header)).await;
873    }
874
875    /// Reads response from tap
876    async 
877    fn read_response(&self, socktap: &mut dyn SocketTap<LOC>) -> CDnsResult<DnsRequestAnswer<'_>>
878    {
879        if socktap.is_tcp() == false
880        {
881            let mut rcvbuf = vec![0_u8; 1457];
882
883            // receive message
884            let n = socktap.recv(rcvbuf.as_mut_slice()).await?;
885
886            // parsing response to structure
887            return DnsRequestAnswer::parse(&rcvbuf); //DnsRequestAnswer::try_from(rcvbuf.as_slice(), n, socktap.is_tcp())?;
888        }
889        else
890        {
891            let mut pkg_pen: [u8; 2] = [0, 0];
892            let n = socktap.recv(&mut pkg_pen).await?;
893
894            if n == 0
895            {
896                internal_error!(CDnsErrorType::IoError, "tcp received zero len message!");
897            }
898            else if n != 2
899            {
900                internal_error!(CDnsErrorType::IoError, "tcp expected 2 bytes to be read!");
901            }
902
903            let ln = u16::from_be_bytes(pkg_pen);
904
905            let mut rcvbuf = vec![0_u8; ln as usize];
906
907            // receive message
908            let mut n = socktap.recv(rcvbuf.as_mut_slice()).await?;
909
910            if n == 0
911            {
912                internal_error!(CDnsErrorType::IoError, "tcp received zero len message!");
913            }
914            else if n == 1
915            {
916                n = socktap.recv(&mut rcvbuf[1..]).await?;
917
918                if n == 0
919                {
920                    internal_error!(CDnsErrorType::IoError, "tcp received zero len message again!");
921                }
922
923                n += 1;
924            }
925
926            return DnsRequestAnswer::parse(&rcvbuf); 
927        }
928    }
929}
930
931#[cfg(feature = "use_async_tokio")]
932#[cfg(test)]
933mod tests
934{
935    use std::{net::IpAddr, sync::Arc};
936
937    use crate::{a_sync::{query::QDns, CachesController}, common::{byte2hexchar, ip2pkt, RecordPTR, RecordReader}, QDnsQueryRec, QType, QuerySetup};
938
939    #[tokio::test]
940    async fn test_ip2pkt()
941    {
942        use tokio::time::Instant;
943        use std::net::{IpAddr, Ipv4Addr};
944   
945        let test = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
946
947        let now = Instant::now();
948
949        let res = ip2pkt(&test);
950
951        let elapsed = now.elapsed();
952        println!("Elapsed: {:.2?}", elapsed);
953
954        let ctrl = b"\x01\x38\x01\x38\x01\x38\x01\x38\x07\x69\x6e\x2d\x61\x64\x64\x72\x04\x61\x72\x70\x61\x00";
955
956        assert_eq!(res.as_slice(), ctrl);
957    }
958
959
960    #[tokio::test]
961    async fn test_byte2hexchar()
962    {
963        assert_eq!(byte2hexchar(1), 0x31);
964        assert_eq!(byte2hexchar(9), 0x39);
965        assert_eq!(byte2hexchar(10), 'a' as u8);
966        assert_eq!(byte2hexchar(15), 'f' as u8);
967    }
968
969
970    #[tokio::test]
971    async fn reverse_lookup_test()
972    {
973        use tokio::time::Instant;
974        
975        let cache = Arc::new(CachesController::new().await.unwrap());
976        
977        let ipp: IpAddr = "8.8.8.8".parse().unwrap();
978        //let test = QDnsName::from(&ipp);
979
980        let mut query_setup = QuerySetup::default();
981        query_setup.set_measure_time(true);
982
983        let now = Instant::now();
984
985        let mut dns_req = 
986            QDns::builtin_make_empty(None, query_setup, cache).await.unwrap();
987
988        dns_req.add_request(QType::PTR, ipp).unwrap();
989
990        let res = dns_req.query().await;
991
992        let elapsed = now.elapsed();
993        println!("Elapsed: {:.2?}", elapsed);
994
995        println!("{}", res);
996
997        assert_eq!(res.is_empty(), false);
998
999        let recs = res.collect_ok();
1000        let rec = &recs[0];
1001        //assert_eq!(rec.server.as_str(), "/etc/hosts");
1002        assert_eq!(rec.status, QDnsQueryRec::Ok);
1003
1004        assert_eq!(rec.resp.len(), 1);
1005        assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "dns.google".to_string() }));
1006    }
1007
1008    #[tokio::test]
1009    async fn reverse_lookup_hosts_test()
1010    {
1011        use tokio::time::Instant;
1012
1013        let cache = Arc::new(CachesController::new().await.unwrap());
1014
1015        let ipp: IpAddr = "127.0.0.1".parse().unwrap();
1016        //let test = QDnsName::from(&ipp);
1017        
1018        let now = Instant::now();
1019
1020        let mut query_setup = QuerySetup::default();
1021        query_setup.set_measure_time(true);
1022
1023        let mut dns_req = 
1024            QDns::builtin_make_empty(None, query_setup, cache).await.unwrap();
1025
1026        dns_req.add_request(QType::PTR, ipp).unwrap();
1027
1028        let res = dns_req.query().await;
1029        
1030        let elapsed = now.elapsed();
1031        println!("Elapsed: {:.2?}", elapsed);
1032
1033        println!("{}", res);
1034
1035        assert_eq!(res.is_empty(), false);
1036
1037        let recs = res.collect_ok();
1038        let rec = &recs[0];
1039
1040        assert_eq!(rec.server.as_str(), "/etc/hosts");
1041        assert_eq!(rec.status, QDnsQueryRec::Ok);
1042
1043        assert_eq!(rec.resp.len(), 1);
1044        assert_eq!(rec.resp[0].rdata, RecordPTR::wrap(RecordPTR{ fqdn: "localhost".to_string() }));
1045    }
1046
1047
1048    #[tokio::test]
1049    async fn reverse_lookup_a()
1050    {
1051        use tokio::time::Instant;
1052
1053       // let test = QDnsName::from("dns.google");
1054
1055        let cache = Arc::new(CachesController::new().await.unwrap());
1056
1057        let mut query_setup = QuerySetup::default();
1058        query_setup.set_measure_time(true);
1059
1060        
1061        let res = 
1062            QDns::buildin_make_a_aaaa_request(None, "dns.google", query_setup, cache).await.unwrap();
1063        
1064        
1065        let now = Instant::now();
1066        let res = res.query().await;
1067        
1068
1069        let elapsed = now.elapsed();
1070        println!("Elapsed: {:.2?}", elapsed);
1071
1072        println!("{}", res);
1073    }
1074
1075    #[tokio::test]
1076    async fn reverse_lookup_a_idn()
1077    {
1078        use std::time::Instant;
1079
1080        let cache = Arc::new(CachesController::new().await.unwrap());
1081
1082        let mut query_setup = QuerySetup::default();
1083        query_setup.set_measure_time(true);
1084
1085
1086
1087        let res = 
1088            QDns
1089                ::buildin_make_a_aaaa_request(None, "законипорядок.бел", query_setup, cache).await.unwrap();
1090        
1091        let now = Instant::now();
1092        let res = res.query().await;
1093        
1094
1095        let elapsed = now.elapsed();
1096        println!("Elapsed: {:.2?}", elapsed);
1097
1098    /*  assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
1099        
1100        let res = res.unwrap();*/
1101        println!("{}", res);
1102
1103        let ok: Vec<crate::QDnsQuery> = res.collect_ok();
1104        let name = ok[0].get_responses()[0].name.clone();
1105        let idn_name = ok[0].get_responses()[0].get_full_domain_name_with_idn_decode().unwrap();
1106
1107        println!("{} -> {}", name, idn_name);
1108        assert_eq!(name, "xn--80aihfjcshcbin9q.xn--90ais");
1109
1110        assert_eq!(idn_name, "законипорядок.бел");
1111    }
1112}