mdns_sd/
dns_parser.rs

1//! DNS parsing utility.
2//!
3//! [DnsIncoming] is the logic representation of an incoming DNS packet.
4//! [DnsOutgoing] is the logic representation of an outgoing DNS message of one or more packets.
5//! [DnsOutPacket] is the encoded one packet for [DnsOutgoing].
6
7#[cfg(feature = "logging")]
8use crate::log::trace;
9
10use crate::error::{e_fmt, Error, Result};
11
12use if_addrs::Interface;
13
14use std::{
15    any::Any,
16    cmp,
17    collections::HashMap,
18    convert::TryInto,
19    fmt,
20    net::{IpAddr, Ipv4Addr, Ipv6Addr},
21    str,
22    time::SystemTime,
23};
24
25/// Represents a network interface identifier defined by the OS.
26#[derive(Clone, Debug, Eq, Hash, PartialEq, Default)]
27pub struct InterfaceId {
28    /// Interface name, e.g. "en0", "wlan0", etc.
29    pub name: String,
30
31    /// Interface index assigned by the OS, e.g. 1, 2, etc.
32    pub index: u32,
33}
34
35impl fmt::Display for InterfaceId {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "{}('{}')", self.index, self.name)
38    }
39}
40
41impl From<&Interface> for InterfaceId {
42    fn from(interface: &Interface) -> Self {
43        InterfaceId {
44            name: interface.name.clone(),
45            index: interface.index.unwrap_or_default(),
46        }
47    }
48}
49
50/// An IPv4 address used in `ScopedIp`.
51///
52/// Note: IPv4 addresses don't have scope IDs, but this type is named for consistency
53/// with the rest of the addressing system.
54#[derive(Debug, Clone, Eq, PartialEq, Hash)]
55pub struct ScopedIpV4 {
56    addr: Ipv4Addr,
57}
58
59impl ScopedIpV4 {
60    /// Returns the IPv4 address.
61    pub const fn addr(&self) -> &Ipv4Addr {
62        &self.addr
63    }
64}
65
66/// An IPv6 address with scope_id (interface identifier).
67#[derive(Debug, Clone, Eq, PartialEq, Hash)]
68pub struct ScopedIpV6 {
69    addr: Ipv6Addr,
70    scope_id: InterfaceId,
71}
72
73impl ScopedIpV6 {
74    /// Returns the IPv6 address.
75    pub const fn addr(&self) -> &Ipv6Addr {
76        &self.addr
77    }
78
79    /// Returns the scope_id for this IPv6 address.
80    pub const fn scope_id(&self) -> &InterfaceId {
81        &self.scope_id
82    }
83}
84
85/// An IP address, either IPv4 or IPv6, that supports scope_id for IPv6.
86#[derive(Debug, Clone, Eq, PartialEq, Hash)]
87#[non_exhaustive]
88pub enum ScopedIp {
89    V4(ScopedIpV4),
90    V6(ScopedIpV6),
91}
92
93impl ScopedIp {
94    pub const fn to_ip_addr(&self) -> IpAddr {
95        match self {
96            ScopedIp::V4(v4) => IpAddr::V4(v4.addr),
97            ScopedIp::V6(v6) => IpAddr::V6(v6.addr),
98        }
99    }
100
101    pub const fn is_ipv4(&self) -> bool {
102        matches!(self, ScopedIp::V4(_))
103    }
104
105    pub const fn is_ipv6(&self) -> bool {
106        matches!(self, ScopedIp::V6(_))
107    }
108}
109
110impl From<IpAddr> for ScopedIp {
111    fn from(ip: IpAddr) -> Self {
112        match ip {
113            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 { addr: v4 }),
114            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
115                addr: v6,
116                scope_id: InterfaceId::default(),
117            }),
118        }
119    }
120}
121
122impl From<&Interface> for ScopedIp {
123    fn from(interface: &Interface) -> Self {
124        match interface.ip() {
125            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 { addr: v4 }),
126            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
127                addr: v6,
128                scope_id: InterfaceId::from(interface),
129            }),
130        }
131    }
132}
133
134impl fmt::Display for ScopedIp {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        match self {
137            ScopedIp::V4(v4) => write!(f, "{}", v4.addr),
138            ScopedIp::V6(v6) => {
139                if v6.scope_id.index != 0 {
140                    #[cfg(windows)]
141                    {
142                        write!(f, "{}%{}", v6.addr, v6.scope_id.index)
143                    }
144                    #[cfg(not(windows))]
145                    {
146                        write!(f, "{}%{}", v6.addr, v6.scope_id.name)
147                    }
148                } else {
149                    write!(f, "{}", v6.addr)
150                }
151            }
152        }
153    }
154}
155
156/// DNS resource record types, stored as `u16`. Can do `as u16` when needed.
157///
158/// See [RFC 1035 section 3.2.2](https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2)
159#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
160#[non_exhaustive]
161#[repr(u16)]
162pub enum RRType {
163    /// DNS record type for IPv4 address
164    A = 1,
165
166    /// DNS record type for Canonical Name
167    CNAME = 5,
168
169    /// DNS record type for Pointer
170    PTR = 12,
171
172    /// DNS record type for Host Info
173    HINFO = 13,
174
175    /// DNS record type for Text (properties)
176    TXT = 16,
177
178    /// DNS record type for IPv6 address
179    AAAA = 28,
180
181    /// DNS record type for Service
182    SRV = 33,
183
184    /// DNS record type for Negative Responses
185    NSEC = 47,
186
187    /// DNS record type for any records (wildcard)
188    ANY = 255,
189}
190
191impl RRType {
192    /// Converts `u16` into `RRType` if possible.
193    pub const fn from_u16(value: u16) -> Option<RRType> {
194        match value {
195            1 => Some(RRType::A),
196            5 => Some(RRType::CNAME),
197            12 => Some(RRType::PTR),
198            13 => Some(RRType::HINFO),
199            16 => Some(RRType::TXT),
200            28 => Some(RRType::AAAA),
201            33 => Some(RRType::SRV),
202            47 => Some(RRType::NSEC),
203            255 => Some(RRType::ANY),
204            _ => None,
205        }
206    }
207}
208
209impl fmt::Display for RRType {
210    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211        match self {
212            RRType::A => write!(f, "TYPE_A"),
213            RRType::CNAME => write!(f, "TYPE_CNAME"),
214            RRType::PTR => write!(f, "TYPE_PTR"),
215            RRType::HINFO => write!(f, "TYPE_HINFO"),
216            RRType::TXT => write!(f, "TYPE_TXT"),
217            RRType::AAAA => write!(f, "TYPE_AAAA"),
218            RRType::SRV => write!(f, "TYPE_SRV"),
219            RRType::NSEC => write!(f, "TYPE_NSEC"),
220            RRType::ANY => write!(f, "TYPE_ANY"),
221        }
222    }
223}
224
225/// The class value for the Internet.
226pub const CLASS_IN: u16 = 1;
227pub const CLASS_MASK: u16 = 0x7FFF;
228
229/// Cache-flush bit: the most significant bit of the rrclass field of the resource record.  
230pub const CLASS_CACHE_FLUSH: u16 = 0x8000;
231
232/// Max size of UDP datagram payload.
233///
234/// It is calculated as: 9000 bytes - IP header 20 bytes - UDP header 8 bytes.
235/// Reference: [RFC6762 section 17](https://datatracker.ietf.org/doc/html/rfc6762#section-17)
236pub const MAX_MSG_ABSOLUTE: usize = 8972;
237
238const MSG_HEADER_LEN: usize = 12;
239
240// Definitions for DNS message header "flags" field
241//
242// The "flags" field is 16-bit long, in this format:
243// (RFC 1035 section 4.1.1)
244//
245//   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
246// |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
247//
248pub const FLAGS_QR_MASK: u16 = 0x8000; // mask for query/response bit
249
250/// Flag bit to indicate a query
251pub const FLAGS_QR_QUERY: u16 = 0x0000;
252
253/// Flag bit to indicate a response
254pub const FLAGS_QR_RESPONSE: u16 = 0x8000;
255
256/// Flag bit for Authoritative Answer
257pub const FLAGS_AA: u16 = 0x0400;
258
259/// mask for TC(Truncated) bit
260///
261/// 2024-08-10: currently this flag is only supported on the querier side,
262///             not supported on the responder side. I.e. the responder only
263///             handles the first packet and ignore this bit. Since the
264///             additional packets have 0 questions, the processing of them
265///             is no-op.
266///             In practice, this means the responder supports Known-Answer
267///             only with single packet, not multi-packet. The querier supports
268///             both single packet and multi-packet.
269pub const FLAGS_TC: u16 = 0x0200;
270
271/// A convenience type alias for DNS record trait objects.
272pub type DnsRecordBox = Box<dyn DnsRecordExt>;
273
274impl Clone for DnsRecordBox {
275    fn clone(&self) -> Self {
276        self.clone_box()
277    }
278}
279
280const U16_SIZE: usize = 2;
281
282/// Returns `RRType` for a given IP address.
283#[inline]
284pub const fn ip_address_rr_type(address: &IpAddr) -> RRType {
285    match address {
286        IpAddr::V4(_) => RRType::A,
287        IpAddr::V6(_) => RRType::AAAA,
288    }
289}
290
291#[derive(Eq, PartialEq, Debug, Clone)]
292pub struct DnsEntry {
293    pub(crate) name: String, // always lower case.
294    pub(crate) ty: RRType,
295    class: u16,
296    cache_flush: bool,
297}
298
299impl DnsEntry {
300    const fn new(name: String, ty: RRType, class: u16) -> Self {
301        Self {
302            name,
303            ty,
304            class: class & CLASS_MASK,
305            cache_flush: (class & CLASS_CACHE_FLUSH) != 0,
306        }
307    }
308}
309
310/// Common methods for all DNS entries:  questions and resource records.
311pub trait DnsEntryExt: fmt::Debug {
312    fn entry_name(&self) -> &str;
313
314    fn entry_type(&self) -> RRType;
315}
316
317/// A DNS question entry
318#[derive(Debug)]
319pub struct DnsQuestion {
320    pub(crate) entry: DnsEntry,
321}
322
323impl DnsEntryExt for DnsQuestion {
324    fn entry_name(&self) -> &str {
325        &self.entry.name
326    }
327
328    fn entry_type(&self) -> RRType {
329        self.entry.ty
330    }
331}
332
333/// A DNS Resource Record - like a DNS entry, but has a TTL.
334/// RFC: https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1
335///      https://www.rfc-editor.org/rfc/rfc1035#section-4.1.3
336#[derive(Debug, Clone)]
337pub struct DnsRecord {
338    pub(crate) entry: DnsEntry,
339    ttl: u32,     // in seconds, 0 means this record should not be cached
340    created: u64, // UNIX time in millis
341    expires: u64, // expires at this UNIX time in millis
342
343    /// Support re-query an instance before its PTR record expires.
344    /// See https://datatracker.ietf.org/doc/html/rfc6762#section-5.2
345    refresh: u64, // UNIX time in millis
346
347    /// If conflict resolution decides to change the name, this is the new one.
348    new_name: Option<String>,
349}
350
351impl DnsRecord {
352    fn new(name: &str, ty: RRType, class: u16, ttl: u32) -> Self {
353        let created = current_time_millis();
354
355        // From RFC 6762 section 5.2:
356        // "... The querier should plan to issue a query at 80% of the record
357        // lifetime, and then if no answer is received, at 85%, 90%, and 95%."
358        let refresh = get_expiration_time(created, ttl, 80);
359
360        let expires = get_expiration_time(created, ttl, 100);
361
362        Self {
363            entry: DnsEntry::new(name.to_string(), ty, class),
364            ttl,
365            created,
366            expires,
367            refresh,
368            new_name: None,
369        }
370    }
371
372    pub const fn get_ttl(&self) -> u32 {
373        self.ttl
374    }
375
376    pub const fn get_expire_time(&self) -> u64 {
377        self.expires
378    }
379
380    pub const fn get_refresh_time(&self) -> u64 {
381        self.refresh
382    }
383
384    pub const fn is_expired(&self, now: u64) -> bool {
385        now >= self.expires
386    }
387
388    /// Returns whether record expires in 1 second.
389    ///
390    /// This is useful because mDNS sets TTL to 1 (not 0) for expiring records.
391    pub const fn expires_soon(&self, now: u64) -> bool {
392        now + 1000 >= self.expires
393    }
394
395    pub const fn refresh_due(&self, now: u64) -> bool {
396        now >= self.refresh
397    }
398
399    /// Returns whether `now` (in millis) has passed half of TTL.
400    pub fn halflife_passed(&self, now: u64) -> bool {
401        let halflife = get_expiration_time(self.created, self.ttl, 50);
402        now > halflife
403    }
404
405    pub fn is_unique(&self) -> bool {
406        self.entry.cache_flush
407    }
408
409    /// Updates the refresh time to be the same as the expire time so that
410    /// this record will not refresh again and will just expire.
411    pub fn refresh_no_more(&mut self) {
412        self.refresh = get_expiration_time(self.created, self.ttl, 100);
413    }
414
415    /// Returns if this record is due for refresh. If yes, `refresh` time is updated.
416    pub fn refresh_maybe(&mut self, now: u64) -> bool {
417        if self.is_expired(now) || !self.refresh_due(now) {
418            return false;
419        }
420
421        trace!(
422            "{} qtype {} is due to refresh",
423            &self.entry.name,
424            self.entry.ty
425        );
426
427        // From RFC 6762 section 5.2:
428        // "... The querier should plan to issue a query at 80% of the record
429        // lifetime, and then if no answer is received, at 85%, 90%, and 95%."
430        //
431        // If the answer is received in time, 'refresh' will be reset outside
432        // this function, back to 80% of the new TTL.
433        if self.refresh == get_expiration_time(self.created, self.ttl, 80) {
434            self.refresh = get_expiration_time(self.created, self.ttl, 85);
435        } else if self.refresh == get_expiration_time(self.created, self.ttl, 85) {
436            self.refresh = get_expiration_time(self.created, self.ttl, 90);
437        } else if self.refresh == get_expiration_time(self.created, self.ttl, 90) {
438            self.refresh = get_expiration_time(self.created, self.ttl, 95);
439        } else {
440            self.refresh_no_more();
441        }
442
443        true
444    }
445
446    /// Returns the remaining TTL in seconds
447    fn get_remaining_ttl(&self, now: u64) -> u32 {
448        let remaining_millis = get_expiration_time(self.created, self.ttl, 100) - now;
449        cmp::max(0, remaining_millis / 1000) as u32
450    }
451
452    /// Return the absolute time for this record being created
453    pub const fn get_created(&self) -> u64 {
454        self.created
455    }
456
457    /// Set the absolute expiration time in millis
458    fn set_expire(&mut self, expire_at: u64) {
459        self.expires = expire_at;
460    }
461
462    fn reset_ttl(&mut self, other: &Self) {
463        self.ttl = other.ttl;
464        self.created = other.created;
465        self.expires = get_expiration_time(self.created, self.ttl, 100);
466        self.refresh = if self.ttl > 1 {
467            get_expiration_time(self.created, self.ttl, 80)
468        } else {
469            // If TTL is 1, it means this record is expiring,
470            // then we set refresh to the same time as expires.
471            self.expires
472        };
473    }
474
475    /// Modify TTL to reflect the remaining life time from `now`.
476    pub fn update_ttl(&mut self, now: u64) {
477        if now > self.created {
478            let elapsed = now - self.created;
479            self.ttl -= (elapsed / 1000) as u32;
480        }
481    }
482
483    pub fn set_new_name(&mut self, new_name: String) {
484        if new_name == self.entry.name {
485            self.new_name = None;
486        } else {
487            self.new_name = Some(new_name);
488        }
489    }
490
491    pub fn get_new_name(&self) -> Option<&str> {
492        self.new_name.as_deref()
493    }
494
495    /// Return the new name if exists, otherwise the regular name in DnsEntry.
496    pub(crate) fn get_name(&self) -> &str {
497        self.new_name.as_deref().unwrap_or(&self.entry.name)
498    }
499
500    pub fn get_original_name(&self) -> &str {
501        &self.entry.name
502    }
503}
504
505impl PartialEq for DnsRecord {
506    fn eq(&self, other: &Self) -> bool {
507        self.entry == other.entry
508    }
509}
510
511/// Common methods for DNS resource records.
512pub trait DnsRecordExt: fmt::Debug {
513    fn get_record(&self) -> &DnsRecord;
514    fn get_record_mut(&mut self) -> &mut DnsRecord;
515    fn write(&self, packet: &mut DnsOutPacket);
516    fn any(&self) -> &dyn Any;
517
518    /// Returns whether `other` record is considered the same except TTL.
519    fn matches(&self, other: &dyn DnsRecordExt) -> bool;
520
521    /// Returns whether `other` record has the same rdata.
522    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool;
523
524    /// Returns the result based on a byte-level comparison of `rdata`.
525    /// If `other` is not valid, returns `Greater`.
526    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering;
527
528    /// Returns the result based on "lexicographically later" defined below.
529    fn compare(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
530        /*
531        RFC 6762: https://datatracker.ietf.org/doc/html/rfc6762#section-8.2
532
533        ... The determination of "lexicographically later" is performed by first
534        comparing the record class (excluding the cache-flush bit described
535        in Section 10.2), then the record type, then raw comparison of the
536        binary content of the rdata without regard for meaning or structure.
537        If the record classes differ, then the numerically greater class is
538        considered "lexicographically later".  Otherwise, if the record types
539        differ, then the numerically greater type is considered
540        "lexicographically later".  If the rrtype and rrclass both match,
541        then the rdata is compared. ...
542        */
543        match self.get_class().cmp(&other.get_class()) {
544            cmp::Ordering::Equal => match self.get_type().cmp(&other.get_type()) {
545                cmp::Ordering::Equal => self.compare_rdata(other),
546                not_equal => not_equal,
547            },
548            not_equal => not_equal,
549        }
550    }
551
552    /// Returns a human-readable string of rdata.
553    fn rdata_print(&self) -> String;
554
555    /// Returns the class only, excluding class_flush / unique bit.
556    fn get_class(&self) -> u16 {
557        self.get_record().entry.class
558    }
559
560    fn get_cache_flush(&self) -> bool {
561        self.get_record().entry.cache_flush
562    }
563
564    /// Return the new name if exists, otherwise the regular name in DnsEntry.
565    fn get_name(&self) -> &str {
566        self.get_record().get_name()
567    }
568
569    fn get_type(&self) -> RRType {
570        self.get_record().entry.ty
571    }
572
573    /// Resets TTL using `other` record.
574    /// `self.refresh` and `self.expires` are also reset.
575    fn reset_ttl(&mut self, other: &dyn DnsRecordExt) {
576        self.get_record_mut().reset_ttl(other.get_record());
577    }
578
579    fn get_created(&self) -> u64 {
580        self.get_record().get_created()
581    }
582
583    fn get_expire(&self) -> u64 {
584        self.get_record().get_expire_time()
585    }
586
587    fn set_expire(&mut self, expire_at: u64) {
588        self.get_record_mut().set_expire(expire_at);
589    }
590
591    /// Set expire as `expire_at` if it is sooner than the current `expire`.
592    fn set_expire_sooner(&mut self, expire_at: u64) {
593        if expire_at < self.get_expire() {
594            self.get_record_mut().set_expire(expire_at);
595        }
596    }
597
598    /// Returns true if the record expires in 1 second from `now`.
599    fn expires_soon(&self, now: u64) -> bool {
600        self.get_record().expires_soon(now)
601    }
602
603    /// Given `now`, if the record is due to refresh, this method updates the refresh time
604    /// and returns the new refresh time. Otherwise, returns None.
605    fn updated_refresh_time(&mut self, now: u64) -> Option<u64> {
606        if self.get_record_mut().refresh_maybe(now) {
607            Some(self.get_record().get_refresh_time())
608        } else {
609            None
610        }
611    }
612
613    /// Returns true if another record has matched content,
614    /// and if its TTL is at least half of this record's.
615    fn suppressed_by_answer(&self, other: &dyn DnsRecordExt) -> bool {
616        self.matches(other) && (other.get_record().ttl > self.get_record().ttl / 2)
617    }
618
619    /// Required by RFC 6762 Section 7.1: Known-Answer Suppression.
620    fn suppressed_by(&self, msg: &DnsIncoming) -> bool {
621        for answer in msg.answers.iter() {
622            if self.suppressed_by_answer(answer.as_ref()) {
623                return true;
624            }
625        }
626        false
627    }
628
629    fn clone_box(&self) -> DnsRecordBox;
630
631    fn boxed(self) -> DnsRecordBox;
632}
633
634/// Resource Record for IPv4 address or IPv6 address.
635#[derive(Debug, Clone)]
636pub(crate) struct DnsAddress {
637    pub(crate) record: DnsRecord,
638    address: IpAddr,
639    pub(crate) interface_id: InterfaceId,
640}
641
642impl DnsAddress {
643    pub fn new(
644        name: &str,
645        ty: RRType,
646        class: u16,
647        ttl: u32,
648        address: IpAddr,
649        interface_id: InterfaceId,
650    ) -> Self {
651        let record = DnsRecord::new(name, ty, class, ttl);
652        Self {
653            record,
654            address,
655            interface_id,
656        }
657    }
658
659    pub fn address(&self) -> ScopedIp {
660        match self.address {
661            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 { addr: v4 }),
662            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
663                addr: v6,
664                scope_id: self.interface_id.clone(),
665            }),
666        }
667    }
668}
669
670impl DnsRecordExt for DnsAddress {
671    fn get_record(&self) -> &DnsRecord {
672        &self.record
673    }
674
675    fn get_record_mut(&mut self) -> &mut DnsRecord {
676        &mut self.record
677    }
678
679    fn write(&self, packet: &mut DnsOutPacket) {
680        match self.address {
681            IpAddr::V4(addr) => packet.write_bytes(addr.octets().as_ref()),
682            IpAddr::V6(addr) => packet.write_bytes(addr.octets().as_ref()),
683        };
684    }
685
686    fn any(&self) -> &dyn Any {
687        self
688    }
689
690    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
691        if let Some(other_a) = other.any().downcast_ref::<Self>() {
692            return self.address == other_a.address
693                && self.record.entry == other_a.record.entry
694                && self.interface_id == other_a.interface_id;
695        }
696        false
697    }
698
699    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
700        if let Some(other_a) = other.any().downcast_ref::<Self>() {
701            return self.address == other_a.address;
702        }
703        false
704    }
705
706    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
707        if let Some(other_a) = other.any().downcast_ref::<Self>() {
708            self.address.cmp(&other_a.address)
709        } else {
710            cmp::Ordering::Greater
711        }
712    }
713
714    fn rdata_print(&self) -> String {
715        format!("{}", self.address)
716    }
717
718    fn clone_box(&self) -> DnsRecordBox {
719        Box::new(self.clone())
720    }
721
722    fn boxed(self) -> DnsRecordBox {
723        Box::new(self)
724    }
725}
726
727/// Resource Record for a DNS pointer
728#[derive(Debug, Clone)]
729pub struct DnsPointer {
730    record: DnsRecord,
731    alias: String, // the full name of Service Instance
732}
733
734impl DnsPointer {
735    pub fn new(name: &str, ty: RRType, class: u16, ttl: u32, alias: String) -> Self {
736        let record = DnsRecord::new(name, ty, class, ttl);
737        Self { record, alias }
738    }
739
740    pub fn alias(&self) -> &str {
741        &self.alias
742    }
743}
744
745impl DnsRecordExt for DnsPointer {
746    fn get_record(&self) -> &DnsRecord {
747        &self.record
748    }
749
750    fn get_record_mut(&mut self) -> &mut DnsRecord {
751        &mut self.record
752    }
753
754    fn write(&self, packet: &mut DnsOutPacket) {
755        packet.write_name(&self.alias);
756    }
757
758    fn any(&self) -> &dyn Any {
759        self
760    }
761
762    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
763        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
764            return self.alias == other_ptr.alias && self.record.entry == other_ptr.record.entry;
765        }
766        false
767    }
768
769    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
770        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
771            return self.alias == other_ptr.alias;
772        }
773        false
774    }
775
776    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
777        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
778            self.alias.cmp(&other_ptr.alias)
779        } else {
780            cmp::Ordering::Greater
781        }
782    }
783
784    fn rdata_print(&self) -> String {
785        self.alias.clone()
786    }
787
788    fn clone_box(&self) -> DnsRecordBox {
789        Box::new(self.clone())
790    }
791
792    fn boxed(self) -> DnsRecordBox {
793        Box::new(self)
794    }
795}
796
797/// Resource Record for a DNS service.
798#[derive(Debug, Clone)]
799pub struct DnsSrv {
800    pub(crate) record: DnsRecord,
801    pub(crate) priority: u16, // lower number means higher priority. Should be 0 in common cases.
802    pub(crate) weight: u16,   // Should be 0 in common cases
803    host: String,
804    port: u16,
805}
806
807impl DnsSrv {
808    pub fn new(
809        name: &str,
810        class: u16,
811        ttl: u32,
812        priority: u16,
813        weight: u16,
814        port: u16,
815        host: String,
816    ) -> Self {
817        let record = DnsRecord::new(name, RRType::SRV, class, ttl);
818        Self {
819            record,
820            priority,
821            weight,
822            host,
823            port,
824        }
825    }
826
827    pub fn host(&self) -> &str {
828        &self.host
829    }
830
831    pub fn port(&self) -> u16 {
832        self.port
833    }
834
835    pub fn set_host(&mut self, host: String) {
836        self.host = host;
837    }
838}
839
840impl DnsRecordExt for DnsSrv {
841    fn get_record(&self) -> &DnsRecord {
842        &self.record
843    }
844
845    fn get_record_mut(&mut self) -> &mut DnsRecord {
846        &mut self.record
847    }
848
849    fn write(&self, packet: &mut DnsOutPacket) {
850        packet.write_short(self.priority);
851        packet.write_short(self.weight);
852        packet.write_short(self.port);
853        packet.write_name(&self.host);
854    }
855
856    fn any(&self) -> &dyn Any {
857        self
858    }
859
860    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
861        if let Some(other_svc) = other.any().downcast_ref::<Self>() {
862            return self.host == other_svc.host
863                && self.port == other_svc.port
864                && self.weight == other_svc.weight
865                && self.priority == other_svc.priority
866                && self.record.entry == other_svc.record.entry;
867        }
868        false
869    }
870
871    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
872        if let Some(other_srv) = other.any().downcast_ref::<Self>() {
873            return self.host == other_srv.host
874                && self.port == other_srv.port
875                && self.weight == other_srv.weight
876                && self.priority == other_srv.priority;
877        }
878        false
879    }
880
881    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
882        let Some(other_srv) = other.any().downcast_ref::<Self>() else {
883            return cmp::Ordering::Greater;
884        };
885
886        // 1. compare `priority`
887        match self
888            .priority
889            .to_be_bytes()
890            .cmp(&other_srv.priority.to_be_bytes())
891        {
892            cmp::Ordering::Equal => {
893                // 2. compare `weight`
894                match self
895                    .weight
896                    .to_be_bytes()
897                    .cmp(&other_srv.weight.to_be_bytes())
898                {
899                    cmp::Ordering::Equal => {
900                        // 3. compare `port`.
901                        match self.port.to_be_bytes().cmp(&other_srv.port.to_be_bytes()) {
902                            cmp::Ordering::Equal => self.host.cmp(&other_srv.host),
903                            not_equal => not_equal,
904                        }
905                    }
906                    not_equal => not_equal,
907                }
908            }
909            not_equal => not_equal,
910        }
911    }
912
913    fn rdata_print(&self) -> String {
914        format!(
915            "priority: {}, weight: {}, port: {}, host: {}",
916            self.priority, self.weight, self.port, self.host
917        )
918    }
919
920    fn clone_box(&self) -> DnsRecordBox {
921        Box::new(self.clone())
922    }
923
924    fn boxed(self) -> DnsRecordBox {
925        Box::new(self)
926    }
927}
928
929/// Resource Record for a DNS TXT record.
930///
931/// From [RFC 6763 section 6]:
932///
933/// The format of each constituent string within the DNS TXT record is a
934/// single length byte, followed by 0-255 bytes of text data.
935///
936/// DNS-SD uses DNS TXT records to store arbitrary key/value pairs
937///    conveying additional information about the named service.  Each
938///    key/value pair is encoded as its own constituent string within the
939///    DNS TXT record, in the form "key=value" (without the quotation
940///    marks).  Everything up to the first '=' character is the key (Section
941///    6.4).  Everything after the first '=' character to the end of the
942///    string (including subsequent '=' characters, if any) is the value
943#[derive(Clone)]
944pub struct DnsTxt {
945    pub(crate) record: DnsRecord,
946    text: Vec<u8>,
947}
948
949impl DnsTxt {
950    pub fn new(name: &str, class: u16, ttl: u32, text: Vec<u8>) -> Self {
951        let record = DnsRecord::new(name, RRType::TXT, class, ttl);
952        Self { record, text }
953    }
954
955    pub fn text(&self) -> &[u8] {
956        &self.text
957    }
958}
959
960impl DnsRecordExt for DnsTxt {
961    fn get_record(&self) -> &DnsRecord {
962        &self.record
963    }
964
965    fn get_record_mut(&mut self) -> &mut DnsRecord {
966        &mut self.record
967    }
968
969    fn write(&self, packet: &mut DnsOutPacket) {
970        packet.write_bytes(&self.text);
971    }
972
973    fn any(&self) -> &dyn Any {
974        self
975    }
976
977    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
978        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
979            return self.text == other_txt.text && self.record.entry == other_txt.record.entry;
980        }
981        false
982    }
983
984    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
985        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
986            return self.text == other_txt.text;
987        }
988        false
989    }
990
991    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
992        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
993            self.text.cmp(&other_txt.text)
994        } else {
995            cmp::Ordering::Greater
996        }
997    }
998
999    fn rdata_print(&self) -> String {
1000        format!("{:?}", decode_txt(&self.text))
1001    }
1002
1003    fn clone_box(&self) -> DnsRecordBox {
1004        Box::new(self.clone())
1005    }
1006
1007    fn boxed(self) -> DnsRecordBox {
1008        Box::new(self)
1009    }
1010}
1011
1012impl fmt::Debug for DnsTxt {
1013    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1014        let properties = decode_txt(&self.text);
1015        write!(
1016            f,
1017            "DnsTxt {{ record: {:?}, text: {:?} }}",
1018            self.record, properties
1019        )
1020    }
1021}
1022
1023// Convert from DNS TXT record content to key/value pairs
1024fn decode_txt(txt: &[u8]) -> Vec<TxtProperty> {
1025    let mut properties = Vec::new();
1026    let mut offset = 0;
1027    while offset < txt.len() {
1028        let length = txt[offset] as usize;
1029        if length == 0 {
1030            break; // reached the end
1031        }
1032        offset += 1; // move over the length byte
1033
1034        let offset_end = offset + length;
1035        if offset_end > txt.len() {
1036            trace!("ERROR: DNS TXT: size given for property is out of range. (offset={}, length={}, offset_end={}, record length={})", offset, length, offset_end, txt.len());
1037            break; // Skipping the rest of the record content, as the size for this property would already be out of range.
1038        }
1039        let kv_bytes = &txt[offset..offset_end];
1040
1041        // split key and val using the first `=`
1042        let (k, v) = kv_bytes.iter().position(|&x| x == b'=').map_or_else(
1043            || (kv_bytes.to_vec(), None),
1044            |idx| (kv_bytes[..idx].to_vec(), Some(kv_bytes[idx + 1..].to_vec())),
1045        );
1046
1047        // Make sure the key can be stored in UTF-8.
1048        match String::from_utf8(k) {
1049            Ok(k_string) => {
1050                properties.push(TxtProperty {
1051                    key: k_string,
1052                    val: v,
1053                });
1054            }
1055            Err(e) => trace!("ERROR: convert to String from key: {}", e),
1056        }
1057
1058        offset += length;
1059    }
1060
1061    properties
1062}
1063
1064/// Represents a property in a TXT record.
1065#[derive(Clone, PartialEq, Eq)]
1066pub struct TxtProperty {
1067    /// The name of the property. The original cases are kept.
1068    key: String,
1069
1070    /// RFC 6763 says values are bytes, not necessarily UTF-8.
1071    /// It is also possible that there is no value, in which case
1072    /// the key is a boolean key.
1073    val: Option<Vec<u8>>,
1074}
1075
1076impl TxtProperty {
1077    /// Returns the value of a property as str.
1078    pub fn val_str(&self) -> &str {
1079        self.val
1080            .as_ref()
1081            .map_or("", |v| std::str::from_utf8(&v[..]).unwrap_or_default())
1082    }
1083}
1084
1085/// Supports constructing from a tuple.
1086impl<K, V> From<&(K, V)> for TxtProperty
1087where
1088    K: ToString,
1089    V: ToString,
1090{
1091    fn from(prop: &(K, V)) -> Self {
1092        Self {
1093            key: prop.0.to_string(),
1094            val: Some(prop.1.to_string().into_bytes()),
1095        }
1096    }
1097}
1098
1099impl<K, V> From<(K, V)> for TxtProperty
1100where
1101    K: ToString,
1102    V: AsRef<[u8]>,
1103{
1104    fn from(prop: (K, V)) -> Self {
1105        Self {
1106            key: prop.0.to_string(),
1107            val: Some(prop.1.as_ref().into()),
1108        }
1109    }
1110}
1111
1112/// Support a property that has no value.
1113impl From<&str> for TxtProperty {
1114    fn from(key: &str) -> Self {
1115        Self {
1116            key: key.to_string(),
1117            val: None,
1118        }
1119    }
1120}
1121
1122impl fmt::Display for TxtProperty {
1123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124        write!(f, "{}={}", self.key, self.val_str())
1125    }
1126}
1127
1128/// Mimic the default debug output for a struct, with a twist:
1129/// - If self.var is UTF-8, will output it as a string in double quotes.
1130/// - If self.var is not UTF-8, will output its bytes as in hex.
1131impl fmt::Debug for TxtProperty {
1132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133        let val_string = self.val.as_ref().map_or_else(
1134            || "None".to_string(),
1135            |v| {
1136                std::str::from_utf8(&v[..]).map_or_else(
1137                    |_| format!("Some({})", u8_slice_to_hex(&v[..])),
1138                    |s| format!("Some(\"{s}\")"),
1139                )
1140            },
1141        );
1142
1143        write!(
1144            f,
1145            "TxtProperty {{key: \"{}\", val: {}}}",
1146            &self.key, &val_string,
1147        )
1148    }
1149}
1150
1151const HEX_TABLE: [char; 16] = [
1152    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
1153];
1154
1155/// Create a hex string from `slice`, with a "0x" prefix.
1156///
1157/// For example, [1u8, 2u8] -> "0x0102"
1158fn u8_slice_to_hex(slice: &[u8]) -> String {
1159    let mut hex = String::with_capacity(slice.len() * 2 + 2);
1160    hex.push_str("0x");
1161    for b in slice {
1162        hex.push(HEX_TABLE[(b >> 4) as usize]);
1163        hex.push(HEX_TABLE[(b & 0x0F) as usize]);
1164    }
1165    hex
1166}
1167
1168/// A DNS host information record
1169#[derive(Debug, Clone)]
1170struct DnsHostInfo {
1171    record: DnsRecord,
1172    cpu: String,
1173    os: String,
1174}
1175
1176impl DnsHostInfo {
1177    fn new(name: &str, ty: RRType, class: u16, ttl: u32, cpu: String, os: String) -> Self {
1178        let record = DnsRecord::new(name, ty, class, ttl);
1179        Self { record, cpu, os }
1180    }
1181}
1182
1183impl DnsRecordExt for DnsHostInfo {
1184    fn get_record(&self) -> &DnsRecord {
1185        &self.record
1186    }
1187
1188    fn get_record_mut(&mut self) -> &mut DnsRecord {
1189        &mut self.record
1190    }
1191
1192    fn write(&self, packet: &mut DnsOutPacket) {
1193        println!("writing HInfo: cpu {} os {}", &self.cpu, &self.os);
1194        packet.write_bytes(self.cpu.as_bytes());
1195        packet.write_bytes(self.os.as_bytes());
1196    }
1197
1198    fn any(&self) -> &dyn Any {
1199        self
1200    }
1201
1202    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1203        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1204            return self.cpu == other_hinfo.cpu
1205                && self.os == other_hinfo.os
1206                && self.record.entry == other_hinfo.record.entry;
1207        }
1208        false
1209    }
1210
1211    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1212        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1213            return self.cpu == other_hinfo.cpu && self.os == other_hinfo.os;
1214        }
1215        false
1216    }
1217
1218    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1219        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1220            match self.cpu.cmp(&other_hinfo.cpu) {
1221                cmp::Ordering::Equal => self.os.cmp(&other_hinfo.os),
1222                ordering => ordering,
1223            }
1224        } else {
1225            cmp::Ordering::Greater
1226        }
1227    }
1228
1229    fn rdata_print(&self) -> String {
1230        format!("cpu: {}, os: {}", self.cpu, self.os)
1231    }
1232
1233    fn clone_box(&self) -> DnsRecordBox {
1234        Box::new(self.clone())
1235    }
1236
1237    fn boxed(self) -> DnsRecordBox {
1238        Box::new(self)
1239    }
1240}
1241
1242/// Resource Record for negative responses
1243///
1244/// [RFC4034 section 4.1](https://datatracker.ietf.org/doc/html/rfc4034#section-4.1)
1245/// and
1246/// [RFC6762 section 6.1](https://datatracker.ietf.org/doc/html/rfc6762#section-6.1)
1247#[derive(Debug, Clone)]
1248pub struct DnsNSec {
1249    record: DnsRecord,
1250    next_domain: String,
1251    type_bitmap: Vec<u8>,
1252}
1253
1254impl DnsNSec {
1255    pub fn new(
1256        name: &str,
1257        class: u16,
1258        ttl: u32,
1259        next_domain: String,
1260        type_bitmap: Vec<u8>,
1261    ) -> Self {
1262        let record = DnsRecord::new(name, RRType::NSEC, class, ttl);
1263        Self {
1264            record,
1265            next_domain,
1266            type_bitmap,
1267        }
1268    }
1269
1270    /// Returns the types marked by `type_bitmap`
1271    pub fn _types(&self) -> Vec<u16> {
1272        // From RFC 4034: 4.1.2 The Type Bit Maps Field
1273        // https://datatracker.ietf.org/doc/html/rfc4034#section-4.1.2
1274        //
1275        // Each bitmap encodes the low-order 8 bits of RR types within the
1276        // window block, in network bit order.  The first bit is bit 0.  For
1277        // window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
1278        // to RR type 2 (NS), and so forth.
1279
1280        let mut bit_num = 0;
1281        let mut results = Vec::new();
1282
1283        for byte in self.type_bitmap.iter() {
1284            let mut bit_mask: u8 = 0x80; // for bit 0 in network bit order
1285
1286            // check every bit in this byte, one by one.
1287            for _ in 0..8 {
1288                if (byte & bit_mask) != 0 {
1289                    results.push(bit_num);
1290                }
1291                bit_num += 1;
1292                bit_mask >>= 1; // mask for the next bit
1293            }
1294        }
1295        results
1296    }
1297}
1298
1299impl DnsRecordExt for DnsNSec {
1300    fn get_record(&self) -> &DnsRecord {
1301        &self.record
1302    }
1303
1304    fn get_record_mut(&mut self) -> &mut DnsRecord {
1305        &mut self.record
1306    }
1307
1308    fn write(&self, packet: &mut DnsOutPacket) {
1309        packet.write_bytes(self.next_domain.as_bytes());
1310        packet.write_bytes(&self.type_bitmap);
1311    }
1312
1313    fn any(&self) -> &dyn Any {
1314        self
1315    }
1316
1317    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1318        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1319            return self.next_domain == other_record.next_domain
1320                && self.type_bitmap == other_record.type_bitmap
1321                && self.record.entry == other_record.record.entry;
1322        }
1323        false
1324    }
1325
1326    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1327        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1328            return self.next_domain == other_record.next_domain
1329                && self.type_bitmap == other_record.type_bitmap;
1330        }
1331        false
1332    }
1333
1334    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1335        if let Some(other_nsec) = other.any().downcast_ref::<Self>() {
1336            match self.next_domain.cmp(&other_nsec.next_domain) {
1337                cmp::Ordering::Equal => self.type_bitmap.cmp(&other_nsec.type_bitmap),
1338                ordering => ordering,
1339            }
1340        } else {
1341            cmp::Ordering::Greater
1342        }
1343    }
1344
1345    fn rdata_print(&self) -> String {
1346        format!(
1347            "next_domain: {}, type_bitmap len: {}",
1348            self.next_domain,
1349            self.type_bitmap.len()
1350        )
1351    }
1352
1353    fn clone_box(&self) -> DnsRecordBox {
1354        Box::new(self.clone())
1355    }
1356
1357    fn boxed(self) -> DnsRecordBox {
1358        Box::new(self)
1359    }
1360}
1361
1362#[derive(PartialEq)]
1363enum PacketState {
1364    Init = 0,
1365    Finished = 1,
1366}
1367
1368/// A single packet for outgoing DNS message.
1369pub struct DnsOutPacket {
1370    /// All bytes in `data` concatenated is the actual packet on the wire.
1371    data: Vec<Vec<u8>>,
1372
1373    /// Current logical size of the packet. It starts with the size of the mandatory header.
1374    size: usize,
1375
1376    /// An internal state, not defined by DNS.
1377    state: PacketState,
1378
1379    /// k: name, v: offset
1380    names: HashMap<String, u16>,
1381}
1382
1383impl DnsOutPacket {
1384    fn new() -> Self {
1385        Self {
1386            data: Vec::new(),
1387            size: MSG_HEADER_LEN, // Header is mandatory.
1388            state: PacketState::Init,
1389            names: HashMap::new(),
1390        }
1391    }
1392
1393    pub fn size(&self) -> usize {
1394        self.size
1395    }
1396
1397    pub fn to_bytes(&self) -> Vec<u8> {
1398        self.data.concat()
1399    }
1400
1401    fn write_question(&mut self, question: &DnsQuestion) {
1402        self.write_name(&question.entry.name);
1403        self.write_short(question.entry.ty as u16);
1404        self.write_short(question.entry.class);
1405    }
1406
1407    /// Writes a record (answer, authoritative answer, additional)
1408    /// Returns false if the packet exceeds the max size with this record, nothing is written to the packet.
1409    /// otherwise returns true.
1410    fn write_record(&mut self, record_ext: &dyn DnsRecordExt, now: u64) -> bool {
1411        let start_data_length = self.data.len();
1412        let start_size = self.size;
1413
1414        let record = record_ext.get_record();
1415        self.write_name(record.get_name());
1416        self.write_short(record.entry.ty as u16);
1417        if record.entry.cache_flush {
1418            // check "multicast"
1419            self.write_short(record.entry.class | CLASS_CACHE_FLUSH);
1420        } else {
1421            self.write_short(record.entry.class);
1422        }
1423
1424        if now == 0 {
1425            self.write_u32(record.ttl);
1426        } else {
1427            self.write_u32(record.get_remaining_ttl(now));
1428        }
1429
1430        let index = self.data.len();
1431
1432        // Adjust size for the short we will write before this record
1433        self.size += 2;
1434        record_ext.write(self);
1435        self.size -= 2;
1436
1437        let length: usize = self.data[index..].iter().map(|x| x.len()).sum();
1438        self.insert_short(index, length as u16);
1439
1440        if self.size > MAX_MSG_ABSOLUTE {
1441            self.data.truncate(start_data_length);
1442            self.size = start_size;
1443            self.state = PacketState::Finished;
1444            return false;
1445        }
1446
1447        true
1448    }
1449
1450    pub(crate) fn insert_short(&mut self, index: usize, value: u16) {
1451        self.data.insert(index, value.to_be_bytes().to_vec());
1452        self.size += 2;
1453    }
1454
1455    // Write name to packet
1456    //
1457    // [RFC1035]
1458    // 4.1.4. Message compression
1459    //
1460    // In order to reduce the size of messages, the domain system utilizes a
1461    // compression scheme which eliminates the repetition of domain names in a
1462    // message.  In this scheme, an entire domain name or a list of labels at
1463    // the end of a domain name is replaced with a pointer to a prior occurrence
1464    // of the same name.
1465    // The pointer takes the form of a two octet sequence:
1466    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1467    //     | 1  1|                OFFSET                   |
1468    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1469    // The first two bits are ones.  This allows a pointer to be distinguished
1470    // from a label, since the label must begin with two zero bits because
1471    // labels are restricted to 63 octets or less.  (The 10 and 01 combinations
1472    // are reserved for future use.)  The OFFSET field specifies an offset from
1473    // the start of the message (i.e., the first octet of the ID field in the
1474    // domain header).  A zero offset specifies the first byte of the ID field,
1475    // etc.
1476    fn write_name(&mut self, name: &str) {
1477        // ignore the ending "." if exists
1478        let end = name.len();
1479        let end = if end > 0 && &name[end - 1..] == "." {
1480            end - 1
1481        } else {
1482            end
1483        };
1484
1485        let mut here = 0;
1486        while here < end {
1487            const POINTER_MASK: u16 = 0xC000;
1488            let remaining = &name[here..end];
1489
1490            // Check if 'remaining' already appeared in this message
1491            match self.names.get(remaining) {
1492                Some(offset) => {
1493                    let pointer = *offset | POINTER_MASK;
1494                    self.write_short(pointer);
1495                    // println!(
1496                    //     "written pointer {} ({}) for {}",
1497                    //     pointer,
1498                    //     pointer ^ POINTER_MASK,
1499                    //     remaining
1500                    // );
1501                    break;
1502                }
1503                None => {
1504                    // Remember the remaining parts so we can point to it
1505                    self.names.insert(remaining.to_string(), self.size as u16);
1506                    // println!("set offset {} for {}", self.size, remaining);
1507
1508                    // Find the current label to write into the packet
1509                    let stop = remaining.find('.').map_or(end, |i| here + i);
1510                    let label = &name[here..stop];
1511                    self.write_utf8(label);
1512
1513                    here = stop + 1; // move past the current label
1514                }
1515            }
1516
1517            if here >= end {
1518                self.write_byte(0); // name ends with 0 if not using a pointer
1519            }
1520        }
1521    }
1522
1523    fn write_utf8(&mut self, utf: &str) {
1524        assert!(utf.len() < 64);
1525        self.write_byte(utf.len() as u8);
1526        self.write_bytes(utf.as_bytes());
1527    }
1528
1529    fn write_bytes(&mut self, s: &[u8]) {
1530        self.data.push(s.to_vec());
1531        self.size += s.len();
1532    }
1533
1534    fn write_u32(&mut self, int: u32) {
1535        self.data.push(int.to_be_bytes().to_vec());
1536        self.size += 4;
1537    }
1538
1539    fn write_short(&mut self, short: u16) {
1540        self.data.push(short.to_be_bytes().to_vec());
1541        self.size += 2;
1542    }
1543
1544    fn write_byte(&mut self, byte: u8) {
1545        self.data.push(vec![byte]);
1546        self.size += 1;
1547    }
1548
1549    /// Writes the header fields and finish the packet.
1550    /// This function should be only called when finishing a packet.
1551    ///
1552    /// The header format is based on RFC 1035 section 4.1.1:
1553    /// https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
1554    //
1555    //                                  1  1  1  1  1  1
1556    //    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
1557    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1558    //    |                      ID                       |
1559    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1560    //    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
1561    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1562    //    |                    QDCOUNT                    |
1563    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1564    //    |                    ANCOUNT                    |
1565    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1566    //    |                    NSCOUNT                    |
1567    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1568    //    |                    ARCOUNT                    |
1569    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1570    //
1571    fn write_header(
1572        &mut self,
1573        id: u16,
1574        flags: u16,
1575        q_count: u16,
1576        a_count: u16,
1577        auth_count: u16,
1578        addi_count: u16,
1579    ) {
1580        self.insert_short(0, addi_count);
1581        self.insert_short(0, auth_count);
1582        self.insert_short(0, a_count);
1583        self.insert_short(0, q_count);
1584        self.insert_short(0, flags);
1585        self.insert_short(0, id);
1586
1587        // Adjust the size as it was already initialized to include the header.
1588        self.size -= MSG_HEADER_LEN;
1589
1590        self.state = PacketState::Finished;
1591    }
1592}
1593
1594/// Representation of one outgoing DNS message that could be sent in one or more packet(s).
1595pub struct DnsOutgoing {
1596    flags: u16,
1597    id: u16,
1598    multicast: bool,
1599    questions: Vec<DnsQuestion>,
1600    answers: Vec<(DnsRecordBox, u64)>,
1601    authorities: Vec<DnsRecordBox>,
1602    additionals: Vec<DnsRecordBox>,
1603    known_answer_count: i64, // for internal maintenance only
1604}
1605
1606impl DnsOutgoing {
1607    pub fn new(flags: u16) -> Self {
1608        Self {
1609            flags,
1610            id: 0,
1611            multicast: true,
1612            questions: Vec::new(),
1613            answers: Vec::new(),
1614            authorities: Vec::new(),
1615            additionals: Vec::new(),
1616            known_answer_count: 0,
1617        }
1618    }
1619
1620    pub fn questions(&self) -> &[DnsQuestion] {
1621        &self.questions
1622    }
1623
1624    /// For testing purposes only.
1625    pub(crate) fn _answers(&self) -> &[(DnsRecordBox, u64)] {
1626        &self.answers
1627    }
1628
1629    pub fn answers_count(&self) -> usize {
1630        self.answers.len()
1631    }
1632
1633    pub fn authorities(&self) -> &[DnsRecordBox] {
1634        &self.authorities
1635    }
1636
1637    pub fn additionals(&self) -> &[DnsRecordBox] {
1638        &self.additionals
1639    }
1640
1641    pub fn known_answer_count(&self) -> i64 {
1642        self.known_answer_count
1643    }
1644
1645    pub fn set_id(&mut self, id: u16) {
1646        self.id = id;
1647    }
1648
1649    pub const fn is_query(&self) -> bool {
1650        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1651    }
1652
1653    const fn is_response(&self) -> bool {
1654        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
1655    }
1656
1657    // Adds an additional answer
1658
1659    // From: RFC 6763, DNS-Based Service Discovery, February 2013
1660
1661    // 12.  DNS Additional Record Generation
1662
1663    //    DNS has an efficiency feature whereby a DNS server may place
1664    //    additional records in the additional section of the DNS message.
1665    //    These additional records are records that the client did not
1666    //    explicitly request, but the server has reasonable grounds to expect
1667    //    that the client might request them shortly, so including them can
1668    //    save the client from having to issue additional queries.
1669
1670    //    This section recommends which additional records SHOULD be generated
1671    //    to improve network efficiency, for both Unicast and Multicast DNS-SD
1672    //    responses.
1673
1674    // 12.1.  PTR Records
1675
1676    //    When including a DNS-SD Service Instance Enumeration or Selective
1677    //    Instance Enumeration (subtype) PTR record in a response packet, the
1678    //    server/responder SHOULD include the following additional records:
1679
1680    //    o  The SRV record(s) named in the PTR rdata.
1681    //    o  The TXT record(s) named in the PTR rdata.
1682    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1683
1684    // 12.2.  SRV Records
1685
1686    //    When including an SRV record in a response packet, the
1687    //    server/responder SHOULD include the following additional records:
1688
1689    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1690    pub fn add_additional_answer(&mut self, answer: impl DnsRecordExt + 'static) {
1691        trace!("add_additional_answer: {:?}", &answer);
1692        self.additionals.push(answer.boxed());
1693    }
1694
1695    /// A workaround as Rust doesn't allow us to pass DnsRecordBox in as `impl DnsRecordExt`
1696    pub fn add_answer_box(&mut self, answer_box: DnsRecordBox) {
1697        self.answers.push((answer_box, 0));
1698    }
1699
1700    pub fn add_authority(&mut self, record: DnsRecordBox) {
1701        self.authorities.push(record);
1702    }
1703
1704    /// Returns true if `answer` is added to the outgoing msg.
1705    /// Returns false if `answer` was not added as it expired or suppressed by the incoming `msg`.
1706    pub fn add_answer(
1707        &mut self,
1708        msg: &DnsIncoming,
1709        answer: impl DnsRecordExt + Send + 'static,
1710    ) -> bool {
1711        trace!("Check for add_answer");
1712        if answer.suppressed_by(msg) {
1713            trace!("my answer is suppressed by incoming msg");
1714            self.known_answer_count += 1;
1715            return false;
1716        }
1717
1718        self.add_answer_at_time(answer, 0)
1719    }
1720
1721    /// Returns true if `answer` is added to the outgoing msg.
1722    /// Returns false if the answer is expired `now` hence not added.
1723    /// If `now` is 0, do not check if the answer expires.
1724    pub fn add_answer_at_time(
1725        &mut self,
1726        answer: impl DnsRecordExt + Send + 'static,
1727        now: u64,
1728    ) -> bool {
1729        if now == 0 || !answer.get_record().is_expired(now) {
1730            trace!("add_answer push: {:?}", &answer);
1731            self.answers.push((answer.boxed(), now));
1732            return true;
1733        }
1734        false
1735    }
1736
1737    pub fn add_question(&mut self, name: &str, qtype: RRType) {
1738        let q = DnsQuestion {
1739            entry: DnsEntry::new(name.to_string(), qtype, CLASS_IN),
1740        };
1741        self.questions.push(q);
1742    }
1743
1744    /// Returns a list of actual DNS packet data to be sent on the wire.
1745    pub fn to_data_on_wire(&self) -> Vec<Vec<u8>> {
1746        let packet_list = self.to_packets();
1747        packet_list.iter().map(|p| p.data.concat()).collect()
1748    }
1749
1750    /// Encode self into one or more packets.
1751    pub fn to_packets(&self) -> Vec<DnsOutPacket> {
1752        let mut packet_list = Vec::new();
1753        let mut packet = DnsOutPacket::new();
1754
1755        let mut question_count = self.questions.len() as u16;
1756        let mut answer_count = 0;
1757        let mut auth_count = 0;
1758        let mut addi_count = 0;
1759        let id = if self.multicast { 0 } else { self.id };
1760
1761        for question in self.questions.iter() {
1762            packet.write_question(question);
1763        }
1764
1765        for (answer, time) in self.answers.iter() {
1766            if packet.write_record(answer.as_ref(), *time) {
1767                answer_count += 1;
1768            }
1769        }
1770
1771        for auth in self.authorities.iter() {
1772            auth_count += u16::from(packet.write_record(auth.as_ref(), 0));
1773        }
1774
1775        for addi in self.additionals.iter() {
1776            if packet.write_record(addi.as_ref(), 0) {
1777                addi_count += 1;
1778                continue;
1779            }
1780
1781            // No more processing for response packets.
1782            if self.is_response() {
1783                break;
1784            }
1785
1786            // For query, the current packet exceeds its max size due to known answers,
1787            // need to truncate.
1788
1789            // finish the current packet first.
1790            packet.write_header(
1791                id,
1792                self.flags | FLAGS_TC,
1793                question_count,
1794                answer_count,
1795                auth_count,
1796                addi_count,
1797            );
1798
1799            packet_list.push(packet);
1800
1801            // create a new packet and reset counts.
1802            packet = DnsOutPacket::new();
1803            packet.write_record(addi.as_ref(), 0);
1804
1805            question_count = 0;
1806            answer_count = 0;
1807            auth_count = 0;
1808            addi_count = 1;
1809        }
1810
1811        packet.write_header(
1812            id,
1813            self.flags,
1814            question_count,
1815            answer_count,
1816            auth_count,
1817            addi_count,
1818        );
1819
1820        packet_list.push(packet);
1821        packet_list
1822    }
1823}
1824
1825/// An incoming DNS message. It could be a query or a response.
1826#[derive(Debug)]
1827pub struct DnsIncoming {
1828    offset: usize,
1829    data: Vec<u8>,
1830    questions: Vec<DnsQuestion>,
1831    answers: Vec<DnsRecordBox>,
1832    authorities: Vec<DnsRecordBox>,
1833    additional: Vec<DnsRecordBox>,
1834    id: u16,
1835    flags: u16,
1836    num_questions: u16,
1837    num_answers: u16,
1838    num_authorities: u16,
1839    num_additionals: u16,
1840    interface_id: InterfaceId,
1841}
1842
1843impl DnsIncoming {
1844    pub fn new(data: Vec<u8>, interface_id: InterfaceId) -> Result<Self> {
1845        let mut incoming = Self {
1846            offset: 0,
1847            data,
1848            questions: Vec::new(),
1849            answers: Vec::new(),
1850            authorities: Vec::new(),
1851            additional: Vec::new(),
1852            id: 0,
1853            flags: 0,
1854            num_questions: 0,
1855            num_answers: 0,
1856            num_authorities: 0,
1857            num_additionals: 0,
1858            interface_id,
1859        };
1860
1861        /*
1862        RFC 1035 section 4.1: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1
1863        ...
1864        All communications inside of the domain protocol are carried in a single
1865        format called a message.  The top level format of message is divided
1866        into 5 sections (some of which are empty in certain cases) shown below:
1867
1868            +---------------------+
1869            |        Header       |
1870            +---------------------+
1871            |       Question      | the question for the name server
1872            +---------------------+
1873            |        Answer       | RRs answering the question
1874            +---------------------+
1875            |      Authority      | RRs pointing toward an authority
1876            +---------------------+
1877            |      Additional     | RRs holding additional information
1878            +---------------------+
1879         */
1880        incoming.read_header()?;
1881        incoming.read_questions()?;
1882        incoming.read_answers()?;
1883        incoming.read_authorities()?;
1884        incoming.read_additional()?;
1885
1886        Ok(incoming)
1887    }
1888
1889    pub fn id(&self) -> u16 {
1890        self.id
1891    }
1892
1893    pub fn questions(&self) -> &[DnsQuestion] {
1894        &self.questions
1895    }
1896
1897    pub fn answers(&self) -> &[DnsRecordBox] {
1898        &self.answers
1899    }
1900
1901    pub fn authorities(&self) -> &[DnsRecordBox] {
1902        &self.authorities
1903    }
1904
1905    pub fn additionals(&self) -> &[DnsRecordBox] {
1906        &self.additional
1907    }
1908
1909    pub fn answers_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1910        &mut self.answers
1911    }
1912
1913    pub fn authorities_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1914        &mut self.authorities
1915    }
1916
1917    pub fn additionals_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1918        &mut self.additional
1919    }
1920
1921    pub fn all_records(self) -> impl Iterator<Item = DnsRecordBox> {
1922        self.answers
1923            .into_iter()
1924            .chain(self.authorities)
1925            .chain(self.additional)
1926    }
1927
1928    pub fn num_additionals(&self) -> u16 {
1929        self.num_additionals
1930    }
1931
1932    pub fn num_authorities(&self) -> u16 {
1933        self.num_authorities
1934    }
1935
1936    pub fn num_questions(&self) -> u16 {
1937        self.num_questions
1938    }
1939
1940    pub const fn is_query(&self) -> bool {
1941        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1942    }
1943
1944    pub const fn is_response(&self) -> bool {
1945        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
1946    }
1947
1948    fn read_header(&mut self) -> Result<()> {
1949        if self.data.len() < MSG_HEADER_LEN {
1950            return Err(e_fmt!(
1951                "DNS incoming: header is too short: {} bytes",
1952                self.data.len()
1953            ));
1954        }
1955
1956        let data = &self.data[0..];
1957        self.id = u16_from_be_slice(&data[..2]);
1958        self.flags = u16_from_be_slice(&data[2..4]);
1959        self.num_questions = u16_from_be_slice(&data[4..6]);
1960        self.num_answers = u16_from_be_slice(&data[6..8]);
1961        self.num_authorities = u16_from_be_slice(&data[8..10]);
1962        self.num_additionals = u16_from_be_slice(&data[10..12]);
1963
1964        self.offset = MSG_HEADER_LEN;
1965
1966        trace!(
1967            "read_header: id {}, {} questions {} answers {} authorities {} additionals",
1968            self.id,
1969            self.num_questions,
1970            self.num_answers,
1971            self.num_authorities,
1972            self.num_additionals
1973        );
1974        Ok(())
1975    }
1976
1977    fn read_questions(&mut self) -> Result<()> {
1978        trace!("read_questions: {}", &self.num_questions);
1979        for i in 0..self.num_questions {
1980            let name = self.read_name()?;
1981
1982            let data = &self.data[self.offset..];
1983            if data.len() < 4 {
1984                return Err(Error::Msg(format!(
1985                    "DNS incoming: question idx {} too short: {}",
1986                    i,
1987                    data.len()
1988                )));
1989            }
1990            let ty = u16_from_be_slice(&data[..2]);
1991            let class = u16_from_be_slice(&data[2..4]);
1992            self.offset += 4;
1993
1994            let Some(rr_type) = RRType::from_u16(ty) else {
1995                return Err(Error::Msg(format!(
1996                    "DNS incoming: question idx {i} qtype unknown: {ty}",
1997                )));
1998            };
1999
2000            self.questions.push(DnsQuestion {
2001                entry: DnsEntry::new(name, rr_type, class),
2002            });
2003        }
2004        Ok(())
2005    }
2006
2007    fn read_answers(&mut self) -> Result<()> {
2008        self.answers = self.read_rr_records(self.num_answers)?;
2009        Ok(())
2010    }
2011
2012    fn read_authorities(&mut self) -> Result<()> {
2013        self.authorities = self.read_rr_records(self.num_authorities)?;
2014        Ok(())
2015    }
2016
2017    fn read_additional(&mut self) -> Result<()> {
2018        self.additional = self.read_rr_records(self.num_additionals)?;
2019        Ok(())
2020    }
2021
2022    /// Decodes a sequence of RR records (in answers, authorities and additionals).
2023    fn read_rr_records(&mut self, count: u16) -> Result<Vec<DnsRecordBox>> {
2024        trace!("read_rr_records: {}", count);
2025        let mut rr_records = Vec::new();
2026
2027        // RFC 1035: https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.1
2028        //
2029        // All RRs have the same top level format shown below:
2030        //                               1  1  1  1  1  1
2031        // 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
2032        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2033        // |                                               |
2034        // /                                               /
2035        // /                      NAME                     /
2036        // |                                               |
2037        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2038        // |                      TYPE                     |
2039        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2040        // |                     CLASS                     |
2041        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2042        // |                      TTL                      |
2043        // |                                               |
2044        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2045        // |                   RDLENGTH                    |
2046        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
2047        // /                     RDATA                     /
2048        // /                                               /
2049        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2050
2051        // Muse have at least TYPE, CLASS, TTL, RDLENGTH fields: 10 bytes.
2052        const RR_HEADER_REMAIN: usize = 10;
2053
2054        for _ in 0..count {
2055            let name = self.read_name()?;
2056            let slice = &self.data[self.offset..];
2057
2058            if slice.len() < RR_HEADER_REMAIN {
2059                return Err(Error::Msg(format!(
2060                    "read_others: RR '{}' is too short after name: {} bytes",
2061                    &name,
2062                    slice.len()
2063                )));
2064            }
2065
2066            let ty = u16_from_be_slice(&slice[..2]);
2067            let class = u16_from_be_slice(&slice[2..4]);
2068            let mut ttl = u32_from_be_slice(&slice[4..8]);
2069            if ttl == 0 && self.is_response() {
2070                // RFC 6762 section 10.1:
2071                // "...Queriers receiving a Multicast DNS response with a TTL of zero SHOULD
2072                // NOT immediately delete the record from the cache, but instead record
2073                // a TTL of 1 and then delete the record one second later."
2074                // See https://datatracker.ietf.org/doc/html/rfc6762#section-10.1
2075
2076                ttl = 1;
2077            }
2078            let rdata_len = u16_from_be_slice(&slice[8..10]) as usize;
2079            self.offset += RR_HEADER_REMAIN;
2080            let next_offset = self.offset + rdata_len;
2081
2082            // Sanity check for RDATA length.
2083            if next_offset > self.data.len() {
2084                return Err(Error::Msg(format!(
2085                    "RR {name} RDATA length {rdata_len} is invalid: remain data len: {}",
2086                    self.data.len() - self.offset
2087                )));
2088            }
2089
2090            // decode RDATA based on the record type.
2091            let rec: Option<DnsRecordBox> = match RRType::from_u16(ty) {
2092                None => None,
2093
2094                Some(rr_type) => match rr_type {
2095                    RRType::CNAME | RRType::PTR => {
2096                        Some(DnsPointer::new(&name, rr_type, class, ttl, self.read_name()?).boxed())
2097                    }
2098                    RRType::TXT => {
2099                        Some(DnsTxt::new(&name, class, ttl, self.read_vec(rdata_len)?).boxed())
2100                    }
2101                    RRType::SRV => Some(
2102                        DnsSrv::new(
2103                            &name,
2104                            class,
2105                            ttl,
2106                            self.read_u16()?,
2107                            self.read_u16()?,
2108                            self.read_u16()?,
2109                            self.read_name()?,
2110                        )
2111                        .boxed(),
2112                    ),
2113                    RRType::HINFO => Some(
2114                        DnsHostInfo::new(
2115                            &name,
2116                            rr_type,
2117                            class,
2118                            ttl,
2119                            self.read_char_string()?,
2120                            self.read_char_string()?,
2121                        )
2122                        .boxed(),
2123                    ),
2124                    RRType::A => Some(
2125                        DnsAddress::new(
2126                            &name,
2127                            rr_type,
2128                            class,
2129                            ttl,
2130                            self.read_ipv4()?.into(),
2131                            self.interface_id.clone(),
2132                        )
2133                        .boxed(),
2134                    ),
2135                    RRType::AAAA => Some(
2136                        DnsAddress::new(
2137                            &name,
2138                            rr_type,
2139                            class,
2140                            ttl,
2141                            self.read_ipv6()?.into(),
2142                            self.interface_id.clone(),
2143                        )
2144                        .boxed(),
2145                    ),
2146                    RRType::NSEC => Some(
2147                        DnsNSec::new(
2148                            &name,
2149                            class,
2150                            ttl,
2151                            self.read_name()?,
2152                            self.read_type_bitmap()?,
2153                        )
2154                        .boxed(),
2155                    ),
2156                    _ => None,
2157                },
2158            };
2159
2160            if let Some(record) = rec {
2161                trace!("read_rr_records: {:?}", &record);
2162                rr_records.push(record);
2163            } else {
2164                trace!("Unsupported DNS record type: {} name: {}", ty, &name);
2165                self.offset += rdata_len;
2166            }
2167
2168            // sanity check.
2169            if self.offset != next_offset {
2170                return Err(Error::Msg(format!(
2171                    "read_rr_records: decode offset error for RData type {} offset: {} expected offset: {}",
2172                    ty, self.offset, next_offset,
2173                )));
2174            }
2175        }
2176
2177        Ok(rr_records)
2178    }
2179
2180    fn read_char_string(&mut self) -> Result<String> {
2181        let length = self.data[self.offset];
2182        self.offset += 1;
2183        self.read_string(length as usize)
2184    }
2185
2186    fn read_u16(&mut self) -> Result<u16> {
2187        let slice = &self.data[self.offset..];
2188        if slice.len() < U16_SIZE {
2189            return Err(Error::Msg(format!(
2190                "read_u16: slice len is only {}",
2191                slice.len()
2192            )));
2193        }
2194        let num = u16_from_be_slice(&slice[..U16_SIZE]);
2195        self.offset += U16_SIZE;
2196        Ok(num)
2197    }
2198
2199    /// Reads the "Type Bit Map" block for a DNS NSEC record.
2200    fn read_type_bitmap(&mut self) -> Result<Vec<u8>> {
2201        // From RFC 6762: 6.1.  Negative Responses
2202        // https://datatracker.ietf.org/doc/html/rfc6762#section-6.1
2203        //   o The Type Bit Map block number is 0.
2204        //   o The Type Bit Map block length byte is a value in the range 1-32.
2205        //   o The Type Bit Map data is 1-32 bytes, as indicated by length
2206        //     byte.
2207
2208        // Sanity check: at least 2 bytes to read.
2209        if self.data.len() < self.offset + 2 {
2210            return Err(Error::Msg(format!(
2211                "DnsIncoming is too short: {} at NSEC Type Bit Map offset {}",
2212                self.data.len(),
2213                self.offset
2214            )));
2215        }
2216
2217        let block_num = self.data[self.offset];
2218        self.offset += 1;
2219        if block_num != 0 {
2220            return Err(Error::Msg(format!(
2221                "NSEC block number is not 0: {block_num}"
2222            )));
2223        }
2224
2225        let block_len = self.data[self.offset] as usize;
2226        if !(1..=32).contains(&block_len) {
2227            return Err(Error::Msg(format!(
2228                "NSEC block length must be in the range 1-32: {block_len}"
2229            )));
2230        }
2231        self.offset += 1;
2232
2233        let end = self.offset + block_len;
2234        if end > self.data.len() {
2235            return Err(Error::Msg(format!(
2236                "NSEC block overflow: {} over RData len {}",
2237                end,
2238                self.data.len()
2239            )));
2240        }
2241        let bitmap = self.data[self.offset..end].to_vec();
2242        self.offset += block_len;
2243
2244        Ok(bitmap)
2245    }
2246
2247    fn read_vec(&mut self, length: usize) -> Result<Vec<u8>> {
2248        if self.data.len() < self.offset + length {
2249            return Err(e_fmt!(
2250                "DNS Incoming: not enough data to read a chunk of data"
2251            ));
2252        }
2253
2254        let v = self.data[self.offset..self.offset + length].to_vec();
2255        self.offset += length;
2256        Ok(v)
2257    }
2258
2259    fn read_ipv4(&mut self) -> Result<Ipv4Addr> {
2260        if self.data.len() < self.offset + 4 {
2261            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV4"));
2262        }
2263
2264        let bytes: [u8; 4] = self.data[self.offset..self.offset + 4]
2265            .try_into()
2266            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV4"))?;
2267        self.offset += bytes.len();
2268        Ok(Ipv4Addr::from(bytes))
2269    }
2270
2271    fn read_ipv6(&mut self) -> Result<Ipv6Addr> {
2272        if self.data.len() < self.offset + 16 {
2273            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV6"));
2274        }
2275
2276        let bytes: [u8; 16] = self.data[self.offset..self.offset + 16]
2277            .try_into()
2278            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV6"))?;
2279        self.offset += bytes.len();
2280        Ok(Ipv6Addr::from(bytes))
2281    }
2282
2283    fn read_string(&mut self, length: usize) -> Result<String> {
2284        if self.data.len() < self.offset + length {
2285            return Err(e_fmt!("DNS Incoming: not enough data to read a string"));
2286        }
2287
2288        let s = str::from_utf8(&self.data[self.offset..self.offset + length])
2289            .map_err(|e| Error::Msg(e.to_string()))?;
2290        self.offset += length;
2291        Ok(s.to_string())
2292    }
2293
2294    /// Reads a domain name at the current location of `self.data`.
2295    ///
2296    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 for
2297    /// domain name encoding.
2298    fn read_name(&mut self) -> Result<String> {
2299        let data = &self.data[..];
2300        let start_offset = self.offset;
2301        let mut offset = start_offset;
2302        let mut name = "".to_string();
2303        let mut at_end = false;
2304
2305        // From RFC1035:
2306        // "...Domain names in messages are expressed in terms of a sequence of labels.
2307        // Each label is represented as a one octet length field followed by that
2308        // number of octets."
2309        //
2310        // "...The compression scheme allows a domain name in a message to be
2311        // represented as either:
2312        // - a sequence of labels ending in a zero octet
2313        // - a pointer
2314        // - a sequence of labels ending with a pointer"
2315        loop {
2316            if offset >= data.len() {
2317                return Err(Error::Msg(format!(
2318                    "read_name: offset: {} data len {}. DnsIncoming: {:?}",
2319                    offset,
2320                    data.len(),
2321                    self
2322                )));
2323            }
2324            let length = data[offset];
2325
2326            // From RFC1035:
2327            // "...Since every domain name ends with the null label of
2328            // the root, a domain name is terminated by a length byte of zero."
2329            if length == 0 {
2330                if !at_end {
2331                    self.offset = offset + 1;
2332                }
2333                break; // The end of the name
2334            }
2335
2336            // Check the first 2 bits for possible "Message compression".
2337            match length & 0xC0 {
2338                0x00 => {
2339                    // regular utf8 string with length
2340                    offset += 1;
2341                    let ending = offset + length as usize;
2342
2343                    // Never read beyond the whole data length.
2344                    if ending > data.len() {
2345                        return Err(Error::Msg(format!(
2346                            "read_name: ending {} exceeds data length {}",
2347                            ending,
2348                            data.len()
2349                        )));
2350                    }
2351
2352                    name += str::from_utf8(&data[offset..ending])
2353                        .map_err(|e| Error::Msg(format!("read_name: from_utf8: {e}")))?;
2354                    name += ".";
2355                    offset += length as usize;
2356                }
2357                0xC0 => {
2358                    // Message compression.
2359                    // See https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4
2360                    let slice = &data[offset..];
2361                    if slice.len() < U16_SIZE {
2362                        return Err(Error::Msg(format!(
2363                            "read_name: u16 slice len is only {}",
2364                            slice.len()
2365                        )));
2366                    }
2367                    let pointer = (u16_from_be_slice(slice) ^ 0xC000) as usize;
2368                    if pointer >= start_offset {
2369                        // Error: could trigger an infinite loop.
2370                        return Err(Error::Msg(format!(
2371                            "Invalid name compression: pointer {} must be less than the start offset {}",
2372                            &pointer, &start_offset
2373                        )));
2374                    }
2375
2376                    // A pointer marks the end of a domain name.
2377                    if !at_end {
2378                        self.offset = offset + U16_SIZE;
2379                        at_end = true;
2380                    }
2381                    offset = pointer;
2382                }
2383                _ => {
2384                    return Err(Error::Msg(format!(
2385                        "Bad name with invalid length: 0x{:x} offset {}, data (so far): {:x?}",
2386                        length,
2387                        offset,
2388                        &data[..offset]
2389                    )));
2390                }
2391            };
2392        }
2393
2394        Ok(name)
2395    }
2396}
2397
2398/// Returns UNIX time in millis
2399fn current_time_millis() -> u64 {
2400    SystemTime::now()
2401        .duration_since(SystemTime::UNIX_EPOCH)
2402        .expect("failed to get current UNIX time")
2403        .as_millis() as u64
2404}
2405
2406const fn u16_from_be_slice(bytes: &[u8]) -> u16 {
2407    let u8_array: [u8; 2] = [bytes[0], bytes[1]];
2408    u16::from_be_bytes(u8_array)
2409}
2410
2411const fn u32_from_be_slice(s: &[u8]) -> u32 {
2412    let u8_array: [u8; 4] = [s[0], s[1], s[2], s[3]];
2413    u32::from_be_bytes(u8_array)
2414}
2415
2416/// Returns the UNIX time in millis at which this record will have expired
2417/// by a certain percentage.
2418const fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
2419    // 'created' is in millis, 'ttl' is in seconds, hence:
2420    // ttl * 1000 * (percent / 100) => ttl * percent * 10
2421    created + (ttl * percent * 10) as u64
2422}