nex_packet/
dns.rs

1use crate::packet::Packet;
2use bytes::{BufMut, Bytes, BytesMut};
3use core::str;
4use nex_core::bitfield::{u1, u16be, u32be};
5use std::{
6    net::{IpAddr, Ipv4Addr, Ipv6Addr},
7    str::Utf8Error,
8};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13/// Represents an DNS operation.
14/// These identifiers correspond to DNS resource record classes.
15/// <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2>
16#[repr(u16)]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub enum DnsClass {
20    IN = 1, // Internet
21    CS = 2, // CSNET (Obsolete)
22    CH = 3, // Chaos
23    HS = 4, // Hesiod
24    Unknown(u16),
25}
26
27impl DnsClass {
28    pub fn new(value: u16) -> Self {
29        match value {
30            1 => DnsClass::IN,
31            2 => DnsClass::CS,
32            3 => DnsClass::CH,
33            4 => DnsClass::HS,
34            v => DnsClass::Unknown(v),
35        }
36    }
37
38    pub fn value(&self) -> u16 {
39        match self {
40            DnsClass::IN => 1,
41            DnsClass::CS => 2,
42            DnsClass::CH => 3,
43            DnsClass::HS => 4,
44            DnsClass::Unknown(v) => *v,
45        }
46    }
47
48    pub fn name(&self) -> &'static str {
49        match self {
50            DnsClass::IN => "IN",
51            DnsClass::CS => "CS",
52            DnsClass::CH => "CH",
53            DnsClass::HS => "HS",
54            DnsClass::Unknown(_) => "Unknown",
55        }
56    }
57}
58
59#[allow(non_camel_case_types)]
60#[repr(u16)]
61#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63pub enum DnsType {
64    A = 1,
65    NS = 2,
66    MD = 3,
67    MF = 4,
68    CNAME = 5,
69    SOA = 6,
70    MB = 7,
71    MG = 8,
72    MR = 9,
73    NULL = 10,
74    WKS = 11,
75    PTR = 12,
76    HINFO = 13,
77    MINFO = 14,
78    MX = 15,
79    TXT = 16,
80    RP = 17,
81    AFSDB = 18,
82    X25 = 19,
83    ISDN = 20,
84    RT = 21,
85    NSAP = 22,
86    NSAP_PTR = 23,
87    SIG = 24,
88    KEY = 25,
89    PX = 26,
90    GPOS = 27,
91    AAAA = 28,
92    LOC = 29,
93    NXT = 30,
94    EID = 31,
95    NIMLOC = 32,
96    SRV = 33,
97    ATMA = 34,
98    NAPTR = 35,
99    KX = 36,
100    CERT = 37,
101    A6 = 38,
102    DNAME = 39,
103    SINK = 40,
104    OPT = 41,
105    APL = 42,
106    DS = 43,
107    SSHFP = 44,
108    IPSECKEY = 45,
109    RRSIG = 46,
110    NSEC = 47,
111    DNSKEY = 48,
112    DHCID = 49,
113    NSEC3 = 50,
114    NSEC3PARAM = 51,
115    TLSA = 52,
116    SMIMEA = 53,
117    HIP = 55,
118    NINFO = 56,
119    RKEY = 57,
120    TALINK = 58,
121    CDS = 59,
122    CDNSKEY = 60,
123    OPENPGPKEY = 61,
124    CSYNC = 62,
125    ZONEMD = 63,
126    SVCB = 64,
127    HTTPS = 65,
128    SPF = 99,
129    UINFO = 100,
130    UID = 101,
131    GID = 102,
132    UNSPEC = 103,
133    NID = 104,
134    L32 = 105,
135    L64 = 106,
136    LP = 107,
137    EUI48 = 108,
138    EUI64 = 109,
139    TKEY = 249,
140    TSIG = 250,
141    IXFR = 251,
142    AXFR = 252,
143    MAILB = 253,
144    MAILA = 254,
145    ANY = 255,
146    URI = 256,
147    CAA = 257,
148    AVC = 258,
149    DOA = 259,
150    AMTRELAY = 260,
151    TA = 32768,
152    DLV = 32769,
153    Unknown(u16),
154}
155
156impl DnsType {
157    pub fn new(value: u16) -> Self {
158        match value {
159            1 => DnsType::A,
160            2 => DnsType::NS,
161            3 => DnsType::MD,
162            4 => DnsType::MF,
163            5 => DnsType::CNAME,
164            6 => DnsType::SOA,
165            7 => DnsType::MB,
166            8 => DnsType::MG,
167            9 => DnsType::MR,
168            10 => DnsType::NULL,
169            11 => DnsType::WKS,
170            12 => DnsType::PTR,
171            13 => DnsType::HINFO,
172            14 => DnsType::MINFO,
173            15 => DnsType::MX,
174            16 => DnsType::TXT,
175            17 => DnsType::RP,
176            18 => DnsType::AFSDB,
177            19 => DnsType::X25,
178            20 => DnsType::ISDN,
179            21 => DnsType::RT,
180            22 => DnsType::NSAP,
181            23 => DnsType::NSAP_PTR,
182            24 => DnsType::SIG,
183            25 => DnsType::KEY,
184            26 => DnsType::PX,
185            27 => DnsType::GPOS,
186            28 => DnsType::AAAA,
187            29 => DnsType::LOC,
188            30 => DnsType::NXT,
189            31 => DnsType::EID,
190            32 => DnsType::NIMLOC,
191            33 => DnsType::SRV,
192            34 => DnsType::ATMA,
193            35 => DnsType::NAPTR,
194            36 => DnsType::KX,
195            37 => DnsType::CERT,
196            38 => DnsType::A6,
197            39 => DnsType::DNAME,
198            40 => DnsType::SINK,
199            41 => DnsType::OPT,
200            42 => DnsType::APL,
201            43 => DnsType::DS,
202            44 => DnsType::SSHFP,
203            45 => DnsType::IPSECKEY,
204            46 => DnsType::RRSIG,
205            47 => DnsType::NSEC,
206            48 => DnsType::DNSKEY,
207            49 => DnsType::DHCID,
208            50 => DnsType::NSEC3,
209            51 => DnsType::NSEC3PARAM,
210            52 => DnsType::TLSA,
211            53 => DnsType::SMIMEA,
212            55 => DnsType::HIP,
213            56 => DnsType::NINFO,
214            57 => DnsType::RKEY,
215            58 => DnsType::TALINK,
216            59 => DnsType::CDS,
217            60 => DnsType::CDNSKEY,
218            61 => DnsType::OPENPGPKEY,
219            62 => DnsType::CSYNC,
220            63 => DnsType::ZONEMD,
221            64 => DnsType::SVCB,
222            65 => DnsType::HTTPS,
223            99 => DnsType::SPF,
224            100 => DnsType::UINFO,
225            101 => DnsType::UID,
226            102 => DnsType::GID,
227            103 => DnsType::UNSPEC,
228            104 => DnsType::NID,
229            105 => DnsType::L32,
230            106 => DnsType::L64,
231            107 => DnsType::LP,
232            108 => DnsType::EUI48,
233            109 => DnsType::EUI64,
234            249 => DnsType::TKEY,
235            250 => DnsType::TSIG,
236            251 => DnsType::IXFR,
237            252 => DnsType::AXFR,
238            253 => DnsType::MAILB,
239            254 => DnsType::MAILA,
240            255 => DnsType::ANY,
241            256 => DnsType::URI,
242            257 => DnsType::CAA,
243            258 => DnsType::AVC,
244            259 => DnsType::DOA,
245            260 => DnsType::AMTRELAY,
246            32768 => DnsType::TA,
247            32769 => DnsType::DLV,
248            v => DnsType::Unknown(v),
249        }
250    }
251
252    pub fn value(&self) -> u16 {
253        match self {
254            DnsType::A => 1,
255            DnsType::NS => 2,
256            DnsType::MD => 3,
257            DnsType::MF => 4,
258            DnsType::CNAME => 5,
259            DnsType::SOA => 6,
260            DnsType::MB => 7,
261            DnsType::MG => 8,
262            DnsType::MR => 9,
263            DnsType::NULL => 10,
264            DnsType::WKS => 11,
265            DnsType::PTR => 12,
266            DnsType::HINFO => 13,
267            DnsType::MINFO => 14,
268            DnsType::MX => 15,
269            DnsType::TXT => 16,
270            DnsType::RP => 17,
271            DnsType::AFSDB => 18,
272            DnsType::X25 => 19,
273            DnsType::ISDN => 20,
274            DnsType::RT => 21,
275            DnsType::NSAP => 22,
276            DnsType::NSAP_PTR => 23,
277            DnsType::SIG => 24,
278            DnsType::KEY => 25,
279            DnsType::PX => 26,
280            DnsType::GPOS => 27,
281            DnsType::AAAA => 28,
282            DnsType::LOC => 29,
283            DnsType::NXT => 30,
284            DnsType::EID => 31,
285            DnsType::NIMLOC => 32,
286            DnsType::SRV => 33,
287            DnsType::ATMA => 34,
288            DnsType::NAPTR => 35,
289            DnsType::KX => 36,
290            DnsType::CERT => 37,
291            DnsType::A6 => 38,
292            DnsType::DNAME => 39,
293            DnsType::SINK => 40,
294            DnsType::OPT => 41,
295            DnsType::APL => 42,
296            DnsType::DS => 43,
297            DnsType::SSHFP => 44,
298            DnsType::IPSECKEY => 45,
299            DnsType::RRSIG => 46,
300            DnsType::NSEC => 47,
301            DnsType::DNSKEY => 48,
302            DnsType::DHCID => 49,
303            DnsType::NSEC3 => 50,
304            DnsType::NSEC3PARAM => 51,
305            DnsType::TLSA => 52,
306            DnsType::SMIMEA => 53,
307            DnsType::HIP => 55,
308            DnsType::NINFO => 56,
309            DnsType::RKEY => 57,
310            DnsType::TALINK => 58,
311            DnsType::CDS => 59,
312            DnsType::CDNSKEY => 60,
313            DnsType::OPENPGPKEY => 61,
314            DnsType::CSYNC => 62,
315            DnsType::ZONEMD => 63,
316            DnsType::SVCB => 64,
317            DnsType::HTTPS => 65,
318            DnsType::SPF => 99,
319            DnsType::UINFO => 100,
320            DnsType::UID => 101,
321            DnsType::GID => 102,
322            DnsType::UNSPEC => 103,
323            DnsType::NID => 104,
324            DnsType::L32 => 105,
325            DnsType::L64 => 106,
326            DnsType::LP => 107,
327            DnsType::EUI48 => 108,
328            DnsType::EUI64 => 109,
329            DnsType::TKEY => 249,
330            DnsType::TSIG => 250,
331            DnsType::IXFR => 251,
332            DnsType::AXFR => 252,
333            DnsType::MAILB => 253,
334            DnsType::MAILA => 254,
335            DnsType::ANY => 255,
336            DnsType::URI => 256,
337            DnsType::CAA => 257,
338            DnsType::AVC => 258,
339            DnsType::DOA => 259,
340            DnsType::AMTRELAY => 260,
341            DnsType::TA => 32768,
342            DnsType::DLV => 32769,
343            DnsType::Unknown(v) => *v,
344        }
345    }
346
347    pub fn name(&self) -> &'static str {
348        match self {
349            DnsType::A => "A",                   // 1
350            DnsType::NS => "NS",                 // 2
351            DnsType::MD => "MD",                 // 3
352            DnsType::MF => "MF",                 // 4
353            DnsType::CNAME => "CNAME",           // 5
354            DnsType::SOA => "SOA",               // 6
355            DnsType::MB => "MB",                 // 7
356            DnsType::MG => "MG",                 // 8
357            DnsType::MR => "MR",                 // 9
358            DnsType::NULL => "NULL",             // 10
359            DnsType::WKS => "WKS",               // 11
360            DnsType::PTR => "PTR",               // 12
361            DnsType::HINFO => "HINFO",           // 13
362            DnsType::MINFO => "MINFO",           // 14
363            DnsType::MX => "MX",                 // 15
364            DnsType::TXT => "TXT",               // 16
365            DnsType::RP => "RP",                 // 17
366            DnsType::AFSDB => "AFSDB",           // 18
367            DnsType::X25 => "X25",               // 19
368            DnsType::ISDN => "ISDN",             // 20
369            DnsType::RT => "RT",                 // 21
370            DnsType::NSAP => "NSAP",             // 22
371            DnsType::NSAP_PTR => "NSAP_PTR",     // 23
372            DnsType::SIG => "SIG",               // 24
373            DnsType::KEY => "KEY",               // 25
374            DnsType::PX => "PX",                 // 26
375            DnsType::GPOS => "GPOS",             // 27
376            DnsType::AAAA => "AAAA",             // 28
377            DnsType::LOC => "LOC",               // 29
378            DnsType::NXT => "NXT",               // 30
379            DnsType::EID => "EID",               // 31
380            DnsType::NIMLOC => "NIMLOC",         // 32
381            DnsType::SRV => "SRV",               // 33
382            DnsType::ATMA => "ATMA",             // 34
383            DnsType::NAPTR => "NAPTR",           // 35
384            DnsType::KX => "KX",                 // 36
385            DnsType::CERT => "CERT",             // 37
386            DnsType::A6 => "A6",                 // 38
387            DnsType::DNAME => "DNAME",           // 39
388            DnsType::SINK => "SINK",             // 40
389            DnsType::OPT => "OPT",               // 41
390            DnsType::APL => "APL",               // 42
391            DnsType::DS => "DS",                 // 43
392            DnsType::SSHFP => "SSHFP",           // 44
393            DnsType::IPSECKEY => "IPSECKEY",     // 45
394            DnsType::RRSIG => "RRSIG",           // 46
395            DnsType::NSEC => "NSEC",             // 47
396            DnsType::DNSKEY => "DNSKEY",         // 48
397            DnsType::DHCID => "DHCID",           // 49
398            DnsType::NSEC3 => "NSEC3",           // 50
399            DnsType::NSEC3PARAM => "NSEC3PARAM", // 51
400            DnsType::TLSA => "TLSA",             // 52
401            DnsType::SMIMEA => "SMIMEA",         // 53
402            DnsType::HIP => "HIP",               // 55
403            DnsType::NINFO => "NINFO",           // 56
404            DnsType::RKEY => "RKEY",             // 57
405            DnsType::TALINK => "TALINK",         // 58
406            DnsType::CDS => "CDS",               // 59
407            DnsType::CDNSKEY => "CDNSKEY",       // 60
408            DnsType::OPENPGPKEY => "OPENPGPKEY", // 61
409            DnsType::CSYNC => "CSYNC",           // 62
410            DnsType::ZONEMD => "ZONEMD",         // 63
411            DnsType::SVCB => "SVCB",             // 64
412            DnsType::HTTPS => "HTTPS",           // 65
413            DnsType::SPF => "SPF",               // 99
414            DnsType::UINFO => "UINFO",           // 100
415            DnsType::UID => "UID",               // 101
416            DnsType::GID => "GID",               // 102
417            DnsType::UNSPEC => "UNSPEC",         // 103
418            DnsType::NID => "NID",               // 104
419            DnsType::L32 => "L32",               // 105
420            DnsType::L64 => "L64",               // 106
421            DnsType::LP => "LP",                 // 107
422            DnsType::EUI48 => "EUI48",           // 108
423            DnsType::EUI64 => "EUI64",           // 109
424            DnsType::TKEY => "TKEY",             // 249
425            DnsType::TSIG => "TSIG",             // 250
426            DnsType::IXFR => "IXFR",             // 251
427            DnsType::AXFR => "AXFR",             // 252
428            DnsType::MAILB => "MAILB",           // 253
429            DnsType::MAILA => "MAILA",           // 254
430            DnsType::ANY => "ANY",               // 255
431            DnsType::URI => "URI",               // 256
432            DnsType::CAA => "CAA",               // 257
433            DnsType::AVC => "AVC",               // 258
434            DnsType::DOA => "DOA",               // 259
435            DnsType::AMTRELAY => "AMTRELAY",     // 260
436            DnsType::TA => "TA",                 // 32768
437            DnsType::DLV => "DLV",               // 32769
438            _ => "unknown",
439        }
440    }
441}
442
443/// Represents an DNS operation code.
444/// <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5>
445#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
446#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
447pub enum OpCode {
448    Query,
449    InverseQuery,
450    Status,
451    Reserved,
452    Notify,
453    Update,
454    Dso,
455    Unassigned(u8),
456}
457
458impl OpCode {
459    pub fn new(value: u8) -> Self {
460        match value {
461            0 => Self::Query,
462            1 => Self::InverseQuery,
463            2 => Self::Status,
464            3 => Self::Reserved,
465            4 => Self::Notify,
466            5 => Self::Update,
467            6 => Self::Dso,
468            _ => Self::Unassigned(value),
469        }
470    }
471    pub fn value(&self) -> u8 {
472        match self {
473            Self::Query => 0,
474            Self::InverseQuery => 1,
475            Self::Status => 2,
476            Self::Reserved => 3,
477            Self::Notify => 4,
478            Self::Update => 5,
479            Self::Dso => 6,
480            Self::Unassigned(v) => *v,
481        }
482    }
483    pub fn name(&self) -> &'static str {
484        match self {
485            Self::Query => "Query",
486            Self::InverseQuery => "Inverse Query",
487            Self::Status => "Status",
488            Self::Reserved => "Reserved",
489            Self::Notify => "Notify",
490            Self::Update => "Update",
491            Self::Dso => "DSO",
492            Self::Unassigned(_) => "Unassigned",
493        }
494    }
495}
496
497/// Represents an DNS return code.
498/// <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6>
499#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
500#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
501pub enum RetCode {
502    NoError,
503    FormErr,
504    ServFail,
505    NXDomain,
506    NotImp,
507    Refused,
508    YXDomain,
509    YXRRSet,
510    NXRRSet,
511    NotAuth,
512    NotZone,
513    Dsotypeni,
514    BadVers,
515    BadKey,
516    BadTime,
517    BadMode,
518    BadName,
519    BadAlg,
520    BadTrunc,
521    BadCookie,
522    Unassigned(u8),
523}
524
525impl RetCode {
526    pub fn new(value: u8) -> Self {
527        match value {
528            0 => Self::NoError,
529            1 => Self::FormErr,
530            2 => Self::ServFail,
531            3 => Self::NXDomain,
532            4 => Self::NotImp,
533            5 => Self::Refused,
534            6 => Self::YXDomain,
535            7 => Self::YXRRSet,
536            8 => Self::NXRRSet,
537            9 => Self::NotAuth,
538            10 => Self::NotZone,
539            11 => Self::Dsotypeni,
540            12 => Self::BadVers,
541            13 => Self::BadKey,
542            14 => Self::BadTime,
543            15 => Self::BadMode,
544            16 => Self::BadName,
545            17 => Self::BadAlg,
546            18 => Self::BadTrunc,
547            19 => Self::BadCookie,
548            _ => Self::Unassigned(value),
549        }
550    }
551
552    pub fn value(&self) -> u8 {
553        match self {
554            Self::NoError => 0,
555            Self::FormErr => 1,
556            Self::ServFail => 2,
557            Self::NXDomain => 3,
558            Self::NotImp => 4,
559            Self::Refused => 5,
560            Self::YXDomain => 6,
561            Self::YXRRSet => 7,
562            Self::NXRRSet => 8,
563            Self::NotAuth => 9,
564            Self::NotZone => 10,
565            Self::Dsotypeni => 11,
566            Self::BadVers => 12,
567            Self::BadKey => 13,
568            Self::BadTime => 14,
569            Self::BadMode => 15,
570            Self::BadName => 16,
571            Self::BadAlg => 17,
572            Self::BadTrunc => 18,
573            Self::BadCookie => 19,
574            Self::Unassigned(v) => *v,
575        }
576    }
577
578    pub fn name(&self) -> &'static str {
579        match self {
580            RetCode::NoError => "No Error",
581            RetCode::FormErr => "Format Error",
582            RetCode::ServFail => "Server Failure",
583            RetCode::NXDomain => "Non-Existent Domain",
584            RetCode::NotImp => "Not Implemented",
585            RetCode::Refused => "Query Refused",
586            RetCode::YXDomain => "Name Exists When It Shouldn't",
587            RetCode::YXRRSet => "RR Set Exists When It Shouldn't",
588            RetCode::NXRRSet => "RR Set Doesn't Exist When It Should",
589            RetCode::NotAuth => "Not Authorized",
590            RetCode::NotZone => "Name Not Zone",
591            RetCode::Dsotypeni => "DSO Type NI",
592            RetCode::BadVers => "Bad Version",
593            RetCode::BadKey => "Bad Key",
594            RetCode::BadTime => "Bad Time",
595            RetCode::BadMode => "Bad Mode",
596            RetCode::BadName => "Bad Name",
597            RetCode::BadAlg => "Bad Algorithm",
598            RetCode::BadTrunc => "Bad Truncation",
599            RetCode::BadCookie => "Bad Cookie",
600            RetCode::Unassigned(_) => "Unassigned",
601        }
602    }
603}
604
605/// DNS query packet structure.
606#[derive(Clone, Debug, PartialEq, Eq)]
607#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
608pub struct DnsQueryPacket {
609    pub qname: Vec<u8>,
610    pub qtype: DnsType,
611    pub qclass: DnsClass,
612    pub payload: Bytes,
613}
614
615impl Packet for DnsQueryPacket {
616    type Header = ();
617    fn from_buf(buf: &[u8]) -> Option<Self> {
618        let mut pos = 0;
619        let mut qname = Vec::new();
620
621        // Parse the QNAME field
622        loop {
623            if pos >= buf.len() {
624                return None;
625            }
626
627            let len = buf[pos];
628            pos += 1;
629            qname.push(len);
630
631            if len == 0 {
632                break;
633            }
634
635            if pos + len as usize > buf.len() {
636                return None;
637            }
638
639            qname.extend_from_slice(&buf[pos..pos + len as usize]);
640            pos += len as usize;
641        }
642
643        // Read QTYPE and QCLASS
644        if pos + 4 > buf.len() {
645            return None;
646        }
647
648        let qtype = DnsType::new(u16::from_be_bytes([buf[pos], buf[pos + 1]]));
649        let qclass = DnsClass::new(u16::from_be_bytes([buf[pos + 2], buf[pos + 3]]));
650        pos += 4;
651
652        // The rest is stored as payload
653        let payload = Bytes::copy_from_slice(&buf[pos..]);
654
655        Some(Self {
656            qname,
657            qtype,
658            qclass,
659            payload,
660        })
661    }
662
663    fn from_bytes(mut bytes: Bytes) -> Option<Self> {
664        Self::from_buf(&mut bytes)
665    }
666
667    fn to_bytes(&self) -> Bytes {
668        let mut buf = BytesMut::with_capacity(self.qname.len() + 4);
669        buf.extend_from_slice(&self.qname);
670        buf.put_u16(self.qtype.value());
671        buf.put_u16(self.qclass.value());
672        buf.freeze()
673    }
674
675    fn header(&self) -> Bytes {
676        self.to_bytes().slice(0..self.header_len())
677    }
678
679    fn payload(&self) -> Bytes {
680        self.payload.clone()
681    }
682
683    fn header_len(&self) -> usize {
684        self.qname.len() + 4
685    }
686
687    fn payload_len(&self) -> usize {
688        self.payload.len()
689    }
690
691    fn total_len(&self) -> usize {
692        self.header_len() + self.payload_len()
693    }
694
695    fn into_parts(self) -> (Self::Header, Bytes) {
696        let header = ();
697        let payload = self.payload;
698        (header, payload)
699    }
700}
701
702impl DnsQueryPacket {
703    pub fn get_qname_parsed(&self) -> Result<String, Utf8Error> {
704        let name = &self.qname;
705        let mut qname = String::new();
706        let mut offset = 0;
707        loop {
708            let label_len = name[offset] as usize;
709            if label_len == 0 {
710                break;
711            }
712            if !qname.is_empty() {
713                qname.push('.');
714            }
715            match str::from_utf8(&name[offset + 1..offset + 1 + label_len]) {
716                Ok(label) => qname.push_str(label),
717                Err(e) => return Err(e),
718            }
719            offset += label_len + 1;
720        }
721        Ok(qname)
722    }
723    pub fn qname_length(&self) -> usize {
724        self.to_bytes().iter().take_while(|w| *w != &0).count() + 1
725    }
726    pub fn from_buf_mut(buf: &mut &[u8]) -> Option<Self> {
727        let mut qname = Vec::new();
728
729        loop {
730            if buf.is_empty() {
731                return None;
732            }
733            let len = buf[0];
734            *buf = &buf[1..];
735            qname.push(len);
736            if len == 0 {
737                break;
738            }
739            if buf.len() < len as usize {
740                return None;
741            }
742            qname.extend_from_slice(&buf[..len as usize]);
743            *buf = &buf[len as usize..];
744        }
745
746        if buf.len() < 4 {
747            return None;
748        }
749
750        let qtype = DnsType::new(u16::from_be_bytes([buf[0], buf[1]]));
751        *buf = &buf[2..];
752
753        let qclass = DnsClass::new(u16::from_be_bytes([buf[0], buf[1]]));
754        *buf = &buf[2..];
755
756        let payload = Bytes::copy_from_slice(buf);
757
758        Some(Self {
759            qname,
760            qtype,
761            qclass,
762            payload,
763        })
764    }
765}
766
767/// DNS response packet structure.
768#[derive(Clone, Debug, PartialEq, Eq)]
769#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
770pub struct DnsResponsePacket {
771    pub name_tag: u16be,
772    pub rtype: DnsType,
773    pub rclass: DnsClass,
774    pub ttl: u32be,
775    pub data_len: u16be,
776    pub data: Vec<u8>,
777    pub payload: Bytes,
778}
779
780impl Packet for DnsResponsePacket {
781    type Header = ();
782    fn from_buf(buf: &[u8]) -> Option<Self> {
783        if buf.len() < 12 {
784            return None;
785        }
786
787        let mut pos = 0;
788
789        let name_tag = u16::from_be_bytes([buf[pos], buf[pos + 1]]).into();
790        pos += 2;
791
792        let rtype = DnsType::new(u16::from_be_bytes([buf[pos], buf[pos + 1]]));
793        pos += 2;
794
795        let rclass = DnsClass::new(u16::from_be_bytes([buf[pos], buf[pos + 1]]));
796        pos += 2;
797
798        let ttl = u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]).into();
799        pos += 4;
800
801        let data_len = u16::from_be_bytes([buf[pos], buf[pos + 1]]).into();
802        pos += 2;
803
804        let data_len_usize = data_len as usize;
805
806        if buf.len() < pos + data_len_usize {
807            return None;
808        }
809
810        let data = buf[pos..pos + data_len_usize].to_vec();
811        pos += data_len_usize;
812
813        let payload = Bytes::copy_from_slice(&buf[pos..]);
814
815        Some(Self {
816            name_tag,
817            rtype,
818            rclass,
819            ttl,
820            data_len,
821            data,
822            payload,
823        })
824    }
825    fn from_bytes(mut bytes: Bytes) -> Option<Self> {
826        Self::from_buf(&mut bytes)
827    }
828
829    fn to_bytes(&self) -> Bytes {
830        let mut buf = bytes::BytesMut::with_capacity(self.total_len());
831
832        buf.put_u16(self.name_tag.into());
833        buf.put_u16(self.rtype.value());
834        buf.put_u16(self.rclass.value());
835        buf.put_u32(self.ttl.into());
836        buf.put_u16(self.data_len.into());
837        buf.put_slice(&self.data);
838
839        buf.freeze()
840    }
841
842    fn header(&self) -> Bytes {
843        self.to_bytes().slice(0..self.total_len())
844    }
845
846    fn payload(&self) -> Bytes {
847        self.payload.clone()
848    }
849
850    fn header_len(&self) -> usize {
851        12
852    }
853
854    fn payload_len(&self) -> usize {
855        self.payload.len()
856    }
857
858    fn total_len(&self) -> usize {
859        self.header_len() + self.payload_len()
860    }
861
862    fn into_parts(self) -> (Self::Header, Bytes) {
863        let header = ();
864        let payload = self.payload;
865        (header, payload)
866    }
867}
868
869impl DnsResponsePacket {
870    /// Creates a new `DnsResponsePacket` from a mutable buffer.
871    pub fn from_buf_mut(buf: &mut &[u8]) -> Option<Self> {
872        if buf.len() < 12 {
873            return None;
874        }
875
876        // name_tag (2)
877        let name_tag = u16::from_be_bytes([buf[0], buf[1]]).into();
878        *buf = &buf[2..];
879
880        // rtype (2)
881        let rtype = DnsType::new(u16::from_be_bytes([buf[0], buf[1]]));
882        *buf = &buf[2..];
883
884        // rclass (2)
885        let rclass = DnsClass::new(u16::from_be_bytes([buf[0], buf[1]]));
886        *buf = &buf[2..];
887
888        // ttl (4)
889        let ttl = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into();
890        *buf = &buf[4..];
891
892        // data_len (2)
893        let data_len = u16::from_be_bytes([buf[0], buf[1]]);
894        *buf = &buf[2..];
895
896        let safe_data_len = std::cmp::min(buf.len(), data_len as usize);
897        let data = buf[..safe_data_len].to_vec();
898        *buf = &buf[safe_data_len..];
899
900        // Remaining bytes are stored as payload
901        let payload = Bytes::copy_from_slice(buf);
902
903        Some(Self {
904            name_tag,
905            rtype,
906            rclass,
907            ttl,
908            data_len: data_len.into(),
909            data,
910            payload,
911        })
912    }
913
914    /// Returns the IPv4 address if the record type is A and data length is 4 bytes.
915    pub fn get_ipv4(&self) -> Option<Ipv4Addr> {
916        if self.rtype == DnsType::A && self.data.len() == 4 {
917            Some(Ipv4Addr::new(
918                self.data[0],
919                self.data[1],
920                self.data[2],
921                self.data[3],
922            ))
923        } else {
924            None
925        }
926    }
927    /// Returns the IPv6 address if the record type is AAAA and data length is 16 bytes.
928    pub fn get_ipv6(&self) -> Option<Ipv6Addr> {
929        if self.rtype == DnsType::AAAA && self.data.len() == 16 {
930            Some(Ipv6Addr::from(<[u8; 16]>::try_from(&self.data[..]).ok()?))
931        } else {
932            None
933        }
934    }
935
936    /// Returns the IP address based on the record type.
937    pub fn get_ip(&self) -> Option<IpAddr> {
938        match self.rtype {
939            DnsType::A => self.get_ipv4().map(IpAddr::V4),
940            DnsType::AAAA => self.get_ipv6().map(IpAddr::V6),
941            _ => None,
942        }
943    }
944
945    /// Returns the DNS name if the record type is CNAME, NS, or PTR.
946    pub fn get_name(&self) -> Option<DnsName> {
947        match self.rtype {
948            DnsType::CNAME | DnsType::NS | DnsType::PTR => DnsName::from_bytes(&self.data).ok(),
949            _ => None,
950        }
951    }
952
953    /// Returns the TXT strings if the record type is TXT.
954    pub fn get_txt_strings(&self) -> Option<Vec<String>> {
955        if self.rtype != DnsType::TXT {
956            return None;
957        }
958
959        let mut pos = 0;
960        let mut result = Vec::new();
961
962        while pos < self.data.len() {
963            let len = self.data[pos] as usize;
964            pos += 1;
965            if pos + len > self.data.len() {
966                break;
967            }
968
969            match std::str::from_utf8(&self.data[pos..pos + len]) {
970                Ok(s) => result.push(s.to_string()),
971                Err(_) => return None,
972            }
973
974            pos += len;
975        }
976
977        Some(result)
978    }
979}
980
981#[derive(Clone, Debug, PartialEq, Eq)]
982#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
983pub struct DnsHeader {
984    pub id: u16be,
985    pub is_response: u1,
986    pub opcode: OpCode,
987    pub is_authoriative: u1,
988    pub is_truncated: u1,
989    pub is_recursion_desirable: u1,
990    pub is_recursion_available: u1,
991    pub zero_reserved: u1,
992    pub is_answer_authenticated: u1,
993    pub is_non_authenticated_data: u1,
994    pub rcode: RetCode,
995    pub query_count: u16be,
996    pub response_count: u16be,
997    pub authority_rr_count: u16be,
998    pub additional_rr_count: u16be,
999}
1000
1001/// Represents a DNS packet.
1002/// Including its header and all the associated records.
1003#[derive(Clone, Debug, PartialEq, Eq)]
1004pub struct DnsPacket {
1005    pub header: DnsHeader,
1006    pub queries: Vec<DnsQueryPacket>,
1007    pub responses: Vec<DnsResponsePacket>,
1008    pub authorities: Vec<DnsResponsePacket>,
1009    pub additionals: Vec<DnsResponsePacket>,
1010    pub payload: Bytes,
1011}
1012
1013impl Packet for DnsPacket {
1014    type Header = ();
1015    fn from_buf(buf: &[u8]) -> Option<Self> {
1016        if buf.len() < 12 {
1017            return None;
1018        }
1019
1020        let mut cursor = buf;
1021
1022        // Read DNS header
1023        let id = u16::from_be_bytes([cursor[0], cursor[1]]);
1024        let flags = u16::from_be_bytes([cursor[2], cursor[3]]);
1025        let query_count = u16::from_be_bytes([cursor[4], cursor[5]]);
1026        let response_count = u16::from_be_bytes([cursor[6], cursor[7]]);
1027        let authority_rr_count = u16::from_be_bytes([cursor[8], cursor[9]]);
1028        let additional_rr_count = u16::from_be_bytes([cursor[10], cursor[11]]);
1029        cursor = &cursor[12..];
1030
1031        let header = DnsHeader {
1032            id: id.into(),
1033            is_response: ((flags >> 15) & 0x1) as u8,
1034            opcode: OpCode::new(((flags >> 11) & 0xF) as u8),
1035            is_authoriative: ((flags >> 10) & 0x1) as u8,
1036            is_truncated: ((flags >> 9) & 0x1) as u8,
1037            is_recursion_desirable: ((flags >> 8) & 0x1) as u8,
1038            is_recursion_available: ((flags >> 7) & 0x1) as u8,
1039            zero_reserved: ((flags >> 6) & 0x1) as u8,
1040            is_answer_authenticated: ((flags >> 5) & 0x1) as u8,
1041            is_non_authenticated_data: ((flags >> 4) & 0x1) as u8,
1042            rcode: RetCode::new((flags & 0xF) as u8),
1043            query_count: query_count.into(),
1044            response_count: response_count.into(),
1045            authority_rr_count: authority_rr_count.into(),
1046            additional_rr_count: additional_rr_count.into(),
1047        };
1048
1049        // Parse each section, passing mutable slices
1050        fn parse_queries(count: usize, buf: &mut &[u8]) -> Option<Vec<DnsQueryPacket>> {
1051            (0..count)
1052                .map(|_| DnsQueryPacket::from_buf_mut(buf))
1053                .collect()
1054        }
1055
1056        fn parse_responses(count: usize, buf: &mut &[u8]) -> Option<Vec<DnsResponsePacket>> {
1057            let mut packets = Vec::with_capacity(count);
1058            for _ in 0..count {
1059                if let Some(pkt) = DnsResponsePacket::from_buf_mut(buf) {
1060                    packets.push(pkt);
1061                } else {
1062                    break;
1063                }
1064            }
1065            Some(packets)
1066        }
1067
1068        let mut working_buf = cursor;
1069
1070        let queries = parse_queries(query_count as usize, &mut working_buf)?;
1071        let responses = parse_responses(response_count as usize, &mut working_buf)?;
1072        let authorities = parse_responses(authority_rr_count as usize, &mut working_buf)?;
1073        let additionals = parse_responses(additional_rr_count as usize, &mut working_buf)?;
1074
1075        // Remaining data becomes the payload
1076        let payload = Bytes::copy_from_slice(working_buf);
1077
1078        Some(Self {
1079            header,
1080            queries,
1081            responses,
1082            authorities,
1083            additionals,
1084            payload,
1085        })
1086    }
1087
1088    fn from_bytes(mut bytes: Bytes) -> Option<Self> {
1089        Self::from_buf(&mut bytes)
1090    }
1091
1092    fn to_bytes(&self) -> Bytes {
1093        use bytes::{BufMut, BytesMut};
1094
1095        let mut buf = BytesMut::with_capacity(self.header_len() + self.payload.len());
1096
1097        // DNS Header
1098        let mut flags = 0u16;
1099        flags |= (self.header.is_response as u16) << 15;
1100        flags |= (self.header.opcode.value() as u16) << 11;
1101        flags |= (self.header.is_authoriative as u16) << 10;
1102        flags |= (self.header.is_truncated as u16) << 9;
1103        flags |= (self.header.is_recursion_desirable as u16) << 8;
1104        flags |= (self.header.is_recursion_available as u16) << 7;
1105        flags |= (self.header.zero_reserved as u16) << 6;
1106        flags |= (self.header.is_answer_authenticated as u16) << 5;
1107        flags |= (self.header.is_non_authenticated_data as u16) << 4;
1108        flags |= self.header.rcode.value() as u16;
1109
1110        buf.put_u16(self.header.id.into());
1111        buf.put_u16(flags);
1112        buf.put_u16(self.header.query_count.into());
1113        buf.put_u16(self.header.response_count.into());
1114        buf.put_u16(self.header.authority_rr_count.into());
1115        buf.put_u16(self.header.additional_rr_count.into());
1116
1117        // Write all queries
1118        for query in &self.queries {
1119            buf.extend_from_slice(&query.to_bytes());
1120        }
1121
1122        // Write all responses
1123        for response in &self.responses {
1124            buf.extend_from_slice(&response.to_bytes());
1125        }
1126
1127        // Write authorities
1128        for auth in &self.authorities {
1129            buf.extend_from_slice(&auth.to_bytes());
1130        }
1131
1132        // Write additionals
1133        for add in &self.additionals {
1134            buf.extend_from_slice(&add.to_bytes());
1135        }
1136
1137        Bytes::from(buf)
1138    }
1139
1140    fn header(&self) -> Bytes {
1141        self.to_bytes().slice(0..12)
1142    }
1143
1144    fn payload(&self) -> Bytes {
1145        self.payload.clone()
1146    }
1147
1148    fn header_len(&self) -> usize {
1149        12
1150    }
1151
1152    fn payload_len(&self) -> usize {
1153        self.payload.len()
1154    }
1155
1156    fn total_len(&self) -> usize {
1157        self.header_len() + self.payload_len()
1158    }
1159
1160    fn into_parts(self) -> (Self::Header, Bytes) {
1161        let header = ();
1162        let payload = self.payload;
1163        (header, payload)
1164    }
1165}
1166
1167/// Represents a DNS name
1168pub struct DnsName(String);
1169
1170impl DnsName {
1171    /// Creates a new `DnsName` string from bytes.
1172    pub fn from_bytes(buf: &[u8]) -> Result<Self, Utf8Error> {
1173        let mut pos = 0;
1174        let mut labels = Vec::new();
1175
1176        while pos < buf.len() {
1177            let len = buf[pos] as usize;
1178            if len == 0 {
1179                break;
1180            }
1181            pos += 1;
1182            if pos + len > buf.len() {
1183                break;
1184            }
1185            let label = std::str::from_utf8(&buf[pos..pos + len])?;
1186            labels.push(label);
1187            pos += len;
1188        }
1189
1190        Ok(DnsName(labels.join(".")))
1191    }
1192
1193    /// Returns the DNS name as a string slice.
1194    pub fn as_str(&self) -> &str {
1195        &self.0
1196    }
1197
1198    /// Splits the DNS name into its labels.
1199    /// For example, "example.com" becomes ["example", "com"].
1200    pub fn labels(&self) -> Vec<&str> {
1201        self.0.split('.').collect()
1202    }
1203}
1204
1205impl std::fmt::Display for DnsName {
1206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1207        write!(f, "{}", self.0)
1208    }
1209}
1210
1211#[cfg(test)]
1212mod tests {
1213    use super::*;
1214
1215    #[test]
1216    fn test_dns_query() {
1217        let bytes = Bytes::from_static(&[
1218            0x07, b'b', b'e', b'a', b'c', b'o', b'n', b's', 0x04, b'g', b'v', b't', b'2', 0x03,
1219            b'c', b'o', b'm', 0x00, 0x00, 0x41, 0x00, 0x01, // type: HTTPS, class: IN
1220        ]);
1221        let packet = DnsQueryPacket::from_bytes(bytes).unwrap();
1222        assert_eq!(
1223            packet.qname,
1224            vec![
1225                0x07, b'b', b'e', b'a', b'c', b'o', b'n', b's', 0x04, b'g', b'v', b't', b'2', 0x03,
1226                b'c', b'o', b'm', 0x00
1227            ]
1228        );
1229        assert_eq!(packet.qtype, DnsType::HTTPS);
1230        assert_eq!(packet.qclass, DnsClass::IN);
1231    }
1232
1233    #[test]
1234    fn test_dns_response() {
1235        let bytes = Bytes::from_static(&[
1236            0xc0, 0x0c, // name_tag
1237            0x00, 0x01, // type = A
1238            0x00, 0x01, // class = IN
1239            0x00, 0x00, 0x00, 0x3c, // TTL = 60
1240            0x00, 0x04, // data_len = 4
1241            0x0d, 0xe2, 0x02, 0x12, // data
1242        ]);
1243        let packet = DnsResponsePacket::from_bytes(bytes).unwrap();
1244        assert_eq!(packet.rtype, DnsType::A);
1245        assert_eq!(packet.rclass, DnsClass::IN);
1246        assert_eq!(packet.ttl, 60);
1247        assert_eq!(packet.data_len, 4);
1248        assert_eq!(packet.data, vec![13, 226, 2, 18]);
1249    }
1250
1251    #[test]
1252    fn test_dns_query_packet() {
1253        let bytes = Bytes::from_static(&[
1254            0x9b, 0xa0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, b'_',
1255            b'l', b'd', b'a', b'p', 0x04, b'_', b't', b'c', b'p', 0x02, b'd', b'c', 0x06, b'_',
1256            b'm', b's', b'd', b'c', b's', 0x05, b'S', b'4', b'D', b'O', b'M', 0x07, b'P', b'R',
1257            b'I', b'V', b'A', b'T', b'E', 0x00, 0x00, 0x21, 0x00, 0x01,
1258        ]);
1259        let packet = DnsPacket::from_bytes(bytes).unwrap();
1260        assert_eq!(packet.header.id, 0x9ba0);
1261        assert_eq!(packet.header.is_response, 0);
1262        assert_eq!(packet.header.query_count, 1);
1263        assert_eq!(packet.queries.len(), 1);
1264        assert_eq!(
1265            packet.queries[0].get_qname_parsed().unwrap(),
1266            "_ldap._tcp.dc._msdcs.S4DOM.PRIVATE"
1267        );
1268        assert_eq!(packet.queries[0].qtype, DnsType::SRV);
1269        assert_eq!(packet.queries[0].qclass, DnsClass::IN);
1270    }
1271    #[test]
1272    fn test_dns_response_packet() {
1273        let bytes = Bytes::from_static(&[
1274            0xbc, 0x12, 0x85, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, b's',
1275            b'4', b'd', b'c', b'1', 0x05, b's', b'a', b'm', b'b', b'a', 0x08, b'w', b'i', b'n',
1276            b'd', b'o', b'w', b's', b'8', 0x07, b'p', b'r', b'i', b'v', b'a', b't', b'e', 0x00,
1277            0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x03, 0x84,
1278            0x00, 0x04, 0xc0, 0xa8, 0x7a, 0xbd,
1279        ]);
1280        let packet = DnsPacket::from_bytes(bytes).unwrap();
1281        assert_eq!(packet.header.id, 0xbc12);
1282        assert_eq!(packet.header.is_response, 1);
1283        assert_eq!(packet.header.query_count, 1);
1284        assert_eq!(packet.header.response_count, 1);
1285        assert_eq!(packet.queries.len(), 1);
1286        assert_eq!(
1287            packet.queries[0].get_qname_parsed().unwrap(),
1288            "s4dc1.samba.windows8.private"
1289        );
1290        assert_eq!(packet.queries[0].qtype, DnsType::A);
1291        assert_eq!(packet.responses[0].rtype, DnsType::A);
1292        assert_eq!(packet.responses[0].rclass, DnsClass::IN);
1293        assert_eq!(packet.responses[0].ttl, 900);
1294        assert_eq!(packet.responses[0].data_len, 4);
1295        assert_eq!(packet.responses[0].data, vec![192, 168, 122, 189]);
1296    }
1297}