Skip to main content

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