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::{debug, 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#[non_exhaustive]
128pub enum ScopedIp {
129    V4(ScopedIpV4),
130    V6(ScopedIpV6),
131}
132
133impl ScopedIp {
134    pub const fn to_ip_addr(&self) -> IpAddr {
135        match self {
136            ScopedIp::V4(v4) => IpAddr::V4(v4.addr),
137            ScopedIp::V6(v6) => IpAddr::V6(v6.addr),
138        }
139    }
140
141    pub const fn is_ipv4(&self) -> bool {
142        matches!(self, ScopedIp::V4(_))
143    }
144
145    pub const fn is_ipv6(&self) -> bool {
146        matches!(self, ScopedIp::V6(_))
147    }
148
149    pub const fn is_loopback(&self) -> bool {
150        match self {
151            ScopedIp::V4(v4) => v4.addr.is_loopback(),
152            ScopedIp::V6(v6) => v6.addr.is_loopback(),
153        }
154    }
155}
156
157impl From<IpAddr> for ScopedIp {
158    fn from(ip: IpAddr) -> Self {
159        match ip {
160            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
161                addr: v4,
162                interface_ids: vec![],
163            }),
164            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
165                addr: v6,
166                scope_id: InterfaceId::default(),
167            }),
168        }
169    }
170}
171
172impl From<&Interface> for ScopedIp {
173    fn from(interface: &Interface) -> Self {
174        match interface.ip() {
175            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
176                addr: v4,
177                interface_ids: vec![InterfaceId::from(interface)],
178            }),
179            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
180                addr: v6,
181                scope_id: InterfaceId::from(interface),
182            }),
183        }
184    }
185}
186
187impl fmt::Display for ScopedIp {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        match self {
190            ScopedIp::V4(v4) => write!(f, "{}", v4.addr),
191            ScopedIp::V6(v6) => {
192                if v6.scope_id.index != 0 && is_unicast_link_local(&v6.addr) {
193                    #[cfg(windows)]
194                    {
195                        write!(f, "{}%{}", v6.addr, v6.scope_id.index)
196                    }
197                    #[cfg(not(windows))]
198                    {
199                        write!(f, "{}%{}", v6.addr, v6.scope_id.name)
200                    }
201                } else {
202                    write!(f, "{}", v6.addr)
203                }
204            }
205        }
206    }
207}
208
209/// DNS resource record types, stored as `u16`. Can do `as u16` when needed.
210///
211/// See [RFC 1035 section 3.2.2](https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2)
212#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
213#[non_exhaustive]
214#[repr(u16)]
215pub enum RRType {
216    /// DNS record type for IPv4 address
217    A = 1,
218
219    /// DNS record type for Canonical Name
220    CNAME = 5,
221
222    /// DNS record type for Pointer
223    PTR = 12,
224
225    /// DNS record type for Host Info
226    HINFO = 13,
227
228    /// DNS record type for Text (properties)
229    TXT = 16,
230
231    /// DNS record type for IPv6 address
232    AAAA = 28,
233
234    /// DNS record type for Service
235    SRV = 33,
236
237    /// DNS record type for Negative Responses
238    NSEC = 47,
239
240    /// DNS record type for any records (wildcard)
241    ANY = 255,
242}
243
244impl RRType {
245    /// Converts `u16` into `RRType` if possible.
246    pub const fn from_u16(value: u16) -> Option<Self> {
247        match value {
248            1 => Some(RRType::A),
249            5 => Some(RRType::CNAME),
250            12 => Some(RRType::PTR),
251            13 => Some(RRType::HINFO),
252            16 => Some(RRType::TXT),
253            28 => Some(RRType::AAAA),
254            33 => Some(RRType::SRV),
255            47 => Some(RRType::NSEC),
256            255 => Some(RRType::ANY),
257            _ => None,
258        }
259    }
260}
261
262impl fmt::Display for RRType {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        match self {
265            RRType::A => write!(f, "TYPE_A"),
266            RRType::CNAME => write!(f, "TYPE_CNAME"),
267            RRType::PTR => write!(f, "TYPE_PTR"),
268            RRType::HINFO => write!(f, "TYPE_HINFO"),
269            RRType::TXT => write!(f, "TYPE_TXT"),
270            RRType::AAAA => write!(f, "TYPE_AAAA"),
271            RRType::SRV => write!(f, "TYPE_SRV"),
272            RRType::NSEC => write!(f, "TYPE_NSEC"),
273            RRType::ANY => write!(f, "TYPE_ANY"),
274        }
275    }
276}
277
278/// The class value for the Internet.
279pub const CLASS_IN: u16 = 1;
280pub const CLASS_MASK: u16 = 0x7FFF;
281
282/// Cache-flush bit: the most significant bit of the rrclass field of the resource record.  
283pub const CLASS_CACHE_FLUSH: u16 = 0x8000;
284
285/// Absolute max size of UDP datagram payload for an mDNS packet over IPv4.
286///
287/// RFC 6762 section 17:
288/// "Even when fragmentation is used, a Multicast DNS packet, including IP and UDP
289/// headers, MUST NOT exceed 9000 bytes."
290///
291/// It is calculated as: 9000 bytes - IPv4 header 20 bytes - UDP header 8 bytes.
292pub(crate) const MAX_PKT_ABSOLUTE_IPV4: usize = 8972;
293
294/// Absolute max size of UDP datagram payload for an mDNS packet over IPv6.
295///
296/// Same 9000-byte ceiling as [`MAX_PKT_ABSOLUTE_IPV4`], less the bigger IPv6 header:
297/// 9000 bytes - IPv6 header 40 bytes - UDP header 8 bytes.
298pub(crate) const MAX_PKT_ABSOLUTE_IPV6: usize = 8952;
299
300/// Absolute max size of an mDNS packet for the given IP version.
301pub(crate) const fn max_pkt_absolute(is_ipv4: bool) -> usize {
302    if is_ipv4 {
303        MAX_PKT_ABSOLUTE_IPV4
304    } else {
305        MAX_PKT_ABSOLUTE_IPV6
306    }
307}
308
309/// Default max size of a generated (i.e. outgoing) packet.
310///
311/// Calculated as: 1500 bytes Ethernet MTU - IPv6 header 40 bytes - UDP header 8 bytes.
312/// It is safe on both IPv4 and IPv6, at the cost of 20 unused bytes for IPv4.
313///
314/// The idea is to keep generated packets unfragmented at IP layer. See RFC 6762 section 17.
315pub const MAX_PKT_DEFAULT: usize = 1452;
316
317const MSG_HEADER_LEN: usize = 12;
318
319/// Max size of a single DNS label, in bytes.
320///
321/// Reference: [RFC1035 section 2.3.4](https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.4)
322const MAX_LABEL_BYTES: usize = 63;
323
324/// Max size of a whole domain name, in bytes.
325///
326/// Reference: [RFC1035 section 2.3.4](https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.4)
327const MAX_NAME_BYTES: usize = 255;
328
329/// Why a question or a record could not be written into a packet.
330///
331/// In either case nothing is left behind in the packet: the caller rolls back
332/// whatever was written and skips the item.
333#[derive(Debug, PartialEq, Eq)]
334pub enum WriteError {
335    /// A label in a name is longer than [`MAX_LABEL_BYTES`].
336    NameTooLong,
337
338    /// The packet would exceed its max size with this record.
339    PacketFull,
340}
341
342/// `crate::error::Result` shadows the std alias here, hence the full path.
343type WriteResult = core::result::Result<(), WriteError>;
344
345// Definitions for DNS message header "flags" field
346//
347// The "flags" field is 16-bit long, in this format:
348// (RFC 1035 section 4.1.1)
349//
350//   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
351// |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
352//
353pub const FLAGS_QR_MASK: u16 = 0x8000; // mask for query/response bit
354
355/// Flag bit to indicate a query
356pub const FLAGS_QR_QUERY: u16 = 0x0000;
357
358/// Flag bit to indicate a response
359pub const FLAGS_QR_RESPONSE: u16 = 0x8000;
360
361/// Flag bit for Authoritative Answer
362pub const FLAGS_AA: u16 = 0x0400;
363
364/// mask for TC(Truncated) bit
365///
366/// 2024-08-10: currently this flag is only supported on the querier side,
367///             not supported on the responder side. I.e. the responder only
368///             handles the first packet and ignore this bit. Since the
369///             additional packets have 0 questions, the processing of them
370///             is no-op.
371///             In practice, this means the responder supports Known-Answer
372///             only with single packet, not multi-packet. The querier supports
373///             both single packet and multi-packet.
374pub const FLAGS_TC: u16 = 0x0200;
375
376/// A convenience type alias for DNS record trait objects.
377pub type DnsRecordBox = Box<dyn DnsRecordExt>;
378
379impl Clone for DnsRecordBox {
380    fn clone(&self) -> Self {
381        self.clone_box()
382    }
383}
384
385const U16_SIZE: usize = 2;
386
387/// Returns `RRType` for a given IP address.
388#[inline]
389pub const fn ip_address_rr_type(address: &IpAddr) -> RRType {
390    match address {
391        IpAddr::V4(_) => RRType::A,
392        IpAddr::V6(_) => RRType::AAAA,
393    }
394}
395
396#[derive(Eq, PartialEq, Debug, Clone)]
397pub struct DnsEntry {
398    pub(crate) name: String, // always lower case.
399    pub(crate) ty: RRType,
400    class: u16,
401    cache_flush: bool,
402}
403
404impl DnsEntry {
405    const fn new(name: String, ty: RRType, class: u16) -> Self {
406        Self {
407            name,
408            ty,
409            class: class & CLASS_MASK,
410            cache_flush: (class & CLASS_CACHE_FLUSH) != 0,
411        }
412    }
413}
414
415/// Common methods for all DNS entries:  questions and resource records.
416pub trait DnsEntryExt: fmt::Debug {
417    fn entry_name(&self) -> &str;
418
419    fn entry_type(&self) -> RRType;
420}
421
422/// A DNS question entry
423#[derive(Debug)]
424pub struct DnsQuestion {
425    pub(crate) entry: DnsEntry,
426}
427
428impl DnsEntryExt for DnsQuestion {
429    fn entry_name(&self) -> &str {
430        &self.entry.name
431    }
432
433    fn entry_type(&self) -> RRType {
434        self.entry.ty
435    }
436}
437
438/// A DNS Resource Record - like a DNS entry, but has a TTL.
439/// RFC: https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1
440///      https://www.rfc-editor.org/rfc/rfc1035#section-4.1.3
441#[derive(Debug, Clone)]
442pub struct DnsRecord {
443    pub(crate) entry: DnsEntry,
444    ttl: u32,     // in seconds, 0 means this record should not be cached
445    created: u64, // UNIX time in millis
446    expires: u64, // expires at this UNIX time in millis
447
448    /// Support re-query an instance before its PTR record expires.
449    /// See https://datatracker.ietf.org/doc/html/rfc6762#section-5.2
450    refresh: u64, // UNIX time in millis
451
452    /// If conflict resolution decides to change the name, this is the new one.
453    new_name: Option<String>,
454}
455
456impl DnsRecord {
457    fn new(name: &str, ty: RRType, class: u16, ttl: u32) -> Self {
458        let created = current_time_millis();
459
460        // From RFC 6762 section 5.2:
461        // "... The querier should plan to issue a query at 80% of the record
462        // lifetime, and then if no answer is received, at 85%, 90%, and 95%."
463        let refresh = get_expiration_time(created, ttl, 80);
464
465        let expires = get_expiration_time(created, ttl, 100);
466
467        Self {
468            entry: DnsEntry::new(name.to_string(), ty, class),
469            ttl,
470            created,
471            expires,
472            refresh,
473            new_name: None,
474        }
475    }
476
477    pub const fn get_ttl(&self) -> u32 {
478        self.ttl
479    }
480
481    pub const fn get_expire_time(&self) -> u64 {
482        self.expires
483    }
484
485    pub const fn get_refresh_time(&self) -> u64 {
486        self.refresh
487    }
488
489    pub const fn is_expired(&self, now: u64) -> bool {
490        now >= self.expires
491    }
492
493    /// Returns whether record expires in 1 second.
494    ///
495    /// This is useful because mDNS sets TTL to 1 (not 0) for expiring records.
496    pub const fn expires_soon(&self, now: u64) -> bool {
497        now + 1000 >= self.expires
498    }
499
500    pub const fn refresh_due(&self, now: u64) -> bool {
501        now >= self.refresh
502    }
503
504    /// Returns whether `now` (in millis) has passed half of TTL.
505    pub fn halflife_passed(&self, now: u64) -> bool {
506        let halflife = get_expiration_time(self.created, self.ttl, 50);
507        now > halflife
508    }
509
510    pub fn is_unique(&self) -> bool {
511        self.entry.cache_flush
512    }
513
514    /// Updates the refresh time to be the same as the expire time so that
515    /// this record will not refresh again and will just expire.
516    pub fn refresh_no_more(&mut self) {
517        self.refresh = get_expiration_time(self.created, self.ttl, 100);
518    }
519
520    /// Returns if this record is due for refresh. If yes, `refresh` time is updated.
521    pub fn refresh_maybe(&mut self, now: u64) -> bool {
522        if self.is_expired(now) || !self.refresh_due(now) {
523            return false;
524        }
525
526        trace!(
527            "{} qtype {} is due to refresh",
528            &self.entry.name,
529            self.entry.ty
530        );
531
532        // From RFC 6762 section 5.2:
533        // "... The querier should plan to issue a query at 80% of the record
534        // lifetime, and then if no answer is received, at 85%, 90%, and 95%."
535        //
536        // If the answer is received in time, 'refresh' will be reset outside
537        // this function, back to 80% of the new TTL.
538        if self.refresh == get_expiration_time(self.created, self.ttl, 80) {
539            self.refresh = get_expiration_time(self.created, self.ttl, 85);
540        } else if self.refresh == get_expiration_time(self.created, self.ttl, 85) {
541            self.refresh = get_expiration_time(self.created, self.ttl, 90);
542        } else if self.refresh == get_expiration_time(self.created, self.ttl, 90) {
543            self.refresh = get_expiration_time(self.created, self.ttl, 95);
544        } else {
545            self.refresh_no_more();
546        }
547
548        true
549    }
550
551    /// Returns the remaining TTL in seconds
552    fn get_remaining_ttl(&self, now: u64) -> u32 {
553        let remaining_millis = get_expiration_time(self.created, self.ttl, 100) - now;
554        cmp::max(0, remaining_millis / 1000) as u32
555    }
556
557    /// Return the absolute time for this record being created
558    pub const fn get_created(&self) -> u64 {
559        self.created
560    }
561
562    /// Set the absolute expiration time in millis
563    fn set_expire(&mut self, expire_at: u64) {
564        self.expires = expire_at;
565    }
566
567    fn reset_ttl(&mut self, other: &Self) {
568        self.ttl = other.ttl;
569        self.created = other.created;
570        self.expires = get_expiration_time(self.created, self.ttl, 100);
571        self.refresh = if self.ttl > 1 {
572            get_expiration_time(self.created, self.ttl, 80)
573        } else {
574            // If TTL is 1, it means this record is expiring,
575            // then we set refresh to the same time as expires.
576            self.expires
577        };
578    }
579
580    /// Modify TTL to reflect the remaining life time from `now`.
581    pub fn update_ttl(&mut self, now: u64) {
582        if now > self.created {
583            let elapsed = now - self.created;
584            self.ttl -= (elapsed / 1000) as u32;
585        }
586    }
587
588    pub fn set_new_name(&mut self, new_name: String) {
589        if new_name == self.entry.name {
590            self.new_name = None;
591        } else {
592            self.new_name = Some(new_name);
593        }
594    }
595
596    pub fn get_new_name(&self) -> Option<&str> {
597        self.new_name.as_deref()
598    }
599
600    /// Return the new name if exists, otherwise the regular name in DnsEntry.
601    pub(crate) fn get_name(&self) -> &str {
602        self.new_name.as_deref().unwrap_or(&self.entry.name)
603    }
604
605    pub fn get_original_name(&self) -> &str {
606        &self.entry.name
607    }
608}
609
610impl PartialEq for DnsRecord {
611    fn eq(&self, other: &Self) -> bool {
612        self.entry == other.entry
613    }
614}
615
616/// Common methods for DNS resource records.
617pub trait DnsRecordExt: fmt::Debug {
618    fn get_record(&self) -> &DnsRecord;
619    fn get_record_mut(&mut self) -> &mut DnsRecord;
620    /// Writes the rdata of this record into `packet`.
621    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult;
622    fn any(&self) -> &dyn Any;
623
624    /// Returns whether `other` record is considered the same except TTL.
625    fn matches(&self, other: &dyn DnsRecordExt) -> bool;
626
627    /// Returns whether `other` record has the same rdata.
628    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool;
629
630    /// Returns the result based on a byte-level comparison of `rdata`.
631    /// If `other` is not valid, returns `Greater`.
632    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering;
633
634    /// Returns the result based on "lexicographically later" defined below.
635    fn compare(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
636        /*
637        RFC 6762: https://datatracker.ietf.org/doc/html/rfc6762#section-8.2
638
639        ... The determination of "lexicographically later" is performed by first
640        comparing the record class (excluding the cache-flush bit described
641        in Section 10.2), then the record type, then raw comparison of the
642        binary content of the rdata without regard for meaning or structure.
643        If the record classes differ, then the numerically greater class is
644        considered "lexicographically later".  Otherwise, if the record types
645        differ, then the numerically greater type is considered
646        "lexicographically later".  If the rrtype and rrclass both match,
647        then the rdata is compared. ...
648        */
649        match self.get_class().cmp(&other.get_class()) {
650            cmp::Ordering::Equal => match self.get_type().cmp(&other.get_type()) {
651                cmp::Ordering::Equal => self.compare_rdata(other),
652                not_equal => not_equal,
653            },
654            not_equal => not_equal,
655        }
656    }
657
658    /// Returns a human-readable string of rdata.
659    fn rdata_print(&self) -> String;
660
661    /// Returns the class only, excluding class_flush / unique bit.
662    fn get_class(&self) -> u16 {
663        self.get_record().entry.class
664    }
665
666    fn get_cache_flush(&self) -> bool {
667        self.get_record().entry.cache_flush
668    }
669
670    /// Return the new name if exists, otherwise the regular name in DnsEntry.
671    fn get_name(&self) -> &str {
672        self.get_record().get_name()
673    }
674
675    fn get_type(&self) -> RRType {
676        self.get_record().entry.ty
677    }
678
679    /// Resets TTL using `other` record.
680    /// `self.refresh` and `self.expires` are also reset.
681    fn reset_ttl(&mut self, other: &dyn DnsRecordExt) {
682        self.get_record_mut().reset_ttl(other.get_record());
683    }
684
685    fn get_created(&self) -> u64 {
686        self.get_record().get_created()
687    }
688
689    fn get_expire(&self) -> u64 {
690        self.get_record().get_expire_time()
691    }
692
693    fn set_expire(&mut self, expire_at: u64) {
694        self.get_record_mut().set_expire(expire_at);
695    }
696
697    /// Set expire as `expire_at` if it is sooner than the current `expire`.
698    fn set_expire_sooner(&mut self, expire_at: u64) {
699        if expire_at < self.get_expire() {
700            self.get_record_mut().set_expire(expire_at);
701        }
702    }
703
704    /// Returns true if the record expires in 1 second from `now`.
705    fn expires_soon(&self, now: u64) -> bool {
706        self.get_record().expires_soon(now)
707    }
708
709    /// Given `now`, if the record is due to refresh, this method updates the refresh time
710    /// and returns the new refresh time. Otherwise, returns None.
711    fn updated_refresh_time(&mut self, now: u64) -> Option<u64> {
712        if self.get_record_mut().refresh_maybe(now) {
713            Some(self.get_record().get_refresh_time())
714        } else {
715            None
716        }
717    }
718
719    /// Returns true if another record has matched content,
720    /// and if its TTL is at least half of this record's.
721    fn suppressed_by_answer(&self, other: &dyn DnsRecordExt) -> bool {
722        self.matches(other) && (other.get_record().ttl > self.get_record().ttl / 2)
723    }
724
725    /// Required by RFC 6762 Section 7.1: Known-Answer Suppression.
726    fn suppressed_by(&self, msg: &DnsIncoming) -> bool {
727        for answer in msg.answers.iter() {
728            if self.suppressed_by_answer(answer.as_ref()) {
729                return true;
730            }
731        }
732        false
733    }
734
735    fn clone_box(&self) -> DnsRecordBox;
736
737    fn boxed(self) -> DnsRecordBox;
738}
739
740/// Resource Record for IPv4 address or IPv6 address.
741#[derive(Debug, Clone)]
742pub(crate) struct DnsAddress {
743    pub(crate) record: DnsRecord,
744    address: IpAddr,
745    pub(crate) interface_id: InterfaceId,
746}
747
748impl DnsAddress {
749    pub fn new(
750        name: &str,
751        ty: RRType,
752        class: u16,
753        ttl: u32,
754        address: IpAddr,
755        interface_id: InterfaceId,
756    ) -> Self {
757        let record = DnsRecord::new(name, ty, class, ttl);
758        Self {
759            record,
760            address,
761            interface_id,
762        }
763    }
764
765    pub fn address(&self) -> ScopedIp {
766        match self.address {
767            IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
768                addr: v4,
769                interface_ids: vec![self.interface_id.clone()],
770            }),
771            IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
772                addr: v6,
773                scope_id: self.interface_id.clone(),
774            }),
775        }
776    }
777}
778
779impl DnsRecordExt for DnsAddress {
780    fn get_record(&self) -> &DnsRecord {
781        &self.record
782    }
783
784    fn get_record_mut(&mut self) -> &mut DnsRecord {
785        &mut self.record
786    }
787
788    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
789        match self.address {
790            IpAddr::V4(addr) => packet.write_bytes(addr.octets().as_ref()),
791            IpAddr::V6(addr) => packet.write_bytes(addr.octets().as_ref()),
792        };
793        Ok(())
794    }
795
796    fn any(&self) -> &dyn Any {
797        self
798    }
799
800    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
801        if let Some(other_a) = other.any().downcast_ref::<Self>() {
802            return self.address == other_a.address
803                && self.record.entry == other_a.record.entry
804                && self.interface_id == other_a.interface_id;
805        }
806        false
807    }
808
809    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
810        if let Some(other_a) = other.any().downcast_ref::<Self>() {
811            return self.address == other_a.address;
812        }
813        false
814    }
815
816    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
817        if let Some(other_a) = other.any().downcast_ref::<Self>() {
818            self.address.cmp(&other_a.address)
819        } else {
820            cmp::Ordering::Greater
821        }
822    }
823
824    fn rdata_print(&self) -> String {
825        format!("{}", self.address)
826    }
827
828    fn clone_box(&self) -> DnsRecordBox {
829        Box::new(self.clone())
830    }
831
832    fn boxed(self) -> DnsRecordBox {
833        Box::new(self)
834    }
835}
836
837/// Resource Record for a DNS pointer
838#[derive(Debug, Clone)]
839pub struct DnsPointer {
840    record: DnsRecord,
841    alias: String, // the full name of Service Instance
842}
843
844impl DnsPointer {
845    pub fn new(name: &str, ty: RRType, class: u16, ttl: u32, alias: String) -> Self {
846        let record = DnsRecord::new(name, ty, class, ttl);
847        Self { record, alias }
848    }
849
850    pub fn alias(&self) -> &str {
851        &self.alias
852    }
853}
854
855impl DnsRecordExt for DnsPointer {
856    fn get_record(&self) -> &DnsRecord {
857        &self.record
858    }
859
860    fn get_record_mut(&mut self) -> &mut DnsRecord {
861        &mut self.record
862    }
863
864    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
865        packet.write_name(&self.alias)
866    }
867
868    fn any(&self) -> &dyn Any {
869        self
870    }
871
872    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
873        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
874            return self.alias == other_ptr.alias && self.record.entry == other_ptr.record.entry;
875        }
876        false
877    }
878
879    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
880        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
881            return self.alias == other_ptr.alias;
882        }
883        false
884    }
885
886    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
887        if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
888            self.alias.cmp(&other_ptr.alias)
889        } else {
890            cmp::Ordering::Greater
891        }
892    }
893
894    fn rdata_print(&self) -> String {
895        self.alias.clone()
896    }
897
898    fn clone_box(&self) -> DnsRecordBox {
899        Box::new(self.clone())
900    }
901
902    fn boxed(self) -> DnsRecordBox {
903        Box::new(self)
904    }
905}
906
907/// Resource Record for a DNS service.
908#[derive(Debug, Clone)]
909pub struct DnsSrv {
910    pub(crate) record: DnsRecord,
911    pub(crate) priority: u16, // lower number means higher priority. Should be 0 in common cases.
912    pub(crate) weight: u16,   // Should be 0 in common cases
913    host: String,
914    port: u16,
915}
916
917impl DnsSrv {
918    pub fn new(
919        name: &str,
920        class: u16,
921        ttl: u32,
922        priority: u16,
923        weight: u16,
924        port: u16,
925        host: String,
926    ) -> Self {
927        let record = DnsRecord::new(name, RRType::SRV, class, ttl);
928        Self {
929            record,
930            priority,
931            weight,
932            host,
933            port,
934        }
935    }
936
937    pub fn host(&self) -> &str {
938        &self.host
939    }
940
941    pub fn port(&self) -> u16 {
942        self.port
943    }
944
945    pub fn set_host(&mut self, host: String) {
946        self.host = host;
947    }
948}
949
950impl DnsRecordExt for DnsSrv {
951    fn get_record(&self) -> &DnsRecord {
952        &self.record
953    }
954
955    fn get_record_mut(&mut self) -> &mut DnsRecord {
956        &mut self.record
957    }
958
959    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
960        packet.write_short(self.priority);
961        packet.write_short(self.weight);
962        packet.write_short(self.port);
963        packet.write_name(&self.host)
964    }
965
966    fn any(&self) -> &dyn Any {
967        self
968    }
969
970    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
971        if let Some(other_svc) = other.any().downcast_ref::<Self>() {
972            return self.host == other_svc.host
973                && self.port == other_svc.port
974                && self.weight == other_svc.weight
975                && self.priority == other_svc.priority
976                && self.record.entry == other_svc.record.entry;
977        }
978        false
979    }
980
981    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
982        if let Some(other_srv) = other.any().downcast_ref::<Self>() {
983            return self.host == other_srv.host
984                && self.port == other_srv.port
985                && self.weight == other_srv.weight
986                && self.priority == other_srv.priority;
987        }
988        false
989    }
990
991    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
992        let Some(other_srv) = other.any().downcast_ref::<Self>() else {
993            return cmp::Ordering::Greater;
994        };
995
996        // 1. compare `priority`
997        match self
998            .priority
999            .to_be_bytes()
1000            .cmp(&other_srv.priority.to_be_bytes())
1001        {
1002            cmp::Ordering::Equal => {
1003                // 2. compare `weight`
1004                match self
1005                    .weight
1006                    .to_be_bytes()
1007                    .cmp(&other_srv.weight.to_be_bytes())
1008                {
1009                    cmp::Ordering::Equal => {
1010                        // 3. compare `port`.
1011                        match self.port.to_be_bytes().cmp(&other_srv.port.to_be_bytes()) {
1012                            cmp::Ordering::Equal => self.host.cmp(&other_srv.host),
1013                            not_equal => not_equal,
1014                        }
1015                    }
1016                    not_equal => not_equal,
1017                }
1018            }
1019            not_equal => not_equal,
1020        }
1021    }
1022
1023    fn rdata_print(&self) -> String {
1024        format!(
1025            "priority: {}, weight: {}, port: {}, host: {}",
1026            self.priority, self.weight, self.port, self.host
1027        )
1028    }
1029
1030    fn clone_box(&self) -> DnsRecordBox {
1031        Box::new(self.clone())
1032    }
1033
1034    fn boxed(self) -> DnsRecordBox {
1035        Box::new(self)
1036    }
1037}
1038
1039/// Resource Record for a DNS TXT record.
1040///
1041/// From [RFC 6763 section 6]:
1042///
1043/// The format of each constituent string within the DNS TXT record is a
1044/// single length byte, followed by 0-255 bytes of text data.
1045///
1046/// DNS-SD uses DNS TXT records to store arbitrary key/value pairs
1047///    conveying additional information about the named service.  Each
1048///    key/value pair is encoded as its own constituent string within the
1049///    DNS TXT record, in the form "key=value" (without the quotation
1050///    marks).  Everything up to the first '=' character is the key (Section
1051///    6.4).  Everything after the first '=' character to the end of the
1052///    string (including subsequent '=' characters, if any) is the value
1053#[derive(Clone)]
1054pub struct DnsTxt {
1055    pub(crate) record: DnsRecord,
1056    text: Vec<u8>,
1057}
1058
1059impl DnsTxt {
1060    pub fn new(name: &str, class: u16, ttl: u32, text: Vec<u8>) -> Self {
1061        let record = DnsRecord::new(name, RRType::TXT, class, ttl);
1062        Self { record, text }
1063    }
1064
1065    pub fn text(&self) -> &[u8] {
1066        &self.text
1067    }
1068}
1069
1070impl DnsRecordExt for DnsTxt {
1071    fn get_record(&self) -> &DnsRecord {
1072        &self.record
1073    }
1074
1075    fn get_record_mut(&mut self) -> &mut DnsRecord {
1076        &mut self.record
1077    }
1078
1079    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1080        packet.write_bytes(&self.text);
1081        Ok(())
1082    }
1083
1084    fn any(&self) -> &dyn Any {
1085        self
1086    }
1087
1088    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1089        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1090            return self.text == other_txt.text && self.record.entry == other_txt.record.entry;
1091        }
1092        false
1093    }
1094
1095    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1096        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1097            return self.text == other_txt.text;
1098        }
1099        false
1100    }
1101
1102    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1103        if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1104            self.text.cmp(&other_txt.text)
1105        } else {
1106            cmp::Ordering::Greater
1107        }
1108    }
1109
1110    fn rdata_print(&self) -> String {
1111        format!("{:?}", decode_txt(&self.text))
1112    }
1113
1114    fn clone_box(&self) -> DnsRecordBox {
1115        Box::new(self.clone())
1116    }
1117
1118    fn boxed(self) -> DnsRecordBox {
1119        Box::new(self)
1120    }
1121}
1122
1123impl fmt::Debug for DnsTxt {
1124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1125        let properties = decode_txt(&self.text);
1126        write!(
1127            f,
1128            "DnsTxt {{ record: {:?}, text: {:?} }}",
1129            self.record, properties
1130        )
1131    }
1132}
1133
1134// Convert from DNS TXT record content to key/value pairs
1135fn decode_txt(txt: &[u8]) -> Vec<TxtProperty> {
1136    let mut properties = Vec::new();
1137    let mut offset = 0;
1138    while offset < txt.len() {
1139        let length = txt[offset] as usize;
1140        if length == 0 {
1141            break; // reached the end
1142        }
1143        offset += 1; // move over the length byte
1144
1145        let offset_end = offset + length;
1146        if offset_end > txt.len() {
1147            trace!("ERROR: DNS TXT: size given for property is out of range. (offset={}, length={}, offset_end={}, record length={})", offset, length, offset_end, txt.len());
1148            break; // Skipping the rest of the record content, as the size for this property would already be out of range.
1149        }
1150        let kv_bytes = &txt[offset..offset_end];
1151
1152        // split key and val using the first `=`
1153        let (k, v) = kv_bytes.iter().position(|&x| x == b'=').map_or_else(
1154            || (kv_bytes.to_vec(), None),
1155            |idx| (kv_bytes[..idx].to_vec(), Some(kv_bytes[idx + 1..].to_vec())),
1156        );
1157
1158        // Make sure the key can be stored in UTF-8.
1159        match String::from_utf8(k) {
1160            Ok(k_string) => {
1161                properties.push(TxtProperty {
1162                    key: k_string,
1163                    val: v,
1164                });
1165            }
1166            Err(e) => trace!("ERROR: convert to String from key: {}", e),
1167        }
1168
1169        offset += length;
1170    }
1171
1172    properties
1173}
1174
1175/// Represents a property in a TXT record.
1176#[derive(Clone, PartialEq, Eq)]
1177pub struct TxtProperty {
1178    /// The name of the property. The original cases are kept.
1179    key: String,
1180
1181    /// RFC 6763 says values are bytes, not necessarily UTF-8.
1182    /// It is also possible that there is no value, in which case
1183    /// the key is a boolean key.
1184    val: Option<Vec<u8>>,
1185}
1186
1187impl TxtProperty {
1188    /// Returns the value of a property as str.
1189    pub fn val_str(&self) -> &str {
1190        self.val
1191            .as_ref()
1192            .map_or("", |v| std::str::from_utf8(&v[..]).unwrap_or_default())
1193    }
1194}
1195
1196/// Supports constructing from a tuple.
1197impl<K, V> From<&(K, V)> for TxtProperty
1198where
1199    K: ToString,
1200    V: ToString,
1201{
1202    fn from(prop: &(K, V)) -> Self {
1203        Self {
1204            key: prop.0.to_string(),
1205            val: Some(prop.1.to_string().into_bytes()),
1206        }
1207    }
1208}
1209
1210impl<K, V> From<(K, V)> for TxtProperty
1211where
1212    K: ToString,
1213    V: AsRef<[u8]>,
1214{
1215    fn from(prop: (K, V)) -> Self {
1216        Self {
1217            key: prop.0.to_string(),
1218            val: Some(prop.1.as_ref().into()),
1219        }
1220    }
1221}
1222
1223/// Support a property that has no value.
1224impl From<&str> for TxtProperty {
1225    fn from(key: &str) -> Self {
1226        Self {
1227            key: key.to_string(),
1228            val: None,
1229        }
1230    }
1231}
1232
1233impl fmt::Display for TxtProperty {
1234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1235        write!(f, "{}={}", self.key, self.val_str())
1236    }
1237}
1238
1239/// Mimic the default debug output for a struct, with a twist:
1240/// - If self.var is UTF-8, will output it as a string in double quotes.
1241/// - If self.var is not UTF-8, will output its bytes as in hex.
1242impl fmt::Debug for TxtProperty {
1243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1244        let val_string = self.val.as_ref().map_or_else(
1245            || "None".to_string(),
1246            |v| {
1247                std::str::from_utf8(&v[..]).map_or_else(
1248                    |_| format!("Some({})", u8_slice_to_hex(&v[..])),
1249                    |s| format!("Some(\"{s}\")"),
1250                )
1251            },
1252        );
1253
1254        write!(
1255            f,
1256            "TxtProperty {{key: \"{}\", val: {}}}",
1257            &self.key, &val_string,
1258        )
1259    }
1260}
1261
1262const HEX_TABLE: [char; 16] = [
1263    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
1264];
1265
1266/// Create a hex string from `slice`, with a "0x" prefix.
1267///
1268/// For example, [1u8, 2u8] -> "0x0102"
1269fn u8_slice_to_hex(slice: &[u8]) -> String {
1270    let mut hex = String::with_capacity(slice.len() * 2 + 2);
1271    hex.push_str("0x");
1272    for b in slice {
1273        hex.push(HEX_TABLE[(b >> 4) as usize]);
1274        hex.push(HEX_TABLE[(b & 0x0F) as usize]);
1275    }
1276    hex
1277}
1278
1279/// A DNS host information record
1280#[derive(Debug, Clone)]
1281struct DnsHostInfo {
1282    record: DnsRecord,
1283    cpu: String,
1284    os: String,
1285}
1286
1287impl DnsHostInfo {
1288    fn new(name: &str, ty: RRType, class: u16, ttl: u32, cpu: String, os: String) -> Self {
1289        let record = DnsRecord::new(name, ty, class, ttl);
1290        Self { record, cpu, os }
1291    }
1292}
1293
1294impl DnsRecordExt for DnsHostInfo {
1295    fn get_record(&self) -> &DnsRecord {
1296        &self.record
1297    }
1298
1299    fn get_record_mut(&mut self) -> &mut DnsRecord {
1300        &mut self.record
1301    }
1302
1303    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1304        debug!("Writing HInfo: cpu {} os {}", &self.cpu, &self.os);
1305        packet.write_bytes(self.cpu.as_bytes());
1306        packet.write_bytes(self.os.as_bytes());
1307        Ok(())
1308    }
1309
1310    fn any(&self) -> &dyn Any {
1311        self
1312    }
1313
1314    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1315        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1316            return self.cpu == other_hinfo.cpu
1317                && self.os == other_hinfo.os
1318                && self.record.entry == other_hinfo.record.entry;
1319        }
1320        false
1321    }
1322
1323    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1324        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1325            return self.cpu == other_hinfo.cpu && self.os == other_hinfo.os;
1326        }
1327        false
1328    }
1329
1330    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1331        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1332            match self.cpu.cmp(&other_hinfo.cpu) {
1333                cmp::Ordering::Equal => self.os.cmp(&other_hinfo.os),
1334                ordering => ordering,
1335            }
1336        } else {
1337            cmp::Ordering::Greater
1338        }
1339    }
1340
1341    fn rdata_print(&self) -> String {
1342        format!("cpu: {}, os: {}", self.cpu, self.os)
1343    }
1344
1345    fn clone_box(&self) -> DnsRecordBox {
1346        Box::new(self.clone())
1347    }
1348
1349    fn boxed(self) -> DnsRecordBox {
1350        Box::new(self)
1351    }
1352}
1353
1354/// Resource Record for negative responses
1355///
1356/// [RFC4034 section 4.1](https://datatracker.ietf.org/doc/html/rfc4034#section-4.1)
1357/// and
1358/// [RFC6762 section 6.1](https://datatracker.ietf.org/doc/html/rfc6762#section-6.1)
1359#[derive(Debug, Clone)]
1360pub struct DnsNSec {
1361    record: DnsRecord,
1362    next_domain: String,
1363    type_bitmap: Vec<u8>,
1364}
1365
1366impl DnsNSec {
1367    pub fn new(
1368        name: &str,
1369        class: u16,
1370        ttl: u32,
1371        next_domain: String,
1372        type_bitmap: Vec<u8>,
1373    ) -> Self {
1374        let record = DnsRecord::new(name, RRType::NSEC, class, ttl);
1375        Self {
1376            record,
1377            next_domain,
1378            type_bitmap,
1379        }
1380    }
1381
1382    /// Returns the types marked by `type_bitmap`
1383    pub fn _types(&self) -> Vec<u16> {
1384        // From RFC 4034: 4.1.2 The Type Bit Maps Field
1385        // https://datatracker.ietf.org/doc/html/rfc4034#section-4.1.2
1386        //
1387        // Each bitmap encodes the low-order 8 bits of RR types within the
1388        // window block, in network bit order.  The first bit is bit 0.  For
1389        // window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
1390        // to RR type 2 (NS), and so forth.
1391
1392        let mut bit_num = 0;
1393        let mut results = Vec::new();
1394
1395        for byte in self.type_bitmap.iter() {
1396            let mut bit_mask: u8 = 0x80; // for bit 0 in network bit order
1397
1398            // check every bit in this byte, one by one.
1399            for _ in 0..8 {
1400                if (byte & bit_mask) != 0 {
1401                    results.push(bit_num);
1402                }
1403                bit_num += 1;
1404                bit_mask >>= 1; // mask for the next bit
1405            }
1406        }
1407        results
1408    }
1409}
1410
1411impl DnsRecordExt for DnsNSec {
1412    fn get_record(&self) -> &DnsRecord {
1413        &self.record
1414    }
1415
1416    fn get_record_mut(&mut self) -> &mut DnsRecord {
1417        &mut self.record
1418    }
1419
1420    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1421        packet.write_bytes(self.next_domain.as_bytes());
1422        packet.write_bytes(&self.type_bitmap);
1423        Ok(())
1424    }
1425
1426    fn any(&self) -> &dyn Any {
1427        self
1428    }
1429
1430    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1431        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1432            return self.next_domain == other_record.next_domain
1433                && self.type_bitmap == other_record.type_bitmap
1434                && self.record.entry == other_record.record.entry;
1435        }
1436        false
1437    }
1438
1439    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1440        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1441            return self.next_domain == other_record.next_domain
1442                && self.type_bitmap == other_record.type_bitmap;
1443        }
1444        false
1445    }
1446
1447    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1448        if let Some(other_nsec) = other.any().downcast_ref::<Self>() {
1449            match self.next_domain.cmp(&other_nsec.next_domain) {
1450                cmp::Ordering::Equal => self.type_bitmap.cmp(&other_nsec.type_bitmap),
1451                ordering => ordering,
1452            }
1453        } else {
1454            cmp::Ordering::Greater
1455        }
1456    }
1457
1458    fn rdata_print(&self) -> String {
1459        format!(
1460            "next_domain: {}, type_bitmap len: {}",
1461            self.next_domain,
1462            self.type_bitmap.len()
1463        )
1464    }
1465
1466    fn clone_box(&self) -> DnsRecordBox {
1467        Box::new(self.clone())
1468    }
1469
1470    fn boxed(self) -> DnsRecordBox {
1471        Box::new(self)
1472    }
1473}
1474
1475/// Which section of a DNS message an item belongs to.
1476#[derive(Clone, Copy, Debug)]
1477enum Section {
1478    Question,
1479    Answer,
1480    Authority,
1481    Additional,
1482}
1483
1484/// A single packet for outgoing DNS message.
1485pub struct DnsOutPacket {
1486    /// All bytes in `data` is the actual packet on the wire.
1487    data: Vec<u8>,
1488
1489    /// k: name, v: offset
1490    names: HashMap<String, u16>,
1491
1492    /// Max byte size of `data`. i.e. the max packet size.
1493    max_size: usize,
1494
1495    /// How many items `data` holds in each section, i.e. the header counts.
1496    question_count: u16,
1497    answer_count: u16,
1498    auth_count: u16,
1499    addi_count: u16,
1500}
1501
1502impl DnsOutPacket {
1503    fn new(max_size: usize) -> Self {
1504        Self {
1505            data: vec![0; MSG_HEADER_LEN],
1506            names: HashMap::new(),
1507            max_size,
1508            question_count: 0,
1509            answer_count: 0,
1510            auth_count: 0,
1511            addi_count: 0,
1512        }
1513    }
1514
1515    pub fn size(&self) -> usize {
1516        self.data.len()
1517    }
1518
1519    pub fn as_bytes(&self) -> &[u8] {
1520        &self.data
1521    }
1522
1523    /// True if nothing has been written into this packet yet.
1524    fn is_empty(&self) -> bool {
1525        self.question_count == 0
1526            && self.answer_count == 0
1527            && self.auth_count == 0
1528            && self.addi_count == 0
1529    }
1530
1531    /// Counts one more item in `section`.
1532    fn bump(&mut self, section: Section) {
1533        match section {
1534            Section::Question => self.question_count += 1,
1535            Section::Answer => self.answer_count += 1,
1536            Section::Authority => self.auth_count += 1,
1537            Section::Additional => self.addi_count += 1,
1538        }
1539    }
1540
1541    fn write_question(&mut self, question: &DnsQuestion) -> WriteResult {
1542        let start_size = self.size();
1543
1544        self.write_name(&question.entry.name).map_err(|e| {
1545            self.rollback(start_size);
1546            e
1547        })?;
1548        self.write_short(question.entry.ty as u16);
1549        self.write_short(question.entry.class);
1550
1551        if self.size() > self.max_size {
1552            self.rollback(start_size);
1553            return Err(WriteError::PacketFull);
1554        }
1555
1556        Ok(())
1557    }
1558
1559    /// Discards everything written since `start_size`, including the name
1560    /// compression offsets that point into the discarded bytes.
1561    fn rollback(&mut self, start_size: usize) {
1562        self.data.truncate(start_size);
1563        self.names
1564            .retain(|_, offset| (*offset as usize) < start_size);
1565    }
1566
1567    /// Writes a record (answer, authoritative answer, additional).
1568    ///
1569    /// In error cases nothing is written to the packet.
1570    fn write_record(&mut self, record_ext: &dyn DnsRecordExt, now: u64) -> WriteResult {
1571        let start_size = self.size();
1572
1573        let record = record_ext.get_record();
1574        self.write_name(record.get_name())?;
1575        self.write_short(record.entry.ty as u16);
1576        if record.entry.cache_flush {
1577            // check "multicast"
1578            self.write_short(record.entry.class | CLASS_CACHE_FLUSH);
1579        } else {
1580            self.write_short(record.entry.class);
1581        }
1582
1583        if now == 0 {
1584            self.write_u32(record.ttl);
1585        } else {
1586            self.write_u32(record.get_remaining_ttl(now));
1587        }
1588
1589        // Placeholder for record size
1590        self.write_short(0);
1591        let record_offset = self.size();
1592
1593        if let Err(e) = record_ext.write(self) {
1594            self.rollback(start_size);
1595            return Err(e);
1596        }
1597
1598        self.set_short_at(record_offset - 2, (self.size() - record_offset) as u16);
1599
1600        if self.size() > self.max_size {
1601            self.rollback(start_size);
1602            return Err(WriteError::PacketFull);
1603        }
1604
1605        Ok(())
1606    }
1607
1608    fn set_short_at(&mut self, index: usize, value: u16) {
1609        self.data[index..index + 2].copy_from_slice(&value.to_be_bytes());
1610    }
1611
1612    /// Parses a DNS name that may contain escaped characters according to RFC 6763 Section 4.3.
1613    /// Returns a vector of labels where each label is the unescaped content.
1614    ///
1615    /// Escape sequences:
1616    /// - \\. becomes . (literal dot)
1617    /// - \\\\ becomes \\ (literal backslash)
1618    fn parse_escaped_name(name: &str) -> Vec<String> {
1619        let mut labels = Vec::new();
1620        let mut current_label = String::new();
1621        let mut chars = name.chars().peekable();
1622
1623        while let Some(ch) = chars.next() {
1624            match ch {
1625                '\\' => {
1626                    // Backslash escape sequence
1627                    if let Some(&next_ch) = chars.peek() {
1628                        match next_ch {
1629                            '.' | '\\' => {
1630                                // \\. or \\\\ - consume the backslash and add the escaped char
1631                                chars.next();
1632                                current_label.push(next_ch);
1633                            }
1634                            _ => {
1635                                // Not a recognized escape - treat backslash literally
1636                                current_label.push(ch);
1637                            }
1638                        }
1639                    } else {
1640                        // Trailing backslash - add it literally
1641                        current_label.push(ch);
1642                    }
1643                }
1644                '.' => {
1645                    // Unescaped dot - label separator
1646                    if !current_label.is_empty() {
1647                        labels.push(current_label.clone());
1648                        current_label.clear();
1649                    }
1650                }
1651                _ => {
1652                    current_label.push(ch);
1653                }
1654            }
1655        }
1656
1657        // Add the last label if not empty
1658        if !current_label.is_empty() {
1659            labels.push(current_label);
1660        }
1661
1662        labels
1663    }
1664
1665    // Write name to packet
1666    //
1667    // [RFC1035]
1668    // 4.1.4. Message compression
1669    //
1670    // In order to reduce the size of messages, the domain system utilizes a
1671    // compression scheme which eliminates the repetition of domain names in a
1672    // message.  In this scheme, an entire domain name or a list of labels at
1673    // the end of a domain name is replaced with a pointer to a prior occurrence
1674    // of the same name.
1675    // The pointer takes the form of a two octet sequence:
1676    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1677    //     | 1  1|                OFFSET                   |
1678    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1679    // The first two bits are ones.  This allows a pointer to be distinguished
1680    // from a label, since the label must begin with two zero bits because
1681    // labels are restricted to 63 octets or less.  (The 10 and 01 combinations
1682    // are reserved for future use.)  The OFFSET field specifies an offset from
1683    // the start of the message (i.e., the first octet of the ID field in the
1684    // domain header).  A zero offset specifies the first byte of the ID field,
1685    // etc.
1686    //
1687    // This function also handles RFC 6763 Section 4.3 escaping where dots and backslashes
1688    // in instance names are escaped (e.g., "My\\.Service" represents a single label "My.Service").
1689    // The actual name sent over the wire is the unescaped version.
1690    fn write_name(&mut self, name: &str) -> WriteResult {
1691        // Remove trailing dot if present
1692        let name_to_parse = name.strip_suffix('.').unwrap_or(name);
1693
1694        // Parse the name considering escape sequences
1695        let labels = Self::parse_escaped_name(name_to_parse);
1696
1697        if labels.is_empty() {
1698            self.write_byte(0);
1699            return Ok(());
1700        }
1701
1702        // Validate before writing anything.
1703        if labels.iter().any(|label| label.len() > MAX_LABEL_BYTES) {
1704            return Err(WriteError::NameTooLong);
1705        }
1706
1707        // Write each label
1708        for (i, label) in labels.iter().enumerate() {
1709            // Build the remaining name for compression (with dots as separators)
1710            let remaining: String = labels[i..].join(".");
1711
1712            // Check if we can use compression for the remaining part
1713            const POINTER_MASK: u16 = 0xC000;
1714            if let Some(&offset) = self.names.get(&remaining) {
1715                let pointer = offset | POINTER_MASK;
1716                self.write_short(pointer);
1717                return Ok(());
1718            }
1719
1720            // Store this position for potential future compression
1721            self.names.insert(remaining, self.size() as u16);
1722
1723            // Write the label
1724            self.write_utf8(label)?;
1725        }
1726
1727        // Write terminating zero byte
1728        self.write_byte(0);
1729        Ok(())
1730    }
1731
1732    fn write_byte(&mut self, v: u8) {
1733        self.data.push(v);
1734    }
1735
1736    fn write_bytes(&mut self, s: &[u8]) {
1737        self.data.extend(s);
1738    }
1739
1740    /// Writes a single label. Nothing is written if the label is too long to
1741    /// be encoded.
1742    fn write_utf8(&mut self, s: &str) -> WriteResult {
1743        if s.len() > MAX_LABEL_BYTES {
1744            return Err(WriteError::NameTooLong);
1745        }
1746        self.write_byte(s.len() as u8);
1747        self.write_bytes(s.as_bytes());
1748        Ok(())
1749    }
1750
1751    fn write_u32(&mut self, v: u32) {
1752        self.data.extend(&v.to_be_bytes());
1753    }
1754
1755    fn write_short(&mut self, v: u16) {
1756        self.data.extend(&v.to_be_bytes());
1757    }
1758
1759    /// Marks this finished packet as truncated, i.e. the message continues in
1760    /// the next packet.
1761    fn set_truncated(&mut self) {
1762        let flags = u16::from_be_bytes([self.data[2], self.data[3]]);
1763        self.set_short_at(2, flags | FLAGS_TC);
1764    }
1765
1766    /// Writes the header fields and finish the packet.
1767    /// This function should be only called when finishing a packet.
1768    ///
1769    /// The header format is based on RFC 1035 section 4.1.1:
1770    /// https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
1771    //
1772    //                                  1  1  1  1  1  1
1773    //    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
1774    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1775    //    |                      ID                       |
1776    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1777    //    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
1778    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1779    //    |                    QDCOUNT                    |
1780    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1781    //    |                    ANCOUNT                    |
1782    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1783    //    |                    NSCOUNT                    |
1784    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1785    //    |                    ARCOUNT                    |
1786    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1787    //
1788    fn write_header(&mut self, id: u16, flags: u16) {
1789        self.set_short_at(0, id);
1790        self.set_short_at(2, flags);
1791        self.set_short_at(4, self.question_count);
1792        self.set_short_at(6, self.answer_count);
1793        self.set_short_at(8, self.auth_count);
1794        self.set_short_at(10, self.addi_count);
1795    }
1796}
1797
1798/// Encodes a [`DnsOutgoing`] into one or more [`DnsOutPacket`], starting a new
1799/// packet whenever the current one runs out of room.
1800struct PacketBuilder<'a> {
1801    out: &'a DnsOutgoing,
1802
1803    /// Max size of a packet that holds more than one record.
1804    max_size: usize,
1805
1806    /// IP version these packets are bound for, which decides their absolute
1807    /// ceiling: see [`max_pkt_absolute`].
1808    is_ipv4: bool,
1809
1810    finished: Vec<DnsOutPacket>,
1811    current: DnsOutPacket,
1812}
1813
1814impl<'a> PacketBuilder<'a> {
1815    fn new(out: &'a DnsOutgoing, max_size: usize, is_ipv4: bool) -> Self {
1816        Self {
1817            out,
1818            max_size,
1819            is_ipv4,
1820            finished: Vec::new(),
1821            current: DnsOutPacket::new(max_size),
1822        }
1823    }
1824
1825    /// Writes one question or record into the current packet, starting a new
1826    /// packet if it does not fit in the current one.
1827    ///
1828    /// An item that cannot be encoded at all is skipped, leaving the packet as
1829    /// it was. Sections are written in message order, so an item that spills
1830    /// never lands ahead of one already written.
1831    fn add<F>(&mut self, section: Section, write: F)
1832    where
1833        F: Fn(&mut DnsOutPacket) -> WriteResult,
1834    {
1835        match write(&mut self.current) {
1836            Ok(()) => {
1837                self.current.bump(section);
1838                return;
1839            }
1840            // The item can never be encoded: skip it.
1841            Err(WriteError::NameTooLong) => return,
1842            Err(WriteError::PacketFull) => {}
1843        }
1844
1845        // Packet is full. Flush the current and create a new one.
1846        if !self.current.is_empty() {
1847            self.flush();
1848
1849            match write(&mut self.current) {
1850                Ok(()) => {
1851                    self.current.bump(section);
1852                    return;
1853                }
1854                Err(WriteError::NameTooLong) => return,
1855                Err(WriteError::PacketFull) => {}
1856            }
1857        }
1858
1859        // Packet is still full. A question such big is not legitimate.
1860        if matches!(section, Section::Question) {
1861            return;
1862        }
1863
1864        // Packet is still full. We will send this single record.
1865
1866        // RFC 6762 section 17:
1867        // "a record too large for one MTU-sized packet SHOULD be sent alone, in a
1868        // single IP datagram".
1869        self.current.max_size = max_pkt_absolute(self.is_ipv4);
1870
1871        if write(&mut self.current).is_ok() {
1872            self.current.bump(section);
1873            self.flush();
1874        } else {
1875            // Too big even for the hard ceiling: skip the record and carry on.
1876            self.current.max_size = self.max_size;
1877            debug!(
1878                "Record too big for absolute max size, skipping: {:?}",
1879                section
1880            );
1881        }
1882    }
1883
1884    /// Finishes the current packet and starts a new empty one.
1885    fn flush(&mut self) {
1886        self.current
1887            .write_header(self.out.wire_id(), self.out.flags);
1888
1889        let next = DnsOutPacket::new(self.max_size);
1890        self.finished
1891            .push(std::mem::replace(&mut self.current, next));
1892    }
1893
1894    fn finish(mut self) -> Vec<DnsOutPacket> {
1895        // Always produce at least one packet, even an empty one, but never leave a
1896        // trailing empty packet behind a full one.
1897        if !self.current.is_empty() || self.finished.is_empty() {
1898            self.flush();
1899        }
1900
1901        let mut packets = self.finished;
1902
1903        /*
1904        RFC 6762 section 7.2: https://datatracker.ietf.org/doc/html/rfc6762#section-7.2
1905        ...
1906            When a Multicast DNS querier sends a query to which it already knows some
1907            answers, it ... sets the TC (Truncated) bit in the header ... [so that the
1908            responder knows] to wait for the remaining known answers before responding.
1909         */
1910        if self.out.is_query() {
1911            if let Some((_last, rest)) = packets.split_last_mut() {
1912                for packet in rest {
1913                    packet.set_truncated();
1914                }
1915            }
1916        }
1917
1918        packets
1919    }
1920}
1921
1922/// Representation of one outgoing DNS message that could be sent in one or more packet(s).
1923#[derive(Debug)]
1924pub struct DnsOutgoing {
1925    flags: u16,
1926    id: u16,
1927    multicast: bool,
1928    questions: Vec<DnsQuestion>,
1929    answers: Vec<(DnsRecordBox, u64)>,
1930    authorities: Vec<DnsRecordBox>,
1931    additionals: Vec<DnsRecordBox>,
1932    known_answer_count: i64, // for internal maintenance only
1933}
1934
1935impl DnsOutgoing {
1936    pub fn new(flags: u16) -> Self {
1937        Self {
1938            flags,
1939            id: 0,
1940            multicast: true,
1941            questions: Vec::new(),
1942            answers: Vec::new(),
1943            authorities: Vec::new(),
1944            additionals: Vec::new(),
1945            known_answer_count: 0,
1946        }
1947    }
1948
1949    pub fn questions(&self) -> &[DnsQuestion] {
1950        &self.questions
1951    }
1952
1953    /// For testing purposes only.
1954    pub(crate) fn _answers(&self) -> &[(DnsRecordBox, u64)] {
1955        &self.answers
1956    }
1957
1958    pub fn answers_count(&self) -> usize {
1959        self.answers.len()
1960    }
1961
1962    pub fn authorities(&self) -> &[DnsRecordBox] {
1963        &self.authorities
1964    }
1965
1966    pub fn additionals(&self) -> &[DnsRecordBox] {
1967        &self.additionals
1968    }
1969
1970    pub fn known_answer_count(&self) -> i64 {
1971        self.known_answer_count
1972    }
1973
1974    pub fn set_id(&mut self, id: u16) {
1975        self.id = id;
1976    }
1977
1978    /// The id to put in the header, always 0 for multicast.
1979    const fn wire_id(&self) -> u16 {
1980        if self.multicast {
1981            0
1982        } else {
1983            self.id
1984        }
1985    }
1986
1987    pub const fn is_query(&self) -> bool {
1988        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1989    }
1990
1991    // Adds an additional answer
1992
1993    // From: RFC 6763, DNS-Based Service Discovery, February 2013
1994
1995    // 12.  DNS Additional Record Generation
1996
1997    //    DNS has an efficiency feature whereby a DNS server may place
1998    //    additional records in the additional section of the DNS message.
1999    //    These additional records are records that the client did not
2000    //    explicitly request, but the server has reasonable grounds to expect
2001    //    that the client might request them shortly, so including them can
2002    //    save the client from having to issue additional queries.
2003
2004    //    This section recommends which additional records SHOULD be generated
2005    //    to improve network efficiency, for both Unicast and Multicast DNS-SD
2006    //    responses.
2007
2008    // 12.1.  PTR Records
2009
2010    //    When including a DNS-SD Service Instance Enumeration or Selective
2011    //    Instance Enumeration (subtype) PTR record in a response packet, the
2012    //    server/responder SHOULD include the following additional records:
2013
2014    //    o  The SRV record(s) named in the PTR rdata.
2015    //    o  The TXT record(s) named in the PTR rdata.
2016    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
2017
2018    // 12.2.  SRV Records
2019
2020    //    When including an SRV record in a response packet, the
2021    //    server/responder SHOULD include the following additional records:
2022
2023    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
2024    pub fn add_additional_answer(&mut self, answer: impl DnsRecordExt + 'static) {
2025        trace!("add_additional_answer: {:?}", &answer);
2026        self.additionals.push(answer.boxed());
2027    }
2028
2029    /// A workaround as Rust doesn't allow us to pass DnsRecordBox in as `impl DnsRecordExt`
2030    pub fn add_answer_box(&mut self, answer_box: DnsRecordBox) {
2031        self.answers.push((answer_box, 0));
2032    }
2033
2034    pub fn add_authority(&mut self, record: DnsRecordBox) {
2035        self.authorities.push(record);
2036    }
2037
2038    /// Retains only the answers for which `keep` returns true.
2039    pub(crate) fn retain_answers<F>(&mut self, mut keep: F)
2040    where
2041        F: FnMut(&DnsRecordBox) -> bool,
2042    {
2043        self.answers.retain(|(record, _)| keep(record));
2044    }
2045
2046    /// Retains only the additional records for which `keep` returns true.
2047    pub(crate) fn retain_additionals<F>(&mut self, mut keep: F)
2048    where
2049        F: FnMut(&DnsRecordBox) -> bool,
2050    {
2051        self.additionals.retain(|record| keep(record));
2052    }
2053
2054    /// Returns true if `answer` is added to the outgoing msg.
2055    /// Returns false if `answer` was not added as it expired or suppressed by the incoming `msg`.
2056    pub fn add_answer(
2057        &mut self,
2058        msg: &DnsIncoming,
2059        answer: impl DnsRecordExt + Send + 'static,
2060    ) -> bool {
2061        trace!("Check for add_answer");
2062        if answer.suppressed_by(msg) {
2063            trace!("my answer is suppressed by incoming msg");
2064            self.known_answer_count += 1;
2065            return false;
2066        }
2067
2068        self.add_answer_at_time(answer, 0)
2069    }
2070
2071    /// Returns true if `answer` is added to the outgoing msg.
2072    /// Returns false if the answer is expired `now` hence not added.
2073    /// If `now` is 0, do not check if the answer expires.
2074    pub fn add_answer_at_time(
2075        &mut self,
2076        answer: impl DnsRecordExt + Send + 'static,
2077        now: u64,
2078    ) -> bool {
2079        if now == 0 || !answer.get_record().is_expired(now) {
2080            trace!("add_answer push: {:?}", &answer);
2081            self.answers.push((answer.boxed(), now));
2082            return true;
2083        }
2084        false
2085    }
2086
2087    /// Adds a PTR answer for `service` along with recommended additional records
2088    /// (SRV, TXT, and address records) per [RFC 6763 Section 12.1].
2089    ///
2090    /// Resolves any name conflicts via `dns_registry` and selects addresses
2091    /// matching the given interface. Does nothing if no addresses are available
2092    /// on `intf` or if the PTR answer is suppressed by known-answer entries in `msg`.
2093    ///
2094    /// [RFC 6763 Section 12.1]: https://tools.ietf.org/html/rfc6763#section-12.1
2095    pub(crate) fn add_answer_with_additionals(
2096        &mut self,
2097        msg: &DnsIncoming,
2098        service: &ServiceInfo,
2099        intf: &MyIntf,
2100        dns_registry: &DnsRegistry,
2101        is_ipv4: bool,
2102    ) {
2103        let intf_addrs = if is_ipv4 {
2104            service.get_addrs_on_my_intf_v4(intf)
2105        } else {
2106            service.get_addrs_on_my_intf_v6(intf)
2107        };
2108        if intf_addrs.is_empty() {
2109            trace!("No addrs on LAN of intf {:?}", intf);
2110            return;
2111        }
2112
2113        // check if we changed our name due to conflicts.
2114        let service_fullname = dns_registry.resolve_name(service.get_fullname());
2115        let hostname = dns_registry.resolve_name(service.get_hostname());
2116
2117        let ptr_added = self.add_answer(
2118            msg,
2119            DnsPointer::new(
2120                service.get_type(),
2121                RRType::PTR,
2122                CLASS_IN,
2123                service.get_other_ttl(),
2124                service_fullname.to_string(),
2125            ),
2126        );
2127
2128        if !ptr_added {
2129            trace!("answer was not added for msg {:?}", msg);
2130            return;
2131        }
2132
2133        if let Some(sub) = service.get_subtype() {
2134            trace!("Adding subdomain {}", sub);
2135            self.add_additional_answer(DnsPointer::new(
2136                sub,
2137                RRType::PTR,
2138                CLASS_IN,
2139                service.get_other_ttl(),
2140                service_fullname.to_string(),
2141            ));
2142        }
2143
2144        // Add recommended additional answers according to
2145        // https://tools.ietf.org/html/rfc6763#section-12.1.
2146        self.add_additional_answer(DnsSrv::new(
2147            service_fullname,
2148            CLASS_IN | CLASS_CACHE_FLUSH,
2149            service.get_host_ttl(),
2150            service.get_priority(),
2151            service.get_weight(),
2152            service.get_port(),
2153            hostname.to_string(),
2154        ));
2155
2156        self.add_additional_answer(DnsTxt::new(
2157            service_fullname,
2158            CLASS_IN | CLASS_CACHE_FLUSH,
2159            service.get_other_ttl(),
2160            service.generate_txt(),
2161        ));
2162
2163        for address in intf_addrs {
2164            self.add_additional_answer(DnsAddress::new(
2165                hostname,
2166                ip_address_rr_type(&address),
2167                CLASS_IN | CLASS_CACHE_FLUSH,
2168                service.get_host_ttl(),
2169                address,
2170                intf.into(),
2171            ));
2172        }
2173    }
2174
2175    pub fn add_question(&mut self, name: &str, qtype: RRType) {
2176        let q = DnsQuestion {
2177            entry: DnsEntry::new(name.to_string(), qtype, CLASS_IN),
2178        };
2179        self.questions.push(q);
2180    }
2181
2182    /// Clear the cache-flush (unique) bit on every answer and additional
2183    /// record. Required for RFC 6762 §6.7 (Legacy Unicast Responses) and
2184    /// §10.2 — a legacy resolver doesn't know about the cache-flush bit
2185    /// and may misinterpret responses where it is set.
2186    pub fn clear_cache_flush_bits(&mut self) {
2187        for (rec, _) in &mut self.answers {
2188            rec.get_record_mut().entry.cache_flush = false;
2189        }
2190        for rec in &mut self.additionals {
2191            rec.get_record_mut().entry.cache_flush = false;
2192        }
2193        for rec in &mut self.authorities {
2194            rec.get_record_mut().entry.cache_flush = false;
2195        }
2196    }
2197
2198    /// Returns a list of actual DNS packet data to be sent on the wire, each no
2199    /// bigger than `max_size`, over the IP version given by `is_ipv4`.
2200    ///
2201    /// Most callers want [`MAX_PKT_DEFAULT`] for `max_size`.
2202    pub fn to_data_on_wire(&self, max_size: usize, is_ipv4: bool) -> Vec<Vec<u8>> {
2203        let packet_list = self.to_packets(max_size, is_ipv4);
2204        packet_list.into_iter().map(|p| p.data).collect()
2205    }
2206
2207    /// Encode self into one or more packets, each no bigger than `max_size`.
2208    ///
2209    /// Questions and records are written in message order and spill into a new
2210    /// packet whenever the current one is full, so none is dropped for lack of
2211    /// room. The one exception is a single record too big to fit in an otherwise
2212    /// empty packet: it is sent alone in an oversized packet, per RFC 6762
2213    /// section 17.
2214    ///
2215    /// `is_ipv4` tells which IP version the packets are bound for, and so how big
2216    /// that lone oversized packet may get: see [`max_pkt_absolute`]. A record too
2217    /// big even for that could not be sent at all, and is dropped.
2218    ///
2219    /// `max_size` must be no bigger than [`MAX_PKT_ABSOLUTE_IPV6`], the RFC 6762
2220    /// section 17 ceiling that is legal over either IP version;
2221    /// [`ServiceDaemon::set_max_packet_size`](crate::ServiceDaemon::set_max_packet_size)
2222    /// caps what it accepts. Most callers want [`MAX_PKT_DEFAULT`].
2223    pub fn to_packets(&self, max_size: usize, is_ipv4: bool) -> Vec<DnsOutPacket> {
2224        debug_assert!(
2225            max_size <= MAX_PKT_ABSOLUTE_IPV6,
2226            "max_size {} exceeds the RFC 6762 section 17 ceiling",
2227            max_size
2228        );
2229        let mut builder = PacketBuilder::new(self, max_size, is_ipv4);
2230
2231        for question in self.questions.iter() {
2232            builder.add(Section::Question, |packet| packet.write_question(question));
2233        }
2234
2235        for (answer, time) in self.answers.iter() {
2236            builder.add(Section::Answer, |packet| {
2237                packet.write_record(answer.as_ref(), *time)
2238            });
2239        }
2240
2241        for auth in self.authorities.iter() {
2242            builder.add(Section::Authority, |packet| {
2243                packet.write_record(auth.as_ref(), 0)
2244            });
2245        }
2246
2247        for addi in self.additionals.iter() {
2248            builder.add(Section::Additional, |packet| {
2249                packet.write_record(addi.as_ref(), 0)
2250            });
2251        }
2252
2253        builder.finish()
2254    }
2255}
2256
2257/// An incoming DNS message. It could be a query or a response.
2258#[derive(Debug)]
2259pub struct DnsIncoming {
2260    offset: usize,
2261    data: Vec<u8>,
2262    questions: Vec<DnsQuestion>,
2263    answers: Vec<DnsRecordBox>,
2264    authorities: Vec<DnsRecordBox>,
2265    additional: Vec<DnsRecordBox>,
2266    id: u16,
2267    flags: u16,
2268    num_questions: u16,
2269    num_answers: u16,
2270    num_authorities: u16,
2271    num_additionals: u16,
2272    interface_id: InterfaceId,
2273}
2274
2275impl DnsIncoming {
2276    pub fn new(data: Vec<u8>, interface_id: InterfaceId) -> Result<Self> {
2277        let mut incoming = Self {
2278            offset: 0,
2279            data,
2280            questions: Vec::new(),
2281            answers: Vec::new(),
2282            authorities: Vec::new(),
2283            additional: Vec::new(),
2284            id: 0,
2285            flags: 0,
2286            num_questions: 0,
2287            num_answers: 0,
2288            num_authorities: 0,
2289            num_additionals: 0,
2290            interface_id,
2291        };
2292
2293        /*
2294        RFC 1035 section 4.1: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1
2295        ...
2296        All communications inside of the domain protocol are carried in a single
2297        format called a message.  The top level format of message is divided
2298        into 5 sections (some of which are empty in certain cases) shown below:
2299
2300            +---------------------+
2301            |        Header       |
2302            +---------------------+
2303            |       Question      | the question for the name server
2304            +---------------------+
2305            |        Answer       | RRs answering the question
2306            +---------------------+
2307            |      Authority      | RRs pointing toward an authority
2308            +---------------------+
2309            |      Additional     | RRs holding additional information
2310            +---------------------+
2311         */
2312        if let Err(e) = incoming.read_sections() {
2313            // Annotate the failure with the raw packet, so a malformed message
2314            // can be inspected or decoded offline without a separate capture.
2315            return Err(Error::Msg(format!(
2316                "{e}; raw packet ({} bytes): {:02x?}",
2317                incoming.data.len(),
2318                incoming.data,
2319            )));
2320        }
2321
2322        Ok(incoming)
2323    }
2324
2325    /// Reads the five message sections in order. Kept separate from `new` so a
2326    /// parse failure can be annotated with the raw packet bytes.
2327    fn read_sections(&mut self) -> Result<()> {
2328        self.read_header()?;
2329        self.read_questions()?;
2330        self.read_answers()?;
2331        self.read_authorities()?;
2332        self.read_additional()?;
2333        Ok(())
2334    }
2335
2336    pub fn id(&self) -> u16 {
2337        self.id
2338    }
2339
2340    pub fn questions(&self) -> &[DnsQuestion] {
2341        &self.questions
2342    }
2343
2344    pub fn answers(&self) -> &[DnsRecordBox] {
2345        &self.answers
2346    }
2347
2348    pub fn authorities(&self) -> &[DnsRecordBox] {
2349        &self.authorities
2350    }
2351
2352    pub fn additionals(&self) -> &[DnsRecordBox] {
2353        &self.additional
2354    }
2355
2356    pub fn answers_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2357        &mut self.answers
2358    }
2359
2360    pub fn authorities_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2361        &mut self.authorities
2362    }
2363
2364    pub fn additionals_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2365        &mut self.additional
2366    }
2367
2368    pub fn all_records(self) -> impl Iterator<Item = DnsRecordBox> {
2369        self.answers
2370            .into_iter()
2371            .chain(self.authorities)
2372            .chain(self.additional)
2373    }
2374
2375    pub fn num_additionals(&self) -> u16 {
2376        self.num_additionals
2377    }
2378
2379    pub fn num_authorities(&self) -> u16 {
2380        self.num_authorities
2381    }
2382
2383    pub fn num_questions(&self) -> u16 {
2384        self.num_questions
2385    }
2386
2387    pub const fn is_query(&self) -> bool {
2388        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
2389    }
2390
2391    pub const fn is_response(&self) -> bool {
2392        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
2393    }
2394
2395    fn read_header(&mut self) -> Result<()> {
2396        if self.data.len() < MSG_HEADER_LEN {
2397            return Err(e_fmt!(
2398                "DNS incoming: header is too short: {} bytes",
2399                self.data.len()
2400            ));
2401        }
2402
2403        let data = &self.data[0..];
2404        self.id = u16_from_be_slice(&data[..2]);
2405        self.flags = u16_from_be_slice(&data[2..4]);
2406        self.num_questions = u16_from_be_slice(&data[4..6]);
2407        self.num_answers = u16_from_be_slice(&data[6..8]);
2408        self.num_authorities = u16_from_be_slice(&data[8..10]);
2409        self.num_additionals = u16_from_be_slice(&data[10..12]);
2410
2411        self.offset = MSG_HEADER_LEN;
2412
2413        trace!(
2414            "read_header: id {}, {} questions {} answers {} authorities {} additionals",
2415            self.id,
2416            self.num_questions,
2417            self.num_answers,
2418            self.num_authorities,
2419            self.num_additionals
2420        );
2421        Ok(())
2422    }
2423
2424    fn read_questions(&mut self) -> Result<()> {
2425        trace!("read_questions: {}", &self.num_questions);
2426        for i in 0..self.num_questions {
2427            let name = self.read_name()?;
2428
2429            let data = &self.data[self.offset..];
2430            if data.len() < 4 {
2431                return Err(Error::Msg(format!(
2432                    "DNS incoming: question idx {} too short: {}",
2433                    i,
2434                    data.len()
2435                )));
2436            }
2437            let ty = u16_from_be_slice(&data[..2]);
2438            let class = u16_from_be_slice(&data[2..4]);
2439            self.offset += 4;
2440
2441            let Some(rr_type) = RRType::from_u16(ty) else {
2442                return Err(Error::Msg(format!(
2443                    "DNS incoming: question idx {i} qtype unknown: {ty}",
2444                )));
2445            };
2446
2447            self.questions.push(DnsQuestion {
2448                entry: DnsEntry::new(name, rr_type, class),
2449            });
2450        }
2451        Ok(())
2452    }
2453
2454    fn read_answers(&mut self) -> Result<()> {
2455        self.answers = self.read_rr_records(self.num_answers)?;
2456        Ok(())
2457    }
2458
2459    fn read_authorities(&mut self) -> Result<()> {
2460        self.authorities = self.read_rr_records(self.num_authorities)?;
2461        Ok(())
2462    }
2463
2464    fn read_additional(&mut self) -> Result<()> {
2465        self.additional = self.read_rr_records(self.num_additionals)?;
2466        Ok(())
2467    }
2468
2469    /// Decodes a sequence of RR records (in answers, authorities and additionals).
2470    fn read_rr_records(&mut self, count: u16) -> Result<Vec<DnsRecordBox>> {
2471        trace!("read_rr_records: {}", count);
2472        let mut rr_records = Vec::new();
2473
2474        // RFC 1035: https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.1
2475        //
2476        // All RRs have the same top level format shown below:
2477        //                               1  1  1  1  1  1
2478        // 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
2479        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2480        // |                                               |
2481        // /                                               /
2482        // /                      NAME                     /
2483        // |                                               |
2484        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2485        // |                      TYPE                     |
2486        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2487        // |                     CLASS                     |
2488        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2489        // |                      TTL                      |
2490        // |                                               |
2491        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2492        // |                   RDLENGTH                    |
2493        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
2494        // /                     RDATA                     /
2495        // /                                               /
2496        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2497
2498        // Muse have at least TYPE, CLASS, TTL, RDLENGTH fields: 10 bytes.
2499        const RR_HEADER_REMAIN: usize = 10;
2500
2501        for _ in 0..count {
2502            let name = self.read_name()?;
2503            let slice = &self.data[self.offset..];
2504
2505            if slice.len() < RR_HEADER_REMAIN {
2506                return Err(Error::Msg(format!(
2507                    "read_others: RR '{}' is too short after name: {} bytes",
2508                    &name,
2509                    slice.len()
2510                )));
2511            }
2512
2513            let ty = u16_from_be_slice(&slice[..2]);
2514            let class = u16_from_be_slice(&slice[2..4]);
2515            let mut ttl = u32_from_be_slice(&slice[4..8]);
2516            if ttl == 0 && self.is_response() {
2517                // RFC 6762 section 10.1:
2518                // "...Queriers receiving a Multicast DNS response with a TTL of zero SHOULD
2519                // NOT immediately delete the record from the cache, but instead record
2520                // a TTL of 1 and then delete the record one second later."
2521                // See https://datatracker.ietf.org/doc/html/rfc6762#section-10.1
2522
2523                ttl = 1;
2524            }
2525            let rdata_len = u16_from_be_slice(&slice[8..10]) as usize;
2526            self.offset += RR_HEADER_REMAIN;
2527            let next_offset = self.offset + rdata_len;
2528
2529            // Sanity check for RDATA length.
2530            if next_offset > self.data.len() {
2531                return Err(Error::Msg(format!(
2532                    "RR {name} RDATA length {rdata_len} is invalid: remain data len: {}",
2533                    self.data.len() - self.offset
2534                )));
2535            }
2536
2537            // Decode the RDATA based on the record type. A single record with
2538            // malformed RDATA must not discard the whole message: skip just
2539            // that record and resume at the next one using RDLENGTH.
2540            match self.read_rdata(ty, class, ttl, rdata_len, &name) {
2541                Ok(Some(record)) => {
2542                    if self.offset == next_offset {
2543                        trace!("read_rr_records: {:?}", &record);
2544                        rr_records.push(record);
2545                    } else {
2546                        debug!(
2547                            "skipping record '{}' (type {}): RDATA ended at {}, expected {}",
2548                            &name, ty, self.offset, next_offset
2549                        );
2550                    }
2551                }
2552                Ok(None) => {
2553                    trace!("Unsupported DNS record type: {} name: {}", ty, &name);
2554                }
2555                Err(e) => {
2556                    debug!(
2557                        "skipping record '{}' (type {}) with invalid RDATA: {}",
2558                        &name, ty, e,
2559                    );
2560                }
2561            }
2562
2563            // Re-anchor to the record boundary defined by RDLENGTH, regardless
2564            // of how the RDATA decoded, so the next record is read from the
2565            // correct offset.
2566            self.offset = next_offset;
2567        }
2568
2569        Ok(rr_records)
2570    }
2571
2572    /// Decodes the RDATA of a single record whose header fields have already
2573    /// been read, returning `None` for record types we do not parse.
2574    ///
2575    /// On success the read cursor is left at the end of the RDATA; the caller
2576    /// verifies that against RDLENGTH. Errors are per-record: the caller skips
2577    /// the offending record and continues with the rest of the message.
2578    fn read_rdata(
2579        &mut self,
2580        ty: u16,
2581        class: u16,
2582        ttl: u32,
2583        rdata_len: usize,
2584        name: &str,
2585    ) -> Result<Option<DnsRecordBox>> {
2586        let rec: Option<DnsRecordBox> = match RRType::from_u16(ty) {
2587            None => None,
2588
2589            Some(rr_type) => match rr_type {
2590                RRType::CNAME | RRType::PTR => {
2591                    Some(DnsPointer::new(name, rr_type, class, ttl, self.read_name()?).boxed())
2592                }
2593                RRType::TXT => {
2594                    Some(DnsTxt::new(name, class, ttl, self.read_vec(rdata_len)?).boxed())
2595                }
2596                RRType::SRV => Some(
2597                    DnsSrv::new(
2598                        name,
2599                        class,
2600                        ttl,
2601                        self.read_u16()?,
2602                        self.read_u16()?,
2603                        self.read_u16()?,
2604                        self.read_name()?,
2605                    )
2606                    .boxed(),
2607                ),
2608                RRType::HINFO => Some(
2609                    DnsHostInfo::new(
2610                        name,
2611                        rr_type,
2612                        class,
2613                        ttl,
2614                        self.read_char_string()?,
2615                        self.read_char_string()?,
2616                    )
2617                    .boxed(),
2618                ),
2619                RRType::A => Some(
2620                    DnsAddress::new(
2621                        name,
2622                        rr_type,
2623                        class,
2624                        ttl,
2625                        self.read_ipv4()?.into(),
2626                        self.interface_id.clone(),
2627                    )
2628                    .boxed(),
2629                ),
2630                RRType::AAAA => Some(
2631                    DnsAddress::new(
2632                        name,
2633                        rr_type,
2634                        class,
2635                        ttl,
2636                        self.read_ipv6()?.into(),
2637                        self.interface_id.clone(),
2638                    )
2639                    .boxed(),
2640                ),
2641                RRType::NSEC => Some(
2642                    DnsNSec::new(
2643                        name,
2644                        class,
2645                        ttl,
2646                        self.read_name()?,
2647                        self.read_type_bitmap()?,
2648                    )
2649                    .boxed(),
2650                ),
2651                _ => None,
2652            },
2653        };
2654
2655        Ok(rec)
2656    }
2657
2658    fn read_char_string(&mut self) -> Result<String> {
2659        let length = self.data[self.offset];
2660        self.offset += 1;
2661        self.read_string(length as usize)
2662    }
2663
2664    fn read_u16(&mut self) -> Result<u16> {
2665        let slice = &self.data[self.offset..];
2666        if slice.len() < U16_SIZE {
2667            return Err(Error::Msg(format!(
2668                "read_u16: slice len is only {}",
2669                slice.len()
2670            )));
2671        }
2672        let num = u16_from_be_slice(&slice[..U16_SIZE]);
2673        self.offset += U16_SIZE;
2674        Ok(num)
2675    }
2676
2677    /// Reads the "Type Bit Map" block for a DNS NSEC record.
2678    fn read_type_bitmap(&mut self) -> Result<Vec<u8>> {
2679        // From RFC 6762: 6.1.  Negative Responses
2680        // https://datatracker.ietf.org/doc/html/rfc6762#section-6.1
2681        //   o The Type Bit Map block number is 0.
2682        //   o The Type Bit Map block length byte is a value in the range 1-32.
2683        //   o The Type Bit Map data is 1-32 bytes, as indicated by length
2684        //     byte.
2685
2686        // Sanity check: at least 2 bytes to read.
2687        if self.data.len() < self.offset + 2 {
2688            return Err(Error::Msg(format!(
2689                "DnsIncoming is too short: {} at NSEC Type Bit Map offset {}",
2690                self.data.len(),
2691                self.offset
2692            )));
2693        }
2694
2695        let block_num = self.data[self.offset];
2696        self.offset += 1;
2697        if block_num != 0 {
2698            return Err(Error::Msg(format!(
2699                "NSEC block number is not 0: {block_num}"
2700            )));
2701        }
2702
2703        let block_len = self.data[self.offset] as usize;
2704        if !(1..=32).contains(&block_len) {
2705            return Err(Error::Msg(format!(
2706                "NSEC block length must be in the range 1-32: {block_len}"
2707            )));
2708        }
2709        self.offset += 1;
2710
2711        let end = self.offset + block_len;
2712        if end > self.data.len() {
2713            return Err(Error::Msg(format!(
2714                "NSEC block overflow: {} over RData len {}",
2715                end,
2716                self.data.len()
2717            )));
2718        }
2719        let bitmap = self.data[self.offset..end].to_vec();
2720        self.offset += block_len;
2721
2722        Ok(bitmap)
2723    }
2724
2725    fn read_vec(&mut self, length: usize) -> Result<Vec<u8>> {
2726        if self.data.len() < self.offset + length {
2727            return Err(e_fmt!(
2728                "DNS Incoming: not enough data to read a chunk of data"
2729            ));
2730        }
2731
2732        let v = self.data[self.offset..self.offset + length].to_vec();
2733        self.offset += length;
2734        Ok(v)
2735    }
2736
2737    fn read_ipv4(&mut self) -> Result<Ipv4Addr> {
2738        if self.data.len() < self.offset + 4 {
2739            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV4"));
2740        }
2741
2742        let bytes: [u8; 4] = self.data[self.offset..self.offset + 4]
2743            .try_into()
2744            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV4"))?;
2745        self.offset += bytes.len();
2746        Ok(Ipv4Addr::from(bytes))
2747    }
2748
2749    fn read_ipv6(&mut self) -> Result<Ipv6Addr> {
2750        if self.data.len() < self.offset + 16 {
2751            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV6"));
2752        }
2753
2754        let bytes: [u8; 16] = self.data[self.offset..self.offset + 16]
2755            .try_into()
2756            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV6"))?;
2757        self.offset += bytes.len();
2758        Ok(Ipv6Addr::from(bytes))
2759    }
2760
2761    fn read_string(&mut self, length: usize) -> Result<String> {
2762        if self.data.len() < self.offset + length {
2763            return Err(e_fmt!("DNS Incoming: not enough data to read a string"));
2764        }
2765
2766        let s = str::from_utf8(&self.data[self.offset..self.offset + length])
2767            .map_err(|e| Error::Msg(e.to_string()))?;
2768        self.offset += length;
2769        Ok(s.to_string())
2770    }
2771
2772    /// Reads a domain name at the current location of `self.data`.
2773    ///
2774    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 for
2775    /// domain name encoding.
2776    fn read_name(&mut self) -> Result<String> {
2777        let mut name = String::new();
2778        self.offset = self.read_labels(self.offset, &mut name)?;
2779        Ok(name)
2780    }
2781
2782    /// Appends the labels encoded at `offset` to `name`, and returns the offset
2783    /// just past that encoding: past the terminating zero byte, or past the
2784    /// compression pointer that ended the name.
2785    ///
2786    /// A name is a sequence of labels, where each label is a length byte
2787    /// followed by that many bytes. The name ends either with a zero length
2788    /// byte, or with a "compression pointer" (top 2 bits set) that redirects
2789    /// to a name written earlier in the same packet.
2790    ///
2791    /// For example, a packet where the question name `_http._tcp.local.` is
2792    /// written out in full at offset 12, and the answer name
2793    /// `myprinter._http._tcp.local.` at offset 40 reuses it via compression:
2794    ///
2795    /// ```text
2796    ///  offset:  12   13..17    18   19..22   23   24..28    29
2797    ///          +----+---------+----+--------+----+---------+----+
2798    ///  bytes:  | 05 | "_http" | 04 | "_tcp" | 05 | "local" | 00 |
2799    ///          +----+---------+----+--------+----+---------+----+
2800    ///            ^len           ^len          ^len           ^ zero byte: end of name
2801    ///
2802    ///  offset:  40    41..49     50   51
2803    ///          +----+-------------+----+----+
2804    ///  bytes:  | 09 | "myprinter" | C0 | 0C |
2805    ///          +----+-------------+----+----+
2806    ///            ^len               ^ pointer: 0xC00C ^ 0xC000 = 12, jump back to offset 12
2807    /// ```
2808    ///
2809    /// Takes `&self` so that following a pointer cannot move the read cursor.
2810    fn read_labels(&self, mut offset: usize, name: &mut String) -> Result<usize> {
2811        let data = &self.data[..];
2812
2813        // From RFC1035:
2814        // "...Domain names in messages are expressed in terms of a sequence of labels.
2815        // Each label is represented as a one octet length field followed by that
2816        // number of octets."
2817        //
2818        // "...The compression scheme allows a domain name in a message to be
2819        // represented as either:
2820        // - a sequence of labels ending in a zero octet
2821        // - a pointer
2822        // - a sequence of labels ending with a pointer"
2823        loop {
2824            if offset >= data.len() {
2825                return Err(Error::Msg(format!(
2826                    "read_labels: offset: {} data len {}. DnsIncoming: {:?}",
2827                    offset,
2828                    data.len(),
2829                    self
2830                )));
2831            }
2832            let length = data[offset];
2833
2834            // From RFC1035:
2835            // "...a domain name is terminated by a length byte of zero."
2836            if length == 0 {
2837                return Ok(offset + 1); // The end of the name.
2838            }
2839
2840            // Check the first 2 bits for possible "Message compression".
2841            match length & 0xC0 {
2842                0x00 => {
2843                    // regular utf8 string with length
2844                    offset += 1;
2845                    let ending = offset + length as usize;
2846
2847                    // Never read beyond the whole data length.
2848                    if ending > data.len() {
2849                        return Err(Error::Msg(format!(
2850                            "read_labels: ending {} exceeds data length {}",
2851                            ending,
2852                            data.len()
2853                        )));
2854                    }
2855
2856                    let label = str::from_utf8(&data[offset..ending])
2857                        .map_err(|e| Error::Msg(format!("read_labels: from_utf8: {e}")))?;
2858
2859                    // `MAX_NAME_BYTES` bounds a possible loop where pointer targets a label that
2860                    // is already part of the current name. For example:
2861                    //
2862                    //  offset:  12   13..17    18   19
2863                    //          +----+---------+----+----+
2864                    //  bytes:  | 05 | "_http" | C0 | 0C |
2865                    //          +----+---------+----+----+
2866                    //            ^len           ^pointer targets offset 12.
2867                    if name.len() + label.len() + 1 > MAX_NAME_BYTES {
2868                        return Err(Error::Msg(format!(
2869                            "read_labels: name exceeds {MAX_NAME_BYTES} bytes: {name}"
2870                        )));
2871                    }
2872
2873                    *name += label;
2874                    *name += ".";
2875                    offset = ending;
2876                }
2877                0xC0 => {
2878                    // Message compression: a pointer marks the end of a domain name.
2879                    self.follow_pointer(offset, name)?;
2880                    return Ok(offset + U16_SIZE);
2881                }
2882                _ => {
2883                    return Err(Error::Msg(format!(
2884                        "Bad name with invalid length: 0x{:x} offset {}, data (so far): {:x?}",
2885                        length,
2886                        offset,
2887                        &data[..offset]
2888                    )));
2889                }
2890            };
2891        }
2892    }
2893
2894    /// Follows the compression pointer at offset `at`, appending the labels it
2895    /// names to `name`.
2896    ///
2897    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4 for
2898    /// message compression.
2899    fn follow_pointer(&self, at: usize, name: &mut String) -> Result<()> {
2900        let data = &self.data[..];
2901        let mut pointer_at = at;
2902
2903        // Resolve a run of pointers that target other pointers, so that the
2904        // recursive call below always lands on a label or on the end of a name.
2905        let target = loop {
2906            let slice = &data[pointer_at..];
2907            if slice.len() < U16_SIZE {
2908                return Err(Error::Msg(format!(
2909                    "follow_pointer: u16 slice len is only {}",
2910                    slice.len()
2911                )));
2912            }
2913            let target = (u16_from_be_slice(slice) ^ 0xC000) as usize;
2914
2915            // RFC1035 section 4.1.4 compresses a name into "a pointer to a prior
2916            // occurrence", so a pointer always points strictly backwards.
2917            if target >= pointer_at {
2918                return Err(Error::Msg(format!(
2919                    "Invalid name compression: pointer {target} at offset {pointer_at} must point backwards"
2920                )));
2921            }
2922
2923            if data[target] & 0xC0 != 0xC0 {
2924                break target;
2925            }
2926
2927            // The target is itself a pointer, so follow it.
2928            pointer_at = target;
2929        };
2930
2931        self.read_labels(target, name)?;
2932        Ok(())
2933    }
2934}
2935
2936const fn u16_from_be_slice(bytes: &[u8]) -> u16 {
2937    let u8_array: [u8; 2] = [bytes[0], bytes[1]];
2938    u16::from_be_bytes(u8_array)
2939}
2940
2941const fn u32_from_be_slice(s: &[u8]) -> u32 {
2942    let u8_array: [u8; 4] = [s[0], s[1], s[2], s[3]];
2943    u32::from_be_bytes(u8_array)
2944}
2945
2946/// Returns the UNIX time in millis at which this record will have expired
2947/// by a certain percentage.
2948const fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
2949    // 'created' is in millis, 'ttl' is in seconds, hence:
2950    // ttl * 1000 * (percent / 100) => ttl * percent * 10
2951    created + (ttl as u64 * percent as u64 * 10)
2952}
2953
2954#[cfg(test)]
2955mod tests {
2956    use super::{
2957        u16_from_be_slice, DnsAddress, DnsHostInfo, DnsIncoming, DnsOutPacket, DnsOutgoing,
2958        DnsPointer, DnsTxt, RRType, CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
2959        FLAGS_TC, MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MSG_HEADER_LEN,
2960    };
2961    use crate::InterfaceId;
2962    use std::collections::HashMap;
2963    use std::net::{IpAddr, Ipv4Addr};
2964
2965    /// The `is_ipv4` argument of `to_packets`. IPv6 has the smaller of the two
2966    /// absolute ceilings, so it is the stricter one to encode for.
2967    const IPV6: bool = false;
2968
2969    #[test]
2970    fn test_dns_outgoing_serialization_empty() {
2971        let out = DnsOutgoing::new(0);
2972        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2973        assert_eq!(packets.len(), 1);
2974        assert_eq!(packets[0].as_bytes(), &[0; 12]);
2975        let expected_names = HashMap::new();
2976        assert_eq!(&packets[0].names, &expected_names);
2977    }
2978
2979    #[test]
2980    fn test_dns_outgoing_serialization_question() {
2981        let mut out = DnsOutgoing::new(0);
2982        out.add_question("123.test", RRType::A);
2983        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2984        assert_eq!(packets.len(), 1);
2985        assert_eq!(
2986            packets[0].as_bytes(),
2987            &[
2988                0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Header
2989                // Payload
2990                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
2991            ]
2992        );
2993        let mut expected_names = HashMap::new();
2994        expected_names.insert("123.test".to_string(), 12);
2995        expected_names.insert("test".to_string(), 16);
2996        assert_eq!(&packets[0].names, &expected_names);
2997    }
2998
2999    #[test]
3000    fn test_dns_outgoing_serialization_question_with_authority() {
3001        let mut out = DnsOutgoing::new(0);
3002        out.add_question("123.test", RRType::ANY);
3003        out.add_authority(Box::new(DnsTxt::new(
3004            "124.test",
3005            CLASS_IN,
3006            0x00112233,
3007            b"help".to_vec(),
3008        )));
3009        out.add_authority(Box::new(DnsHostInfo::new(
3010            "124.test",
3011            RRType::CNAME,
3012            CLASS_IN,
3013            0x00112233,
3014            "arm".to_string(),
3015            "linux".to_string(),
3016        )));
3017        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3018        assert_eq!(packets.len(), 1);
3019        assert_eq!(
3020            packets[0].as_bytes(),
3021            &[
3022                0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, // Header
3023                // Payload
3024                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 255, 0, 1, 3, 49, 50, 52, 192, 16, 0,
3025                16, 0, 1, 0, 17, 34, 51, 0, 4, 104, 101, 108, 112, 192, 26, 0, 5, 0, 1, 0, 17, 34,
3026                51, 0, 8, 97, 114, 109, 108, 105, 110, 117, 120,
3027            ]
3028        );
3029        let mut expected_names = HashMap::new();
3030        expected_names.insert("123.test".to_string(), 12);
3031        expected_names.insert("test".to_string(), 16);
3032        expected_names.insert("124.test".to_string(), 26);
3033        assert_eq!(&packets[0].names, &expected_names);
3034    }
3035
3036    #[test]
3037    fn test_dns_outgoing_serialization_additional_answer() {
3038        let mut out = DnsOutgoing::new(0);
3039        out.add_additional_answer(DnsAddress::new(
3040            "test.local",
3041            RRType::A,
3042            CLASS_IN | CLASS_CACHE_FLUSH,
3043            0xdead_beef,
3044            IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
3045            InterfaceId::default(),
3046        ));
3047        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3048        assert_eq!(packets.len(), 1);
3049        assert_eq!(
3050            packets[0].as_bytes(),
3051            &[
3052                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // Header
3053                // Payload
3054                4, 116, 101, 115, 116, 5, 108, 111, 99, 97, 108, 0, 0, 1, 128, 1, 222, 173, 190,
3055                239, 0, 4, 127, 0, 0, 1,
3056            ]
3057        );
3058        let mut expected_names = HashMap::new();
3059        expected_names.insert("test.local".to_string(), 12);
3060        expected_names.insert("local".to_string(), 17);
3061        assert_eq!(&packets[0].names, &expected_names);
3062    }
3063
3064    #[test]
3065    fn test_dns_outgoing_serialization_answer_at_time() {
3066        let mut out = DnsOutgoing::new(0);
3067        out.add_answer_at_time(
3068            DnsPointer::new(
3069                "test",
3070                RRType::PTR,
3071                CLASS_IN,
3072                0xaaaa5555,
3073                "test-service".to_string(),
3074            ),
3075            0,
3076        );
3077        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3078        assert_eq!(packets.len(), 1);
3079        assert_eq!(
3080            packets[0].as_bytes(),
3081            &[
3082                0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // Header
3083                // Payload
3084                4, 116, 101, 115, 116, 0, 0, 12, 0, 1, 170, 170, 85, 85, 0, 14, 12, 116, 101, 115,
3085                116, 45, 115, 101, 114, 118, 105, 99, 101, 0,
3086            ]
3087        );
3088
3089        let mut out = DnsOutgoing::new(0);
3090        out.add_answer_at_time(
3091            DnsPointer::new(
3092                "test",
3093                RRType::CNAME,
3094                CLASS_IN,
3095                0xaaaa5555,
3096                "test-service.local".to_string(),
3097            ),
3098            0,
3099        );
3100        out.add_answer_at_time(
3101            DnsPointer::new(
3102                "test",
3103                RRType::AAAA,
3104                CLASS_IN,
3105                0xffffffff,
3106                "test-service.local".to_string(),
3107            ),
3108            0,
3109        );
3110        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3111        assert_eq!(packets.len(), 1);
3112        assert_eq!(
3113            packets[0].as_bytes(),
3114            &[
3115                0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, // Header
3116                // Payload
3117                4, 116, 101, 115, 116, 0, 0, 5, 0, 1, 170, 170, 85, 85, 0, 20, 12, 116, 101, 115,
3118                116, 45, 115, 101, 114, 118, 105, 99, 101, 5, 108, 111, 99, 97, 108, 0, 192, 12, 0,
3119                28, 0, 1, 255, 255, 255, 255, 0, 2, 192, 28,
3120            ]
3121        );
3122        let mut expected_names = HashMap::new();
3123        expected_names.insert("test".to_string(), 12);
3124        expected_names.insert("test-service.local".to_string(), 28);
3125        expected_names.insert("local".to_string(), 41);
3126        assert_eq!(&packets[0].names, &expected_names);
3127    }
3128
3129    /// A question whose name has a label longer than 63 bytes cannot be
3130    /// encoded. It must be skipped, not panic. (Note the question count in the
3131    /// header must reflect the questions actually written.)
3132    #[test]
3133    fn test_dns_outgoing_question_label_too_long() {
3134        let long_label = "a".repeat(64);
3135        let mut out = DnsOutgoing::new(0);
3136        out.add_question(&format!("{long_label}.local"), RRType::PTR);
3137        out.add_question("123.test", RRType::A);
3138
3139        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3140        assert_eq!(packets.len(), 1);
3141        assert_eq!(
3142            packets[0].as_bytes(),
3143            &[
3144                0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Header: 1 question
3145                // Payload: only "123.test" made it in.
3146                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
3147            ]
3148        );
3149
3150        // The rolled back name must not leave a stale compression offset behind.
3151        let mut expected_names = HashMap::new();
3152        expected_names.insert("123.test".to_string(), 12);
3153        expected_names.insert("test".to_string(), 16);
3154        assert_eq!(&packets[0].names, &expected_names);
3155    }
3156
3157    /// A record whose rdata carries an unencodable name (here a PTR alias) is
3158    /// dropped as a whole, leaving the rest of the packet intact.
3159    #[test]
3160    fn test_dns_outgoing_record_label_too_long() {
3161        let long_label = "a".repeat(64);
3162        let mut out = DnsOutgoing::new(0);
3163        out.add_answer_at_time(
3164            DnsPointer::new(
3165                "_test._tcp.local.",
3166                RRType::PTR,
3167                CLASS_IN,
3168                0,
3169                format!("{long_label}._test._tcp.local."),
3170            ),
3171            0,
3172        );
3173        out.add_answer_at_time(
3174            DnsPointer::new(
3175                "_test._tcp.local.",
3176                RRType::PTR,
3177                CLASS_IN,
3178                0,
3179                "ok._test._tcp.local.".to_string(),
3180            ),
3181            0,
3182        );
3183
3184        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3185        assert_eq!(packets.len(), 1);
3186
3187        // Header answer count is 1: the first answer was dropped.
3188        assert_eq!(&packets[0].as_bytes()[6..8], &[0, 1]);
3189
3190        // Re-parsing must succeed and yield only the good answer.
3191        let incoming = DnsIncoming::new(
3192            packets[0].as_bytes().to_vec(),
3193            InterfaceId {
3194                name: "test".to_string(),
3195                index: 1,
3196            },
3197        )
3198        .unwrap();
3199        assert_eq!(incoming.answers().len(), 1);
3200    }
3201
3202    /// A name learned from the network can hold a label that ends with a
3203    /// backslash, which escapes the following label separator. Unescaping such
3204    /// a name on the way out merges two 63-byte labels into a 127-byte one.
3205    /// This used to panic the daemon thread. See issue #483.
3206    #[test]
3207    fn test_incoming_name_with_merged_labels_does_not_panic() {
3208        // A query with one question: "aa..a\" + "bb..b", 63 bytes each.
3209        let mut data: Vec<u8> = vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0];
3210        data.push(63);
3211        data.extend(vec![b'a'; 62]);
3212        data.push(b'\\');
3213        data.push(63);
3214        data.extend(vec![b'b'; 63]);
3215        data.push(0);
3216        data.extend([0, 12, 0, 1]); // PTR, IN
3217
3218        let incoming = DnsIncoming::new(
3219            data,
3220            InterfaceId {
3221                name: "test".to_string(),
3222                index: 1,
3223            },
3224        )
3225        .unwrap();
3226        let name = incoming.questions()[0].entry.name.clone();
3227
3228        // The two labels merged: the trailing backslash escaped the separator.
3229        assert!(name.starts_with("aaa"));
3230        assert!(name.contains("\\.bbb"));
3231
3232        // Re-emitting it must drop the question rather than panic.
3233        let mut out = DnsOutgoing::new(0);
3234        out.add_question(&name, RRType::PTR);
3235        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3236        assert_eq!(packets.len(), 1);
3237        assert_eq!(packets[0].as_bytes(), &[0; MSG_HEADER_LEN]);
3238    }
3239
3240    /// A pointer that points into the name currently being read is a loop:
3241    /// following it re-reads the same labels and arrives at the same pointer
3242    /// again. `read_name` must reject such a name instead of hanging.
3243    #[test]
3244    fn test_read_name_pointer_loop_is_rejected() {
3245        // A response with one PTR record. Its name starts at offset 12 and is
3246        // encoded as: label "local", label "_x", then a pointer back to 12,
3247        // i.e. to the "local" label of this very name.
3248        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 1, 0, 0, 0, 0];
3249        data.extend_from_slice(&[5, b'l', b'o', b'c', b'a', b'l']); // offset 12
3250        data.extend_from_slice(&[2, b'_', b'x']); // offset 18
3251        data.extend_from_slice(&[0xC0, 12]); // offset 21: pointer to 12
3252        data.extend_from_slice(&[0, 12, 0, 1]); // PTR, IN
3253        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3254        data.extend_from_slice(&[0, 2]); // RDLENGTH
3255        data.extend_from_slice(&[0xC0, 12]); // RDATA: pointer to 12
3256
3257        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3258    }
3259
3260    /// A legal name that follows a pointer backwards and then meets a second
3261    /// pointer whose target sits *after* the start of the name being read, yet
3262    /// still strictly *before* that second pointer's own position.
3263    ///
3264    /// Such a message probably never appears in reality, but it still has to parse.
3265    /// Reading the answer's name walks: 700 -> 640 -> 62-byte label -> 703 ->
3266    /// 702 -> zero byte, name complete.
3267    #[test]
3268    fn test_read_name_pointer_after_backward_jump() {
3269        /// Appends a question: one label of `label_len` 'a' bytes, PTR, IN.
3270        fn push_question(data: &mut Vec<u8>, label_len: usize) {
3271            data.push(label_len as u8);
3272            data.extend(vec![b'a'; label_len]);
3273            data.push(0); // end of the name
3274            data.extend_from_slice(&[0, 12]); // QTYPE: PTR
3275            data.extend_from_slice(&[0, 1]); // QCLASS: IN
3276        }
3277
3278        let mut data: Vec<u8> = vec![
3279            0, 0, // ID
3280            0, 0, // flags: a query
3281            0, 11, // 11 questions
3282            0, 1, // 1 answer
3283            0, 0, 0, 0, // no authorities, no additionals
3284        ];
3285
3286        // Questions #1 to #10, 66 bytes each: 12 + 660 = 672.
3287        for _ in 0..10 {
3288            push_question(&mut data, 60);
3289        }
3290        assert_eq!(data.len(), 672);
3291
3292        // Question #11, 28 bytes, so that the answer record starts at 700.
3293        push_question(&mut data, 22);
3294        assert_eq!(data.len(), 700);
3295
3296        // Plant the label length inside question #10's label.
3297        data[640] = 62;
3298
3299        // The answer record.
3300        data.extend_from_slice(&[0xC2, 0x80]); // 700: name: pointer to 640
3301        data.extend_from_slice(&[0x00, 0xC2]); // 702: TYPE, unknown type 194
3302        data.extend_from_slice(&[0xBE, 0x01]); // 704: CLASS. 703..705 is a pointer to 702
3303        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3304        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3305
3306        // Both pointers point backwards from where they are.
3307        assert_eq!(u16_from_be_slice(&data[700..702]) ^ 0xC000, 640);
3308        assert_eq!(u16_from_be_slice(&data[703..705]) ^ 0xC000, 702);
3309
3310        let incoming = DnsIncoming::new(data, test_interface_id())
3311            .expect("a name whose pointers all point backwards must parse");
3312        assert_eq!(incoming.questions().len(), 11);
3313
3314        // The answer's type is unknown to us, so the record itself is skipped.
3315        assert_eq!(incoming.answers().len(), 0);
3316    }
3317
3318    /// Two pointers at offsets 23 and 25 that target each other (23 -> 25 ->
3319    /// 23). Both sit below offset 27, where the name starts.
3320    ///
3321    /// `follow_pointer` requires each target to be strictly below the
3322    /// pointer's *own* position. A cycle always contains at least one
3323    /// non-backward hop, so this rule breaks every cycle.
3324    #[test]
3325    fn test_read_name_mutual_pointers_are_rejected() {
3326        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3327
3328        // Answer #1: the root name, then an unknown type, so its RDATA is skipped.
3329        data.push(0); // 12: the root name
3330        data.extend_from_slice(&[0x00, 0xC2]); // 13: TYPE: unknown type 194
3331        data.extend_from_slice(&[0x00, 0x01]); // 15: CLASS: IN
3332        data.extend_from_slice(&[0, 0, 0, 120]); // 17: TTL
3333        data.extend_from_slice(&[0x00, 0x04]); // 21: RDLENGTH
3334        data.extend_from_slice(&[0xC0, 25]); // 23: RDATA: pointer to 25
3335        data.extend_from_slice(&[0xC0, 23]); // 25: RDATA: pointer to 23
3336        assert_eq!(data.len(), 27);
3337
3338        // Answer #2, whose name points into that RDATA.
3339        data.extend_from_slice(&[0xC0, 23]); // 27: name: pointer to 23
3340        data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); // TYPE, CLASS
3341        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3342        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3343
3344        // Every pointer targets an offset below the start of the name at 27.
3345        assert_eq!(u16_from_be_slice(&data[27..29]) ^ 0xC000, 23);
3346        assert_eq!(u16_from_be_slice(&data[23..25]) ^ 0xC000, 25);
3347        assert_eq!(u16_from_be_slice(&data[25..27]) ^ 0xC000, 23);
3348
3349        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3350    }
3351
3352    /// A label whose read carries the cursor onto a pointer that jumps back to
3353    /// that same label. Every pointer here points backwards from its own
3354    /// position, so no comparison of offsets rejects it: the cycle is broken
3355    /// only by the name growing past [`MAX_NAME_BYTES`].
3356    #[test]
3357    fn test_read_name_label_cycle_is_rejected() {
3358        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3359
3360        // Answer #1, again an unknown type so that its RDATA is skipped.
3361        data.push(0); // 12: the root name
3362        data.extend_from_slice(&[0x00, 0xC2]); // 13: TYPE: unknown type 194
3363        data.extend_from_slice(&[0x00, 0x01]); // 15: CLASS: IN
3364        data.extend_from_slice(&[0, 0, 0, 120]); // 17: TTL
3365        data.extend_from_slice(&[0x00, 0x07]); // 21: RDLENGTH
3366        data.push(0x04); // 23: RDATA: a label of 4 bytes, ending at 28
3367        data.extend_from_slice(b"aaaa"); // 24
3368        data.extend_from_slice(&[0xC0, 23]); // 28: RDATA: pointer to 23
3369        assert_eq!(data.len(), 30);
3370
3371        // Answer #2, whose name enters the cycle.
3372        data.extend_from_slice(&[0xC0, 23]); // 30: name: pointer to 23
3373        data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); // TYPE, CLASS
3374        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3375        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3376
3377        // Reading the label at 23 leaves the cursor on the pointer at 28, which
3378        // points backwards from 28 and lands back on the label.
3379        assert_eq!(u16_from_be_slice(&data[28..30]) ^ 0xC000, 23);
3380        assert_eq!(u16_from_be_slice(&data[30..32]) ^ 0xC000, 23);
3381
3382        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3383    }
3384
3385    /// A real `_miio._udp.local.` response captured behind an avahi mDNS
3386    /// reflector (see issue #468). It has 5 answers, one of which is an NSEC
3387    /// whose Next Domain Name is a compression pointer to its own offset (a
3388    /// self-reference, offset 121 -> 121). That one record is malformed, but
3389    /// the other four (PTR, A, SRV, TXT) are fine, and lenient parsers such as
3390    /// tcpdump decode the whole packet.
3391    ///
3392    /// The parser must skip only the malformed NSEC and keep the good records,
3393    /// rather than discarding the entire message.
3394    #[test]
3395    fn test_malformed_nsec_record_is_skipped() {
3396        let data: Vec<u8> = vec![
3397            0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x5f,
3398            0x6d, 0x69, 0x69, 0x6f, 0x04, 0x5f, 0x75, 0x64, 0x70, 0x05, 0x6c, 0x6f, 0x63, 0x61,
3399            0x6c, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x24, 0x21, 0x64,
3400            0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d, 0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70,
3401            0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d, 0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30,
3402            0x35, 0x32, 0x34, 0x37, 0xc0, 0x0c, 0x21, 0x64, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d,
3403            0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70, 0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d,
3404            0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30, 0x35, 0x32, 0x34, 0x37, 0x00, 0x00,
3405            0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x09, 0xc0, 0x79, 0x00, 0x05, 0x40,
3406            0x00, 0x00, 0x00, 0x00, 0xc0, 0x4c, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78,
3407            0x00, 0x04, 0x0a, 0x2a, 0x02, 0x32, 0xc0, 0x28, 0x00, 0x21, 0x80, 0x01, 0x00, 0x00,
3408            0x00, 0x78, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x31, 0xc0, 0x4c, 0xc0, 0x28,
3409            0x00, 0x10, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x0e, 0x70, 0x61, 0x74,
3410            0x68, 0x3d, 0x2f, 0x6d, 0x79, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
3411        ];
3412
3413        // The offending record: the NSEC's Next Domain Name at offset 121 is a
3414        // pointer to offset 121 (itself).
3415        assert_eq!(u16_from_be_slice(&data[121..123]) ^ 0xC000, 121);
3416
3417        let incoming = DnsIncoming::new(data, test_interface_id())
3418            .expect("one malformed record must not fail the whole packet");
3419
3420        // Four of the five records survive; only the NSEC is dropped.
3421        assert_eq!(incoming.answers().len(), 4);
3422        assert!(
3423            !incoming
3424                .answers()
3425                .iter()
3426                .any(|r| r.get_type() == RRType::NSEC),
3427            "the malformed NSEC record must be skipped"
3428        );
3429    }
3430
3431    fn test_interface_id() -> InterfaceId {
3432        InterfaceId {
3433            name: "test".to_string(),
3434            index: 1,
3435        }
3436    }
3437
3438    /// The "flags" field of a finished packet.
3439    fn packet_flags(packet: &DnsOutPacket) -> u16 {
3440        let bytes = packet.as_bytes();
3441        u16::from_be_bytes([bytes[2], bytes[3]])
3442    }
3443
3444    fn ptr_answer(index: usize) -> DnsPointer {
3445        DnsPointer::new(
3446            "_spill._tcp.local.",
3447            RRType::PTR,
3448            CLASS_IN,
3449            4500,
3450            format!("instance-{index:04}._spill._tcp.local."),
3451        )
3452    }
3453
3454    /// Re-parses each packet and returns the total number of answers found, which
3455    /// checks the header counts against what each packet actually holds.
3456    fn parsed_answer_count(packets: &[DnsOutPacket]) -> usize {
3457        packets
3458            .iter()
3459            .map(|packet: &DnsOutPacket| {
3460                let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id())
3461                    .expect("each packet must parse on its own");
3462                assert!(
3463                    !parsed.answers().is_empty(),
3464                    "a spilled packet must not be empty"
3465                );
3466                parsed.answers().len()
3467            })
3468            .sum()
3469    }
3470
3471    /// A response too big for one packet spills into more packets. Every record
3472    /// must survive: before, records that did not fit were silently dropped.
3473    #[test]
3474    fn test_dns_outgoing_response_spills_into_packets() {
3475        const ANSWER_COUNT: usize = 100;
3476
3477        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3478        for i in 0..ANSWER_COUNT {
3479            out.add_answer_at_time(ptr_answer(i), 0);
3480        }
3481
3482        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3483        assert!(
3484            packets.len() > 1,
3485            "{} answers should not fit in one packet",
3486            ANSWER_COUNT
3487        );
3488
3489        for packet in &packets {
3490            assert!(
3491                packet.size() <= MAX_PKT_DEFAULT,
3492                "packet of {} bytes exceeds the limit",
3493                packet.size()
3494            );
3495
3496            // A multi-packet response is a series of independent responses: unlike
3497            // a query's known answers, it does not use the TC bit.
3498            assert_eq!(packet_flags(packet) & FLAGS_TC, 0);
3499        }
3500
3501        assert_eq!(parsed_answer_count(&packets), ANSWER_COUNT);
3502    }
3503
3504    /// RFC 6762 section 7.2: a querier sending known answers in more than one
3505    /// packet sets the TC bit in every packet but the last.
3506    #[test]
3507    fn test_dns_outgoing_query_truncation_bit() {
3508        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
3509        out.add_question("_spill._tcp.local.", RRType::PTR);
3510        for i in 0..100 {
3511            out.add_answer_box(Box::new(ptr_answer(i)));
3512        }
3513
3514        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3515        assert!(
3516            packets.len() > 1,
3517            "known answers should not fit in one packet"
3518        );
3519
3520        let (last, rest) = packets.split_last().expect("at least one packet");
3521        for packet in rest {
3522            assert_ne!(
3523                packet_flags(packet) & FLAGS_TC,
3524                0,
3525                "a packet with more known answers to follow must set TC"
3526            );
3527        }
3528        assert_eq!(
3529            packet_flags(last) & FLAGS_TC,
3530            0,
3531            "the last packet must not set TC"
3532        );
3533
3534        // The question goes in the first packet only, and no answer is lost.
3535        assert_eq!(packets[0].as_bytes()[4..6], 1u16.to_be_bytes());
3536        for packet in rest.iter().skip(1) {
3537            assert_eq!(packet.as_bytes()[4..6], [0, 0]);
3538        }
3539        assert_eq!(parsed_answer_count(&packets), 100);
3540    }
3541
3542    /// RFC 6762 section 17: a record too large for one MTU-sized packet is sent
3543    /// alone in an oversized packet, rather than dropped. It must be alone, since
3544    /// a fragmented packet "MUST NOT contain more than one resource record".
3545    #[test]
3546    fn test_dns_outgoing_oversized_record_sent_alone() {
3547        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3548        out.add_answer_at_time(ptr_answer(0), 0);
3549        out.add_answer_at_time(
3550            DnsTxt::new("big._spill._tcp.local.", CLASS_IN, 4500, vec![b'x'; 2000]),
3551            0,
3552        );
3553        out.add_answer_at_time(ptr_answer(1), 0);
3554
3555        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3556        assert_eq!(packets.len(), 3, "the big record needs a packet to itself");
3557
3558        assert!(packets[0].size() <= MAX_PKT_DEFAULT);
3559        assert!(
3560            packets[1].size() > MAX_PKT_DEFAULT,
3561            "the oversized record must not be dropped"
3562        );
3563        // Still small enough that the send path will let it out.
3564        assert!(packets[1].size() <= MAX_PKT_ABSOLUTE_IPV6);
3565        assert!(packets[2].size() <= MAX_PKT_DEFAULT);
3566
3567        // One record per packet here, the middle one being the big TXT.
3568        let parsed = DnsIncoming::new(packets[1].as_bytes().to_vec(), test_interface_id()).unwrap();
3569        assert_eq!(parsed.answers().len(), 1);
3570        assert_eq!(parsed.answers()[0].get_name(), "big._spill._tcp.local.");
3571        assert_eq!(parsed_answer_count(&packets), 3);
3572    }
3573
3574    /// A record over the RFC 6762 section 17 ceiling could not go out on the wire
3575    /// even in a packet of its own, so it is dropped while its neighbors survive.
3576    #[test]
3577    fn test_dns_outgoing_record_over_absolute_ceiling_dropped() {
3578        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3579        out.add_answer_at_time(ptr_answer(0), 0);
3580        out.add_answer_at_time(
3581            DnsTxt::new(
3582                "huge._spill._tcp.local.",
3583                CLASS_IN,
3584                4500,
3585                vec![b'x'; MAX_PKT_ABSOLUTE_IPV6],
3586            ),
3587            0,
3588        );
3589        out.add_answer_at_time(ptr_answer(1), 0);
3590
3591        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3592        for packet in &packets {
3593            assert!(
3594                packet.size() <= MAX_PKT_ABSOLUTE_IPV6,
3595                "an unsendable packet must never be generated"
3596            );
3597        }
3598        assert_eq!(
3599            parsed_answer_count(&packets),
3600            2,
3601            "only the huge record is dropped"
3602        );
3603    }
3604
3605    /// Authorities and additionals spill too, and stay in their own sections.
3606    #[test]
3607    fn test_dns_outgoing_all_sections_spill() {
3608        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3609        for i in 0..40 {
3610            out.add_answer_at_time(ptr_answer(i), 0);
3611        }
3612        for i in 40..80 {
3613            out.add_authority(Box::new(ptr_answer(i)));
3614        }
3615        for i in 80..120 {
3616            out.add_additional_answer(ptr_answer(i));
3617        }
3618
3619        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3620        assert!(packets.len() > 1);
3621
3622        let mut answers = 0;
3623        let mut authorities = 0;
3624        let mut additionals = 0;
3625        for packet in &packets {
3626            assert!(packet.size() <= MAX_PKT_DEFAULT);
3627            let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id()).unwrap();
3628            answers += parsed.answers().len();
3629            authorities += parsed.authorities().len();
3630            additionals += parsed.additionals().len();
3631        }
3632
3633        assert_eq!(answers, 40);
3634        assert_eq!(authorities, 40);
3635        assert_eq!(additionals, 40);
3636    }
3637}