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 2025 Aleksandr Morozov
7 * 
8 * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
9 * the European Commission - subsequent versions of the EUPL (the "Licence").
10 * 
11 * You may not use this work except in compliance with the Licence.
12 * 
13 * You may obtain a copy of the Licence at:
14 * 
15 *    https://joinup.ec.europa.eu/software/page/eupl
16 * 
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
20 * Licence for the specific language governing permissions and limitations
21 * under the Licence.
22 */
23
24use std::{cmp::Ordering, fmt, net::{IpAddr, Ipv4Addr, Ipv6Addr}, path::Path, sync::LazyLock};
25use std::borrow::Borrow;
26use std::hash::{Hash, Hasher};
27
28use crate::{error::*, query_private::QDnsReq, cfg_resolv_parser::ResolveConfigLookup, cfg_host_parser::HostnameEntry};
29use crate::internal_error;
30
31use super::cfg_resolv_parser::ResolveConfig;
32
33/// A location on the disk where resolv.conf is located
34pub const RESOLV_CFG_PATH: &'static str = "/etc/resolv.conf";
35
36/// A hosts file location on disk
37pub const HOST_CFG_PATH: &'static str = "/etc/hosts";
38
39pub static RESOLV_CFG_PATH_P: LazyLock<&'static Path> = LazyLock::new(|| {Path::new(RESOLV_CFG_PATH)});
40pub static HOST_CFG_PATH_P: LazyLock<&'static Path> = LazyLock::new(|| {Path::new(HOST_CFG_PATH)});
41
42/// A nsswitch location
43pub const NSSWITCH_CFG_PATH: &'static str = "/etc/nsswitch.conf";
44
45const IN_ADDR_ARPA: &[u8] = b"\x07in-addr\x04arpa\x00";
46const IN_ADDR6_ARPA: &[u8] = b"\x03ip6\x04arpa\x00";
47
48/// Default BIND for IPv4
49pub const IPV4_BIND_ALL: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
50/// Default BIND for IPv6
51pub const IPV6_BIND_ALL: IpAddr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
52
53
54/// Converts a part of the octec of IP to printable hex i.e valid range is from
55/// 0 up to 15 will be converted to 0x30..0x39 and 'a'..'f'.
56/// 
57/// # Arguments
58/// 
59/// * `b` - a part of the octec
60/// 
61/// # Returns
62/// 
63/// * u8 an ASCII representation
64/// 
65/// # Throws
66/// 
67/// Panic when input b >= 16
68pub 
69fn byte2hexchar(b: u8) -> u8
70{
71    match b
72    {
73        0..=9 => return '0' as u8 + b,
74        10..=15 => return 'a' as u8 + (b - 10),
75        _ => panic!("out of hex range!")
76    }
77}
78
79/// Converts [IpAddr] to sequence of bytes coded specially for the payload
80/// of package.
81/// 
82/// # Arguments
83/// 
84/// * `ip` - the argument with IP address
85/// 
86/// # Returns
87/// 
88/// * [CDnsResult] with vector of coded data
89pub 
90fn ip2pkt(ip: &IpAddr) -> CDnsResult<Vec<u8>>
91{    
92    match *ip
93    {
94        IpAddr::V4(ref ipv4) =>
95            return ipv4_pkt(ipv4),
96        IpAddr::V6(ref ipv6) =>
97            return ipv6_pkt(ipv6)
98    };
99}
100
101const MAX_NAME_LEN: usize = 63;
102
103pub 
104fn ipv4_pkt(ip: &Ipv4Addr) -> CDnsResult<Vec<u8>>
105{    
106
107    // pre allocate space
108    let mut out: Vec<u8> = Vec::with_capacity(16 + IN_ADDR_ARPA.len());
109    
110    let mut octets = ip.octets();
111    octets.reverse();
112
113    for oct in octets
114    {
115        let str_oct = oct.to_string();
116
117        if str_oct.len() > 3
118        {
119            internal_error!(
120                CDnsErrorType::InternalError, 
121                "domain component too long, len: '{}' oct: '{}'", 
122                str_oct.len(), str_oct
123            );
124        }
125
126        let ln: u8 = str_oct.len() as u8;
127
128        out.push(ln);
129        out.extend(str_oct.as_bytes());
130    }
131
132    out.extend(IN_ADDR_ARPA);
133
134    return Ok(out);
135}
136
137pub 
138fn ipv6_pkt(ip: &Ipv6Addr) -> CDnsResult<Vec<u8>>
139{    
140    // pre allocate space
141    let mut out: Vec<u8> = Vec::with_capacity(32 + IN_ADDR6_ARPA.len());
142    
143    let mut octets = ip.octets();
144    octets.reverse();
145
146    for oct in octets
147    {
148        let h_oct = byte2hexchar((oct & 0xF0) >> 4);
149        //format!("{:x}", (oct & 0xF0) >> 4);
150        let l_oct = byte2hexchar(oct & 0x0F);
151        //format!("{:x}", oct & 0x0F);
152
153        //let ln: u8 = str_oct.len() as u8;
154
155        out.push(1);
156        out.push(l_oct);
157        //out.extend(l_oct.as_bytes());
158        out.push(1);
159        out.push(h_oct);
160    }
161
162    out.extend(IN_ADDR6_ARPA);
163
164    return Ok(out);
165}
166
167pub 
168fn name2pkt(name: &str) -> CDnsResult<Vec<u8>>
169{    
170    // pre allocate space
171    let mut out: Vec<u8> = Vec::with_capacity(name.len() + 2);
172    
173    for n in name.split(".")
174    {
175        if n.len() >= MAX_NAME_LEN
176        {
177            internal_error!(CDnsErrorType::InternalError, "name too long: '{}' in: '{}'", n.len(), name);
178        }
179
180        out.push((n.len() & 0xFF) as u8);
181        out.extend(n.as_bytes());
182    }
183
184    out.push(0);
185
186    return Ok(out);
187}
188
189
190/// A two octet code which specifies the type of the query.
191/// TYPE fields are used in resource records.  Note that these types are a
192/// subset of QTYPEs.
193/// QTYPE fields appear in the question part of a query.  QTYPES are a
194/// superset of TYPEs, hence all TYPEs are valid QTYPEs.
195#[repr(u16)]
196#[derive(Clone, Copy, Debug, PartialEq, Eq)]
197pub enum QType
198{
199    /// 1 a host address
200    A = 1,
201    /// 2 an authoritative name server
202    NS = 2,
203    /// 3 a mail destination (Obsolete - use MX)
204    MD = 3,
205    /// 4 a mail forwarder (Obsolete - use MX)
206    MF = 4,
207    /// 5 the canonical name for an alias
208    CNAME = 5,
209    /// 6 marks the start of a zone of authority
210    SOA = 6,
211    /// 7 a mailbox domain name (EXPERIMENTAL)
212    MB = 7,
213    /// 8 a mail group member (EXPERIMENTAL)
214    MG = 8,
215    /// 9 a mail rename domain name (EXPERIMENTAL)
216    MR = 9,
217    /// 10 a null RR (EXPERIMENTAL)
218    NULL = 10,
219    /// 11 a well known service description
220    WKS = 11,
221    /// 12 a domain name pointer
222    PTR = 12,
223    /// 13 host information
224    HINFO = 13,
225    /// 14 mailbox or mail list information
226    MINFO = 14,
227    /// 15 mail exchange
228    MX = 15,
229    /// 16 text strings
230    TXT = 16,
231    /// 18 AFS database record 
232    AFSDB = 18,
233    /// 25 Key record
234    KEY = 25,
235    /// 28 IPv6 address record
236    AAAA = 28,
237    /// 37 Certificate records
238    CERT = 37,
239    /// 43 Delegation signer
240    DS = 43,
241    /// 46 DNSSEC signature
242    RRSIG = 46,
243    /// 47 Next Secure record
244    NSEC = 47,
245    /// DNS Key record
246    DNSKEY = 48,
247    /// 50 Next Secure record version 3
248    NSEC3 = 50,
249    /// 51 NSEC3 parameters
250    NSEC3PARAM = 51,
251    /// 59 Child DS 
252    CDS = 59,
253    /// 60 Child copy of DNSKEY record, for transfer to parent
254    CDNSKEY = 60,
255    /// OpenPGP public key record 
256    OPENPGPKEY = 61,
257    // ---- QTYPE ----
258    /// 252 A request for a transfer of an entire zone
259    AXFR = 252,
260    /// 253 A request for mailbox-related records (MB, MG or MR)
261    MAILB = 253,
262    /// 254 A request for mail agent RRs (Obsolete - see MX)
263    MAILA = 254,
264    /// 257 Certification Authority Authorization 
265    CAA = 257,
266    /// *
267    ALL = 255,
268    /// 32769 DNSSEC Lookaside Validation record
269    DLV = 32769,
270}
271
272impl Default for QType
273{
274    fn default() -> Self 
275    {
276        return Self::A;    
277    }
278}
279
280
281impl Into<u16> for QType
282{
283    fn into(self) -> u16 
284    {
285        return self as u16;
286    }
287}
288
289impl fmt::Display for QType
290{
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
292    {
293        match *self
294        {
295            Self::A          => write!(f, "A"),
296            Self::NS         => write!(f, "NS"),
297            Self::MD         => write!(f, "MD"),
298            Self::MF         => write!(f, "MF"),
299            Self::CNAME      => write!(f, "CNAME"),
300            Self::SOA        => write!(f, "SOA"),
301            Self::MB         => write!(f, "MB"),
302            Self::MG         => write!(f, "MG"),
303            Self::MR         => write!(f, "MR"),
304            Self::NULL       => write!(f, "NULL"),
305            Self::WKS        => write!(f, "WKS"),
306            Self::PTR        => write!(f, "PTR"),
307            Self::HINFO      => write!(f, "HINFO"),
308            Self::MINFO      => write!(f, "MINFO"),
309            Self::MX         => write!(f, "MX"),
310            Self::TXT        => write!(f, "TXT"),
311            Self::AFSDB      => write!(f, "AFSDB"),
312            Self::KEY        => write!(f, "KEY"),
313            Self::AAAA       => write!(f, "AAAA"),
314            Self::CERT       => write!(f, "CERT"),
315            Self::DS         => write!(f, "DS"),
316            Self::RRSIG      => write!(f, "RRSIG"),
317            Self::NSEC       => write!(f, "NSEC"),
318            Self::DNSKEY     => write!(f, "DNSKEY"),
319            Self::NSEC3      => write!(f, "NSEC"),
320            Self::NSEC3PARAM => write!(f, "NSEC3PARAM"),
321            Self::CDS        => write!(f, "CDS"),
322            Self::CDNSKEY    => write!(f, "CDNSKEY"),
323            Self::OPENPGPKEY => write!(f, "OPENPGPKEY"),
324            Self::AXFR       => write!(f, "AXFR"),
325            Self::MAILB      => write!(f, "MAILB"),
326            Self::MAILA      => write!(f, "MAILA"),
327            Self::CAA        => write!(f, "CAA"),
328            Self::ALL        => write!(f, "ALL"),
329            Self::DLV        => write!(f, "DLV"),
330        }
331    }
332}
333
334
335impl QType
336{
337    pub 
338    fn ipaddr_match(&self, ip: &IpAddr) -> bool
339    {
340        match *self
341        {
342            Self::A => return ip.is_ipv4(),
343            Self::AAAA => return ip.is_ipv6(),
344            _ => false,
345        }
346    }
347
348    pub 
349    fn u16_to_qtype(value: u16) -> CDnsResult<QType>
350    {
351        match value
352        {
353            x if x == Self::AXFR as u16    => return Ok(Self::AXFR),
354            x if x == Self::MAILB as u16   => return Ok(Self::MAILB),
355            x if x == Self::MAILA as u16   => return Ok(Self::MAILA),
356            x if x == Self::ALL as u16     => return Ok(Self::ALL),
357            x if x == Self::DLV as u16     => return Ok(Self::DLV),
358            _ => return Self::u16_to_type(value),
359        }
360    }
361
362    pub 
363    fn u16_to_type(value: u16) -> CDnsResult<QType>
364    {
365
366        match value
367        {
368            x if x == Self::A as u16            => return Ok(Self::A),
369            x if x == Self::NS as u16           => return Ok(Self::NS),
370            x if x == Self::MD as u16           => return Ok(Self::MD),
371            x if x == Self::MF as u16           => return Ok(Self::MF),
372            x if x == Self::CNAME as u16        => return Ok(Self::CNAME),
373            x if x == Self::SOA as u16          => return Ok(Self::SOA),
374            x if x == Self::MB as u16           => return Ok(Self::MB),
375            x if x == Self::MG as u16           => return Ok(Self::MG),
376            x if x == Self::MR as u16           => return Ok(Self::MR),
377            x if x == Self::NULL as u16         => return Ok(Self::NULL),
378            x if x == Self::WKS as u16          => return Ok(Self::WKS),
379            x if x == Self::PTR as u16          => return Ok(Self::PTR),
380            x if x == Self::HINFO as u16        => return Ok(Self::HINFO),
381            x if x == Self::MINFO as u16        => return Ok(Self::MINFO),
382            x if x == Self::MX as u16           => return Ok(Self::MX),
383            x if x == Self::TXT as u16          => return Ok(Self::TXT),
384            x if x == Self::AFSDB as u16        => return Ok(Self::AFSDB),
385            x if x == Self::KEY as u16          => return Ok(Self::KEY),
386            x if x == Self::AAAA as u16         => return Ok(Self::AAAA),
387            x if x == Self::CERT as u16         => return Ok(Self::CERT),
388            x if x == Self::DS as u16           => return Ok(Self::DS),
389            x if x == Self::RRSIG as u16        => return Ok(Self::RRSIG),
390            x if x == Self::NSEC as u16         => return Ok(Self::NSEC),
391            x if x == Self::DNSKEY as u16       => return Ok(Self::DNSKEY),
392            x if x == Self::NSEC3 as u16        => return Ok(Self::NSEC3),
393            x if x == Self::NSEC3PARAM as u16   => return Ok(Self::NSEC3PARAM),
394            x if x == Self::CDS as u16          => return Ok(Self::CDS),
395            x if x == Self::CDNSKEY as u16      => return Ok(Self::CDNSKEY),
396            x if x == Self::OPENPGPKEY as u16   => return Ok(Self::OPENPGPKEY),
397            _ => internal_error!(CDnsErrorType::DnsResponse, "unknown request record type: '{}'", value),
398        }
399    }
400}
401
402
403/// A two octet code that specifies the class of the query.
404/// 
405/// 
406#[repr(u16)]
407#[derive(Clone, Copy, Debug, PartialEq, Eq)]
408pub enum QClass
409{
410    /// the Internet 1
411    IN = 1,
412    /// the CSNET class (Obsolete) 2
413    CS = 2,
414    /// the CHAOS class 3
415    CH = 3,
416    /// Hesiod [Dyer 87] 4
417    HS = 4,
418    
419    //  --- QClass
420    /// any class 255
421    ALL = 255,
422}
423
424impl fmt::Display for QClass
425{
426    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
427    {
428        match *self
429        {
430            Self::IN  => write!(f, "IN"),
431            Self::CS  => write!(f, "CS"),
432            Self::CH  => write!(f, "CH"),
433            Self::HS  => write!(f, "HS"),
434            Self::ALL => write!(f, "ALL"),
435        }
436    }
437}
438
439impl Default for QClass
440{
441    fn default() -> Self 
442    {
443        return Self::IN;    
444    }
445}
446
447impl Into<u16> for QClass
448{
449    fn into(self) -> u16 
450    {
451        return self as u16;
452    }
453}
454
455impl QClass
456{
457    /// Converts u16 to enum [QClass].
458    /// 
459    /// QCLASS fields appear in the question part of a query.  QCLASS are a
460    /// superset of CLASSes, hence all CLASSes are valid QCLASSes.
461    pub 
462    fn u16_to_qclass(value: u16) -> CDnsResult<QClass>
463    {
464        match value
465        {
466            x if x == QClass::ALL as u16 => return Ok(QClass::ALL),
467            _ => Self::u16_to_class(value),
468        }
469    }
470
471    /// Converts u16 to enum [QClass], but for the response part of a query.
472    pub 
473    fn u16_to_class(value: u16) -> CDnsResult<QClass>
474    {
475        match value
476        {
477            x if x == QClass::IN as u16 => return Ok(QClass::IN),
478            x if x == QClass::CS as u16 => return Ok(QClass::CS),
479            x if x == QClass::CH as u16 => return Ok(QClass::CH),
480            x if x == QClass::HS as u16 => return Ok(QClass::HS),
481            _ => internal_error!(CDnsErrorType::DnsResponse, "unknown QCLASS type: '{}'", value),
482        }
483    }
484}
485
486// (req.status & !StatusBits::OPCODE_STANDARD) | ...
487// () 
488
489bitflags! {     
490    /// Flags  which control the status of th DNS query    
491    #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] 
492    pub struct StatusBits: u16  
493    {     
494        // Pkt type Request/Result R/W    
495        /// A request/response bit, when 1 - response
496        const QR_RESP           = 0x8000;
497
498        // Request Type (Write only)
499        /// a standard query (QUERY) USE inverse to reset
500        const OPCODE_STANDARD   = 0x87FF;
501        /// an inverse query (IQUERY)
502        const OPCODE_IQUERY     = 0x0040;
503        /// a server status request (STATUS)
504        const OPCODE_STATUS     = 0x0020;
505        // reserved for future use 3-15
506        // 0x4000 .. 0x0800
507
508        /// AA  Authoritative Answer (Read only)
509        /// Authoritative Answer - this bit is valid in responses,
510        /// and specifies that the responding name server is an
511        /// authority for the domain name in question section.
512        const AUTH_ANSWER       = 0x0400;
513
514        /// TrunCation (Read only)
515        /// TrunCation - specifies that this message was truncated
516        /// due to length greater than that permitted on the transmission channel.
517        const TRUN_CATION       = 0x0200;
518
519        /// RD Recursion desired (write only)
520        /// Recursion Desired - this bit may be set in a query and
521        /// is copied into the response.  If RD is set, it directs
522        /// the name server to pursue the query recursively.
523        /// Recursive query support is optional.
524        const RECURSION_DESIRED = 0x0100;
525
526        /// RA Recursion available (read only)
527        /// Recursion Available - this be is set or cleared in a
528        /// response, and denotes whether recursive query support is
529        /// available in the name server.
530        const RECURSION_AVAIL   = 0x0080;
531
532        /// Z Zero reserver
533        /// Reserved for future use.  Must be zero in all queries
534        /// and responses.
535        const RSERVER0          = 0x0040; 
536
537        const ANSWER_AUTHN      = 0x0020; 
538        const NON_AUTH_DATA     = 0x0010; 
539
540        // RCODE response code 
541
542        /// No error condition
543        const RESP_NOERROR      = 0x0000; 
544        /// Format error - The name server was unable to interpret the query.
545        const RESP_FORMERR      = 0x0001; 
546        /// Server failure - The name server was unable to process this query due to a
547        /// problem with the name server.
548        const RESP_SERVFAIL     = 0x0002; 
549        /// Name Error - Meaningful only for responses from an authoritative name
550        /// server, this code signifies that the domain name referenced in the query does
551        /// not exist.
552        const RESP_NXDOMAIN     = 0x0003;
553        /// Not Implemented - The name server does not support the requested kind of query.
554        const RESP_NOT_IMPL     = 0x0004; 
555        /// Refused - The name server refuses to perform the specified operation for
556        /// policy reasons.
557        const RESP_REFUSED      = 0x0005; 
558        // ..= 0x000F
559    }
560}
561
562/// An structure for the target in request.
563/// Implements From for [IpAddr], [Ipv4Addr], [Ipv6Addr], [str]
564/// In case if IP address is in the human readable 'string' format
565/// it will be stored as Name. And later the code will try to convert it
566/// to IP address before returing as string.
567#[derive(Clone, Debug, Hash)]
568pub enum QDnsName
569{
570    //Ip(&'temp IpAddr),
571    IpV4(Ipv4Addr),
572    IpV6(Ipv6Addr),
573    Name(String),
574}
575
576impl QDnsName
577{
578    /// Answers if current type is IpV4.
579    /// But does not performs check if Name is an IP in str format
580    pub
581    fn is_ipv4(&self) -> bool
582    {
583        match *self
584        {
585            Self::IpV4(_) => return true,
586            _ => return false,
587        }
588    }
589
590    /// Answers if current type is IpV6.
591    /// But does not performs check if Name is an IP in str format
592    pub 
593    fn is_ipv6(&self) -> bool
594    {
595        match *self
596        {
597            Self::IpV6(_) => return true,
598            _ => return false,
599        }
600    }
601
602    /// Answers if current type is IpV4 or IpV6.
603    /// But does not performs check if Name is an IP in str format
604    pub 
605    fn is_ip(&self) -> bool
606    {
607        match *self
608        {
609            Self::IpV4(_) => return true,
610            Self::IpV6(_) => return true,
611            _ => return false,
612        }
613    }
614
615    /// Returns the type of the IP address version in [QType] format.
616    pub 
617    fn get_ip_qtype(&self) -> Option<QType>
618    {
619        match *self
620        {
621            Self::IpV4(_) => return Some(QType::A),
622            Self::IpV6(_) => return Some(QType::AAAA),
623            Self::Name(_) =>
624            {
625                return None;
626            }
627        }
628    }
629}
630
631impl Eq for QDnsName {}
632
633impl PartialEq for QDnsName
634{
635    fn eq(&self, other: &Self) -> bool 
636    {
637        return self == other;    
638    }
639}
640
641impl PartialEq<str> for QDnsName
642{
643    fn eq(&self, other: &str) -> bool 
644    {
645        match *self
646        {
647            Self::Name(ref name) => return name == other,
648            Self::IpV4(ref ip) =>
649            {
650                if let Ok(other_ip) = other.parse::<Ipv4Addr>()
651                {   
652                    return &other_ip == ip;
653                }
654                
655                return false;
656            },
657            Self::IpV6(ref ip) =>
658            {
659                if let Ok(other_ip) = other.parse::<Ipv6Addr>()
660                {
661                    return &other_ip == ip;
662                }
663
664                return false;
665            }
666        }
667    }
668}
669
670impl From<&IpAddr> for QDnsName
671{
672    fn from(ip: &IpAddr) -> Self 
673    {
674        match *ip
675        {
676            IpAddr::V4(ref ip) => 
677                return Self::IpV4(ip.clone()),
678            IpAddr::V6(ref ip) => 
679                return Self::IpV6(ip.clone()),
680        }
681    }
682}
683
684impl From<IpAddr> for QDnsName
685{
686    fn from(ip: IpAddr) -> Self 
687    {
688        match ip
689        {
690            IpAddr::V4(ip) => 
691                return Self::IpV4(ip),
692            IpAddr::V6(ip) => 
693                return Self::IpV6(ip),
694        }
695    }
696}
697
698impl From<&Ipv4Addr> for QDnsName
699{
700    fn from(ip: &Ipv4Addr) -> Self 
701    {
702        return Self::IpV4(ip.clone());
703    }
704}
705
706impl From<Ipv4Addr> for QDnsName
707{
708    fn from(ip: Ipv4Addr) -> Self 
709    {
710        return Self::IpV4(ip);
711    }
712}
713
714impl From<&Ipv6Addr> for QDnsName
715{
716    fn from(ip: &Ipv6Addr) -> Self 
717    {
718        return Self::IpV6(ip.clone());
719    }
720}
721
722impl From<Ipv6Addr> for QDnsName
723{
724    fn from(ip: Ipv6Addr) -> Self 
725    {
726        return Self::IpV6(ip);
727    }
728}
729
730impl From<&str> for QDnsName
731{
732    fn from(name: &str) -> Self 
733    {
734        let ipp = name.parse::<IpAddr>();
735        if ipp.is_err()
736        {
737            return Self::Name(name.to_string());
738        }
739        else
740        {
741            return QDnsName::from(ipp.unwrap());
742        }
743    }
744}
745
746impl TryInto<Vec<u8>> for QDnsName
747{
748    type Error = CDnsError;
749    fn try_into(self) -> Result<Vec<u8>, Self::Error> 
750    {
751        match self
752        {
753            Self::IpV4(ref ip) =>
754            {
755                return ipv4_pkt(ip);
756            },
757            Self::IpV6(ref ip) =>
758            {
759                return ipv6_pkt(ip);
760            },
761            Self::Name(ref name) =>
762            {
763                if let Ok(ip) = name.parse::<Ipv4Addr>()
764                {   
765                    return ipv4_pkt(&ip);
766                }
767                else if let Ok(ip) = name.parse::<Ipv6Addr>()
768                {
769                    return ipv6_pkt(&ip);
770                }
771                else
772                {
773                    return name2pkt(name);
774                }
775            }
776        }
777    }
778}
779
780impl From<&QDnsName> for String
781{
782    fn from(dnsname: &QDnsName) -> Self 
783    {
784        match *dnsname
785        {
786            QDnsName::IpV4(ref ip) =>
787            {
788                return ip.to_string();
789            },
790            QDnsName::IpV6(ref ip) =>
791            {
792                return ip.to_string();
793            },
794            QDnsName::Name(ref name) =>
795            {
796                return name.to_string();
797            }
798        }
799    }
800}
801
802
803impl TryFrom<&QDnsName> for IpAddr
804{
805    type Error = CDnsError;
806    fn try_from(value: &QDnsName) -> Result<Self, Self::Error> 
807    {
808        match *value
809        {
810            QDnsName::IpV4(ref ip) =>
811            {
812                return Ok(IpAddr::V4(ip.clone()));
813            },
814            QDnsName::IpV6(ref ip) =>
815            {
816                return Ok(IpAddr::V6(ip.clone()));
817            },
818            QDnsName::Name(ref name) =>
819            {
820                if let Ok(ip) = name.parse::<Ipv4Addr>()
821                {   
822                    return Ok(IpAddr::V4(ip.clone()));
823                }
824                else if let Ok(ip) = name.parse::<Ipv6Addr>()
825                {
826                    return Ok(IpAddr::V6(ip.clone()));
827                }
828                else
829                {
830                    internal_error!(CDnsErrorType::InternalError, "not ip address!")
831                }
832            }
833        }
834    }
835}
836
837
838impl TryFrom<QDnsName> for IpAddr
839{
840    type Error = CDnsError;
841    fn try_from(value: QDnsName) -> Result<Self, Self::Error> 
842    {
843        match value
844        {
845            QDnsName::IpV4(ip) =>
846            {
847                return Ok(IpAddr::V4(ip));
848            },
849            QDnsName::IpV6(ip) =>
850            {
851                return Ok(IpAddr::V6(ip));
852            },
853            QDnsName::Name(ref name) =>
854            {
855                if let Ok(ip) = name.parse::<Ipv4Addr>()
856                {   
857                    return Ok(IpAddr::V4(ip));
858                }
859                else if let Ok(ip) = name.parse::<Ipv6Addr>()
860                {
861                    return Ok(IpAddr::V6(ip));
862                }
863                else
864                {
865                    internal_error!(CDnsErrorType::InternalError, "not ip address!")
866                }
867            }
868        }
869    }
870}
871
872#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
873pub struct DnsHeader
874{
875    /// A 16 bit identifier assigned by the program that
876    /// generates any kind of query.
877    pub id: u16,
878
879    /// Query control flags
880    pub status: StatusBits,
881
882    /// an unsigned 16 bit integer specifying the number of
883    /// entries in the question section.
884    pub qdcount: u16,
885
886    /// an unsigned 16 bit integer specifying the number of
887    /// resource records in the answer section.
888    pub ancount: u16,
889
890    /// an unsigned 16 bit integer specifying the number of name
891    /// server resource records in the authority records
892    /// section.
893    pub nscount: u16,
894
895    /// an unsigned 16 bit integer specifying the number of
896    /// resource records in the additional records section.
897    pub arcount: u16,
898}
899
900
901#[derive(Clone, Debug, Default, PartialEq, Eq)]
902pub struct DnsRequestAnswer
903{
904    /// request header
905    pub header: DnsHeader,
906    /// Query content
907    pub request: DnsRequestPayload,
908    /// Resonse section
909    pub response: Vec<DnsResponsePayload>,
910    /// Additional RR
911    pub additional: Vec<DnsResponsePayload>,
912    /// Authortative nameservers
913    pub authoratives: Vec<DnsResponsePayload>,
914}
915
916impl DnsRequestAnswer
917{
918    /// Validates the content
919    /// 
920    /// # Arguments
921    /// 
922    /// * `req` - a request which was sent 
923    pub 
924    fn verify(&self, req: &DnsRequestHeader) -> CDnsResult<()>
925    {
926        if self.header.id != req.header.id
927        {
928            internal_error!(
929                CDnsErrorType::DnsResponse, 
930                "request and response ID did not match: '{}' != '{}'", 
931                req.header.id, self.header.id
932            );
933        }
934
935        // check if request matches with what we sent previously
936        if self.request != req.payload
937        {
938            internal_error!(CDnsErrorType::DnsResponse, 
939                "received request section is different from sent");
940        }
941        else if req.payload.qtype != QType::ALL
942        {
943            // check qtype matches requested. (is it correct?)
944            if req.payload.qtype != self.request.qtype
945            {
946                internal_error!(
947                    CDnsErrorType::DnsResponse, 
948                    "requested QTYPE differ received TYPE: '{}' != '{}'", 
949                    req.payload.qtype, 
950                    self.request.qtype
951                );
952            }
953        }
954        else if self.header.status.contains(StatusBits::TRUN_CATION) == true
955        {
956            internal_error!(CDnsErrorType::MessageTruncated, 
957                "DNS response was truncated, aborting processing");
958        }
959
960        return Ok(());
961    }
962
963}
964
965#[derive(Clone, Debug, Default)]
966pub struct DnsRequestHeader
967{
968    /// request header
969    pub header: DnsHeader,
970    /// Query content
971    pub payload: DnsRequestPayload,
972}
973
974impl Eq for DnsRequestHeader {}
975
976impl PartialEq for DnsRequestHeader
977{
978    fn eq(&self, other: &DnsRequestHeader) -> bool 
979    {
980        return self.header.id == other.header.id;
981    }
982}
983
984impl Ord for DnsRequestHeader 
985{
986    fn cmp(&self, other: &Self) -> Ordering 
987    {
988        // Sort in reverse order
989        return self.header.id.cmp(&other.header.id);
990    }
991}
992
993impl PartialOrd for DnsRequestHeader 
994{
995    fn partial_cmp(&self, other: &Self) -> Option<Ordering> 
996    {
997        return Some(self.cmp(other));
998    }
999}
1000
1001impl Hash for DnsRequestHeader
1002{
1003    fn hash<H: Hasher>(&self, state: &mut H) 
1004    {
1005        self.header.id.hash(state);
1006    }
1007}
1008
1009impl Borrow<u16> for DnsRequestHeader
1010{
1011    fn borrow(&self) -> &u16 
1012    {
1013        return &self.header.id;
1014    }
1015}
1016
1017
1018
1019impl DnsRequestHeader
1020{
1021    pub 
1022    fn regenerate_id(&mut self)
1023    {
1024        self.header.id = rand::random();
1025    }
1026
1027    pub 
1028    fn get_id(&self) -> u16
1029    {
1030        return self.header.id;
1031    }
1032
1033    pub 
1034    fn from_qdns_req(qrec: &QDnsReq, resolvers: &ResolveConfig) -> CDnsResult<Self>
1035    {
1036        if resolvers.lookup.contains(ResolveConfigLookup::BIND) == true
1037        {
1038            return DnsRequestHeader::construct_lookup(qrec.get_req_name().clone(), *qrec.get_type());
1039        }
1040        else
1041        {
1042            panic!("QDnsReq::get_header() misuse!");
1043        };
1044    }
1045
1046    pub 
1047    fn derive(&self) -> Self
1048    {
1049        let header = 
1050            DnsHeader
1051            {
1052                id: rand::random(),
1053                status: self.header.status,
1054                qdcount: self.header.qdcount,
1055                ancount: self.header.ancount,
1056                nscount: self.header.nscount,
1057                arcount: self.header.arcount,
1058            };
1059
1060        return DnsRequestHeader{ header: header, payload: self.payload.clone() };
1061    }
1062
1063    /// Constructs the request from input.
1064    pub
1065    fn construct_lookup(name: QDnsName, qtype: QType) -> CDnsResult<DnsRequestHeader>
1066    {
1067        //let rng = rand::thread_rng();
1068        // preparing status register
1069        let mut status: StatusBits = StatusBits::empty();
1070        status = (status & !StatusBits::OPCODE_STANDARD) | StatusBits::RECURSION_DESIRED;
1071
1072        // constructing request structure
1073        let mut req: DnsRequestHeader = DnsRequestHeader{ ..Default::default() };
1074
1075        req.header.id = rand::random();
1076        req.header.status = status;
1077        req.header.qdcount = 1;
1078
1079        // creating payload request
1080        req.payload = DnsRequestPayload::new(name.try_into()?, qtype, QClass::IN);
1081
1082        
1083        /*let pkt = req.to_bytes().map_err(|e|
1084            internal_error_map!(CDnsErrorType::InternalError, "{}", e)
1085        )?;*/
1086
1087        return Ok(req);
1088    }
1089
1090}
1091
1092/// A request payload with (request) lines.
1093#[derive(Clone, Debug, Default, PartialEq, Eq)]
1094pub struct DnsRequestPayload
1095{
1096    /// a domain name represented as a sequence of labels
1097    pub qname: Vec<u8>,
1098
1099    /// a two octet code which specifies the type of the query.
1100    pub qtype: QType,
1101    
1102    /// a two octet code that specifies the class of the query.
1103    pub qclass: QClass,
1104}
1105
1106impl DnsRequestPayload
1107{
1108    pub 
1109    fn new(qname: Vec<u8>, qtype: QType, qclass: QClass) -> Self
1110    {
1111        return DnsRequestPayload{ qname: qname, qtype: qtype.into(), qclass: qclass.into() };
1112    }
1113}
1114
1115/// A response section
1116#[derive(Clone, Debug, Default, Eq, PartialEq)]
1117pub struct DnsResponsePayload
1118{
1119    // A domain name that was queried, in the same format as the QNAME in the question
1120    pub name: String,
1121    /// Two octets containing one of th type codes.
1122    pub dtype: QType,
1123    /// Two octets which specify the class of the data in the RDATA field
1124    pub class: QClass,
1125    /// specifies the time interval that the resource record may be cached before the source
1126    /// of the information should again be consulted
1127    pub ttl: i32,
1128    /// specifies the length in octets of the RDATA field
1129    pub rdlength: u16,
1130    /// a variable length string of octets that describes the resource
1131    pub rdata: DnsRdata,
1132}
1133
1134impl DnsResponsePayload
1135{
1136    /// Creates a record from [HostnameEntry], but only for types like
1137    /// A, AAAA, PTR
1138    pub(crate)
1139    fn new_local(dtype: QType, data: &HostnameEntry) -> CDnsResult<Vec<Self>>
1140    {
1141
1142        match dtype
1143        {
1144            QType::A => 
1145            {
1146                let mut out: Vec<Self> = Vec::with_capacity(1);
1147
1148                let IpAddr::V4(ipv4) = data.get_ip()
1149                else { internal_error!(CDnsErrorType::InternalError, "wrong data type") };
1150
1151                out.push(
1152                    DnsResponsePayload
1153                    {
1154                        name: [data.get_hostnames()[0].as_str(), ".local"].concat(),
1155                        dtype: dtype,
1156                        class: QClass::IN,
1157                        ttl: i32::MAX,
1158                        rdlength: 0,
1159                        rdata: DnsRdata::A{ ip: ipv4.clone() },
1160                    }
1161                );
1162
1163                return Ok(out);
1164            },
1165            QType::AAAA => 
1166            {
1167                let mut out: Vec<Self> = Vec::with_capacity(1);
1168
1169                let IpAddr::V6(ipv6) = data.get_ip()
1170                else { internal_error!(CDnsErrorType::InternalError, "wrong data type") };
1171
1172                out.push(
1173                    DnsResponsePayload
1174                    {
1175                        name: [data.get_hostnames()[0].as_str(), ".local"].concat(),
1176                        dtype: dtype,
1177                        class: QClass::IN,
1178                        ttl: i32::MAX,
1179                        rdlength: 0,
1180                        rdata: DnsRdata::AAAA{ ip: ipv6.clone() },
1181                    }
1182                );
1183
1184                return Ok(out);
1185            },
1186            QType::PTR => 
1187            {
1188                let mut out: Vec<Self> = Vec::with_capacity(data.get_hostnames().len());
1189
1190                // copy all hostnames from the list
1191                for h in data.get_hostnames_iter()
1192                {
1193                    out.push(
1194                        DnsResponsePayload
1195                        {
1196                            name: [data.get_ip().to_string().as_str(), ".local"].concat(),
1197                            dtype: dtype,
1198                            class: QClass::IN,
1199                            ttl: i32::MAX,
1200                            rdlength: 0,
1201                            rdata: DnsRdata::PTR{ fqdn: h.clone() },
1202                        }
1203                    );
1204                }
1205            
1206                return Ok(out);
1207            },
1208            _ => 
1209            {
1210                internal_error!(CDnsErrorType::InternalError, "new_local can not be used for types except A, AAAA, PTR");
1211            }
1212        }
1213        
1214    }
1215}
1216
1217/*impl Default for DnsResponsePayload
1218{
1219    fn default() -> Self 
1220    {
1221        return Self::Empty;    
1222    }
1223}*/
1224
1225impl fmt::Display for DnsResponsePayload
1226{
1227    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1228    {
1229        write!(f, "{} {} {} {} {}", 
1230            self.name, self.dtype, self.class, self.ttl, self.rdata)  
1231    }
1232}
1233
1234#[derive(Clone, Debug, Eq, PartialEq)]
1235pub struct DnsSoa
1236{
1237    /// primary name server
1238    pub pnm: String, 
1239    /// responsible authority mailbox
1240    pub ram: String,
1241    /// serial number
1242    pub serial: u32,
1243    /// refresh interval
1244    pub interv_refr: u32,
1245    /// retry interval
1246    pub interv_retry: u32,
1247    /// expire limit
1248    pub expire_limit: u32,
1249    /// minimum TTL
1250    pub min_ttl: u32,
1251}
1252
1253impl fmt::Display for DnsSoa
1254{
1255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
1256    {
1257        writeln!(f, "{} {} {} {} {} {} {}", 
1258            self.pnm, self.ram, self.serial, self.interv_refr, 
1259            self.interv_retry, self.expire_limit, self.min_ttl)
1260    }
1261}
1262
1263#[derive(Clone, Debug, Eq, PartialEq)]
1264pub enum DnsRdata
1265{
1266    None,
1267    A{ ip: Ipv4Addr },
1268    NS{ fqdn: String },
1269    MD{ data: Vec<u8> },
1270    MF{ data: Vec<u8> },
1271    CNAME{ fqdn: String },
1272    SOA{ soa: DnsSoa },
1273    MB{ data: Vec<u8> },
1274    MG{ data: Vec<u8> },
1275    MR{ data: Vec<u8> },
1276    NULL{ data: Vec<u8> },
1277    WKS{ data: Vec<u8> },
1278    PTR{ fqdn: String },
1279    HINFO{ data: Vec<u8> },
1280    MX{ preference: u16, exchange: String },
1281    TXT{ data: Vec<u8> },
1282    AFSDB{ data: Vec<u8> },
1283    KEY{ data: Vec<u8> },
1284    AAAA{ ip: Ipv6Addr },
1285    CERT{ data: Vec<u8> },
1286    DS{ data: Vec<u8> },
1287    RRSIG{ data: Vec<u8> },
1288    NSEC{ data: Vec<u8> },
1289    DNSKEY{ data: Vec<u8> },
1290    NSEC3{ data: Vec<u8> },
1291    NSEC3PARAM{ data: Vec<u8> },
1292    CDS{ data: Vec<u8> },
1293    CDNSKEY{ data: Vec<u8> },
1294    OPENPGPKEY{ data: Vec<u8> },    
1295    UNKNOWN{ data: Vec<u8> },
1296}
1297
1298impl fmt::Display for DnsRdata
1299{
1300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
1301    {
1302        match *self
1303        {
1304            Self::None => 
1305                write!(f, "No record"),
1306            Self::A{ ref ip } => 
1307                write!(f, "{}", ip),
1308            Self::NS{ ref fqdn } => 
1309                write!(f, "{}", fqdn),
1310            Self::AAAA{ ref ip} => 
1311                write!(f, "{}", ip),
1312            Self::MX{ preference, ref exchange } =>
1313                write!(f, "{} {}", preference, exchange),
1314            Self::CNAME{ ref fqdn } => 
1315                write!(f, "{}", fqdn),
1316            Self::PTR{ ref fqdn } => 
1317                write!(f, "{}", fqdn),
1318            Self::SOA{ ref soa } => 
1319                write!(f, "{}", soa),
1320            Self::UNKNOWN{ .. } => 
1321                write!(f, "UNKNOWN"),
1322            _ => write!(f, "RAW DATA"),
1323        }
1324    }
1325}
1326
1327impl Default for DnsRdata
1328{
1329    fn default() -> Self 
1330    {
1331        return Self::None;   
1332    }
1333}
1334
1335impl DnsRdata
1336{
1337    pub 
1338    fn is_some(&self) -> bool
1339    {
1340        return *self != Self::None;
1341    }
1342}
1343