cdns_rs/
common.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 /*
17                                1  1  1  1  1  1
18  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
19+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
20                    | ID |
21+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
22|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
23+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
24                    | QDCOUNT |
25+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
26                    | ANCOUNT |
27+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
28                    | NSCOUNT |
29+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
30                    | ARCOUNT |
31+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
32
33                                1  1  1  1  1  1
34  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
35+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
36|                                               |
37/                       QNAME                   /
38/                                               /
39+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40|                       QTYPE                   |
41+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42|                       QCLASS                  |
43+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44
45*/
46
47/// This file contains the common structures and constants of DNS protocol and 
48/// other parts of the code. Also it contains a parser from/to network packet.
49
50use std::{borrow::Cow, cmp::Ordering, fmt::{self}, io::{Cursor, Read, Write}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, path::Path, sync::{LazyLock, OnceLock}, time::Duration};
51use std::borrow::Borrow;
52use std::hash::{Hash, Hasher};
53
54use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
55
56use crate::{cfg_host_parser::HostnameEntry, common, error::*, internal_error_map, query_private::QDnsReq};
57use crate::internal_error;
58
59/// A location on the disk where resolv.conf is located
60pub const RESOLV_CFG_PATH: &'static str = "/etc/resolv.conf";
61
62/// A hosts file location on disk
63pub const HOST_CFG_PATH: &'static str = "/etc/hosts";
64
65pub static RESOLV_CFG_PATH_P: LazyLock<&'static Path> = LazyLock::new(|| {Path::new(RESOLV_CFG_PATH)});
66pub static HOST_CFG_PATH_P: LazyLock<&'static Path> = LazyLock::new(|| {Path::new(HOST_CFG_PATH)});
67
68pub static GLOBALS: OnceLock<CDdnsGlobals> = OnceLock::new();
69
70/// A nsswitch location
71pub const NSSWITCH_CFG_PATH: &'static str = "/etc/nsswitch.conf";
72
73const IN_ADDR_ARPA: &[u8] = b"\x07in-addr\x04arpa\x00";
74const IN_ADDR6_ARPA: &[u8] = b"\x03ip6\x04arpa\x00";
75
76pub const DEF_USERAGENT: &'static str = concat!("CDNS-RS/", env!("CARGO_PKG_VERSION"));
77pub const DEF_TLS_PORT: u16 = 853;
78pub const DEF_HTTPS_PORT: u16 = 443;
79
80/// Default BIND for IPv4
81pub const IPV4_BIND_ALL: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
82/// Default BIND for IPv6
83pub const IPV6_BIND_ALL: IpAddr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
84
85#[derive(Debug)]
86pub struct CDdnsGlobals
87{
88     pub tcp_timeout: Option<Duration>,
89}
90
91impl CDdnsGlobals
92{
93    /// Many threads may call `init_once` concurrently with different initializing functions, 
94    /// but it is guaranteed that only one function will be executed.
95    pub 
96    fn init_once(globals: CDdnsGlobals)
97    {
98        GLOBALS.get_or_init(|| globals);
99
100        return;
101    }
102
103    pub 
104    fn get_tcp_conn_timeout() -> Option<Duration>
105    {
106        return GLOBALS.get().map_or(None, |f| f.tcp_timeout);
107    }
108}
109
110#[inline]
111pub 
112fn bind_all(ip_addr: IpAddr) -> SocketAddr
113{
114    match ip_addr
115    {
116        IpAddr::V4(_) => 
117            SocketAddr::from((IPV4_BIND_ALL, 0)),
118        IpAddr::V6(_) => 
119            SocketAddr::from((IPV6_BIND_ALL, 0)),
120    }
121}
122
123pub 
124fn pkt2string_exact(pkt: &mut Cursor<&[u8]>, rdlen: u16) -> CDnsResult<String>
125{
126    let mut new_string = vec![0_u8; rdlen as usize];
127
128    
129    pkt.read_exact(&mut new_string).map_err(map_read_err)?;
130
131
132    return 
133        String::from_utf8(new_string)
134            .map_err(|e| 
135                internal_error_map!(CDnsErrorType::InternalError, "UTF-8 decode error, {}", e)
136            );
137}
138
139pub 
140fn pkt2vec(pkt: &mut Cursor<&[u8]>, rdlen: Option<u16>) -> CDnsResult<Vec<u8>>
141{
142    if let Some(rdl) = rdlen
143    {
144        let mut new_buf = vec![0_u8; rdl as usize];
145
146        
147        pkt.read_exact(&mut new_buf).map_err(map_read_err)?;
148
149
150        return Ok(new_buf);
151    }
152    else
153    {
154        let mut new_buf = Vec::new();
155
156        pkt.read_to_end(&mut new_buf).map_err(map_read_err)?;
157
158        return Ok(new_buf);
159    }
160}
161
162/// Verifies the sequence of labels coding and copies data from pkt to
163/// buffer.
164/// 
165/// # Arguments
166/// 
167/// * `pkt` - a reference to the [Cursor]
168/// 
169/// # Returns 
170/// 
171/// * [CDnsResult] with data copied to new [Vec][u8]
172pub 
173fn pkt2name(pkt: &mut Cursor<&[u8]>) -> CDnsResult<Vec<u8>>
174{
175    let qname_s = pkt.position() as usize;
176
177    //let mut doms: Vec<String> = Vec::with_capacity(3);
178
179    loop
180    {
181        let cnt = pkt.read_u8().map_err(map_read_err)? as usize;
182
183        
184
185        if cnt == 0
186        {
187            break;
188        }
189        else
190        {
191            /*let mut dname: Vec<u8> = vec![0_u8; cnt];
192            
193            pkt.read_exact(&mut dname);
194
195            let dn = 
196                String::from_utf8(dname)
197                    .map_err(|e|
198                        internal_error_map!(
199                            CDnsErrorType::DnsResponse, 
200                            "invalid UTF-8 sequence, pkt pos: '{}', err: '{}'",
201                            pkt.position(), e
202                        )
203                    )?;
204
205            if dn.starts_with("xn-") == true
206            {
207                let decoded_dn = rust_punycode::decode(&dn)?;
208
209                doms.p
210            }
211            else
212            {
213
214            }
215*/
216            for _ in 0..cnt
217            {
218                let c = pkt.read_u8().map_err(map_read_err)?;
219                if c == 0
220                {
221                    internal_error!(
222                        CDnsErrorType::DnsResponse, 
223                        "incorrectly encoded QNAME in response, found '0' at offset: '{}'",
224                        pkt.position()
225                    );
226                }
227            }
228        }
229    } // loop
230
231    // temporary store the position of the cursor
232    let cur_pos = pkt.position() as usize;
233
234    if (cur_pos - qname_s) <= 1
235    {
236        internal_error!(
237            CDnsErrorType::DnsResponse, 
238            "read name is too short"
239        );
240    }
241
242    /*pkt.set_position(qname_s);
243    
244    // creating buffer for QNAME
245    let mut req: Vec<u8> = vec![0_u8; (cur_pos - qname_s) as usize];
246    pkt.read_exact(&mut req).map_err(map_read_err)?;
247
248    // restore position
249    pkt.set_position(cur_pos);*/
250    
251
252    return Ok(pkt.get_ref()[qname_s..cur_pos].to_vec());
253}
254
255
256/// This function converts a QNAME (encoded domains) to the String FQDN.
257pub 
258fn name2str(pkt: &mut Cursor<&[u8]>, mut opt_rdlen: Option<u16>) -> CDnsResult<String>
259{
260    let cur_in_pos = pkt.position();
261    //let mut p_comp: u8 = 0;
262    let mut comp: u8;
263    let mut output: Vec<String> = Vec::with_capacity(6);
264
265    loop
266    {
267        if let Some(rdlen) = opt_rdlen
268        {
269            if pkt.position() - cur_in_pos >= rdlen as u64
270            {
271                return Ok(output.join("."));
272            }
273        }
274
275        // reading word from pkt to detect the type of message
276       // p_comp = comp;
277        comp = pkt.read_u8().map_err(map_read_err)?;
278
279        /*if p_comp > 0 && comp > 0
280        {
281            output.push('.');
282        }*/
283
284        let msb = comp & 0xC0;
285
286        if msb == 0xC0
287        {
288            if opt_rdlen.is_none() == true
289            {
290                opt_rdlen = Some(2);
291            }
292
293            let offset1: u16 = ((comp & !0xC0) as u16) << 8;// | pkt.read_u8().map_err(map_read_err)? as u16;
294            let offset2: u16 = pkt.read_u8().map_err(map_read_err)? as u16;
295
296            let offset = offset1 | offset2;
297
298            //println!("debug: 1: {} 2: {} offset: {}", offset1, offset2, offset);
299
300            // C0 0...
301            if offset as usize >= pkt.get_ref().len()
302            {
303                internal_error!(
304                    CDnsErrorType::DnsResponse, 
305                    "incoreclty formated packet: offset: '{}' > len: '{}'", 
306                    offset, pkt.get_ref().len()
307                );
308            }
309
310            // save current cursor position
311            let cur_pos = pkt.position();
312            pkt.set_position(offset as u64);
313
314            // converting the name to FQDN
315            output.push(name2str(pkt, None)?);
316
317            // restoring cursor positon
318            pkt.set_position(cur_pos);
319        }
320        else if msb == 0x00 
321        {
322            if comp == 0
323            {
324                if let Some(rdlen) = opt_rdlen
325                {
326                    let dif = pkt.position() - cur_in_pos;
327
328                    if rdlen as u64 != dif
329                    {
330                        internal_error!(CDnsErrorType::DnsResponse, "incorrect rdlen: '{}', exp: '{}'", rdlen, dif);
331                    }
332                }
333
334                return Ok(output.join("."));
335            }
336            else
337            {
338                let mut tmp = String::with_capacity(comp as usize);
339
340                for _ in 0..comp
341                {
342                    let Some(c) = char::from_u32( pkt.read_u8().map_err(map_read_err)? as u32 )
343                        else
344                        {
345                            internal_error!(CDnsErrorType::DnsResponse, "protocol violation, invalid character received");
346                        };
347
348                    if c.is_ascii_alphanumeric() == false && c != '-'
349                    {
350                        internal_error!(CDnsErrorType::DnsResponse, "protocol violation, forbidden characters in QNAME response");
351                    }
352
353                    tmp.push(c);
354                }
355
356                output.push(tmp);
357            }
358        }
359        else
360        {
361            internal_error!(CDnsErrorType::DnsResponse, "incorrect compression: {:x}", msb);
362        }
363
364    } // loop
365}
366
367
368/// Converts a part of the octec of IP to printable hex i.e valid range is from
369/// 0 up to 15 will be converted to 0x30..0x39 and 'a'..'f'.
370/// 
371/// # Arguments
372/// 
373/// * `b` - a part of the octec
374/// 
375/// # Returns
376/// 
377/// * u8 an ASCII representation
378/// 
379/// # Throws
380/// 
381/// Panic when input b >= 16
382pub 
383fn byte2hexchar(b: u8) -> u8
384{
385    match b
386    {
387        0..=9 => return '0' as u8 + b,
388        10..=15 => return 'a' as u8 + (b - 10),
389        _ => panic!("out of hex range!")
390    }
391}
392
393/// Converts [IpAddr] to sequence of bytes coded specially for the payload
394/// of package.
395/// 
396/// # Arguments
397/// 
398/// * `ip` - the argument with IP address
399/// 
400/// # Returns
401/// 
402/// * [Vec] is returned with encoded data
403pub 
404fn ip2pkt(ip: &IpAddr) -> Vec<u8>
405{    
406    match *ip
407    {
408        IpAddr::V4(ref ipv4) =>
409            return ipv4_pkt(ipv4),
410        IpAddr::V6(ref ipv6) =>
411            return ipv6_pkt(ipv6)
412    };
413}
414
415const MAX_NAME_LEN: usize = 63;
416
417pub 
418fn ipv4_pkt(ip: &Ipv4Addr) -> Vec<u8>
419{    
420
421    // pre allocate space
422    let mut out: Vec<u8> = Vec::with_capacity(16 + IN_ADDR_ARPA.len());
423
424    ip
425        .octets()
426        .into_iter()
427        .rev()
428        .for_each(|v|
429            {
430                let st = v.to_string();
431                out.push(st.len() as u8);
432                out.extend(st.as_bytes());
433            }
434        );
435
436    out.extend_from_slice(IN_ADDR_ARPA);
437
438    return out;
439}
440
441pub 
442fn ipv6_pkt(ip: &Ipv6Addr) -> Vec<u8>
443{    
444    // pre allocate space
445    let mut out: Vec<u8> = Vec::with_capacity(32 + IN_ADDR6_ARPA.len());
446    
447    let mut octets = ip.octets();
448    octets.reverse();
449
450    for oct in octets
451    {
452        let h_oct = byte2hexchar((oct & 0xF0) >> 4);
453        //format!("{:x}", (oct & 0xF0) >> 4);
454        let l_oct = byte2hexchar(oct & 0x0F);
455        //format!("{:x}", oct & 0x0F);
456
457        //let ln: u8 = str_oct.len() as u8;
458
459        out.push(1);
460        out.push(l_oct);
461        //out.extend(l_oct.as_bytes());
462        out.push(1);
463        out.push(h_oct);
464    }
465
466    out.extend(IN_ADDR6_ARPA);
467
468    return out;
469}
470
471 
472#[cfg(feature = "enable_IDN_support")]
473pub mod with_punycode
474{
475    use crate::external::rust_punycode;
476
477    use super::*;
478    
479    pub 
480    fn name2pkt(name: &str) -> CDnsResult<Vec<u8>>
481    {    
482        // pre allocate space
483        let mut out: Vec<u8> = Vec::with_capacity(MAX_NAME_LEN);
484
485        for n in name.split(".")
486        {
487            let dom = 
488                if n.chars().any(|c| c.is_ascii() == false) == true
489                {
490                    rust_punycode::encode(n, true)?
491                }
492                else
493                {
494                    n.to_string()
495                };
496
497            common::check_domain_ascii(&dom)?;
498
499
500            out.push((dom.len() & 0xFF) as u8);
501            out.extend(dom.as_bytes());
502        }
503
504        out.push(0);
505
506        if out.len() > 255
507        {
508            internal_error!(CDnsErrorType::InternalError, 
509                    "DNS name '{}' too long: {}", sanitize_str_unicode(name), out.len());
510        }
511
512        return Ok(out);
513    }
514}
515
516#[cfg(feature = "enable_IDN_support")]
517pub use self::with_punycode::*;
518
519
520#[cfg(not(feature = "enable_IDN_support"))]
521pub mod with_punycode
522{
523    use super::*;
524
525    pub 
526    fn name2pkt(name: &str) -> CDnsResult<Vec<u8>>
527    {    
528        // pre allocate space
529        let mut out: Vec<u8> = Vec::with_capacity(MAX_NAME_LEN);
530
531        for n in name.split(".")
532        {
533            let dom = 
534                if n.chars().any(|c| c.is_ascii() == false) == true
535                {
536                    internal_error!(CDnsErrorType::InternalError, 
537                        "DNS name '{}' contains non-ascii charactes, the IDN is disbaled", 
538                        sanitize_str_unicode(name));
539                }
540                else
541                {
542                    n.to_string()
543                };
544
545            common::check_domain_ascii(&dom)?;
546
547
548            out.push((dom.len() & 0xFF) as u8);
549            out.extend(dom.as_bytes());
550        }
551
552        out.push(0);
553
554        if out.len() > 255
555        {
556            internal_error!(CDnsErrorType::InternalError, 
557                    "DNS name '{}' too long: {}", sanitize_str_unicode(name), out.len());
558        }
559
560        return Ok(out);
561    }
562}
563
564#[cfg(not(feature = "enable_IDN_support"))]
565pub use self::with_punycode::*;
566
567
568
569
570/// A two octet code which specifies the type of the query.
571/// TYPE fields are used in resource records.  Note that these types are a
572/// subset of QTYPEs.
573/// QTYPE fields appear in the question part of a query.  QTYPES are a
574/// superset of TYPEs, hence all TYPEs are valid QTYPEs.
575#[repr(u16)]
576#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
577pub enum QType
578{
579    /// 1 a host address
580    A = 1,
581    /// 2 an authoritative name server
582    NS = 2,
583    /// 3 a mail destination (Obsolete - use MX)
584    MD = 3,
585    /// 4 a mail forwarder (Obsolete - use MX)
586    MF = 4,
587    /// 5 the canonical name for an alias
588    CNAME = 5,
589    /// 6 marks the start of a zone of authority
590    SOA = 6,
591    /// 7 a mailbox domain name (EXPERIMENTAL)
592    MB = 7,
593    /// 8 a mail group member (EXPERIMENTAL)
594    MG = 8,
595    /// 9 a mail rename domain name (EXPERIMENTAL)
596    MR = 9,
597    /// 10 a null RR (EXPERIMENTAL)
598    NULL = 10,
599    /// 11 a well known service description
600    WKS = 11,
601    /// 12 a domain name pointer
602    PTR = 12,
603    /// 13 host information
604    HINFO = 13,
605    /// 14 mailbox or mail list information
606    MINFO = 14,
607    /// 15 mail exchange
608    MX = 15,
609    /// 16 text strings
610    TXT = 16,
611    /// 18 AFS database record 
612    AFSDB = 18,
613    /// 25 Key record
614    KEY = 25,
615    /// 28 IPv6 address record
616    AAAA = 28,
617    /// 33 Service record
618    SRV = 33,
619    /// 37 Certificate records
620    CERT = 37,
621    /// 43 Delegation signer
622    DS = 43,
623    /// 46 DNSSEC signature
624    RRSIG = 46,
625    /// 47 Next Secure record
626    NSEC = 47,
627    /// DNS Key record
628    DNSKEY = 48,
629    /// 50 Next Secure record version 3
630    NSEC3 = 50,
631    /// 51 NSEC3 parameters
632    NSEC3PARAM = 51,
633    /// 59 Child DS 
634    CDS = 59,
635    /// 60 Child copy of DNSKEY record, for transfer to parent
636    CDNSKEY = 60,
637    /// OpenPGP public key record 
638    OPENPGPKEY = 61,
639    // ---- QTYPE ----
640    /// 252 A request for a transfer of an entire zone
641    AXFR = 252,
642    /// 253 A request for mailbox-related records (MB, MG or MR)
643    MAILB = 253,
644    /// 254 A request for mail agent RRs (Obsolete - see MX)
645    MAILA = 254,
646    /// 256 Uniform Resource Identifier RFC 7553
647    URI = 256,
648    /// 257 Certification Authority Authorization 
649    CAA = 257,
650    /// *
651    ALL = 255,
652    /// 32769 DNSSEC Lookaside Validation record
653    DLV = 32769,
654}
655
656impl Default for QType
657{
658    fn default() -> Self 
659    {
660        return Self::A;    
661    }
662}
663
664
665impl Into<u16> for QType
666{
667    fn into(self) -> u16 
668    {
669        return self as u16;
670    }
671}
672
673impl fmt::Display for QType
674{
675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
676    {
677        match *self
678        {
679            Self::A          => write!(f, "A"),
680            Self::NS         => write!(f, "NS"),
681            Self::MD         => write!(f, "MD"),
682            Self::MF         => write!(f, "MF"),
683            Self::CNAME      => write!(f, "CNAME"),
684            Self::SOA        => write!(f, "SOA"),
685            Self::MB         => write!(f, "MB"),
686            Self::MG         => write!(f, "MG"),
687            Self::MR         => write!(f, "MR"),
688            Self::NULL       => write!(f, "NULL"),
689            Self::WKS        => write!(f, "WKS"),
690            Self::PTR        => write!(f, "PTR"),
691            Self::HINFO      => write!(f, "HINFO"),
692            Self::MINFO      => write!(f, "MINFO"),
693            Self::MX         => write!(f, "MX"),
694            Self::TXT        => write!(f, "TXT"),
695            Self::AFSDB      => write!(f, "AFSDB"),
696            Self::KEY        => write!(f, "KEY"),
697            Self::AAAA       => write!(f, "AAAA"),
698            Self::SRV        => write!(f, "SRV"),
699            Self::CERT       => write!(f, "CERT"),
700            Self::DS         => write!(f, "DS"),
701            Self::RRSIG      => write!(f, "RRSIG"),
702            Self::NSEC       => write!(f, "NSEC"),
703            Self::DNSKEY     => write!(f, "DNSKEY"),
704            Self::NSEC3      => write!(f, "NSEC"),
705            Self::NSEC3PARAM => write!(f, "NSEC3PARAM"),
706            Self::CDS        => write!(f, "CDS"),
707            Self::CDNSKEY    => write!(f, "CDNSKEY"),
708            Self::OPENPGPKEY => write!(f, "OPENPGPKEY"),
709            Self::AXFR       => write!(f, "AXFR"),
710            Self::MAILB      => write!(f, "MAILB"),
711            Self::MAILA      => write!(f, "MAILA"),
712            Self::CAA        => write!(f, "CAA"),
713            Self::ALL        => write!(f, "ALL"),
714            Self::DLV        => write!(f, "DLV"),
715            Self::URI        => write!(f, "URI"),
716        }
717    }
718}
719
720
721impl QType
722{
723    pub 
724    fn ipaddr_match(&self, ip: &IpAddr) -> bool
725    {
726        match *self
727        {
728            Self::A => return ip.is_ipv4(),
729            Self::AAAA => return ip.is_ipv6(),
730            _ => false,
731        }
732    }
733
734    pub 
735    fn u16_to_qtype(value: u16) -> CDnsResult<QType>
736    {
737        match value
738        {
739            x if x == Self::AXFR as u16    => return Ok(Self::AXFR),
740            x if x == Self::MAILB as u16   => return Ok(Self::MAILB),
741            x if x == Self::MAILA as u16   => return Ok(Self::MAILA),
742            x if x == Self::ALL as u16     => return Ok(Self::ALL),
743            x if x == Self::DLV as u16     => return Ok(Self::DLV),
744            _ => return Self::u16_to_type(value),
745        }
746    }
747
748    pub 
749    fn u16_to_type(value: u16) -> CDnsResult<QType>
750    {
751
752        match value
753        {
754            x if x == Self::A as u16            => return Ok(Self::A),
755            x if x == Self::NS as u16           => return Ok(Self::NS),
756            x if x == Self::MD as u16           => return Ok(Self::MD),
757            x if x == Self::MF as u16           => return Ok(Self::MF),
758            x if x == Self::CNAME as u16        => return Ok(Self::CNAME),
759            x if x == Self::SOA as u16          => return Ok(Self::SOA),
760            x if x == Self::MB as u16           => return Ok(Self::MB),
761            x if x == Self::MG as u16           => return Ok(Self::MG),
762            x if x == Self::MR as u16           => return Ok(Self::MR),
763            x if x == Self::NULL as u16         => return Ok(Self::NULL),
764            x if x == Self::WKS as u16          => return Ok(Self::WKS),
765            x if x == Self::PTR as u16          => return Ok(Self::PTR),
766            x if x == Self::HINFO as u16        => return Ok(Self::HINFO),
767            x if x == Self::MINFO as u16        => return Ok(Self::MINFO),
768            x if x == Self::MX as u16           => return Ok(Self::MX),
769            x if x == Self::TXT as u16          => return Ok(Self::TXT),
770            x if x == Self::AFSDB as u16        => return Ok(Self::AFSDB),
771            x if x == Self::KEY as u16          => return Ok(Self::KEY),
772            x if x == Self::AAAA as u16         => return Ok(Self::AAAA),
773            x if x == Self::CERT as u16         => return Ok(Self::CERT),
774            x if x == Self::DS as u16           => return Ok(Self::DS),
775            x if x == Self::RRSIG as u16        => return Ok(Self::RRSIG),
776            x if x == Self::NSEC as u16         => return Ok(Self::NSEC),
777            x if x == Self::DNSKEY as u16       => return Ok(Self::DNSKEY),
778            x if x == Self::NSEC3 as u16        => return Ok(Self::NSEC3),
779            x if x == Self::NSEC3PARAM as u16   => return Ok(Self::NSEC3PARAM),
780            x if x == Self::CDS as u16          => return Ok(Self::CDS),
781            x if x == Self::CDNSKEY as u16      => return Ok(Self::CDNSKEY),
782            x if x == Self::OPENPGPKEY as u16   => return Ok(Self::OPENPGPKEY),
783            _ => internal_error!(CDnsErrorType::DnsResponse, "unknown request record type: '{}'", value),
784        }
785    }
786}
787
788
789/// A two octet code that specifies the class of the query.
790/// 
791/// 
792#[repr(u16)]
793#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
794pub enum QClass
795{
796    /// the Internet 1
797    IN = 1,
798    /// the CSNET class (Obsolete) 2
799    CS = 2,
800    /// the CHAOS class 3
801    CH = 3,
802    /// Hesiod [Dyer 87] 4
803    HS = 4,
804    
805    //  --- QClass
806    /// any class 255
807    ALL = 255,
808}
809
810impl fmt::Display for QClass
811{
812    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
813    {
814        match *self
815        {
816            Self::IN  => write!(f, "IN"),
817            Self::CS  => write!(f, "CS"),
818            Self::CH  => write!(f, "CH"),
819            Self::HS  => write!(f, "HS"),
820            Self::ALL => write!(f, "ALL"),
821        }
822    }
823}
824
825impl Default for QClass
826{
827    fn default() -> Self 
828    {
829        return Self::IN;    
830    }
831}
832
833impl Into<u16> for QClass
834{
835    fn into(self) -> u16 
836    {
837        return self as u16;
838    }
839}
840
841impl QClass
842{
843    /// Converts u16 to enum [QClass].
844    /// 
845    /// QCLASS fields appear in the question part of a query.  QCLASS are a
846    /// superset of CLASSes, hence all CLASSes are valid QCLASSes.
847    pub 
848    fn u16_to_qclass(value: u16) -> CDnsResult<QClass>
849    {
850        match value
851        {
852            x if x == QClass::ALL as u16 => return Ok(QClass::ALL),
853            _ => Self::u16_to_class(value),
854        }
855    }
856
857    /// Converts u16 to enum [QClass], but for the response part of a query.
858    pub 
859    fn u16_to_class(value: u16) -> CDnsResult<QClass>
860    {
861        match value
862        {
863            x if x == QClass::IN as u16 => return Ok(QClass::IN),
864            x if x == QClass::CS as u16 => return Ok(QClass::CS),
865            x if x == QClass::CH as u16 => return Ok(QClass::CH),
866            x if x == QClass::HS as u16 => return Ok(QClass::HS),
867            _ => internal_error!(CDnsErrorType::DnsResponse, "unknown QCLASS type: '{}'", value),
868        }
869    }
870}
871
872// (req.status & !StatusBits::OPCODE_STANDARD) | ...
873// () 
874
875bitflags! {     
876    /// Flags  which control the status of th DNS query    
877    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] 
878    pub struct StatusBits: u16  
879    {     
880        // Pkt type Request/Result R/W    
881        /// A request/response bit, when 1 - response
882        const QR_RESP           = 0x8000;
883
884        // Request Type (Write only)
885        /// a standard query (QUERY) USE inverse to reset
886        const OPCODE_STANDARD   = 0x87FF;
887        /// an inverse query (IQUERY)
888        const OPCODE_IQUERY     = 0x0040;
889        /// a server status request (STATUS)
890        const OPCODE_STATUS     = 0x0020;
891        // reserved for future use 3-15
892        // 0x4000 .. 0x0800
893
894        /// AA  Authoritative Answer (Read only)
895        /// Authoritative Answer - this bit is valid in responses,
896        /// and specifies that the responding name server is an
897        /// authority for the domain name in question section.
898        const AUTH_ANSWER       = 0x0400;
899
900        /// TrunCation (Read only)
901        /// TrunCation - specifies that this message was truncated
902        /// due to length greater than that permitted on the transmission channel.
903        const TRUN_CATION       = 0x0200;
904
905        /// RD Recursion desired (write only)
906        /// Recursion Desired - this bit may be set in a query and
907        /// is copied into the response.  If RD is set, it directs
908        /// the name server to pursue the query recursively.
909        /// Recursive query support is optional.
910        const RECURSION_DESIRED = 0x0100;
911
912        /// RA Recursion available (read only)
913        /// Recursion Available - this be is set or cleared in a
914        /// response, and denotes whether recursive query support is
915        /// available in the name server.
916        const RECURSION_AVAIL   = 0x0080;
917
918        /// Z Zero reserver
919        /// Reserved for future use.  Must be zero in all queries
920        /// and responses.
921        const RSERVER0          = 0x0040; 
922
923        const ANSWER_AUTHN      = 0x0020; 
924        const NON_AUTH_DATA     = 0x0010; 
925
926        // RCODE response code 
927
928        /// No error condition
929        const RESP_NOERROR      = 0x0000; 
930        /// Format error - The name server was unable to interpret the query.
931        const RESP_FORMERR      = 0x0001; 
932        /// Server failure - The name server was unable to process this query due to a
933        /// problem with the name server.
934        const RESP_SERVFAIL     = 0x0002; 
935        /// Name Error - Meaningful only for responses from an authoritative name
936        /// server, this code signifies that the domain name referenced in the query does
937        /// not exist.
938        const RESP_NXDOMAIN     = 0x0003;
939        /// Not Implemented - The name server does not support the requested kind of query.
940        const RESP_NOT_IMPL     = 0x0004; 
941        /// Refused - The name server refuses to perform the specified operation for
942        /// policy reasons.
943        const RESP_REFUSED      = 0x0005; 
944        // ..= 0x000F
945    }
946}
947
948/// An structure for the target in request.
949/// Implements From for [IpAddr], [Ipv4Addr], [Ipv6Addr], [str]
950/// In case if IP address is in the human readable 'string' format
951/// it will be stored as Name. And later the code will try to convert it
952/// to IP address before returing as string.
953#[derive(Clone, Debug, PartialEq, Eq)]
954pub enum QDnsName
955{
956    IpV4
957    {
958        query: Ipv4Addr,
959        encoded: Vec<u8>
960    },
961    IpV6
962    {
963        query: Ipv6Addr,
964        encoded: Vec<u8>
965    },
966    Name
967    {
968        query: String,
969        encoded: Vec<u8>
970    },
971}
972
973impl PartialEq<&[u8]> for QDnsName
974{
975    fn eq(&self, other: &&[u8]) -> bool 
976    {
977        match self
978        {
979            Self::IpV4{ encoded, .. } | 
980            Self::IpV6{ encoded, .. } | 
981            Self::Name{ encoded, .. } => 
982                return encoded.as_slice() == *other
983        }
984    }
985}
986
987impl Default for QDnsName
988{
989    fn default() -> Self 
990    {
991        let def = Ipv4Addr::new(0, 0, 0, 0);
992
993        return 
994            Self::IpV4 
995            { 
996                query: def, 
997                encoded: ipv4_pkt(&def)
998            };
999    }
1000}
1001
1002impl fmt::Display for QDnsName
1003{
1004    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1005    {
1006        match self
1007        {
1008            Self::IpV4 { query, .. } =>
1009                write!(f, "{}", query),
1010            Self::IpV6 { query, .. } =>
1011                write!(f, "{}", query),
1012            Self::Name { query, .. } => 
1013                write!(f, "{}", query)
1014        }
1015    }
1016}
1017
1018impl QDnsName
1019{
1020    /// Answers if current type is IpV4.
1021    /// But does not performs check if Name is an IP in str format
1022    pub
1023    fn is_ipv4(&self) -> bool
1024    {
1025        let Self::IpV4 { .. } = self
1026            else { return false };
1027
1028        return true;
1029    }
1030
1031    /// Answers if current type is IpV6.
1032    /// But does not performs check if Name is an IP in str format
1033    pub 
1034    fn is_ipv6(&self) -> bool
1035    {
1036        let Self::IpV6 { .. } = self
1037            else { return false };
1038
1039        return true;
1040    }
1041
1042    /// Answers if current type is IpV4 or IpV6.
1043    /// But does not performs check if Name is an IP in str format
1044    pub 
1045    fn is_ip(&self) -> bool
1046    {
1047        match *self
1048        {
1049            Self::IpV4{ .. } => return true,
1050            Self::IpV6{ .. } => return true,
1051            _ => return false,
1052        }
1053    }
1054
1055    /// Returns the type of the IP address version in [QType] format.
1056    pub 
1057    fn get_ip_qtype(&self) -> Option<QType>
1058    {
1059        match *self
1060        {
1061            Self::IpV4{ .. } => return Some(QType::A),
1062            Self::IpV6{ .. } => return Some(QType::AAAA),
1063            Self::Name{ .. } => return None,
1064        }
1065    }
1066
1067    pub 
1068    fn get_encoded_len(&self) -> usize
1069    {
1070        match self
1071        {
1072            Self::IpV4{ encoded, .. } | 
1073            Self::IpV6{ encoded, .. } | 
1074            Self::Name{ encoded, .. } => 
1075                return encoded.len()
1076        }
1077    }
1078}
1079
1080impl Hash for QDnsName
1081{
1082    fn hash<H: Hasher>(&self, state: &mut H) 
1083    {
1084        core::mem::discriminant(self).hash(state);
1085
1086        match self
1087        {
1088            Self::IpV4{ query, .. } => 
1089                query.hash(state),
1090            Self::IpV6{ query, .. } => 
1091                query.hash(state),
1092            Self::Name{ query, .. } => 
1093                 query.hash(state),
1094        }
1095    }
1096}
1097
1098impl PartialEq<str> for QDnsName
1099{
1100    fn eq(&self, other: &str) -> bool 
1101    {
1102        match *self
1103        {
1104            Self::Name{ ref query, .. } =>
1105                return query.as_str() == other,
1106            Self::IpV4{ ref query, .. } =>
1107            {
1108                if let Ok(other_ip) = other.parse::<Ipv4Addr>()
1109                {   
1110                    return &other_ip == query;
1111                }
1112                
1113                return false;
1114            },
1115            Self::IpV6{ ref query, .. } =>
1116            {
1117                if let Ok(other_ip) = other.parse::<Ipv6Addr>()
1118                {
1119                    return &other_ip == query;
1120                }
1121
1122                return false;
1123            }
1124        }
1125    }
1126}
1127
1128
1129impl TryFrom<&IpAddr> for QDnsName
1130{
1131    type Error = CDnsError;
1132
1133    fn try_from(ip: &IpAddr) -> Result<Self, Self::Error> 
1134    {
1135        let encoded = ip2pkt(ip);
1136
1137        match *ip
1138        {
1139            IpAddr::V4(ref ip) => 
1140                return Ok( Self::IpV4{ query: ip.clone(), encoded: encoded } ),
1141            IpAddr::V6(ref ip) => 
1142                return Ok( Self::IpV6{ query: ip.clone(), encoded: encoded } ),
1143        }
1144    }
1145}
1146
1147
1148impl TryFrom<IpAddr> for QDnsName
1149{
1150    type Error = CDnsError;
1151
1152    fn try_from(ip: IpAddr) -> Result<Self, Self::Error> 
1153    {
1154        return Self::try_from(&ip);
1155    }
1156}
1157
1158
1159impl TryFrom<&Ipv4Addr> for QDnsName
1160{
1161    type Error = CDnsError;
1162
1163    fn try_from(ip: &Ipv4Addr) -> Result<Self, Self::Error> 
1164    {
1165        return Ok(Self::IpV4{ query: ip.clone(), encoded: ipv4_pkt(ip) });
1166    }
1167}
1168
1169impl TryFrom<Ipv4Addr> for QDnsName
1170{
1171    type Error = CDnsError;
1172
1173    fn try_from(ip: Ipv4Addr) -> Result<Self, Self::Error> 
1174    {
1175        return Self::try_from(&ip);
1176    }
1177}
1178
1179impl TryFrom<&Ipv6Addr> for QDnsName
1180{
1181    type Error = CDnsError;
1182
1183    fn try_from(ip: &Ipv6Addr) -> Result<Self, Self::Error> 
1184    {
1185        return Ok( Self::IpV6{ query: ip.clone(), encoded: ipv6_pkt(ip) } );
1186    }
1187}
1188
1189impl TryFrom<Ipv6Addr> for QDnsName
1190{
1191    type Error = CDnsError;
1192
1193    fn try_from(ip: Ipv6Addr) -> Result<Self, Self::Error> 
1194    {
1195        return Self::try_from(&ip);
1196    }
1197}
1198
1199impl TryFrom<&str> for QDnsName
1200{
1201    type Error = CDnsError;
1202
1203    fn try_from(name: &str) -> Result<Self, Self::Error> 
1204    {
1205        return Self::try_from(name.to_string());
1206    }
1207}
1208
1209impl TryFrom<String> for QDnsName
1210{
1211    type Error = CDnsError;
1212
1213    fn try_from(name: String) -> Result<Self, Self::Error> 
1214    {
1215        let Ok(ipp) = name.parse::<IpAddr>()
1216            else
1217            {
1218                let enc_name = name2pkt(&name)?;
1219
1220                return Ok( Self::Name{ query: name, encoded: enc_name} );
1221            };
1222
1223        return QDnsName::try_from(ipp);
1224    }
1225}
1226
1227impl From<QDnsName> for Vec<u8>
1228{
1229    fn from(qns: QDnsName) -> Self
1230    {
1231        match qns
1232        {
1233            QDnsName::IpV4{ encoded, .. } | 
1234            QDnsName::IpV6{ encoded, .. } | 
1235            QDnsName::Name{ encoded, .. } => 
1236                return encoded
1237        }
1238    }
1239}
1240
1241impl<'t> From<&'t QDnsName> for &'t [u8]
1242{
1243    fn from(qns: &'t QDnsName) -> Self
1244    {
1245        match qns
1246        {
1247            QDnsName::IpV4{ encoded, .. } | 
1248            QDnsName::IpV6{ encoded, .. } | 
1249            QDnsName::Name{ encoded, .. } => 
1250                return encoded.as_slice()
1251        }
1252    }
1253}
1254
1255impl<'t> From<&'t QDnsName> for Cow<'t, [u8]>
1256{
1257    fn from(qns: &'t QDnsName) -> Self
1258    {
1259        match qns
1260        {
1261            QDnsName::IpV4{ encoded, .. } | 
1262            QDnsName::IpV6{ encoded, .. } | 
1263            QDnsName::Name{ encoded, .. } => 
1264                return Cow::Borrowed(encoded.as_slice())
1265        }
1266    }
1267}
1268
1269
1270
1271impl From<&QDnsName> for String
1272{
1273    fn from(dnsname: &QDnsName) -> Self 
1274    {
1275        match *dnsname
1276        {
1277            QDnsName::IpV4{ ref query, .. } => 
1278            {
1279                return query.to_string();
1280            },
1281            QDnsName::IpV6{ ref query, .. } => 
1282            {
1283                return query.to_string();
1284            },
1285            QDnsName::Name{ ref query, .. } => 
1286            {
1287                return query.to_string();
1288            }
1289        }
1290    }
1291}
1292
1293
1294impl TryFrom<&QDnsName> for IpAddr
1295{
1296    type Error = CDnsError;
1297    fn try_from(value: &QDnsName) -> Result<Self, Self::Error> 
1298    {
1299        match value
1300        {
1301            QDnsName::IpV4{ query, .. } => 
1302            {
1303                return Ok(IpAddr::V4(query.clone()));
1304            },
1305            QDnsName::IpV6{ query, .. } => 
1306            {
1307                return Ok(IpAddr::V6(query.clone()));
1308            },
1309            QDnsName::Name{ query, .. } =>
1310            {
1311                if let Ok(ip) = query.parse::<Ipv4Addr>()
1312                {   
1313                    return Ok(IpAddr::V4(ip.clone()));
1314                }
1315                else if let Ok(ip) = query.parse::<Ipv6Addr>()
1316                {
1317                    return Ok(IpAddr::V6(ip.clone()));
1318                }
1319                else
1320                {
1321                    internal_error!(CDnsErrorType::InternalError, "not ip address!")
1322                }
1323            }
1324        }
1325    }
1326}
1327
1328
1329impl TryFrom<QDnsName> for IpAddr
1330{
1331    type Error = CDnsError;
1332    fn try_from(value: QDnsName) -> Result<Self, Self::Error> 
1333    {
1334        match value
1335        {
1336            QDnsName::IpV4{ query, .. } => 
1337            {
1338                return Ok(IpAddr::V4(query));
1339            },
1340            QDnsName::IpV6{ query, .. } => 
1341            {
1342                return Ok(IpAddr::V6(query));
1343            },
1344            QDnsName::Name{ query, .. } => 
1345            {
1346                if let Ok(ip) = query.parse::<Ipv4Addr>()
1347                {   
1348                    return Ok(IpAddr::V4(ip));
1349                }
1350                else if let Ok(ip) = query.parse::<Ipv6Addr>()
1351                {
1352                    return Ok(IpAddr::V6(ip));
1353                }
1354                else
1355                {
1356                    internal_error!(CDnsErrorType::InternalError, "not ip address!")
1357                }
1358            }
1359        }
1360    }
1361}
1362
1363#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1364pub struct DnsHeader
1365{
1366    /// A 16 bit identifier assigned by the program that
1367    /// generates any kind of query.
1368    pub id: u16,
1369
1370    /// Query control flags
1371    pub status: StatusBits,
1372
1373    /// an unsigned 16 bit integer specifying the number of
1374    /// entries in the question section.
1375    pub qdcount: u16,
1376
1377    /// an unsigned 16 bit integer specifying the number of
1378    /// resource records in the answer section.
1379    pub ancount: u16,
1380
1381    /// an unsigned 16 bit integer specifying the number of name
1382    /// server resource records in the authority records
1383    /// section.
1384    pub nscount: u16,
1385
1386    /// an unsigned 16 bit integer specifying the number of
1387    /// resource records in the additional records section.
1388    pub arcount: u16,
1389}
1390
1391impl fmt::Display for DnsHeader
1392{
1393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1394    {
1395        write!(f, "ID:{} Status:{:?}, qdcnt:{}, ancnt:{}, nscnt:{}, arcnt:{}",
1396            self.id, self.status, self.qdcount, self.ancount, self.nscount, self.arcount)
1397    }
1398}
1399
1400
1401#[derive(Clone, Debug, PartialEq, Eq)]
1402pub struct DnsRequestAnswer<'temp>
1403{
1404    /// request header
1405    pub req_header: DnsRequestHeader<'temp>,
1406    /// Resonse section
1407    pub response: Vec<DnsResponsePayload>,
1408    /// Additional RR
1409    pub additional: Vec<DnsResponsePayload>,
1410    /// Authortative nameservers
1411    pub authoratives: Vec<DnsResponsePayload>,
1412}
1413
1414impl<'temp> DnsRequestAnswer<'temp>
1415{
1416    #[inline]
1417    pub 
1418    fn get_req_id(&self) -> u16
1419    {
1420        return self.req_header.get_id();
1421    }
1422
1423    /// Validates the content
1424    /// 
1425    /// # Arguments
1426    /// 
1427    /// * `req` - a request which was sent 
1428    pub 
1429    fn verify(&self, req: &DnsRequestHeader<'_>) -> CDnsResult<()>
1430    {
1431        if self.get_req_id() != req.get_id()
1432        {
1433            internal_error!(
1434                CDnsErrorType::DnsResponse, 
1435                "request and response ID did not match: '{}' != '{}'", 
1436                req.header.id, self.get_req_id()
1437            );
1438        }
1439
1440        // check if request matches with what we sent previously
1441        if self.req_header.payload != req.payload
1442        {
1443            internal_error!(CDnsErrorType::DnsResponse, 
1444                "received request section is different from sent");
1445        }
1446        else if req.payload.qtype != QType::ALL
1447        {
1448            // check qtype matches requested. (is it correct?)
1449            if req.payload.qtype != self.req_header.payload.qtype
1450            {
1451                internal_error!(
1452                    CDnsErrorType::DnsResponse, 
1453                    "requested QTYPE differ received TYPE: '{}' != '{}'", 
1454                    req.payload.qtype, 
1455                    self.req_header.payload.qtype
1456                );
1457            }
1458        }
1459        else if self.req_header.header.status.contains(StatusBits::TRUN_CATION) == true
1460        {
1461            internal_error!(CDnsErrorType::MessageTruncated, 
1462                "DNS response was truncated, aborting processing");
1463        }
1464
1465        return Ok(());
1466    }
1467
1468    /// Parses the raw data from received packet.
1469    /// 
1470    /// # Arguments
1471    /// 
1472    /// * `ans` - the received data
1473    pub(crate) 
1474    fn parse(ans: &[u8]) -> CDnsResult<Self>
1475    {
1476        // creating cursor
1477        let mut pkt = Cursor::new(ans);
1478
1479        // parsing header
1480        let id = pkt.read_u16::<BigEndian>().map_err(map_read_err)?;
1481
1482        let status = pkt.read_u16::<BigEndian>().map_err(map_read_err)?;
1483
1484        let header = 
1485            DnsHeader
1486            {
1487                id: id,
1488                status: StatusBits::from_bits(status).ok_or_else(|| 
1489                    internal_error_map!(CDnsErrorType::DnsResponse, "unknown status bits: '{}'", status)
1490                )?,
1491                qdcount: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
1492                ancount: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
1493                nscount: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
1494                arcount: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
1495            };
1496
1497        // todo!("what about truncated messages");
1498
1499        // check if there is no more than 1 answer
1500        if header.status.contains(StatusBits::QR_RESP) == false
1501        {
1502            internal_error!(
1503                CDnsErrorType::DnsResponse, 
1504                "incorret QR flag in STATUS register of response, expected 1 got 0"
1505            );
1506        }
1507       /*else if header.ancount > 1
1508        {
1509            internal_error!(
1510                CDnsErrorType::DnsRespose, 
1511                "too many responses = '{}', multiple responses are not supported", 
1512                header.ancount
1513            );
1514        }*/
1515        /*else if header.ancount == 0 && header.status.contains(StatusBits::RESP_NOERROR) == true
1516        {
1517            internal_error!(CDnsErrorType::DnsRespose, "answer count: 0 while response contains no error");
1518        }*/
1519        
1520        // reading request
1521        //let cur_offset = pkt.position();
1522    
1523        let request = 
1524            DnsRequestPayload
1525            {
1526                qname: Cow::Owned(pkt2name(&mut pkt)?),
1527                qtype: QType::u16_to_qtype(pkt.read_u16::<BigEndian>().map_err(map_read_err)?)?,
1528                qclass: QClass::u16_to_qclass(pkt.read_u16::<BigEndian>().map_err(map_read_err)?)?,
1529            };
1530
1531        let mut an_list: Vec<DnsResponsePayload> = Vec::with_capacity(header.ancount as usize);
1532        let mut rr_list: Vec<DnsResponsePayload> = Vec::with_capacity(header.arcount as usize);
1533        let mut ns_list: Vec<DnsResponsePayload> = Vec::with_capacity(header.nscount as usize);
1534
1535        for _ in 0..header.ancount
1536        {
1537            an_list.push(DnsResponsePayload::new(&mut pkt)?);
1538        }
1539        
1540        // reading authoritative section if any
1541        for _ in 0..header.nscount
1542        {
1543            ns_list.push(DnsResponsePayload::new(&mut pkt)?);
1544        }
1545
1546        // reading additional if any
1547        for _ in 0..header.arcount
1548        {
1549            rr_list.push(DnsResponsePayload::new(&mut pkt)?);
1550        }
1551
1552        return Ok(
1553            DnsRequestAnswer
1554            {
1555                req_header: 
1556                    DnsRequestHeader
1557                    { 
1558                        header, 
1559                        payload: request 
1560                    },
1561                response: an_list,
1562                additional: rr_list,
1563                authoratives: ns_list,
1564            }
1565        );
1566    }
1567
1568}
1569
1570#[derive(Clone, Debug)]
1571pub struct DnsRequestHeader<'temp>
1572{
1573    /// request header
1574    pub header: DnsHeader,
1575    /// Query content
1576    pub payload: DnsRequestPayload<'temp>,
1577}
1578
1579impl<'temp> Eq for DnsRequestHeader<'temp> {}
1580
1581impl<'temp> PartialEq for DnsRequestHeader<'temp>
1582{
1583    fn eq(&self, other: &DnsRequestHeader<'temp>) -> bool 
1584    {
1585        return self.header.id == other.header.id && self.payload == other.payload;
1586    }
1587}
1588
1589impl<'temp> Ord for DnsRequestHeader<'temp>
1590{
1591    fn cmp(&self, other: &Self) -> Ordering 
1592    {
1593        // Sort in reverse order
1594        return self.header.id.cmp(&other.header.id);
1595    }
1596}
1597
1598impl<'temp> PartialOrd for DnsRequestHeader<'temp>
1599{
1600    fn partial_cmp(&self, other: &Self) -> Option<Ordering> 
1601    {
1602        return Some(self.cmp(other));
1603    }
1604}
1605
1606impl<'temp> Hash for DnsRequestHeader<'temp>
1607{
1608    fn hash<H: Hasher>(&self, state: &mut H) 
1609    {
1610        self.header.id.hash(state);
1611        self.payload.hash(state);
1612    }
1613}
1614
1615impl<'temp> Borrow<u16> for DnsRequestHeader<'temp>
1616{
1617    fn borrow(&self) -> &u16 
1618    {
1619        return &self.header.id;
1620    }
1621}
1622
1623impl<'temp> TryFrom<&'temp QDnsReq> for DnsRequestHeader<'temp>
1624{
1625    type Error = CDnsError;
1626
1627    fn try_from(value: &'temp QDnsReq) -> Result<Self, Self::Error> 
1628    {
1629        return DnsRequestHeader::construct_lookup(value);//qrec.get_req_name().clone(), *qrec.get_type());
1630    }
1631}
1632
1633impl<'temp> fmt::Display for DnsRequestHeader<'temp>
1634{
1635    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1636    {
1637        write!(f, "Header: {}, Status: {}", self.header, self.payload)
1638    }
1639}
1640
1641impl<'temp> DnsRequestHeader<'temp>
1642{
1643    pub 
1644    fn get_id(&self) -> u16
1645    {
1646        return self.header.id;
1647    }
1648}
1649
1650
1651impl<'temp> DnsRequestHeader<'temp>
1652{
1653    pub 
1654    fn regenerate_id(&mut self)
1655    {
1656        self.header.id = rand::random();
1657    }
1658
1659
1660   /* pub 
1661    fn from_qdns_req(qrec: &QDnsReq) -> CDnsResult<Self>
1662    {
1663        return DnsRequestHeader::construct_lookup(qrec.get_req_name().clone(), *qrec.get_type());
1664    }
1665    */
1666
1667    pub 
1668    fn derive(&self) -> Self
1669    {
1670        let header = 
1671            DnsHeader
1672            {
1673                id: rand::random(),
1674                status: self.header.status,
1675                qdcount: self.header.qdcount,
1676                ancount: self.header.ancount,
1677                nscount: self.header.nscount,
1678                arcount: self.header.arcount,
1679            };
1680
1681        return DnsRequestHeader{ header: header, payload: self.payload.clone() };
1682    }
1683
1684    /// Constructs the request from input.
1685    pub
1686    fn construct_lookup(qreq: &'temp QDnsReq) -> CDnsResult<DnsRequestHeader<'_>>
1687    {        
1688        // preparing status register
1689        let mut status: StatusBits = StatusBits::empty();
1690        status = (status & !StatusBits::OPCODE_STANDARD) | StatusBits::RECURSION_DESIRED;
1691
1692        // constructing request structure
1693        let req = 
1694            DnsRequestHeader
1695            {
1696                header: 
1697                    DnsHeader
1698                    {
1699                        id: rand::random(),
1700                        status: status,
1701                        qdcount: 1,
1702                        ancount: 0,
1703                        nscount: 0,
1704                        arcount: 0,
1705                    },
1706                payload: 
1707                    DnsRequestPayload
1708                        ::new(qreq.get_req_name().into(), *qreq.get_type(), QClass::IN)
1709            };
1710
1711        return Ok(req);
1712    }
1713    
1714    pub 
1715    fn to_bytes(&self, append_len: bool) -> CDnsResult<Vec<u8>>
1716    {
1717        let mut pkt_size: usize = size_of::<DnsHeader>() + self.payload.qname.len() + 4; 
1718
1719        if append_len == true
1720        {
1721            pkt_size += 2;
1722        }
1723
1724        let mut pkt = Cursor::new(vec![0_u8; pkt_size]);
1725
1726        if append_len == true
1727        {
1728            pkt.write_u16::<BigEndian>((pkt_size-2) as u16).map_err(map_read_err)?;
1729        }
1730
1731        pkt.write_u16::<BigEndian>(self.header.id).map_err(map_read_err)?;
1732        pkt.write_u16::<BigEndian>(self.header.status.bits()).map_err(map_read_err)?;
1733        pkt.write_u16::<BigEndian>(self.header.qdcount).map_err(map_read_err)?;
1734        pkt.write_u16::<BigEndian>(self.header.ancount).map_err(map_read_err)?;
1735        pkt.write_u16::<BigEndian>(self.header.nscount).map_err(map_read_err)?;
1736        pkt.write_u16::<BigEndian>(self.header.arcount).map_err(map_read_err)?;
1737
1738
1739        pkt.write(&self.payload.qname).map_err(map_read_err)?;
1740        pkt.write_u16::<BigEndian>(self.payload.qtype.into()).map_err(map_read_err)?;
1741        pkt.write_u16::<BigEndian>(self.payload.qclass.into()).map_err(map_read_err)?;
1742        
1743
1744        return Ok(pkt.into_inner());
1745    }
1746}
1747
1748/// A request payload with (request) lines.
1749#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1750pub struct DnsRequestPayload<'temp>
1751{
1752    /// a domain name represented as a sequence of labels
1753    pub qname: Cow<'temp, [u8]>,
1754
1755    /// a two octet code which specifies the type of the query.
1756    pub qtype: QType,
1757    
1758    /// a two octet code that specifies the class of the query.
1759    pub qclass: QClass,
1760}
1761
1762
1763impl<'temp> fmt::Display for DnsRequestPayload<'temp>
1764{
1765    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1766    {
1767        write!(f, "qname:{:?} qtype:{}, qclass:{}", self.qname, self.qtype, self.qclass)
1768    }
1769}
1770
1771impl<'temp> DnsRequestPayload<'temp>
1772{
1773    pub 
1774    fn new(qname: Cow<'temp, [u8]>, qtype: QType, qclass: QClass) -> Self
1775    {
1776        return DnsRequestPayload{ qname: qname, qtype: qtype.into(), qclass: qclass.into() };
1777    }
1778}
1779
1780
1781/// A response section
1782#[derive(Clone, Debug, Default, Eq, PartialEq)]
1783pub struct DnsResponsePayload
1784{
1785    // A domain name that was queried, in the same format as the QNAME in the question
1786    pub name: String,
1787    /// Two octets containing one of th type codes.
1788    pub dtype: QType,
1789    /// Two octets which specify the class of the data in the RDATA field
1790    pub class: QClass,
1791    /// specifies the time interval that the resource record may be cached before the source
1792    /// of the information should again be consulted
1793    pub ttl: i32,
1794    /// specifies the length in octets of the RDATA field
1795    pub rdlength: u16,
1796    /// a variable length string of octets that describes the resource
1797    pub rdata: DnsRdata,
1798}
1799
1800impl DnsResponsePayload
1801{
1802    /// Creates a record from [HostnameEntry], but only for types like
1803    /// A, AAAA, PTR
1804    pub(crate)
1805    fn new_local(dtype: QType, data: &HostnameEntry) -> Option<Vec<Self>>
1806    {
1807        match dtype
1808        {
1809            QType::A => 
1810            {
1811                let mut out: Vec<Self> = Vec::with_capacity(1);
1812
1813                let IpAddr::V4(ipv4) = data.get_ip()
1814                else { return None; };
1815
1816                out.push(
1817                    DnsResponsePayload
1818                    {
1819                        name: data.get_hostnames()[0].to_string(),
1820                        dtype: dtype,
1821                        class: QClass::IN,
1822                        ttl: i32::MAX,
1823                        rdlength: 0,
1824                        rdata: RecordA::wrap(RecordA{ ip: ipv4.clone()}),
1825                    }
1826                );
1827
1828                return Some(out);
1829            },
1830            QType::AAAA => 
1831            {
1832                let mut out: Vec<Self> = Vec::with_capacity(1);
1833
1834                let IpAddr::V6(ipv6) = data.get_ip()
1835                else { return None };
1836
1837                out.push(
1838                    DnsResponsePayload
1839                    {
1840                        name: data.get_hostnames()[0].to_string(),
1841                        dtype: dtype,
1842                        class: QClass::IN,
1843                        ttl: i32::MAX,
1844                        rdlength: 0,
1845                        rdata: RecordAAAA::wrap(RecordAAAA{ ip: ipv6.clone() }),
1846                    }
1847                );
1848
1849                return Some(out);
1850            },
1851            QType::PTR => 
1852            {
1853                let mut out: Vec<Self> = Vec::with_capacity(data.get_hostnames().len());
1854
1855                // copy all hostnames from the list
1856                for h in data.get_hostnames_iter()
1857                {
1858                    out.push(
1859                        DnsResponsePayload
1860                        {
1861                            name: [data.get_ip().to_string().as_str(), ".in-addr.arpa"].concat(),
1862                            dtype: dtype,
1863                            class: QClass::IN,
1864                            ttl: i32::MAX,
1865                            rdlength: 0,
1866                            rdata: RecordPTR::wrap( RecordPTR { fqdn: h.clone() }),
1867                        }
1868                    );
1869                }
1870            
1871                return Some(out);
1872            },
1873            _ => 
1874                return None
1875        }
1876        
1877    }
1878
1879    fn new(pkt: &mut Cursor<&[u8]>) -> CDnsResult<Self>
1880    {
1881        let name = name2str(pkt, None)?;
1882        let qtype = QType::u16_to_type(pkt.read_u16::<BigEndian>().map_err(map_read_err)?)?;
1883        let qclass = QClass::u16_to_class(pkt.read_u16::<BigEndian>().map_err(map_read_err)?)?;
1884        let ttl = pkt.read_i32::<BigEndian>().map_err(map_read_err)?;
1885        let rdlength = pkt.read_u16::<BigEndian>().map_err(map_read_err)?;
1886        let rdata = DnsRdata::convert(pkt, rdlength, qtype)?;
1887
1888        return Ok(
1889            DnsResponsePayload
1890            {
1891                name: name,
1892                dtype: qtype,
1893                class: qclass,
1894                ttl: ttl,
1895                rdlength: rdlength,
1896                rdata: rdata,
1897            }
1898        );
1899    }
1900
1901    /// Returns the variable length string of octets that describes the resource 
1902    /// as a reference.
1903    pub 
1904    fn get_rdata(&self) -> &DnsRdata
1905    {
1906        return &self.rdata;
1907    }
1908
1909    /// Returns the variable length string of octets that describes the resource 
1910    /// by consuming the instance.
1911    pub 
1912    fn borrow_rdata(self) -> DnsRdata
1913    {
1914        return self.rdata;
1915    }
1916
1917    /// Attemps to decode the `punycode` into the UTF-8 domain name.
1918    /// 
1919    /// # Returns
1920    /// 
1921    /// An error [Result::Err] is returned if the received data is
1922    /// not possible to decode.
1923    #[cfg(feature = "enable_IDN_support")]
1924    pub 
1925    fn get_full_domain_name_with_idn_decode(&self) -> CDnsResult<String>
1926    {
1927        use crate::external::rust_punycode;
1928
1929        return Ok(
1930            self
1931                .name
1932                .split(".")
1933                .map(|v| 
1934                    rust_punycode::decode(&v)
1935                )
1936                .collect::<CDnsResult<Vec<String>>>()?
1937                .join(".")
1938        );
1939    }
1940
1941    /// Returns the raw domain name as it was recevied.
1942    pub 
1943    fn get_full_domain_name(&self) -> &str
1944    {
1945        return self.name.as_str();
1946    }
1947
1948    pub 
1949    fn get_domain_name_iter(&self) -> std::str::Split<'_, &str>
1950    {
1951        return self.name.split(".");
1952    }
1953
1954    /// Attemps to obtain an iterator of a separated domain
1955    /// name also decoding the `punycode` into the UTF-8 domain name.
1956    /// 
1957    /// # Returns
1958    /// 
1959    /// An error [Result::Err] is returned if the received data is
1960    /// not possible to decode.
1961    #[cfg(feature = "enable_IDN_support")]
1962    pub 
1963    fn get_domain_name_iter_with_idn_decode(&self) -> CDnsResult<std::vec::IntoIter<String>>
1964    {
1965        use crate::external::rust_punycode;
1966
1967        return 
1968            self
1969                .name
1970                .split(".")
1971                .map(|v| rust_punycode::decode(&v))
1972                .collect::<CDnsResult<Vec<String>>>()
1973                .map(|v| v.into_iter());
1974    }
1975}
1976
1977/*impl Default for DnsResponsePayload
1978{
1979    fn default() -> Self 
1980    {
1981        return Self::Empty;    
1982    }
1983}*/
1984
1985#[cfg(feature = "enable_IDN_support")]
1986impl fmt::Display for DnsResponsePayload
1987{
1988    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1989    {
1990        if self.name.starts_with("xn-") == true
1991        {
1992            let idn = 
1993               self.get_full_domain_name_with_idn_decode().unwrap_or_else(|_| "decode_error".into());
1994
1995            write!(f, "{}({}) ", self.name, idn)?;              
1996        }
1997        else
1998        {
1999            write!(f, "{} ", self.name)?;
2000        }
2001
2002        write!(f, "{} {} {} {}", 
2003            self.dtype, self.class, self.ttl, self.rdata)  
2004    }
2005}
2006
2007#[cfg(not(feature = "enable_IDN_support"))]
2008impl fmt::Display for DnsResponsePayload
2009{
2010    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2011    {
2012        if self.name.starts_with("xn-") == true
2013        {
2014            let idn = self.get_full_domain_name();
2015
2016            write!(f, "{}({}) ", self.name, idn)?;              
2017        }
2018        else
2019        {
2020            write!(f, "{} ", self.name)?;
2021        }
2022
2023        write!(f, "{} {} {} {}", 
2024            self.dtype, self.class, self.ttl, self.rdata)  
2025    }
2026}
2027
2028
2029/// Trait for decoding DNS record structures from bytes read over the wire.
2030pub trait RecordReader: Sized 
2031{
2032
2033    /// A [QType] a record type for current instance
2034    const REC_TYPE: QType;
2035
2036    /// A data size
2037    const RLEN: u16;
2038
2039    /// Read at most `len` bytes from the given `Cursor`. This cursor travels
2040    /// throughout the complete data — by this point, we have read the entire
2041    /// response into a buffer.
2042    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self>;
2043
2044    fn wrap(self) -> DnsRdata;
2045}
2046
2047#[derive(Clone, Debug, Eq, PartialEq)]
2048pub struct RecordA
2049{
2050    pub ip: Ipv4Addr
2051}
2052
2053impl RecordReader for RecordA
2054{
2055    const REC_TYPE: QType = QType::A;
2056
2057    const RLEN: u16 = 4;
2058
2059    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2060    {
2061        // read 4 bytes (octets)
2062        if rlen != Self::RLEN
2063        {
2064            internal_error!(CDnsErrorType::DnsResponse, "RecordA len expected: '4', got: '{}'", rlen);
2065        }
2066        else if qtype != Self::REC_TYPE
2067        {
2068            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2069        }
2070
2071        let ip = pkt.read_u32::<BigEndian>().map_err(map_read_err)?;
2072
2073        return Ok(Self{ip: Ipv4Addr::from(ip) });
2074    }
2075
2076    fn wrap(self) -> DnsRdata 
2077    {
2078        return DnsRdata::A(self);
2079    }
2080}
2081
2082impl fmt::Display for RecordA
2083{
2084    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2085    {
2086        write!(f, "{}   {}", Self::REC_TYPE, self.ip)
2087    }
2088}
2089
2090
2091#[derive(Clone, Debug, Eq, PartialEq)]
2092pub struct RecordAAAA
2093{
2094    pub ip: Ipv6Addr
2095}
2096
2097impl RecordReader for RecordAAAA
2098{
2099    const REC_TYPE: QType = QType::AAAA;
2100
2101    const RLEN: u16 = 16;
2102
2103    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2104    {
2105        if rlen != Self::RLEN
2106        {
2107            internal_error!(CDnsErrorType::DnsResponse, "RecordAAAA len expected: '{}', got: '{}'", Self::RLEN, rlen);
2108        }
2109        else if qtype != Self::REC_TYPE
2110        {
2111            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2112        }
2113
2114        let ip = pkt.read_u128::<BigEndian>().map_err(map_read_err)?;
2115        
2116        return Ok(Self{ ip: Ipv6Addr::from(ip) });
2117    }
2118
2119    fn wrap(self) -> DnsRdata 
2120    {
2121        return DnsRdata::AAAA(self);
2122    }
2123}
2124
2125impl fmt::Display for RecordAAAA
2126{
2127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2128    {
2129        write!(f, "{}   {}", Self::REC_TYPE, self.ip)
2130    }
2131}
2132
2133#[derive(Clone, Debug, Eq, PartialEq)]
2134pub struct RecordPTR
2135{
2136    pub fqdn: String
2137}
2138
2139impl RecordReader for RecordPTR
2140{
2141    const REC_TYPE: QType = QType::PTR;
2142
2143    const RLEN: u16 = 0;
2144
2145    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2146    {
2147        if qtype != Self::REC_TYPE
2148        {
2149            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2150        }
2151
2152        return Ok(
2153            Self{ fqdn: name2str(pkt, Some(rlen))? }
2154        );
2155    }
2156
2157    fn wrap(self) -> DnsRdata 
2158    {
2159        return DnsRdata::PTR(self);
2160    }
2161}
2162
2163impl fmt::Display for RecordPTR
2164{
2165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2166    {
2167        write!(f, "{}   {}", Self::REC_TYPE, self.fqdn)
2168    }
2169}
2170
2171#[derive(Clone, Debug, Eq, PartialEq)]
2172pub struct RecordMX
2173{
2174    pub preference: u16, 
2175    pub exchange: String
2176}
2177
2178impl RecordReader for RecordMX
2179{
2180    const REC_TYPE: QType = QType::MX;
2181
2182    const RLEN: u16 = 2;
2183
2184    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2185    {
2186        if rlen <= Self::RLEN
2187        {
2188            internal_error!(CDnsErrorType::DnsResponse, "RecordMX len expected: '{}', got: '{}'", Self::RLEN, rlen);
2189        }
2190        else if qtype != Self::REC_TYPE
2191        {
2192            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2193        }
2194
2195        return Ok(
2196            Self
2197            { 
2198                preference: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2199                exchange: name2str(pkt, Some(rlen - 2))?,
2200            }
2201        );
2202    }
2203
2204    fn wrap(self) -> DnsRdata 
2205    {
2206        return DnsRdata::MX(self);
2207    }
2208}
2209
2210impl fmt::Display for RecordMX
2211{
2212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2213    {
2214        write!(f, "{}   {} {}", Self::REC_TYPE, self.preference, self.exchange)
2215    }
2216}
2217
2218#[derive(Clone, Debug, Eq, PartialEq)]
2219pub struct RecordCNAME
2220{
2221    pub fqdn: String
2222}
2223
2224impl RecordReader for RecordCNAME
2225{
2226    const REC_TYPE: QType = QType::CNAME;
2227
2228    const RLEN: u16 = 0;
2229
2230    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2231    {
2232        if qtype != Self::REC_TYPE
2233        {
2234            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2235        }
2236
2237        return Ok(
2238            Self{ fqdn: name2str(pkt, Some(rlen))? }
2239        );
2240    }
2241
2242    fn wrap(self) -> DnsRdata 
2243    {
2244        return DnsRdata::CNAME(self);
2245    }
2246}
2247
2248impl fmt::Display for RecordCNAME
2249{
2250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2251    {
2252        write!(f, "{}   {}", Self::REC_TYPE, self.fqdn)
2253    }
2254}
2255
2256#[derive(Clone, Debug, Eq, PartialEq)]
2257pub struct RecordNS
2258{
2259    pub fqdn: String
2260}
2261
2262impl RecordReader for RecordNS
2263{
2264    const REC_TYPE: QType = QType::NS;
2265
2266    const RLEN: u16 = 0;
2267
2268    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2269    {
2270        if qtype != Self::REC_TYPE
2271        {
2272            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2273        }
2274
2275        return Ok(
2276            Self{ fqdn: name2str(pkt, Some(rlen))? }
2277        );
2278    }
2279
2280    fn wrap(self) -> DnsRdata 
2281    {
2282        return DnsRdata::NS(self);
2283    }
2284}
2285
2286impl fmt::Display for RecordNS
2287{
2288    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2289    {
2290        write!(f, "{}   {}", Self::REC_TYPE, self.fqdn)
2291    }
2292}
2293
2294#[derive(Clone, Debug, Eq, PartialEq)]
2295pub struct RecordSOA
2296{
2297    /// primary name server
2298    pub pnm: String, 
2299    /// responsible authority mailbox
2300    pub ram: String,
2301    /// serial number
2302    pub serial: u32,
2303    /// refresh interval
2304    pub interv_refr: u32,
2305    /// retry interval
2306    pub interv_retry: u32,
2307    /// expire limit
2308    pub expire_limit: u32,
2309    /// minimum TTL
2310    pub min_ttl: u32,
2311}
2312
2313impl RecordReader for RecordSOA
2314{
2315    const REC_TYPE: QType = QType::SOA;
2316
2317    const RLEN: u16 = 0;
2318
2319    fn read(pkt: &mut Cursor<&[u8]>, _rlen: u16, qtype: QType) -> CDnsResult<Self> 
2320    {
2321        if qtype != Self::REC_TYPE
2322        {
2323            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2324        }
2325
2326        return Ok(
2327            Self
2328            { 
2329                // primary name server
2330                pnm: name2str(pkt, None)?, 
2331                // responsible authority mailbox
2332                ram: name2str(pkt, None)?,
2333                // serial number
2334                serial: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2335                // refresh interval
2336                interv_refr: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2337                // retry interval
2338                interv_retry: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2339                // expire limit
2340                expire_limit: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2341                // minimum TTL
2342                min_ttl: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2343            }
2344        );
2345    }
2346
2347    fn wrap(self) -> DnsRdata 
2348    {
2349        return DnsRdata::SOA(self);
2350    }
2351}
2352
2353impl fmt::Display for RecordSOA
2354{
2355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2356    {
2357        write!(f, "{}   {} {} {} {} {} {} {}", Self::REC_TYPE, self.pnm, self.ram, self.serial, 
2358            self.interv_refr, self.interv_retry, self.expire_limit, self.min_ttl)
2359    }
2360}
2361
2362#[derive(Clone, Debug, Eq, PartialEq)]
2363pub struct RecordSRV
2364{
2365    /// the priority of the target host, lower value means more preferred.
2366    pub priority: u16,
2367
2368    /// A relative weight for records with the same priority, higher value 
2369    /// means higher chance of getting picked.
2370    pub weight: u16,
2371
2372    /// the TCP or UDP port on which the service is to be found.
2373    pub port: u16,
2374
2375    /// the canonical hostname of the machine providing the service, ending in a dot.
2376    pub target: String,
2377}
2378
2379impl RecordReader for RecordSRV
2380{
2381    const REC_TYPE: QType = QType::SRV;
2382
2383    const RLEN: u16 = 0;
2384
2385    fn read(pkt: &mut Cursor<&[u8]>, _rlen: u16, qtype: QType) -> CDnsResult<Self> 
2386    {
2387        if qtype != Self::REC_TYPE
2388        {
2389            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2390        }
2391
2392        return Ok(
2393            Self
2394            { 
2395                priority: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2396                weight: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2397                port: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2398                target: name2str(pkt, None)?,
2399            }
2400        );
2401    }
2402
2403    fn wrap(self) -> DnsRdata 
2404    {
2405        return DnsRdata::SRV(self);
2406    }
2407}
2408
2409impl fmt::Display for RecordSRV
2410{
2411    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2412    {
2413        write!(f, "{}   {} {} {} \"{}\"", Self::REC_TYPE, self.priority, self.weight, self.port, self.target)
2414    }
2415}
2416
2417#[derive(Clone, Debug, Eq, PartialEq)]
2418pub struct RecordTXT
2419{
2420    /// The character-strings.
2421    pub txt_strings: String,
2422}
2423
2424impl RecordReader for RecordTXT
2425{
2426    const REC_TYPE: QType = QType::TXT;
2427
2428    const RLEN: u16 = 2;
2429
2430    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2431    {
2432        if rlen <= Self::RLEN
2433        {
2434            internal_error!(CDnsErrorType::DnsResponse, "RecordTXT len expected: '{}' >, got: '{}'", Self::RLEN, rlen);
2435        }
2436        else if qtype != Self::REC_TYPE
2437        {
2438            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2439        }
2440
2441        let mut read_length = 0;
2442        
2443
2444        let dmod = ((rlen % 255) > 0) as u16;
2445        let cap = rlen / 255 + dmod;
2446
2447        let mut txt_datas = Vec::<String>::with_capacity(cap as usize);
2448    
2449        while read_length < rlen
2450        {
2451            let mut txt_data = Vec::new();
2452
2453            loop
2454            {
2455                let blk_size = pkt.read_u8().map_err(map_read_err)?;
2456
2457                read_length += blk_size as u16 + 1;
2458
2459                let mut new_txt = Vec::with_capacity(blk_size as usize);//vec![0_u8; blk_size as usize];//Vec::with_capacity(blk_size as usize);// vec![0_u8; blk_size as usize];
2460                unsafe { new_txt.set_len(blk_size as usize); }
2461
2462                pkt.read_exact(&mut new_txt).map_err(map_read_err)?;
2463
2464                txt_data.push(new_txt);
2465
2466                if blk_size < 255
2467                {
2468                    break;
2469                }
2470            }
2471
2472            if txt_data.is_empty() == true
2473            {
2474                internal_error!(
2475                    CDnsErrorType::DnsResponse, 
2476                    "unexpected EOF in TXT rec cur position: '{}', data_length: '{}', read: '{}'",
2477                    pkt.position(), rlen, read_length
2478                );
2479            }
2480
2481            let data = txt_data.concat();
2482
2483            txt_datas.push(
2484                String::from_utf8(data)
2485                    .map_err(|e|
2486                        internal_error_map!(CDnsErrorType::InternalError, "UTF-8 decode error, {}", e)
2487                    )?
2488                );
2489        }
2490
2491        return Ok(
2492            Self
2493            { 
2494                txt_strings: txt_datas.concat()
2495            }
2496        );
2497    }
2498
2499    fn wrap(self) -> DnsRdata 
2500    {
2501        return DnsRdata::TXT(self);
2502    }
2503}
2504
2505impl fmt::Display for RecordTXT
2506{
2507    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2508    {
2509        write!(f, "{}   {}", Self::REC_TYPE, self.txt_strings)
2510    }
2511}
2512
2513#[derive(Clone, Debug, Eq, PartialEq)]
2514pub struct RecordURI
2515{
2516    /// the priority of the target host, lower value means more preferred.
2517    pub priority: u16,
2518
2519    /// A relative weight for records with the same priority, higher value 
2520    /// means higher chance of getting picked.
2521    pub weight: u16,
2522
2523    /// This field holds the URI of the target, enclosed in double-quote characters ('"'),
2524    /// where the URI is as specified in RFC 3986
2525    pub target: String,
2526}
2527
2528impl RecordReader for RecordURI
2529{
2530    const REC_TYPE: QType = QType::URI;
2531
2532    const RLEN: u16 = 4;
2533
2534    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2535    {
2536        if rlen <= Self::RLEN
2537        {
2538            internal_error!(CDnsErrorType::DnsResponse, "RecordURI len expected: '{}' >, got: '{}'", Self::RLEN, rlen);
2539        }
2540        else if qtype != Self::REC_TYPE
2541        {
2542            internal_error!(CDnsErrorType::DnsResponse, "expexted '{}', got: '{}'", Self::REC_TYPE, qtype);
2543        }
2544
2545        return Ok(
2546            Self
2547            { 
2548                priority: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2549                weight: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2550                target: pkt2string_exact(pkt, rlen - 4)?,
2551            }
2552        );
2553    }
2554
2555    fn wrap(self) -> DnsRdata 
2556    {
2557        return DnsRdata::URI(self);
2558    }
2559}
2560
2561impl fmt::Display for RecordURI
2562{
2563    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2564    {
2565        write!(f, "{}   {} {} \"{}\"", Self::REC_TYPE, self.priority, self.weight, self.target)
2566    }
2567}
2568
2569// https://www.ietf.org/rfc/rfc4034.txt
2570
2571#[derive(Clone, Debug, Eq, PartialEq)]
2572pub struct RecordRRSIG
2573{
2574    type_cov: u16,
2575    alg: u8,
2576    labels: u8,
2577    orig_ttl: u32,
2578    sig_exp: u32,
2579    sig_inc: u32,
2580    keytag: u16,
2581    sig_name: String,
2582    key: Vec<u8>,
2583}
2584
2585impl RecordReader for RecordRRSIG
2586{
2587    const REC_TYPE: QType = QType::RRSIG;
2588
2589    const RLEN: u16 = 19;
2590
2591    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, _qtype: QType) -> CDnsResult<Self> 
2592    {
2593        let data = vec![0_u8; rlen as usize];
2594
2595        let pos = pkt.position();
2596
2597        let mut res = 
2598            Self
2599            {
2600                type_cov: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2601                alg: pkt.read_u8().map_err(map_read_err)?,
2602                labels: pkt.read_u8().map_err(map_read_err)?,
2603                orig_ttl: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2604                sig_exp: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2605                sig_inc: pkt.read_u32::<BigEndian>().map_err(map_read_err)?,
2606                keytag: pkt.read_u16::<BigEndian>().map_err(map_read_err)?,
2607                sig_name: name2str(pkt,None)?,
2608                key: Vec::new(),
2609            };
2610
2611        let left_rdlen = rlen - (pkt.position() - pos) as u16;
2612        res.key = pkt2vec(pkt, Some(left_rdlen))?;
2613
2614        return Ok(res);
2615    }
2616
2617    fn wrap(self) -> DnsRdata 
2618    {
2619        return DnsRdata::RRSIG(self);
2620    }
2621}
2622
2623impl fmt::Display for RecordRRSIG
2624{
2625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2626    {
2627        write!(f, "{}   {} {} {} {} {} {} {} {} {}", 
2628            Self::REC_TYPE, self.type_cov, self.alg, self.labels, self.orig_ttl,
2629            self.sig_exp, self.sig_inc, self.keytag, self.sig_name, 
2630            self.key.iter().map(|k| format!("{:02X}", k)).collect::<Vec<String>>().concat()
2631        )
2632    }
2633}
2634
2635#[derive(Clone, Debug, Eq, PartialEq)]
2636pub struct RecordOther
2637{
2638    // record type
2639    pub qtype: QType,
2640
2641    // raw data
2642    pub data: Vec<u8>
2643}
2644
2645impl RecordReader for RecordOther
2646{
2647    const REC_TYPE: QType = QType::ALL;
2648
2649    const RLEN: u16 = 0;
2650
2651    fn read(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self> 
2652    {
2653        let mut data = vec![0_u8; rlen as usize];
2654
2655        pkt.read_exact(&mut data).map_err(map_read_err)?;
2656
2657        return Ok(
2658            Self
2659            { 
2660                qtype: qtype,
2661                data: data,
2662            }
2663        );
2664    }
2665
2666    fn wrap(self) -> DnsRdata 
2667    {
2668        return DnsRdata::OTHER(self);
2669    }
2670}
2671
2672impl fmt::Display for RecordOther
2673{
2674    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2675    {
2676        write!(f, "{}   RAW:", self.qtype)?;
2677
2678        for d in self.data.iter()
2679        {
2680            write!(f, "{:X}", d)?;
2681        }
2682
2683        return Ok(());
2684    }
2685}
2686
2687pub(crate)
2688fn sanitize_str_unicode(st: &str) -> String
2689{
2690    let mut out = String::with_capacity(st.len());
2691
2692    for c in st.chars()
2693    {
2694        if c.is_alphanumeric() == true ||
2695            c.is_ascii_punctuation() == true ||
2696            c == ' '
2697        {
2698            out.push(c);
2699        }
2700        else
2701        {
2702            let mut buf = [0_u8; 4];
2703            c.encode_utf8(&mut buf);
2704
2705            let formatted: String = 
2706                buf[0..c.len_utf8()].into_iter()
2707                    .map(|c| format!("\\x{:02x}", c))
2708                    .collect();
2709
2710            out.push_str(&formatted);
2711        }
2712    }
2713
2714    return out;
2715}
2716
2717pub(crate) 
2718fn check_domain_ascii(st: &str) -> CDnsResult<()>
2719{
2720    if st.len() == 0
2721    {
2722        internal_error!(CDnsErrorType::InternalError, 
2723            "name empty: '{}' in: '{}'", st.len(), sanitize_str_unicode(st));
2724    }
2725    else if st.starts_with("-") == true
2726    {
2727        internal_error!(CDnsErrorType::InternalError, 
2728            "cannot start from '-' in: '{}'", sanitize_str_unicode(st));
2729    }
2730    else if st.ends_with("-") == true
2731    {
2732        internal_error!(CDnsErrorType::InternalError, 
2733            "cannot start from '-' in: '{}'", sanitize_str_unicode(st));
2734    }
2735    else if st.len() >= MAX_NAME_LEN
2736    {
2737        internal_error!(CDnsErrorType::InternalError, 
2738            "name too long: '{}' in: '{}'", st.len(), sanitize_str_unicode(st));
2739    }
2740    else if st.chars().any(|v| v.is_alphanumeric() == false && v != '-') == true
2741    {
2742        internal_error!(CDnsErrorType::InternalError, 
2743            "contains non-valid ASCII chars in: '{}'", sanitize_str_unicode(st));
2744    }
2745
2746    return Ok(());
2747}
2748
2749#[derive(Clone, Debug, Eq, PartialEq)]
2750pub enum DnsRdata
2751{
2752    None,
2753    A(RecordA),
2754    NS(RecordNS),
2755    CNAME(RecordCNAME),
2756    SOA(RecordSOA),
2757    PTR(RecordPTR),
2758    MX(RecordMX),
2759    TXT(RecordTXT),
2760    AAAA(RecordAAAA), 
2761    SRV(RecordSRV),
2762    URI(RecordURI),    
2763    RRSIG(RecordRRSIG),
2764    OTHER(RecordOther),
2765}
2766
2767impl fmt::Display for DnsRdata
2768{
2769    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
2770    {
2771        match self
2772        {
2773            Self::None => 
2774                write!(f, "No record"),
2775            Self::A(ip) => 
2776                write!(f, "{}", ip),
2777            Self::NS(ns) => 
2778                write!(f, "{}", ns),
2779            Self::AAAA(aaaa) => 
2780                write!(f, "{}", aaaa),
2781            Self::MX(mx) =>
2782                write!(f, "{}", mx),
2783            Self::CNAME(cname) => 
2784                write!(f, "{}", cname),
2785            Self::PTR(ptr) => 
2786                write!(f, "{}", ptr),
2787            Self::SOA(soa) => 
2788                write!(f, "{}", soa),
2789            Self::TXT(txt) => 
2790                write!(f, "{}", txt),
2791            Self::SRV(srv) => 
2792                write!(f, "{}", srv),
2793            Self::URI(uri) =>
2794                write!(f, "{}", uri),
2795            Self::RRSIG(rrsig) =>
2796                write!(f, "{}", rrsig),
2797            Self::OTHER(other) => 
2798                write!(f, "{}", other),
2799        }
2800    }
2801}
2802
2803impl Default for DnsRdata
2804{
2805    fn default() -> Self 
2806    {
2807        return Self::None;   
2808    }
2809}
2810
2811impl DnsRdata
2812{
2813    #[inline]
2814    pub 
2815    fn is_some(&self) -> bool
2816    {
2817        return *self != Self::None;
2818    }
2819}
2820
2821
2822impl DnsRdata
2823{
2824    /// Reads the RData from pkt and converts it into QType container
2825    /// 
2826    /// # Arguments
2827    /// 
2828    /// * `pkt` - a [Cursor] mutable reference to raw DNS reply data
2829    /// 
2830    /// * `rlen` - a length of RData section
2831    /// 
2832    /// * `qtype` - a [QType] reference to the response answer Qtype
2833    /// 
2834    /// # Returns
2835    /// 
2836    /// * [CDnsResult] with Self or error
2837    pub 
2838    fn convert(pkt: &mut Cursor<&[u8]>, rlen: u16, qtype: QType) -> CDnsResult<Self>
2839    {
2840        match qtype
2841        {
2842            RecordA::REC_TYPE => 
2843                return Ok(RecordA::wrap(RecordA::read(pkt, rlen, qtype)?)),
2844            RecordAAAA::REC_TYPE => 
2845                return Ok(RecordAAAA::wrap(RecordAAAA::read(pkt, rlen, qtype)?)),
2846            RecordPTR::REC_TYPE => 
2847                return Ok(RecordPTR::wrap(RecordPTR::read(pkt, rlen, qtype)?)),
2848            RecordMX::REC_TYPE =>
2849                return Ok(RecordMX::wrap(RecordMX::read(pkt, rlen, qtype)?)),
2850            RecordCNAME::REC_TYPE =>
2851                return Ok(RecordCNAME::wrap(RecordCNAME::read(pkt, rlen, qtype)?)),
2852            RecordSOA::REC_TYPE =>
2853                return Ok(RecordSOA::wrap(RecordSOA::read(pkt, rlen, qtype)?)),
2854            RecordSRV::REC_TYPE => 
2855                return Ok(RecordSRV::wrap(RecordSRV::read(pkt, rlen, qtype)?)),
2856            RecordTXT::REC_TYPE =>
2857                return Ok(RecordTXT::wrap(RecordTXT::read(pkt, rlen, qtype)?)),
2858            RecordURI::REC_TYPE =>
2859                return Ok(RecordURI::wrap(RecordURI::read(pkt, rlen, qtype)?)),
2860            RecordNS::REC_TYPE => 
2861                return Ok(RecordNS::wrap(RecordNS::read(pkt, rlen, qtype)?)),
2862            RecordRRSIG::REC_TYPE =>
2863                return Ok(RecordRRSIG::wrap(RecordRRSIG::read(pkt, rlen, qtype)?)),
2864            _ =>
2865                return Ok(RecordOther::wrap(RecordOther::read(pkt, rlen, qtype)?)),
2866        }
2867    }
2868
2869    pub 
2870    fn get_ip(&self) -> Option<IpAddr>
2871    {
2872        match self
2873        {
2874            Self::A(a) => return Some(IpAddr::V4(a.ip)),
2875            Self::AAAA(a) => return Some(IpAddr::V6(a.ip)),
2876            _ => return None
2877        }
2878    }
2879}
2880
2881#[cfg(test)]
2882mod tests
2883{
2884    use std::io::Cursor;
2885
2886    use crate::common::*;
2887
2888
2889
2890    #[test]
2891    fn test_pkt2name()
2892    {
2893        use std::time::Instant;
2894    
2895        fn prepare(d: &[u8]) -> Cursor<&[u8]>
2896        {
2897           // let vd = d.to_vec();
2898    
2899            return Cursor::new(d);
2900        }
2901    
2902        let t1 = b"\x03\x64\x6e\x73\x06\x67\x6f\x6f\x67\x6c\x65\x00";
2903    
2904        let mut cur1 = prepare(t1);
2905    
2906        let now = Instant::now();
2907        let r1 = pkt2name(&mut cur1);
2908        let elapsed = now.elapsed();
2909        println!("Elapsed: {:.2?}", elapsed);
2910    
2911        assert_eq!(r1.is_ok(), true);
2912        assert_eq!(r1.as_ref().unwrap(), t1);
2913    
2914        let t2 = 
2915        b"\x0f\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2916        \x30\x30\x03\x6e\x65\x74\x00";
2917    
2918        let mut cur2 = prepare(t2);
2919        let now = Instant::now();
2920        let r2 = pkt2name(&mut cur2);
2921        let elapsed = now.elapsed();
2922        println!("Elapsed: {:.2?}", elapsed);
2923    
2924        assert_eq!(r2.is_ok(), true);
2925        assert_eq!(r2.as_ref().unwrap(), t2);
2926    
2927        let t3 = 
2928        b"\x0f\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2929        \x30\x30\x03\x6e\x65\x74";
2930    
2931        let r3 = pkt2name(&mut prepare(t3));
2932    
2933        assert_eq!(r3.is_ok(), false);
2934    
2935        let t4 = 
2936        b"\x10\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2937        \x30\x30\x03\x6e\x65\x74";
2938    
2939        let r4 = pkt2name(&mut prepare(t4));
2940    
2941        assert_eq!(r4.is_ok(), false);
2942    }
2943    
2944    #[test]
2945    fn test_qname2str()
2946    {
2947        use std::time::Instant;
2948    
2949        fn prepare(d: &[u8]) -> Cursor<&[u8]>
2950        {
2951            //let vd = d.to_vec();
2952    
2953            return Cursor::new(d);
2954        }
2955    
2956        let t1 = b"\x03\x64\x6e\x73\x06\x67\x6f\x6f\x67\x6c\x65\x00";
2957    
2958        let mut cur1 = prepare(t1);
2959        let now = Instant::now();
2960        let r1 = name2str(&mut cur1, None);
2961        let elapsed = now.elapsed();
2962        println!("Elapsed: {:.2?}", elapsed);
2963    
2964        assert_eq!(r1.is_ok(), true);
2965        assert_eq!(r1.as_ref().unwrap(), "dns.google");
2966    
2967        let t2 = 
2968        b"\x0f\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2969        \x30\x30\x03\x6e\x65\x74\x00";
2970    
2971        let mut cur2 = prepare(t2);
2972    
2973        let now = Instant::now();
2974        let r2 = name2str(&mut cur2, None);
2975        let elapsed = now.elapsed();
2976        println!("Elapsed: {:.2?}", elapsed);
2977    
2978        assert_eq!(r2.is_ok(), true);
2979        assert_eq!(r2.as_ref().unwrap(), "mad07s09-in-x0e.1e100.net");
2980    
2981        let t3 = 
2982        b"\x0f\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2983        \x30\x30\x03\x6e\x65\x74";
2984    
2985        let r3 = name2str(&mut prepare(t3), None);
2986    
2987        assert_eq!(r3.is_ok(), false);
2988    
2989        let t4 = 
2990        b"\x10\x6d\x61\x64\x30\x37\x73\x30\x39\x2d\x69\x6e\x2d\x78\x30\x65\x05\x31\x65\x31\
2991        \x30\x30\x03\x6e\x65\x74";
2992    
2993        let r4 = name2str(&mut prepare(t4), None);
2994    
2995        assert_eq!(r4.is_ok(), false);
2996    }
2997    
2998    #[test]
2999    fn test_response_parser()
3000    {
3001        use std::time::Instant;
3002    
3003        let pkt = 
3004        b"\x15\xc8\x81\x80\x00\x01\x00\x01\x00\x00\x00\x02\x01\x38\x01\x38\
3005        \x01\x38\x01\x38\x07\x69\x6e\x2d\x61\x64\x64\x72\x04\x61\x72\x70\
3006        \x61\x00\x00\x0c\x00\x01\xc0\x0c\x00\x0c\x00\x01\x00\x01\x35\xf0\
3007        \x00\x0c\x03\x64\x6e\x73\x06\x67\x6f\x6f\x67\x6c\x65\x00\xc0\x32\
3008        \x00\x01\x00\x01\x00\x00\x00\xe8\x00\x04\x08\x08\x08\x08\xc0\x32\
3009        \x00\x01\x00\x01\x00\x00\x00\xe8\x00\x04\x08\x08\x04\x04";
3010    
3011        let dummy = 
3012            DnsRequestHeader
3013            {
3014                header: DnsHeader {id: 0x15c8, ..Default::default()},
3015                payload: DnsRequestPayload
3016                    {
3017                        qname: Cow::Borrowed(b"\x01\x38\x01\x38\x01\x38\x01\x38\x07\x69\x6e\x2d\x61\x64\x64\x72\x04\x61\x72\x70\x61\x00"),
3018                        qtype: QType::PTR,
3019                        qclass: QClass::IN, 
3020                    }
3021            };
3022    
3023        let now = Instant::now();
3024        let ans = DnsRequestAnswer::parse(pkt.as_slice());
3025        let elapsed = now.elapsed();
3026        println!("Elapsed: {:.2?}", elapsed);
3027    
3028        assert_eq!(ans.is_ok(), true, "{}", ans.err().unwrap());
3029        
3030        let ans = ans.unwrap();
3031    
3032        let verif = ans.verify(&dummy);
3033        assert_eq!(verif.is_ok(), true, "{}", verif.err().unwrap());
3034    
3035        assert_eq!(ans.req_header.header.id, 0x15c8);
3036        assert_eq!(ans.req_header.header.ancount, 1);
3037        assert_eq!(ans.req_header.header.arcount, 2);
3038        assert_eq!(ans.req_header.header.nscount, 0);
3039        assert_eq!(ans.req_header.header.qdcount, 1);
3040    
3041        assert_eq!(ans.response[0].rdata, RecordPTR::wrap(RecordPTR { fqdn: "dns.google".to_string() }) );
3042        assert_eq!(ans.response[0].name, "8.8.8.8.in-addr.arpa".to_string());
3043        assert_eq!(ans.response[0].dtype, QType::PTR);
3044        assert_eq!(ans.response[0].class, QClass::IN);
3045        assert_eq!(ans.response[0].ttl, 79344);
3046        assert_eq!(ans.response[0].rdlength, 12);
3047    
3048        assert_eq!(ans.additional[0].rdata, RecordA::wrap(RecordA { ip: "8.8.8.8".parse().unwrap() }) );
3049        assert_eq!(ans.additional[0].name, "dns.google".to_string());
3050        assert_eq!(ans.additional[0].ttl, 232);
3051        assert_eq!(ans.additional[0].dtype, QType::A);
3052        assert_eq!(ans.additional[0].class, QClass::IN);
3053
3054        assert_eq!(ans.additional[1].rdata, RecordA::wrap(RecordA { ip: "8.8.4.4".parse().unwrap() }) );
3055        assert_eq!(ans.additional[1].name, "dns.google".to_string());
3056        assert_eq!(ans.additional[1].ttl, 232);
3057        assert_eq!(ans.additional[1].dtype, QType::A);
3058        assert_eq!(ans.additional[1].class, QClass::IN);
3059    }
3060    
3061    #[test]
3062    fn test_response2()
3063    {
3064        use std::time::Instant;
3065    
3066        let pkt = 
3067        b"\x4b\x38\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\x05\x67\x6d\x61\
3068        \x69\x6c\x03\x63\x6f\x6d\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\
3069        \x01\x00\x00\x0b\x55\x00\x1b\x00\x05\x0d\x67\x6d\x61\x69\x6c\x2d\
3070        \x73\x6d\x74\x70\x2d\x69\x6e\x01\x6c\x06\x67\x6f\x6f\x67\x6c\x65\
3071        \xc0\x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x0b\x55\x00\x09\x00\x0a\
3072        \x04\x61\x6c\x74\x31\xc0\x29\xc0\x0c\x00\x0f\x00\x01\x00\x00\x0b\
3073        \x55\x00\x09\x00\x1e\x04\x61\x6c\x74\x33\xc0\x29\xc0\x0c\x00\x0f\
3074        \x00\x01\x00\x00\x0b\x55\x00\x09\x00\x14\x04\x61\x6c\x74\x32\xc0\
3075        \x29\xc0\x0c\x00\x0f\x00\x01\x00\x00\x0b\x55\x00\x09\x00\x28\x04\
3076        \x61\x6c\x74\x34\xc0\x29";
3077    
3078        let dummy = 
3079            DnsRequestHeader
3080            {
3081                header: DnsHeader {id: 0x4b38, ..Default::default()},
3082                payload: DnsRequestPayload
3083                    {
3084                        qname: Cow::Borrowed(b"\x05\x67\x6d\x61\x69\x6c\x03\x63\x6f\x6d\x00"),
3085                        qtype: QType::MX,
3086                        qclass: QClass::IN, 
3087                    }
3088            };
3089    
3090        let now = Instant::now();
3091        let ans = DnsRequestAnswer::parse(pkt.as_slice());
3092        let elapsed = now.elapsed();
3093        println!("Elapsed: {:.2?}", elapsed);
3094    
3095        assert_eq!(ans.is_ok(), true, "{}", ans.err().unwrap());
3096        let ans = ans.unwrap();
3097    
3098        let verif = ans.verify(&dummy);
3099        assert_eq!(verif.is_ok(), true, "{}", verif.err().unwrap());
3100    
3101        assert_eq!(ans.req_header.header.id, 0x4b38);
3102        assert_eq!(ans.req_header.header.ancount, 5);
3103        assert_eq!(ans.req_header.header.arcount, 0);
3104        assert_eq!(ans.req_header.header.nscount, 0);
3105        assert_eq!(ans.req_header.header.qdcount, 1);
3106    
3107        assert_eq!(ans.response[0].rdata, RecordMX::wrap(RecordMX { preference: 5, exchange: "gmail-smtp-in.l.google.com".to_string() }) );
3108        assert_eq!(ans.response[0].name, "gmail.com".to_string());
3109        assert_eq!(ans.response[0].dtype, QType::MX);
3110        assert_eq!(ans.response[0].class, QClass::IN);
3111        assert_eq!(ans.response[0].ttl, 2901);
3112        assert_eq!(ans.response[0].rdlength, 27);
3113    
3114        assert_eq!(ans.response[1].rdata, RecordMX::wrap(RecordMX { preference: 10, exchange: "alt1.gmail-smtp-in.l.google.com".to_string() }) );
3115        assert_eq!(ans.response[1].name, "gmail.com".to_string());
3116        assert_eq!(ans.response[1].dtype, QType::MX);
3117        assert_eq!(ans.response[1].class, QClass::IN);
3118        assert_eq!(ans.response[1].ttl, 2901);
3119        assert_eq!(ans.response[1].rdlength, 9);
3120    
3121        assert_eq!(ans.response[2].rdata, RecordMX::wrap(RecordMX { preference: 30, exchange: "alt3.gmail-smtp-in.l.google.com".to_string() }) );
3122        assert_eq!(ans.response[2].name, "gmail.com".to_string());
3123        assert_eq!(ans.response[2].dtype, QType::MX);
3124        assert_eq!(ans.response[2].class, QClass::IN);
3125        assert_eq!(ans.response[2].ttl, 2901);
3126        assert_eq!(ans.response[2].rdlength, 9);
3127    
3128        assert_eq!(ans.response[3].rdata, RecordMX::wrap(RecordMX { preference: 20, exchange: "alt2.gmail-smtp-in.l.google.com".to_string() }) );
3129        assert_eq!(ans.response[3].name, "gmail.com".to_string());
3130        assert_eq!(ans.response[3].dtype, QType::MX);
3131        assert_eq!(ans.response[3].class, QClass::IN);
3132        assert_eq!(ans.response[3].ttl, 2901);
3133        assert_eq!(ans.response[3].rdlength, 9);
3134    
3135        assert_eq!(ans.response[4].rdata, RecordMX::wrap(RecordMX { preference: 40, exchange: "alt4.gmail-smtp-in.l.google.com".to_string() }) );
3136        assert_eq!(ans.response[4].name, "gmail.com".to_string());
3137        assert_eq!(ans.response[4].dtype, QType::MX);
3138        assert_eq!(ans.response[4].class, QClass::IN);
3139        assert_eq!(ans.response[4].ttl, 2901);
3140        assert_eq!(ans.response[4].rdlength, 9);
3141    }
3142    
3143    
3144    #[test]
3145    fn test_response3()
3146    {
3147        use std::time::Instant;
3148    
3149        let pkt = 
3150    b"\xd0\x79\x81\x80\x00\x01\x00\x17\x00\x00\x00\x00\x06\x72\
3151    \x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\x00\xff\x00\x01\xc0\x0c\x00\
3152    \x06\x00\x01\x00\x00\x0e\x10\x00\x30\x04\x6e\x73\x32\x31\x07\x63\
3153    \x6c\x6f\x75\x64\x6e\x73\x03\x6e\x65\x74\x00\x07\x73\x75\x70\x70\
3154    \x6f\x72\x74\xc0\x2c\x78\x77\xe2\xf1\x00\x00\x1c\x20\x00\x00\x07\
3155    \x08\x00\x12\x75\x00\x00\x00\x0e\x10\xc0\x0c\x00\x2e\x00\x01\x00\
3156    \x00\x0e\x10\x00\x5d\x00\x06\x0d\x02\x00\x00\x0e\x10\x61\xf2\xaf\
3157    \x39\x61\xcb\x22\x39\x28\xeb\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\
3158    \x6b\x00\x2f\x79\xed\x73\xd0\x75\xc8\xa9\xa2\x2a\x08\x3c\x78\xb9\
3159    \xfb\x43\xc5\x8e\x62\x4c\xbc\x36\xeb\x22\x96\x45\x59\x36\x1f\x69\
3160    \x3a\x7a\x5e\x67\xd0\x54\x1e\xf0\xf2\x11\x1a\x72\x00\x56\x89\x26\
3161    \x79\xf4\x06\x1a\x0c\x59\x41\x32\x60\x68\x75\x05\x3d\x90\xed\x1e\
3162    \x0f\xfc\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0\x27\
3163    \xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x08\x05\x70\x6e\x73\
3164    \x32\x33\xc0\x2c\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x07\
3165    \x04\x6e\x73\x32\x33\xc0\x2c\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\
3166    \x10\x00\x08\x05\x70\x6e\x73\x32\x32\xc0\x2c\xc0\x0c\x00\x02\x00\
3167    \x01\x00\x00\x0e\x10\x00\x08\x05\x70\x6e\x73\x32\x34\xc0\x2c\xc0\
3168    \x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x07\x04\x6e\x73\x32\x34\
3169    \xc0\x2c\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x08\x05\x70\
3170    \x6e\x73\x32\x31\xc0\x2c\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\
3171    \x00\x07\x04\x6e\x73\x32\x32\xc0\x2c\xc0\x0c\x00\x2e\x00\x01\x00\
3172    \x00\x0e\x10\x00\x5d\x00\x02\x0d\x02\x00\x00\x0e\x10\x61\xf2\xaf\
3173    \x39\x61\xcb\x22\x39\x28\xeb\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\
3174    \x6b\x00\xd1\xc5\x6c\xf1\xfb\xd0\x75\xf1\x38\x20\x28\x80\x4c\xe0\
3175    \x59\xa5\xa8\xab\x84\x79\xd8\x37\x48\xa7\xa5\x3f\x08\x9b\x4c\xca\
3176    \x40\x2b\xcb\x2c\xda\xcc\xc2\x18\xad\x07\x9e\xf8\x4e\x17\x8d\xb1\
3177    \x2b\x2d\xa2\xa6\x17\xdb\x55\x30\xbc\xa2\xb9\xa0\x01\x71\x01\xe5\
3178    \xdc\x4f\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xd9\x14\
3179    \x70\xd0\xc0\x0c\x00\x2e\x00\x01\x00\x00\x0e\x10\x00\x5d\x00\x01\
3180    \x0d\x02\x00\x00\x0e\x10\x61\xf2\xaf\x39\x61\xcb\x22\x39\x28\xeb\
3181    \x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\xf8\x57\x68\xf0\xad\
3182    \x9e\xfb\x3a\x0f\x66\xbd\xcc\x48\xe7\x29\x0a\xf4\xd8\xf6\xbe\xbc\
3183    \x04\x76\x02\x27\x64\xf2\xc9\x42\x6d\x75\x54\x83\x0a\x11\xda\x0a\
3184    \x02\x6b\x8c\xf1\x65\xc4\x21\x44\xea\x89\x09\x01\xc8\xa1\xe2\x11\
3185    \x8f\xed\x67\x39\x69\x33\xdd\x97\x22\x1a\xd3\xc0\x0c\x00\x0f\x00\
3186    \x01\x00\x00\x0e\x10\x00\x11\x00\x0a\x04\x6d\x61\x69\x6c\x04\x6e\
3187    \x69\x78\x64\x03\x6f\x72\x67\x00\xc0\x0c\x00\x2e\x00\x01\x00\x00\
3188    \x0e\x10\x00\x5d\x00\x0f\x0d\x02\x00\x00\x0e\x10\x61\xf2\xaf\x39\
3189    \x61\xcb\x22\x39\x28\xeb\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\
3190    \x00\xd4\xdd\x07\xd9\xb6\xb2\xba\x57\xa9\x1d\x3b\xaa\x6c\x55\xc4\
3191    \x3d\x73\x79\xea\x74\xfe\xd7\x23\x0c\xb4\xab\x8f\x4b\x1f\xd9\x8a\
3192    \xb2\x4a\x5c\xad\x3e\x8e\x4a\x85\xbb\xbd\x75\xf2\x47\x2c\xa8\x89\
3193    \x21\x75\x89\xb1\x12\xc4\xd2\xf7\x40\x06\x52\x57\x83\x8a\xaa\x7b\
3194    \x75\xc0\x0c\x00\x10\x00\x01\x00\x00\x0e\x10\x00\x34\x33\x76\x3d\
3195    \x73\x70\x66\x31\x20\x2b\x6d\x78\x20\x2b\x61\x3a\x6d\x61\x69\x6c\
3196    \x2e\x6e\x69\x78\x64\x2e\x6f\x72\x67\x20\x69\x70\x34\x3a\x32\x31\
3197    \x37\x2e\x32\x30\x2e\x31\x31\x32\x2e\x32\x30\x38\x20\x2d\x61\x6c\
3198    \x6c\xc0\x0c\x00\x2e\x00\x01\x00\x00\x0e\x10\x00\x5d\x00\x10\x0d\
3199    \x02\x00\x00\x0e\x10\x61\xf2\xaf\x39\x61\xcb\x22\x39\x28\xeb\x06\
3200    \x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\xd1\x6c\xd1\xf4\x3b\xe0\
3201    \x44\xba\xfe\xe9\xdb\x82\xbd\x89\x5f\xa1\x07\x72\xdd\x47\xad\x4e\
3202    \x91\xd5\xc3\xfe\x3e\x39\x74\xdb\x50\x50\x19\x6c\x3f\x6c\xb7\xa8\
3203    \x01\x03\x6a\xf5\xa7\xf3\x9b\xf7\x76\xd4\xff\xa3\xd5\x43\xfc\xec\
3204    \xa9\x89\x24\xf8\xd2\xb6\x76\xd4\x20\xbc\xc0\x0c\x00\x30\x00\x01\
3205    \x00\x00\x0e\x10\x00\x44\x01\x01\x03\x0d\xf3\x87\xe2\x7c\x2b\x82\
3206    \x40\x72\x7c\xfd\xc9\x2b\xe8\x22\xd6\xa9\x40\xc0\xab\x03\x25\x7d\
3207    \x92\xae\xf3\x17\x71\x82\x67\xc6\xcd\xb6\x4b\x11\x62\xc6\xfa\x06\
3208    \xec\x4c\x9f\xd9\xe6\xaf\x5c\x3d\xe4\x32\xde\x11\x1b\x09\x13\xe3\
3209    \xd0\xba\x66\xd1\xbc\x32\xdb\x13\xd7\x1d\xc0\x0c\x00\x30\x00\x01\
3210    \x00\x00\x0e\x10\x00\x44\x01\x00\x03\x0d\xd4\x43\xde\x96\xe5\xea\
3211    \x0a\xf9\x5d\x4f\x72\x88\x9c\xd9\x9c\xf7\xa6\x3f\x12\xd7\xf3\xea\
3212    \x8a\x6b\x44\x4c\x79\x23\x81\x94\x43\xa3\xbd\x9e\xb8\xde\xfe\x8c\
3213    \xe6\x21\xe3\x8a\x71\xba\x05\xd2\x0f\x98\x5b\xfc\x7e\x72\x8c\xe9\
3214    \x9a\xc0\x49\x00\xca\xd5\x62\x93\x7f\x03\xc0\x0c\x00\x2e\x00\x01\
3215    \x00\x00\x0e\x10\x00\x5d\x00\x30\x0d\x02\x00\x00\x0e\x10\x61\xf2\
3216    \xaf\x39\x61\xcb\x22\x39\x28\xeb\x06\x72\x65\x6c\x6b\x6f\x6d\x02\
3217    \x73\x6b\x00\xc0\x93\x23\x1d\xcb\x1e\x79\xfe\x7c\x40\x3e\xd4\x33\
3218    \x5f\xed\x69\x8e\x7d\x75\xff\x73\x6b\x24\x71\x8f\x50\xf8\xe0\x49\
3219    \xce\x5f\x62\x0c\x8c\xb3\x06\x8f\x26\xea\x20\xa0\xe3\x71\xe0\xa1\
3220    \x8b\xe0\x4a\x2f\x1d\x4b\x79\x2c\x52\x6b\xa4\x43\xb5\x70\x27\x01\
3221    \xb0\x63\x47\xc0\x0c\x00\x2e\x00\x01\x00\x00\x0e\x10\x00\x5d\x00\
3222    \x30\x0d\x02\x00\x00\x0e\x10\x61\xf2\xaf\x39\x61\xcb\x22\x39\x97\
3223    \x18\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\x41\x87\x75\x1d\
3224    \x30\x44\xd1\x94\x40\xd4\xe6\x40\x98\x62\x94\x53\xad\x53\xe2\xed\
3225    \xc0\xc0\xb7\xa3\x20\x15\xae\x59\xbb\x97\x45\xfb\x0e\xbf\x70\xf3\
3226    \xb1\x24\x79\xe8\x85\x6c\x2a\x66\x10\xb6\x75\x99\x7b\x77\x78\x65\
3227    \xa6\x67\x8d\x59\xa6\x14\xf7\xe6\x77\xab\x53\x9c\xc0\x0c\x00\x33\
3228    \x00\x01\x00\x00\x02\x58\x00\x0d\x01\x00\x00\x0a\x08\x90\xc7\xf1\
3229    \x74\x0b\x0c\xfb\x34\xc0\x0c\x00\x2e\x00\x01\x00\x00\x02\x58\x00\
3230    \x5d\x00\x33\x0d\x02\x00\x00\x00\x00\x61\xf2\xaf\x39\x61\xcb\x22\
3231    \x39\x28\xeb\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\xc4\x4d\
3232    \x00\x48\x9c\x86\x49\xac\x8d\x03\x28\x23\xac\xec\xf5\x5b\xb6\xe5\
3233    \x2f\xf6\xae\xaa\x01\x5a\x66\x52\xf7\x43\xc3\xb1\xe5\xef\xe5\xbf\
3234    \x5f\x71\x5d\xa1\x57\x64\x66\x5e\xa1\x6f\x96\xa8\xcd\x48\x85\xe4\
3235    \x20\xe2\xfb\xb0\xc1\x00\x47\x72\xc8\x72\x98\xc7\x41\xd9";
3236        
3237        let dummy = 
3238            DnsRequestHeader
3239            {
3240                header: DnsHeader {id: 0xd079, ..Default::default()},
3241                payload: DnsRequestPayload
3242                    {
3243                        qname: Cow::Borrowed(b"\x06\x72\x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00"),
3244                        qtype: QType::ALL,
3245                        qclass: QClass::IN, 
3246                    }
3247            };
3248    
3249        let now = Instant::now();
3250        let ans = DnsRequestAnswer::parse(pkt.as_slice());
3251        let elapsed = now.elapsed();
3252        println!("Elapsed: {:.2?}", elapsed);
3253    
3254        assert_eq!(ans.is_ok(), true, "{}", ans.err().unwrap());
3255        let ans = ans.unwrap();
3256    
3257        let verif = ans.verify(&dummy);
3258        assert_eq!(verif.is_ok(), true, "{}", verif.err().unwrap());
3259    
3260        assert_eq!(ans.req_header.header.id, 0xd079);
3261        assert_eq!(ans.req_header.header.ancount, 23);
3262        assert_eq!(ans.req_header.header.arcount, 0);
3263        assert_eq!(ans.req_header.header.nscount, 0);
3264        assert_eq!(ans.req_header.header.qdcount, 1);
3265    
3266        let ansord = &ans.response[0];
3267        assert_eq!(
3268            ansord.rdata, 
3269                RecordSOA::wrap(
3270                    RecordSOA
3271                    { 
3272                        pnm: "ns21.cloudns.net".to_string(), 
3273                        ram: "support.cloudns.net".to_string(), 
3274                        serial: 2021122801,  
3275                        interv_refr: 7200,
3276                        interv_retry: 1800,
3277                        expire_limit: 1209600,
3278                        min_ttl: 3600
3279                    }
3280            )
3281        );
3282        assert_eq!(ansord.name, "relkom.sk".to_string());
3283        assert_eq!(ansord.dtype, QType::SOA);
3284        assert_eq!(ansord.class, QClass::IN);
3285        assert_eq!(ansord.ttl, 3600);
3286        assert_eq!(ansord.rdlength, 48);
3287    
3288        let a1 = 
3289    b"\x00\x06\x0d\x02\
3290    \x00\x00\x0e\x10\x61\xf2\xaf\x39\x61\xcb\x22\x39\x28\xeb\x06\x72\
3291    \x65\x6c\x6b\x6f\x6d\x02\x73\x6b\x00\x2f\x79\xed\x73\xd0\x75\xc8\
3292    \xa9\xa2\x2a\x08\x3c\x78\xb9\xfb\x43\xc5\x8e\x62\x4c\xbc\x36\xeb\
3293    \x22\x96\x45\x59\x36\x1f\x69\x3a\x7a\x5e\x67\xd0\x54\x1e\xf0\xf2\
3294    \x11\x1a\x72\x00\x56\x89\x26\x79\xf4\x06\x1a\x0c\x59\x41\x32\x60\
3295    \x68\x75\x05\x3d\x90\xed\x1e\x0f\xfc";
3296        let mut a1curs = Cursor::new(a1.as_slice());
3297        let a1len = a1.len();
3298
3299        let ansord = &ans.response[1];
3300        assert_eq!(ansord.rdata, RecordRRSIG::wrap( RecordRRSIG::read(&mut a1curs, a1len as u16, QType::RRSIG).unwrap() ));
3301        assert_eq!(ansord.name, "relkom.sk".to_string());
3302        assert_eq!(ansord.dtype, QType::RRSIG);
3303        assert_eq!(ansord.class, QClass::IN);
3304        assert_eq!(ansord.ttl, 3600);
3305        assert_eq!(ansord.rdlength, a1len as u16);
3306    
3307        let ansord = &ans.response[2];
3308        assert_eq!(ansord.rdata, RecordNS::wrap( RecordNS{ fqdn: "ns21.cloudns.net".to_string() }));
3309        assert_eq!(ansord.name, "relkom.sk".to_string());
3310        assert_eq!(ansord.dtype, QType::NS);
3311        assert_eq!(ansord.class, QClass::IN);
3312        assert_eq!(ansord.ttl, 3600);
3313        assert_eq!(ansord.rdlength, 2);
3314    }
3315    
3316    
3317    #[test]
3318    fn test_request()
3319    {
3320        use std::time::Instant;
3321        use std::net::IpAddr;
3322    
3323        let ipp = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
3324        let qdnsreq = 
3325            QDnsReq::new_into(&ipp, QType::PTR)
3326                .unwrap();
3327    
3328        let now = Instant::now();
3329    
3330        let req = DnsRequestHeader::construct_lookup(&qdnsreq);
3331    
3332        let elapsed = now.elapsed();
3333        println!("Elapsed: {:.2?}", elapsed);
3334    
3335        assert_eq!(req.is_ok(), true, "{}", req.err().unwrap());
3336    
3337        let pkt = req.unwrap().to_bytes(false);
3338        assert_eq!(pkt.is_ok(), true);
3339        let pkt = pkt.unwrap();
3340    
3341        let ctrl = 
3342        b"\x15\xc8\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x38\x01\x38\
3343        \x01\x38\x01\x38\x07\x69\x6e\x2d\x61\x64\x64\x72\x04\x61\x72\x70\
3344        \x61\x00\x00\x0c\x00\x01";
3345    
3346        assert_eq!(&pkt[2..], &ctrl[2..]);
3347    }
3348    
3349    #[test]
3350    fn test_request_1()
3351    {
3352        use std::time::Instant;
3353        use std::net::IpAddr;
3354    
3355        let ipp = IpAddr::V4("100.150.111.80".parse().unwrap());
3356        let qdnsreq = 
3357            QDnsReq::new_into(&ipp, QType::PTR)
3358                .unwrap();
3359    
3360        let now = Instant::now();
3361    
3362        let req = DnsRequestHeader::construct_lookup(&qdnsreq);
3363    
3364        let elapsed = now.elapsed();
3365        println!("Elapsed: {:.2?}", elapsed);
3366    
3367        assert_eq!(req.is_ok(), true, "{}", req.err().unwrap());
3368    
3369        let pkt = req.unwrap().to_bytes(false);
3370        assert_eq!(pkt.is_ok(), true);
3371        let pkt = pkt.unwrap();
3372    
3373        let ctrl = 
3374        b"\x74\xa1\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x02\x38\x30\x03\
3375        \x31\x31\x31\x03\x31\x35\x30\x03\x31\x30\x30\x07\x69\x6e\x2d\x61\
3376        \x64\x64\x72\x04\x61\x72\x70\x61\x00\x00\x0c\x00\x01";
3377        
3378        assert_eq!(&pkt[2..], &ctrl[2..]);
3379    }
3380    
3381    #[test]
3382    fn test_request6()
3383    {
3384        use std::time::Instant;
3385        use std::net::IpAddr;
3386        
3387        let ipp =  IpAddr::V6("2a00:1450:4003:802::200e".parse().unwrap());
3388        let qdnsreq = 
3389            QDnsReq::new_into(&ipp, QType::PTR)
3390                .unwrap();
3391    
3392        let now = Instant::now();
3393    
3394        let req = DnsRequestHeader::construct_lookup(&qdnsreq);
3395    
3396        let elapsed = now.elapsed();
3397        println!("Elapsed: {:.2?}", elapsed);
3398    
3399        assert_eq!(req.is_ok(), true, "{}", req.err().unwrap());
3400    
3401        let pkt = req.unwrap().to_bytes(false);
3402        assert_eq!(pkt.is_ok(), true);
3403        let pkt = pkt.unwrap();
3404    
3405        let ctrl = 
3406        b"\xee\xec\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x65\x01\x30\
3407        \x01\x30\x01\x32\x01\x30\x01\x30\x01\x30\x01\x30\x01\x30\x01\x30\
3408        \x01\x30\x01\x30\x01\x30\x01\x30\x01\x30\x01\x30\x01\x32\x01\x30\
3409        \x01\x38\x01\x30\x01\x33\x01\x30\x01\x30\x01\x34\x01\x30\x01\x35\
3410        \x01\x34\x01\x31\x01\x30\x01\x30\x01\x61\x01\x32\x03\x69\x70\x36\
3411        \x04\x61\x72\x70\x61\x00\x00\x0c\x00\x01";
3412    
3413        assert_eq!(&pkt[2..], &ctrl[2..]);
3414    }
3415    
3416}