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::{decode_txt, 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/// A DNS host information record
1135#[derive(Debug, Clone)]
1136struct DnsHostInfo {
1137    record: DnsRecord,
1138    cpu: String,
1139    os: String,
1140}
1141
1142impl DnsHostInfo {
1143    fn new(name: &str, ty: RRType, class: u16, ttl: u32, cpu: String, os: String) -> Self {
1144        let record = DnsRecord::new(name, ty, class, ttl);
1145        Self { record, cpu, os }
1146    }
1147}
1148
1149impl DnsRecordExt for DnsHostInfo {
1150    fn get_record(&self) -> &DnsRecord {
1151        &self.record
1152    }
1153
1154    fn get_record_mut(&mut self) -> &mut DnsRecord {
1155        &mut self.record
1156    }
1157
1158    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1159        debug!("Writing HInfo: cpu {} os {}", &self.cpu, &self.os);
1160        packet.write_bytes(self.cpu.as_bytes());
1161        packet.write_bytes(self.os.as_bytes());
1162        Ok(())
1163    }
1164
1165    fn any(&self) -> &dyn Any {
1166        self
1167    }
1168
1169    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1170        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1171            return self.cpu == other_hinfo.cpu
1172                && self.os == other_hinfo.os
1173                && self.record.entry == other_hinfo.record.entry;
1174        }
1175        false
1176    }
1177
1178    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1179        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1180            return self.cpu == other_hinfo.cpu && self.os == other_hinfo.os;
1181        }
1182        false
1183    }
1184
1185    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1186        if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1187            match self.cpu.cmp(&other_hinfo.cpu) {
1188                cmp::Ordering::Equal => self.os.cmp(&other_hinfo.os),
1189                ordering => ordering,
1190            }
1191        } else {
1192            cmp::Ordering::Greater
1193        }
1194    }
1195
1196    fn rdata_print(&self) -> String {
1197        format!("cpu: {}, os: {}", self.cpu, self.os)
1198    }
1199
1200    fn clone_box(&self) -> DnsRecordBox {
1201        Box::new(self.clone())
1202    }
1203
1204    fn boxed(self) -> DnsRecordBox {
1205        Box::new(self)
1206    }
1207}
1208
1209/// Resource Record for negative responses
1210///
1211/// [RFC4034 section 4.1](https://datatracker.ietf.org/doc/html/rfc4034#section-4.1)
1212/// and
1213/// [RFC6762 section 6.1](https://datatracker.ietf.org/doc/html/rfc6762#section-6.1)
1214#[derive(Debug, Clone)]
1215pub struct DnsNSec {
1216    record: DnsRecord,
1217    next_domain: String,
1218    type_bitmap: Vec<u8>,
1219}
1220
1221impl DnsNSec {
1222    pub fn new(
1223        name: &str,
1224        class: u16,
1225        ttl: u32,
1226        next_domain: String,
1227        type_bitmap: Vec<u8>,
1228    ) -> Self {
1229        let record = DnsRecord::new(name, RRType::NSEC, class, ttl);
1230        Self {
1231            record,
1232            next_domain,
1233            type_bitmap,
1234        }
1235    }
1236
1237    /// Returns the types marked by `type_bitmap`
1238    pub fn _types(&self) -> Vec<u16> {
1239        // From RFC 4034: 4.1.2 The Type Bit Maps Field
1240        // https://datatracker.ietf.org/doc/html/rfc4034#section-4.1.2
1241        //
1242        // Each bitmap encodes the low-order 8 bits of RR types within the
1243        // window block, in network bit order.  The first bit is bit 0.  For
1244        // window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
1245        // to RR type 2 (NS), and so forth.
1246
1247        let mut bit_num = 0;
1248        let mut results = Vec::new();
1249
1250        for byte in self.type_bitmap.iter() {
1251            let mut bit_mask: u8 = 0x80; // for bit 0 in network bit order
1252
1253            // check every bit in this byte, one by one.
1254            for _ in 0..8 {
1255                if (byte & bit_mask) != 0 {
1256                    results.push(bit_num);
1257                }
1258                bit_num += 1;
1259                bit_mask >>= 1; // mask for the next bit
1260            }
1261        }
1262        results
1263    }
1264}
1265
1266impl DnsRecordExt for DnsNSec {
1267    fn get_record(&self) -> &DnsRecord {
1268        &self.record
1269    }
1270
1271    fn get_record_mut(&mut self) -> &mut DnsRecord {
1272        &mut self.record
1273    }
1274
1275    fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1276        packet.write_bytes(self.next_domain.as_bytes());
1277        packet.write_bytes(&self.type_bitmap);
1278        Ok(())
1279    }
1280
1281    fn any(&self) -> &dyn Any {
1282        self
1283    }
1284
1285    fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1286        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1287            return self.next_domain == other_record.next_domain
1288                && self.type_bitmap == other_record.type_bitmap
1289                && self.record.entry == other_record.record.entry;
1290        }
1291        false
1292    }
1293
1294    fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1295        if let Some(other_record) = other.any().downcast_ref::<Self>() {
1296            return self.next_domain == other_record.next_domain
1297                && self.type_bitmap == other_record.type_bitmap;
1298        }
1299        false
1300    }
1301
1302    fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1303        if let Some(other_nsec) = other.any().downcast_ref::<Self>() {
1304            match self.next_domain.cmp(&other_nsec.next_domain) {
1305                cmp::Ordering::Equal => self.type_bitmap.cmp(&other_nsec.type_bitmap),
1306                ordering => ordering,
1307            }
1308        } else {
1309            cmp::Ordering::Greater
1310        }
1311    }
1312
1313    fn rdata_print(&self) -> String {
1314        format!(
1315            "next_domain: {}, type_bitmap len: {}",
1316            self.next_domain,
1317            self.type_bitmap.len()
1318        )
1319    }
1320
1321    fn clone_box(&self) -> DnsRecordBox {
1322        Box::new(self.clone())
1323    }
1324
1325    fn boxed(self) -> DnsRecordBox {
1326        Box::new(self)
1327    }
1328}
1329
1330/// Which section of a DNS message an item belongs to.
1331#[derive(Clone, Copy, Debug)]
1332enum Section {
1333    Question,
1334    Answer,
1335    Authority,
1336    Additional,
1337}
1338
1339/// A single packet for outgoing DNS message.
1340pub struct DnsOutPacket {
1341    /// All bytes in `data` is the actual packet on the wire.
1342    data: Vec<u8>,
1343
1344    /// k: name, v: offset
1345    names: HashMap<String, u16>,
1346
1347    /// Max byte size of `data`. i.e. the max packet size.
1348    max_size: usize,
1349
1350    /// How many items `data` holds in each section, i.e. the header counts.
1351    question_count: u16,
1352    answer_count: u16,
1353    auth_count: u16,
1354    addi_count: u16,
1355}
1356
1357impl DnsOutPacket {
1358    fn new(max_size: usize) -> Self {
1359        Self {
1360            data: vec![0; MSG_HEADER_LEN],
1361            names: HashMap::new(),
1362            max_size,
1363            question_count: 0,
1364            answer_count: 0,
1365            auth_count: 0,
1366            addi_count: 0,
1367        }
1368    }
1369
1370    pub fn size(&self) -> usize {
1371        self.data.len()
1372    }
1373
1374    pub fn as_bytes(&self) -> &[u8] {
1375        &self.data
1376    }
1377
1378    /// True if nothing has been written into this packet yet.
1379    fn is_empty(&self) -> bool {
1380        self.question_count == 0
1381            && self.answer_count == 0
1382            && self.auth_count == 0
1383            && self.addi_count == 0
1384    }
1385
1386    /// Counts one more item in `section`.
1387    fn bump(&mut self, section: Section) {
1388        match section {
1389            Section::Question => self.question_count += 1,
1390            Section::Answer => self.answer_count += 1,
1391            Section::Authority => self.auth_count += 1,
1392            Section::Additional => self.addi_count += 1,
1393        }
1394    }
1395
1396    fn write_question(&mut self, question: &DnsQuestion) -> WriteResult {
1397        let start_size = self.size();
1398
1399        self.write_name(&question.entry.name).map_err(|e| {
1400            self.rollback(start_size);
1401            e
1402        })?;
1403        self.write_short(question.entry.ty as u16);
1404        self.write_short(question.entry.class);
1405
1406        if self.size() > self.max_size {
1407            self.rollback(start_size);
1408            return Err(WriteError::PacketFull);
1409        }
1410
1411        Ok(())
1412    }
1413
1414    /// Discards everything written since `start_size`, including the name
1415    /// compression offsets that point into the discarded bytes.
1416    fn rollback(&mut self, start_size: usize) {
1417        self.data.truncate(start_size);
1418        self.names
1419            .retain(|_, offset| (*offset as usize) < start_size);
1420    }
1421
1422    /// Writes a record (answer, authoritative answer, additional).
1423    ///
1424    /// In error cases nothing is written to the packet.
1425    fn write_record(&mut self, record_ext: &dyn DnsRecordExt, now: u64) -> WriteResult {
1426        let start_size = self.size();
1427
1428        let record = record_ext.get_record();
1429        self.write_name(record.get_name())?;
1430        self.write_short(record.entry.ty as u16);
1431        if record.entry.cache_flush {
1432            // check "multicast"
1433            self.write_short(record.entry.class | CLASS_CACHE_FLUSH);
1434        } else {
1435            self.write_short(record.entry.class);
1436        }
1437
1438        if now == 0 {
1439            self.write_u32(record.ttl);
1440        } else {
1441            self.write_u32(record.get_remaining_ttl(now));
1442        }
1443
1444        // Placeholder for record size
1445        self.write_short(0);
1446        let record_offset = self.size();
1447
1448        if let Err(e) = record_ext.write(self) {
1449            self.rollback(start_size);
1450            return Err(e);
1451        }
1452
1453        self.set_short_at(record_offset - 2, (self.size() - record_offset) as u16);
1454
1455        if self.size() > self.max_size {
1456            self.rollback(start_size);
1457            return Err(WriteError::PacketFull);
1458        }
1459
1460        Ok(())
1461    }
1462
1463    fn set_short_at(&mut self, index: usize, value: u16) {
1464        self.data[index..index + 2].copy_from_slice(&value.to_be_bytes());
1465    }
1466
1467    /// Parses a DNS name that may contain escaped characters according to RFC 6763 Section 4.3.
1468    /// Returns a vector of labels where each label is the unescaped content.
1469    ///
1470    /// Escape sequences:
1471    /// - \\. becomes . (literal dot)
1472    /// - \\\\ becomes \\ (literal backslash)
1473    fn parse_escaped_name(name: &str) -> Vec<String> {
1474        let mut labels = Vec::new();
1475        let mut current_label = String::new();
1476        let mut chars = name.chars().peekable();
1477
1478        while let Some(ch) = chars.next() {
1479            match ch {
1480                '\\' => {
1481                    // Backslash escape sequence
1482                    if let Some(&next_ch) = chars.peek() {
1483                        match next_ch {
1484                            '.' | '\\' => {
1485                                // \\. or \\\\ - consume the backslash and add the escaped char
1486                                chars.next();
1487                                current_label.push(next_ch);
1488                            }
1489                            _ => {
1490                                // Not a recognized escape - treat backslash literally
1491                                current_label.push(ch);
1492                            }
1493                        }
1494                    } else {
1495                        // Trailing backslash - add it literally
1496                        current_label.push(ch);
1497                    }
1498                }
1499                '.' => {
1500                    // Unescaped dot - label separator
1501                    if !current_label.is_empty() {
1502                        labels.push(current_label.clone());
1503                        current_label.clear();
1504                    }
1505                }
1506                _ => {
1507                    current_label.push(ch);
1508                }
1509            }
1510        }
1511
1512        // Add the last label if not empty
1513        if !current_label.is_empty() {
1514            labels.push(current_label);
1515        }
1516
1517        labels
1518    }
1519
1520    // Write name to packet
1521    //
1522    // [RFC1035]
1523    // 4.1.4. Message compression
1524    //
1525    // In order to reduce the size of messages, the domain system utilizes a
1526    // compression scheme which eliminates the repetition of domain names in a
1527    // message.  In this scheme, an entire domain name or a list of labels at
1528    // the end of a domain name is replaced with a pointer to a prior occurrence
1529    // of the same name.
1530    // The pointer takes the form of a two octet sequence:
1531    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1532    //     | 1  1|                OFFSET                   |
1533    //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1534    // The first two bits are ones.  This allows a pointer to be distinguished
1535    // from a label, since the label must begin with two zero bits because
1536    // labels are restricted to 63 octets or less.  (The 10 and 01 combinations
1537    // are reserved for future use.)  The OFFSET field specifies an offset from
1538    // the start of the message (i.e., the first octet of the ID field in the
1539    // domain header).  A zero offset specifies the first byte of the ID field,
1540    // etc.
1541    //
1542    // This function also handles RFC 6763 Section 4.3 escaping where dots and backslashes
1543    // in instance names are escaped (e.g., "My\\.Service" represents a single label "My.Service").
1544    // The actual name sent over the wire is the unescaped version.
1545    fn write_name(&mut self, name: &str) -> WriteResult {
1546        // Remove trailing dot if present
1547        let name_to_parse = name.strip_suffix('.').unwrap_or(name);
1548
1549        // Parse the name considering escape sequences
1550        let labels = Self::parse_escaped_name(name_to_parse);
1551
1552        if labels.is_empty() {
1553            self.write_byte(0);
1554            return Ok(());
1555        }
1556
1557        // Validate before writing anything.
1558        if labels.iter().any(|label| label.len() > MAX_LABEL_BYTES) {
1559            return Err(WriteError::NameTooLong);
1560        }
1561
1562        // Write each label
1563        for (i, label) in labels.iter().enumerate() {
1564            // Build the remaining name for compression (with dots as separators)
1565            let remaining: String = labels[i..].join(".");
1566
1567            // Check if we can use compression for the remaining part
1568            const POINTER_MASK: u16 = 0xC000;
1569            if let Some(&offset) = self.names.get(&remaining) {
1570                let pointer = offset | POINTER_MASK;
1571                self.write_short(pointer);
1572                return Ok(());
1573            }
1574
1575            // Store this position for potential future compression
1576            self.names.insert(remaining, self.size() as u16);
1577
1578            // Write the label
1579            self.write_utf8(label)?;
1580        }
1581
1582        // Write terminating zero byte
1583        self.write_byte(0);
1584        Ok(())
1585    }
1586
1587    fn write_byte(&mut self, v: u8) {
1588        self.data.push(v);
1589    }
1590
1591    fn write_bytes(&mut self, s: &[u8]) {
1592        self.data.extend(s);
1593    }
1594
1595    /// Writes a single label. Nothing is written if the label is too long to
1596    /// be encoded.
1597    fn write_utf8(&mut self, s: &str) -> WriteResult {
1598        if s.len() > MAX_LABEL_BYTES {
1599            return Err(WriteError::NameTooLong);
1600        }
1601        self.write_byte(s.len() as u8);
1602        self.write_bytes(s.as_bytes());
1603        Ok(())
1604    }
1605
1606    fn write_u32(&mut self, v: u32) {
1607        self.data.extend(&v.to_be_bytes());
1608    }
1609
1610    fn write_short(&mut self, v: u16) {
1611        self.data.extend(&v.to_be_bytes());
1612    }
1613
1614    /// Marks this finished packet as truncated, i.e. the message continues in
1615    /// the next packet.
1616    fn set_truncated(&mut self) {
1617        let flags = u16::from_be_bytes([self.data[2], self.data[3]]);
1618        self.set_short_at(2, flags | FLAGS_TC);
1619    }
1620
1621    /// Writes the header fields and finish the packet.
1622    /// This function should be only called when finishing a packet.
1623    ///
1624    /// The header format is based on RFC 1035 section 4.1.1:
1625    /// https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
1626    //
1627    //                                  1  1  1  1  1  1
1628    //    0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
1629    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1630    //    |                      ID                       |
1631    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1632    //    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
1633    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1634    //    |                    QDCOUNT                    |
1635    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1636    //    |                    ANCOUNT                    |
1637    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1638    //    |                    NSCOUNT                    |
1639    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1640    //    |                    ARCOUNT                    |
1641    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1642    //
1643    fn write_header(&mut self, id: u16, flags: u16) {
1644        self.set_short_at(0, id);
1645        self.set_short_at(2, flags);
1646        self.set_short_at(4, self.question_count);
1647        self.set_short_at(6, self.answer_count);
1648        self.set_short_at(8, self.auth_count);
1649        self.set_short_at(10, self.addi_count);
1650    }
1651}
1652
1653/// Encodes a [`DnsOutgoing`] into one or more [`DnsOutPacket`], starting a new
1654/// packet whenever the current one runs out of room.
1655struct PacketBuilder<'a> {
1656    out: &'a DnsOutgoing,
1657
1658    /// Max size of a packet that holds more than one record.
1659    max_size: usize,
1660
1661    /// IP version these packets are bound for, which decides their absolute
1662    /// ceiling: see [`max_pkt_absolute`].
1663    is_ipv4: bool,
1664
1665    finished: Vec<DnsOutPacket>,
1666    current: DnsOutPacket,
1667}
1668
1669impl<'a> PacketBuilder<'a> {
1670    fn new(out: &'a DnsOutgoing, max_size: usize, is_ipv4: bool) -> Self {
1671        Self {
1672            out,
1673            max_size,
1674            is_ipv4,
1675            finished: Vec::new(),
1676            current: DnsOutPacket::new(max_size),
1677        }
1678    }
1679
1680    /// Writes one question or record into the current packet, starting a new
1681    /// packet if it does not fit in the current one.
1682    ///
1683    /// An item that cannot be encoded at all is skipped, leaving the packet as
1684    /// it was. Sections are written in message order, so an item that spills
1685    /// never lands ahead of one already written.
1686    fn add<F>(&mut self, section: Section, write: F)
1687    where
1688        F: Fn(&mut DnsOutPacket) -> WriteResult,
1689    {
1690        match write(&mut self.current) {
1691            Ok(()) => {
1692                self.current.bump(section);
1693                return;
1694            }
1695            // The item can never be encoded: skip it.
1696            Err(WriteError::NameTooLong) => return,
1697            Err(WriteError::PacketFull) => {}
1698        }
1699
1700        // Packet is full. Flush the current and create a new one.
1701        if !self.current.is_empty() {
1702            self.flush();
1703
1704            match write(&mut self.current) {
1705                Ok(()) => {
1706                    self.current.bump(section);
1707                    return;
1708                }
1709                Err(WriteError::NameTooLong) => return,
1710                Err(WriteError::PacketFull) => {}
1711            }
1712        }
1713
1714        // Packet is still full. A question such big is not legitimate.
1715        if matches!(section, Section::Question) {
1716            return;
1717        }
1718
1719        // Packet is still full. We will send this single record.
1720
1721        // RFC 6762 section 17:
1722        // "a record too large for one MTU-sized packet SHOULD be sent alone, in a
1723        // single IP datagram".
1724        self.current.max_size = max_pkt_absolute(self.is_ipv4);
1725
1726        if write(&mut self.current).is_ok() {
1727            self.current.bump(section);
1728            self.flush();
1729        } else {
1730            // Too big even for the hard ceiling: skip the record and carry on.
1731            self.current.max_size = self.max_size;
1732            debug!(
1733                "Record too big for absolute max size, skipping: {:?}",
1734                section
1735            );
1736        }
1737    }
1738
1739    /// Finishes the current packet and starts a new empty one.
1740    fn flush(&mut self) {
1741        self.current
1742            .write_header(self.out.wire_id(), self.out.flags);
1743
1744        let next = DnsOutPacket::new(self.max_size);
1745        self.finished
1746            .push(std::mem::replace(&mut self.current, next));
1747    }
1748
1749    fn finish(mut self) -> Vec<DnsOutPacket> {
1750        // Always produce at least one packet, even an empty one, but never leave a
1751        // trailing empty packet behind a full one.
1752        if !self.current.is_empty() || self.finished.is_empty() {
1753            self.flush();
1754        }
1755
1756        let mut packets = self.finished;
1757
1758        /*
1759        RFC 6762 section 7.2: https://datatracker.ietf.org/doc/html/rfc6762#section-7.2
1760        ...
1761            When a Multicast DNS querier sends a query to which it already knows some
1762            answers, it ... sets the TC (Truncated) bit in the header ... [so that the
1763            responder knows] to wait for the remaining known answers before responding.
1764         */
1765        if self.out.is_query() {
1766            if let Some((_last, rest)) = packets.split_last_mut() {
1767                for packet in rest {
1768                    packet.set_truncated();
1769                }
1770            }
1771        }
1772
1773        packets
1774    }
1775}
1776
1777/// Representation of one outgoing DNS message that could be sent in one or more packet(s).
1778#[derive(Debug)]
1779pub struct DnsOutgoing {
1780    flags: u16,
1781    id: u16,
1782    multicast: bool,
1783    questions: Vec<DnsQuestion>,
1784    answers: Vec<(DnsRecordBox, u64)>,
1785    authorities: Vec<DnsRecordBox>,
1786    additionals: Vec<DnsRecordBox>,
1787    known_answer_count: i64, // for internal maintenance only
1788}
1789
1790impl DnsOutgoing {
1791    pub fn new(flags: u16) -> Self {
1792        Self {
1793            flags,
1794            id: 0,
1795            multicast: true,
1796            questions: Vec::new(),
1797            answers: Vec::new(),
1798            authorities: Vec::new(),
1799            additionals: Vec::new(),
1800            known_answer_count: 0,
1801        }
1802    }
1803
1804    pub fn questions(&self) -> &[DnsQuestion] {
1805        &self.questions
1806    }
1807
1808    /// For testing purposes only.
1809    pub(crate) fn _answers(&self) -> &[(DnsRecordBox, u64)] {
1810        &self.answers
1811    }
1812
1813    pub fn answers_count(&self) -> usize {
1814        self.answers.len()
1815    }
1816
1817    pub fn authorities(&self) -> &[DnsRecordBox] {
1818        &self.authorities
1819    }
1820
1821    pub fn additionals(&self) -> &[DnsRecordBox] {
1822        &self.additionals
1823    }
1824
1825    pub fn known_answer_count(&self) -> i64 {
1826        self.known_answer_count
1827    }
1828
1829    pub fn set_id(&mut self, id: u16) {
1830        self.id = id;
1831    }
1832
1833    /// The id to put in the header, always 0 for multicast.
1834    const fn wire_id(&self) -> u16 {
1835        if self.multicast {
1836            0
1837        } else {
1838            self.id
1839        }
1840    }
1841
1842    pub const fn is_query(&self) -> bool {
1843        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1844    }
1845
1846    // Adds an additional answer
1847
1848    // From: RFC 6763, DNS-Based Service Discovery, February 2013
1849
1850    // 12.  DNS Additional Record Generation
1851
1852    //    DNS has an efficiency feature whereby a DNS server may place
1853    //    additional records in the additional section of the DNS message.
1854    //    These additional records are records that the client did not
1855    //    explicitly request, but the server has reasonable grounds to expect
1856    //    that the client might request them shortly, so including them can
1857    //    save the client from having to issue additional queries.
1858
1859    //    This section recommends which additional records SHOULD be generated
1860    //    to improve network efficiency, for both Unicast and Multicast DNS-SD
1861    //    responses.
1862
1863    // 12.1.  PTR Records
1864
1865    //    When including a DNS-SD Service Instance Enumeration or Selective
1866    //    Instance Enumeration (subtype) PTR record in a response packet, the
1867    //    server/responder SHOULD include the following additional records:
1868
1869    //    o  The SRV record(s) named in the PTR rdata.
1870    //    o  The TXT record(s) named in the PTR rdata.
1871    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1872
1873    // 12.2.  SRV Records
1874
1875    //    When including an SRV record in a response packet, the
1876    //    server/responder SHOULD include the following additional records:
1877
1878    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1879    pub fn add_additional_answer(&mut self, answer: impl DnsRecordExt + 'static) {
1880        trace!("add_additional_answer: {:?}", &answer);
1881        self.additionals.push(answer.boxed());
1882    }
1883
1884    /// A workaround as Rust doesn't allow us to pass DnsRecordBox in as `impl DnsRecordExt`
1885    pub fn add_answer_box(&mut self, answer_box: DnsRecordBox) {
1886        self.answers.push((answer_box, 0));
1887    }
1888
1889    pub fn add_authority(&mut self, record: DnsRecordBox) {
1890        self.authorities.push(record);
1891    }
1892
1893    /// Retains only the answers for which `keep` returns true.
1894    pub(crate) fn retain_answers<F>(&mut self, mut keep: F)
1895    where
1896        F: FnMut(&DnsRecordBox) -> bool,
1897    {
1898        self.answers.retain(|(record, _)| keep(record));
1899    }
1900
1901    /// Retains only the additional records for which `keep` returns true.
1902    pub(crate) fn retain_additionals<F>(&mut self, mut keep: F)
1903    where
1904        F: FnMut(&DnsRecordBox) -> bool,
1905    {
1906        self.additionals.retain(|record| keep(record));
1907    }
1908
1909    /// Returns true if `answer` is added to the outgoing msg.
1910    /// Returns false if `answer` was not added as it expired or suppressed by the incoming `msg`.
1911    pub fn add_answer(
1912        &mut self,
1913        msg: &DnsIncoming,
1914        answer: impl DnsRecordExt + Send + 'static,
1915    ) -> bool {
1916        trace!("Check for add_answer");
1917        if answer.suppressed_by(msg) {
1918            trace!("my answer is suppressed by incoming msg");
1919            self.known_answer_count += 1;
1920            return false;
1921        }
1922
1923        self.add_answer_at_time(answer, 0)
1924    }
1925
1926    /// Returns true if `answer` is added to the outgoing msg.
1927    /// Returns false if the answer is expired `now` hence not added.
1928    /// If `now` is 0, do not check if the answer expires.
1929    pub fn add_answer_at_time(
1930        &mut self,
1931        answer: impl DnsRecordExt + Send + 'static,
1932        now: u64,
1933    ) -> bool {
1934        if now == 0 || !answer.get_record().is_expired(now) {
1935            trace!("add_answer push: {:?}", &answer);
1936            self.answers.push((answer.boxed(), now));
1937            return true;
1938        }
1939        false
1940    }
1941
1942    /// Adds a PTR answer for `service` along with recommended additional records
1943    /// (SRV, TXT, and address records) per [RFC 6763 Section 12.1].
1944    ///
1945    /// Resolves any name conflicts via `dns_registry` and selects addresses
1946    /// matching the given interface. Does nothing if no addresses are available
1947    /// on `intf` or if the PTR answer is suppressed by known-answer entries in `msg`.
1948    ///
1949    /// [RFC 6763 Section 12.1]: https://tools.ietf.org/html/rfc6763#section-12.1
1950    pub(crate) fn add_answer_with_additionals(
1951        &mut self,
1952        msg: &DnsIncoming,
1953        service: &ServiceInfo,
1954        intf: &MyIntf,
1955        dns_registry: &DnsRegistry,
1956        is_ipv4: bool,
1957    ) {
1958        let intf_addrs = if is_ipv4 {
1959            service.get_addrs_on_my_intf_v4(intf)
1960        } else {
1961            service.get_addrs_on_my_intf_v6(intf)
1962        };
1963        if intf_addrs.is_empty() {
1964            trace!("No addrs on LAN of intf {:?}", intf);
1965            return;
1966        }
1967
1968        // check if we changed our name due to conflicts.
1969        let service_fullname = dns_registry.resolve_name(service.get_fullname());
1970        let hostname = dns_registry.resolve_name(service.get_hostname());
1971
1972        let ptr_added = self.add_answer(
1973            msg,
1974            DnsPointer::new(
1975                service.get_type(),
1976                RRType::PTR,
1977                CLASS_IN,
1978                service.get_other_ttl(),
1979                service_fullname.to_string(),
1980            ),
1981        );
1982
1983        if !ptr_added {
1984            trace!("answer was not added for msg {:?}", msg);
1985            return;
1986        }
1987
1988        if let Some(sub) = service.get_subtype() {
1989            trace!("Adding subdomain {}", sub);
1990            self.add_additional_answer(DnsPointer::new(
1991                sub,
1992                RRType::PTR,
1993                CLASS_IN,
1994                service.get_other_ttl(),
1995                service_fullname.to_string(),
1996            ));
1997        }
1998
1999        // Add recommended additional answers according to
2000        // https://tools.ietf.org/html/rfc6763#section-12.1.
2001        self.add_additional_answer(DnsSrv::new(
2002            service_fullname,
2003            CLASS_IN | CLASS_CACHE_FLUSH,
2004            service.get_host_ttl(),
2005            service.get_priority(),
2006            service.get_weight(),
2007            service.get_port(),
2008            hostname.to_string(),
2009        ));
2010
2011        self.add_additional_answer(DnsTxt::new(
2012            service_fullname,
2013            CLASS_IN | CLASS_CACHE_FLUSH,
2014            service.get_other_ttl(),
2015            service.generate_txt(),
2016        ));
2017
2018        for address in intf_addrs {
2019            self.add_additional_answer(DnsAddress::new(
2020                hostname,
2021                ip_address_rr_type(&address),
2022                CLASS_IN | CLASS_CACHE_FLUSH,
2023                service.get_host_ttl(),
2024                address,
2025                intf.into(),
2026            ));
2027        }
2028    }
2029
2030    pub fn add_question(&mut self, name: &str, qtype: RRType) {
2031        let q = DnsQuestion {
2032            entry: DnsEntry::new(name.to_string(), qtype, CLASS_IN),
2033        };
2034        self.questions.push(q);
2035    }
2036
2037    /// Clear the cache-flush (unique) bit on every answer and additional
2038    /// record. Required for RFC 6762 §6.7 (Legacy Unicast Responses) and
2039    /// §10.2 — a legacy resolver doesn't know about the cache-flush bit
2040    /// and may misinterpret responses where it is set.
2041    pub fn clear_cache_flush_bits(&mut self) {
2042        for (rec, _) in &mut self.answers {
2043            rec.get_record_mut().entry.cache_flush = false;
2044        }
2045        for rec in &mut self.additionals {
2046            rec.get_record_mut().entry.cache_flush = false;
2047        }
2048        for rec in &mut self.authorities {
2049            rec.get_record_mut().entry.cache_flush = false;
2050        }
2051    }
2052
2053    /// Returns a list of actual DNS packet data to be sent on the wire, each no
2054    /// bigger than `max_size`, over the IP version given by `is_ipv4`.
2055    ///
2056    /// Most callers want [`MAX_PKT_DEFAULT`] for `max_size`.
2057    pub fn to_data_on_wire(&self, max_size: usize, is_ipv4: bool) -> Vec<Vec<u8>> {
2058        let packet_list = self.to_packets(max_size, is_ipv4);
2059        packet_list.into_iter().map(|p| p.data).collect()
2060    }
2061
2062    /// Encode self into one or more packets, each no bigger than `max_size`.
2063    ///
2064    /// Questions and records are written in message order and spill into a new
2065    /// packet whenever the current one is full, so none is dropped for lack of
2066    /// room. The one exception is a single record too big to fit in an otherwise
2067    /// empty packet: it is sent alone in an oversized packet, per RFC 6762
2068    /// section 17.
2069    ///
2070    /// `is_ipv4` tells which IP version the packets are bound for, and so how big
2071    /// that lone oversized packet may get: see [`max_pkt_absolute`]. A record too
2072    /// big even for that could not be sent at all, and is dropped.
2073    ///
2074    /// `max_size` must be no bigger than [`MAX_PKT_ABSOLUTE_IPV6`], the RFC 6762
2075    /// section 17 ceiling that is legal over either IP version;
2076    /// [`ServiceDaemon::set_max_packet_size`](crate::ServiceDaemon::set_max_packet_size)
2077    /// caps what it accepts. Most callers want [`MAX_PKT_DEFAULT`].
2078    pub fn to_packets(&self, max_size: usize, is_ipv4: bool) -> Vec<DnsOutPacket> {
2079        debug_assert!(
2080            max_size <= MAX_PKT_ABSOLUTE_IPV6,
2081            "max_size {} exceeds the RFC 6762 section 17 ceiling",
2082            max_size
2083        );
2084        let mut builder = PacketBuilder::new(self, max_size, is_ipv4);
2085
2086        for question in self.questions.iter() {
2087            builder.add(Section::Question, |packet| packet.write_question(question));
2088        }
2089
2090        for (answer, time) in self.answers.iter() {
2091            builder.add(Section::Answer, |packet| {
2092                packet.write_record(answer.as_ref(), *time)
2093            });
2094        }
2095
2096        for auth in self.authorities.iter() {
2097            builder.add(Section::Authority, |packet| {
2098                packet.write_record(auth.as_ref(), 0)
2099            });
2100        }
2101
2102        for addi in self.additionals.iter() {
2103            builder.add(Section::Additional, |packet| {
2104                packet.write_record(addi.as_ref(), 0)
2105            });
2106        }
2107
2108        builder.finish()
2109    }
2110}
2111
2112/// An incoming DNS message. It could be a query or a response.
2113pub struct DnsIncoming {
2114    offset: usize,
2115    data: Vec<u8>,
2116    questions: Vec<DnsQuestion>,
2117    answers: Vec<DnsRecordBox>,
2118    authorities: Vec<DnsRecordBox>,
2119    additional: Vec<DnsRecordBox>,
2120    id: u16,
2121    flags: u16,
2122    num_questions: u16,
2123    num_answers: u16,
2124    num_authorities: u16,
2125    num_additionals: u16,
2126    interface_id: InterfaceId,
2127}
2128
2129/// Written by hand rather than derived, so we don't dump the raw packet unbounded.
2130impl fmt::Debug for DnsIncoming {
2131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2132        f.debug_struct("DnsIncoming")
2133            .field("offset", &self.offset)
2134            .field("questions", &self.questions)
2135            .field("answers", &self.answers)
2136            .field("authorities", &self.authorities)
2137            .field("additional", &self.additional)
2138            .field("id", &self.id)
2139            .field("flags", &self.flags)
2140            .field("num_questions", &self.num_questions)
2141            .field("num_answers", &self.num_answers)
2142            .field("num_authorities", &self.num_authorities)
2143            .field("num_additionals", &self.num_additionals)
2144            .field("interface_id", &self.interface_id)
2145            .finish()
2146    }
2147}
2148
2149impl DnsIncoming {
2150    pub fn new(data: Vec<u8>, interface_id: InterfaceId) -> Result<Self> {
2151        let mut incoming = Self {
2152            offset: 0,
2153            data,
2154            questions: Vec::new(),
2155            answers: Vec::new(),
2156            authorities: Vec::new(),
2157            additional: Vec::new(),
2158            id: 0,
2159            flags: 0,
2160            num_questions: 0,
2161            num_answers: 0,
2162            num_authorities: 0,
2163            num_additionals: 0,
2164            interface_id,
2165        };
2166
2167        /*
2168        RFC 1035 section 4.1: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1
2169        ...
2170        All communications inside of the domain protocol are carried in a single
2171        format called a message.  The top level format of message is divided
2172        into 5 sections (some of which are empty in certain cases) shown below:
2173
2174            +---------------------+
2175            |        Header       |
2176            +---------------------+
2177            |       Question      | the question for the name server
2178            +---------------------+
2179            |        Answer       | RRs answering the question
2180            +---------------------+
2181            |      Authority      | RRs pointing toward an authority
2182            +---------------------+
2183            |      Additional     | RRs holding additional information
2184            +---------------------+
2185         */
2186        if let Err(e) = incoming.read_sections() {
2187            return Err(Error::Msg(format!(
2188                "{e}; raw packet length: {}",
2189                incoming.data.len(),
2190            )));
2191        }
2192
2193        Ok(incoming)
2194    }
2195
2196    /// Reads the five message sections in order. Kept separate from `new` so a
2197    /// parse failure can be annotated with the raw packet bytes.
2198    fn read_sections(&mut self) -> Result<()> {
2199        self.read_header()?;
2200        self.read_questions()?;
2201        self.read_answers()?;
2202        self.read_authorities()?;
2203        self.read_additional()?;
2204        Ok(())
2205    }
2206
2207    pub fn id(&self) -> u16 {
2208        self.id
2209    }
2210
2211    pub fn questions(&self) -> &[DnsQuestion] {
2212        &self.questions
2213    }
2214
2215    pub fn answers(&self) -> &[DnsRecordBox] {
2216        &self.answers
2217    }
2218
2219    pub fn authorities(&self) -> &[DnsRecordBox] {
2220        &self.authorities
2221    }
2222
2223    pub fn additionals(&self) -> &[DnsRecordBox] {
2224        &self.additional
2225    }
2226
2227    pub fn answers_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2228        &mut self.answers
2229    }
2230
2231    pub fn authorities_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2232        &mut self.authorities
2233    }
2234
2235    pub fn additionals_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2236        &mut self.additional
2237    }
2238
2239    pub fn all_records(self) -> impl Iterator<Item = DnsRecordBox> {
2240        self.answers
2241            .into_iter()
2242            .chain(self.authorities)
2243            .chain(self.additional)
2244    }
2245
2246    pub fn num_additionals(&self) -> u16 {
2247        self.num_additionals
2248    }
2249
2250    pub fn num_authorities(&self) -> u16 {
2251        self.num_authorities
2252    }
2253
2254    pub fn num_questions(&self) -> u16 {
2255        self.num_questions
2256    }
2257
2258    pub const fn is_query(&self) -> bool {
2259        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
2260    }
2261
2262    pub const fn is_response(&self) -> bool {
2263        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
2264    }
2265
2266    fn read_header(&mut self) -> Result<()> {
2267        if self.data.len() < MSG_HEADER_LEN {
2268            return Err(e_fmt!(
2269                "DNS incoming: header is too short: {} bytes",
2270                self.data.len()
2271            ));
2272        }
2273
2274        let data = &self.data[0..];
2275        self.id = u16_from_be_slice(&data[..2]);
2276        self.flags = u16_from_be_slice(&data[2..4]);
2277        self.num_questions = u16_from_be_slice(&data[4..6]);
2278        self.num_answers = u16_from_be_slice(&data[6..8]);
2279        self.num_authorities = u16_from_be_slice(&data[8..10]);
2280        self.num_additionals = u16_from_be_slice(&data[10..12]);
2281
2282        self.offset = MSG_HEADER_LEN;
2283
2284        trace!(
2285            "read_header: id {}, {} questions {} answers {} authorities {} additionals",
2286            self.id,
2287            self.num_questions,
2288            self.num_answers,
2289            self.num_authorities,
2290            self.num_additionals
2291        );
2292        Ok(())
2293    }
2294
2295    fn read_questions(&mut self) -> Result<()> {
2296        trace!("read_questions: {}", &self.num_questions);
2297        for i in 0..self.num_questions {
2298            let name = self.read_name()?;
2299
2300            let data = &self.data[self.offset..];
2301            if data.len() < 4 {
2302                return Err(Error::Msg(format!(
2303                    "DNS incoming: question idx {} too short: {}",
2304                    i,
2305                    data.len()
2306                )));
2307            }
2308            let ty = u16_from_be_slice(&data[..2]);
2309            let class = u16_from_be_slice(&data[2..4]);
2310            self.offset += 4;
2311
2312            let Some(rr_type) = RRType::from_u16(ty) else {
2313                return Err(Error::Msg(format!(
2314                    "DNS incoming: question idx {i} qtype unknown: {ty}",
2315                )));
2316            };
2317
2318            self.questions.push(DnsQuestion {
2319                entry: DnsEntry::new(name, rr_type, class),
2320            });
2321        }
2322        Ok(())
2323    }
2324
2325    fn read_answers(&mut self) -> Result<()> {
2326        self.answers = self.read_rr_records(self.num_answers)?;
2327        Ok(())
2328    }
2329
2330    fn read_authorities(&mut self) -> Result<()> {
2331        self.authorities = self.read_rr_records(self.num_authorities)?;
2332        Ok(())
2333    }
2334
2335    fn read_additional(&mut self) -> Result<()> {
2336        self.additional = self.read_rr_records(self.num_additionals)?;
2337        Ok(())
2338    }
2339
2340    /// Decodes a sequence of RR records (in answers, authorities and additionals).
2341    fn read_rr_records(&mut self, count: u16) -> Result<Vec<DnsRecordBox>> {
2342        trace!("read_rr_records: {}", count);
2343        let mut rr_records = Vec::new();
2344
2345        // RFC 1035: https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.1
2346        //
2347        // All RRs have the same top level format shown below:
2348        //                               1  1  1  1  1  1
2349        // 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
2350        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2351        // |                                               |
2352        // /                                               /
2353        // /                      NAME                     /
2354        // |                                               |
2355        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2356        // |                      TYPE                     |
2357        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2358        // |                     CLASS                     |
2359        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2360        // |                      TTL                      |
2361        // |                                               |
2362        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2363        // |                   RDLENGTH                    |
2364        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
2365        // /                     RDATA                     /
2366        // /                                               /
2367        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
2368
2369        // Muse have at least TYPE, CLASS, TTL, RDLENGTH fields: 10 bytes.
2370        const RR_HEADER_REMAIN: usize = 10;
2371
2372        for _ in 0..count {
2373            let name = self.read_name()?;
2374            let slice = &self.data[self.offset..];
2375
2376            if slice.len() < RR_HEADER_REMAIN {
2377                return Err(Error::Msg(format!(
2378                    "read_others: RR '{}' is too short after name: {} bytes",
2379                    &name,
2380                    slice.len()
2381                )));
2382            }
2383
2384            let ty = u16_from_be_slice(&slice[..2]);
2385            let class = u16_from_be_slice(&slice[2..4]);
2386            let mut ttl = u32_from_be_slice(&slice[4..8]);
2387            if ttl == 0 && self.is_response() {
2388                // RFC 6762 section 10.1:
2389                // "...Queriers receiving a Multicast DNS response with a TTL of zero SHOULD
2390                // NOT immediately delete the record from the cache, but instead record
2391                // a TTL of 1 and then delete the record one second later."
2392                // See https://datatracker.ietf.org/doc/html/rfc6762#section-10.1
2393
2394                ttl = 1;
2395            }
2396            let rdata_len = u16_from_be_slice(&slice[8..10]) as usize;
2397            self.offset += RR_HEADER_REMAIN;
2398            let next_offset = self.offset + rdata_len;
2399
2400            // Sanity check for RDATA length.
2401            if next_offset > self.data.len() {
2402                return Err(Error::Msg(format!(
2403                    "RR {name} RDATA length {rdata_len} is invalid: remain data len: {}",
2404                    self.data.len() - self.offset
2405                )));
2406            }
2407
2408            // Decode the RDATA based on the record type. A single record with
2409            // malformed RDATA must not discard the whole message: skip just
2410            // that record and resume at the next one using RDLENGTH.
2411            match self.read_rdata(ty, class, ttl, rdata_len, &name) {
2412                Ok(Some(record)) => {
2413                    if self.offset == next_offset {
2414                        trace!("read_rr_records: {:?}", &record);
2415                        rr_records.push(record);
2416                    } else {
2417                        debug!(
2418                            "skipping record '{}' (type {}): RDATA ended at {}, expected {}",
2419                            &name, ty, self.offset, next_offset
2420                        );
2421                    }
2422                }
2423                Ok(None) => {
2424                    trace!("Unsupported DNS record type: {} name: {}", ty, &name);
2425                }
2426                Err(e) => {
2427                    debug!(
2428                        "skipping record '{}' (type {}) with invalid RDATA: {}",
2429                        &name, ty, e,
2430                    );
2431                }
2432            }
2433
2434            // Re-anchor to the record boundary defined by RDLENGTH, regardless
2435            // of how the RDATA decoded, so the next record is read from the
2436            // correct offset.
2437            self.offset = next_offset;
2438        }
2439
2440        Ok(rr_records)
2441    }
2442
2443    /// Decodes the RDATA of a single record whose header fields have already
2444    /// been read, returning `None` for record types we do not parse.
2445    ///
2446    /// On success the read cursor is left at the end of the RDATA; the caller
2447    /// verifies that against RDLENGTH. Errors are per-record: the caller skips
2448    /// the offending record and continues with the rest of the message.
2449    fn read_rdata(
2450        &mut self,
2451        ty: u16,
2452        class: u16,
2453        ttl: u32,
2454        rdata_len: usize,
2455        name: &str,
2456    ) -> Result<Option<DnsRecordBox>> {
2457        let rec: Option<DnsRecordBox> = match RRType::from_u16(ty) {
2458            None => None,
2459
2460            Some(rr_type) => match rr_type {
2461                RRType::CNAME | RRType::PTR => {
2462                    Some(DnsPointer::new(name, rr_type, class, ttl, self.read_name()?).boxed())
2463                }
2464                RRType::TXT => {
2465                    Some(DnsTxt::new(name, class, ttl, self.read_vec(rdata_len)?).boxed())
2466                }
2467                RRType::SRV => Some(
2468                    DnsSrv::new(
2469                        name,
2470                        class,
2471                        ttl,
2472                        self.read_u16()?,
2473                        self.read_u16()?,
2474                        self.read_u16()?,
2475                        self.read_name()?,
2476                    )
2477                    .boxed(),
2478                ),
2479                RRType::HINFO => Some(
2480                    DnsHostInfo::new(
2481                        name,
2482                        rr_type,
2483                        class,
2484                        ttl,
2485                        self.read_char_string()?,
2486                        self.read_char_string()?,
2487                    )
2488                    .boxed(),
2489                ),
2490                RRType::A => Some(
2491                    DnsAddress::new(
2492                        name,
2493                        rr_type,
2494                        class,
2495                        ttl,
2496                        self.read_ipv4()?.into(),
2497                        self.interface_id.clone(),
2498                    )
2499                    .boxed(),
2500                ),
2501                RRType::AAAA => Some(
2502                    DnsAddress::new(
2503                        name,
2504                        rr_type,
2505                        class,
2506                        ttl,
2507                        self.read_ipv6()?.into(),
2508                        self.interface_id.clone(),
2509                    )
2510                    .boxed(),
2511                ),
2512                RRType::NSEC => Some(
2513                    DnsNSec::new(
2514                        name,
2515                        class,
2516                        ttl,
2517                        self.read_name()?,
2518                        self.read_type_bitmap()?,
2519                    )
2520                    .boxed(),
2521                ),
2522                _ => None,
2523            },
2524        };
2525
2526        Ok(rec)
2527    }
2528
2529    fn read_char_string(&mut self) -> Result<String> {
2530        let Some(&length) = self.data.get(self.offset) else {
2531            return Err(e_fmt!(
2532                "read_char_string: no length byte at offset {}, data len {}",
2533                self.offset,
2534                self.data.len()
2535            ));
2536        };
2537        self.offset += 1;
2538        self.read_string(length as usize)
2539    }
2540
2541    fn read_u16(&mut self) -> Result<u16> {
2542        let slice = &self.data[self.offset..];
2543        if slice.len() < U16_SIZE {
2544            return Err(Error::Msg(format!(
2545                "read_u16: slice len is only {}",
2546                slice.len()
2547            )));
2548        }
2549        let num = u16_from_be_slice(&slice[..U16_SIZE]);
2550        self.offset += U16_SIZE;
2551        Ok(num)
2552    }
2553
2554    /// Reads the "Type Bit Map" block for a DNS NSEC record.
2555    fn read_type_bitmap(&mut self) -> Result<Vec<u8>> {
2556        // From RFC 6762: 6.1.  Negative Responses
2557        // https://datatracker.ietf.org/doc/html/rfc6762#section-6.1
2558        //   o The Type Bit Map block number is 0.
2559        //   o The Type Bit Map block length byte is a value in the range 1-32.
2560        //   o The Type Bit Map data is 1-32 bytes, as indicated by length
2561        //     byte.
2562
2563        // Sanity check: at least 2 bytes to read.
2564        if self.data.len() < self.offset + 2 {
2565            return Err(Error::Msg(format!(
2566                "DnsIncoming is too short: {} at NSEC Type Bit Map offset {}",
2567                self.data.len(),
2568                self.offset
2569            )));
2570        }
2571
2572        let block_num = self.data[self.offset];
2573        self.offset += 1;
2574        if block_num != 0 {
2575            return Err(Error::Msg(format!(
2576                "NSEC block number is not 0: {block_num}"
2577            )));
2578        }
2579
2580        let block_len = self.data[self.offset] as usize;
2581        if !(1..=32).contains(&block_len) {
2582            return Err(Error::Msg(format!(
2583                "NSEC block length must be in the range 1-32: {block_len}"
2584            )));
2585        }
2586        self.offset += 1;
2587
2588        let end = self.offset + block_len;
2589        if end > self.data.len() {
2590            return Err(Error::Msg(format!(
2591                "NSEC block overflow: {} over RData len {}",
2592                end,
2593                self.data.len()
2594            )));
2595        }
2596        let bitmap = self.data[self.offset..end].to_vec();
2597        self.offset += block_len;
2598
2599        Ok(bitmap)
2600    }
2601
2602    fn read_vec(&mut self, length: usize) -> Result<Vec<u8>> {
2603        if self.data.len() < self.offset + length {
2604            return Err(e_fmt!(
2605                "DNS Incoming: not enough data to read a chunk of data"
2606            ));
2607        }
2608
2609        let v = self.data[self.offset..self.offset + length].to_vec();
2610        self.offset += length;
2611        Ok(v)
2612    }
2613
2614    fn read_ipv4(&mut self) -> Result<Ipv4Addr> {
2615        if self.data.len() < self.offset + 4 {
2616            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV4"));
2617        }
2618
2619        let bytes: [u8; 4] = self.data[self.offset..self.offset + 4]
2620            .try_into()
2621            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV4"))?;
2622        self.offset += bytes.len();
2623        Ok(Ipv4Addr::from(bytes))
2624    }
2625
2626    fn read_ipv6(&mut self) -> Result<Ipv6Addr> {
2627        if self.data.len() < self.offset + 16 {
2628            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV6"));
2629        }
2630
2631        let bytes: [u8; 16] = self.data[self.offset..self.offset + 16]
2632            .try_into()
2633            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV6"))?;
2634        self.offset += bytes.len();
2635        Ok(Ipv6Addr::from(bytes))
2636    }
2637
2638    fn read_string(&mut self, length: usize) -> Result<String> {
2639        if self.data.len() < self.offset + length {
2640            return Err(e_fmt!("DNS Incoming: not enough data to read a string"));
2641        }
2642
2643        let s = str::from_utf8(&self.data[self.offset..self.offset + length])
2644            .map_err(|e| Error::Msg(e.to_string()))?;
2645        self.offset += length;
2646        Ok(s.to_string())
2647    }
2648
2649    /// Reads a domain name at the current location of `self.data`.
2650    ///
2651    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 for
2652    /// domain name encoding.
2653    fn read_name(&mut self) -> Result<String> {
2654        let mut name = String::new();
2655        self.offset = self.read_labels(self.offset, &mut name)?;
2656        Ok(name)
2657    }
2658
2659    /// Appends the labels encoded at `offset` to `name`, and returns the offset
2660    /// just past that encoding: past the terminating zero byte, or past the
2661    /// compression pointer that ended the name.
2662    ///
2663    /// A name is a sequence of labels, where each label is a length byte
2664    /// followed by that many bytes. The name ends either with a zero length
2665    /// byte, or with a "compression pointer" (top 2 bits set) that redirects
2666    /// to a name written earlier in the same packet.
2667    ///
2668    /// For example, a packet where the question name `_http._tcp.local.` is
2669    /// written out in full at offset 12, and the answer name
2670    /// `myprinter._http._tcp.local.` at offset 40 reuses it via compression:
2671    ///
2672    /// ```text
2673    ///  offset:  12   13..17    18   19..22   23   24..28    29
2674    ///          +----+---------+----+--------+----+---------+----+
2675    ///  bytes:  | 05 | "_http" | 04 | "_tcp" | 05 | "local" | 00 |
2676    ///          +----+---------+----+--------+----+---------+----+
2677    ///            ^len           ^len          ^len           ^ zero byte: end of name
2678    ///
2679    ///  offset:  40    41..49     50   51
2680    ///          +----+-------------+----+----+
2681    ///  bytes:  | 09 | "myprinter" | C0 | 0C |
2682    ///          +----+-------------+----+----+
2683    ///            ^len               ^ pointer: 0xC00C ^ 0xC000 = 12, jump back to offset 12
2684    /// ```
2685    ///
2686    /// Takes `&self` so that following a pointer cannot move the read cursor.
2687    fn read_labels(&self, mut offset: usize, name: &mut String) -> Result<usize> {
2688        let data = &self.data[..];
2689
2690        // From RFC1035:
2691        // "...Domain names in messages are expressed in terms of a sequence of labels.
2692        // Each label is represented as a one octet length field followed by that
2693        // number of octets."
2694        //
2695        // "...The compression scheme allows a domain name in a message to be
2696        // represented as either:
2697        // - a sequence of labels ending in a zero octet
2698        // - a pointer
2699        // - a sequence of labels ending with a pointer"
2700        loop {
2701            if offset >= data.len() {
2702                return Err(Error::Msg(format!(
2703                    "read_labels: offset: {} data len {}",
2704                    offset,
2705                    data.len(),
2706                )));
2707            }
2708            let length = data[offset];
2709
2710            // From RFC1035:
2711            // "...a domain name is terminated by a length byte of zero."
2712            if length == 0 {
2713                return Ok(offset + 1); // The end of the name.
2714            }
2715
2716            // Check the first 2 bits for possible "Message compression".
2717            match length & 0xC0 {
2718                0x00 => {
2719                    // regular utf8 string with length
2720                    offset += 1;
2721                    let ending = offset + length as usize;
2722
2723                    // Never read beyond the whole data length.
2724                    if ending > data.len() {
2725                        return Err(Error::Msg(format!(
2726                            "read_labels: ending {} exceeds data length {}",
2727                            ending,
2728                            data.len()
2729                        )));
2730                    }
2731
2732                    let label = str::from_utf8(&data[offset..ending])
2733                        .map_err(|e| Error::Msg(format!("read_labels: from_utf8: {e}")))?;
2734
2735                    // `MAX_NAME_BYTES` bounds a possible loop where pointer targets a label that
2736                    // is already part of the current name. For example:
2737                    //
2738                    //  offset:  12   13..17    18   19
2739                    //          +----+---------+----+----+
2740                    //  bytes:  | 05 | "_http" | C0 | 0C |
2741                    //          +----+---------+----+----+
2742                    //            ^len           ^pointer targets offset 12.
2743                    if name.len() + label.len() + 1 > MAX_NAME_BYTES {
2744                        return Err(Error::Msg(format!(
2745                            "read_labels: name exceeds {MAX_NAME_BYTES} bytes: {name}"
2746                        )));
2747                    }
2748
2749                    *name += label;
2750                    *name += ".";
2751                    offset = ending;
2752                }
2753                0xC0 => {
2754                    // Message compression: a pointer marks the end of a domain name.
2755                    self.follow_pointer(offset, name)?;
2756                    return Ok(offset + U16_SIZE);
2757                }
2758                _ => {
2759                    return Err(Error::Msg(format!(
2760                        "Bad name with invalid length: 0x{:x} offset {}, data (so far): {:x?}",
2761                        length,
2762                        offset,
2763                        &data[..offset]
2764                    )));
2765                }
2766            };
2767        }
2768    }
2769
2770    /// Follows the compression pointer at offset `at`, appending the labels it
2771    /// names to `name`.
2772    ///
2773    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4 for
2774    /// message compression.
2775    fn follow_pointer(&self, at: usize, name: &mut String) -> Result<()> {
2776        let data = &self.data[..];
2777        let mut pointer_at = at;
2778
2779        // Resolve a run of pointers that target other pointers, so that the
2780        // recursive call below always lands on a label or on the end of a name.
2781        let target = loop {
2782            let slice = &data[pointer_at..];
2783            if slice.len() < U16_SIZE {
2784                return Err(Error::Msg(format!(
2785                    "follow_pointer: u16 slice len is only {}",
2786                    slice.len()
2787                )));
2788            }
2789            let target = (u16_from_be_slice(slice) ^ 0xC000) as usize;
2790
2791            // RFC1035 section 4.1.4 compresses a name into "a pointer to a prior
2792            // occurrence", so a pointer always points strictly backwards.
2793            if target >= pointer_at {
2794                return Err(Error::Msg(format!(
2795                    "Invalid name compression: pointer {target} at offset {pointer_at} must point backwards"
2796                )));
2797            }
2798
2799            if data[target] & 0xC0 != 0xC0 {
2800                break target;
2801            }
2802
2803            // The target is itself a pointer, so follow it.
2804            pointer_at = target;
2805        };
2806
2807        self.read_labels(target, name)?;
2808        Ok(())
2809    }
2810}
2811
2812const fn u16_from_be_slice(bytes: &[u8]) -> u16 {
2813    let u8_array: [u8; 2] = [bytes[0], bytes[1]];
2814    u16::from_be_bytes(u8_array)
2815}
2816
2817const fn u32_from_be_slice(s: &[u8]) -> u32 {
2818    let u8_array: [u8; 4] = [s[0], s[1], s[2], s[3]];
2819    u32::from_be_bytes(u8_array)
2820}
2821
2822/// Returns the UNIX time in millis at which this record will have expired
2823/// by a certain percentage.
2824const fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
2825    // 'created' is in millis, 'ttl' is in seconds, hence:
2826    // ttl * 1000 * (percent / 100) => ttl * percent * 10
2827    created + (ttl as u64 * percent as u64 * 10)
2828}
2829
2830#[cfg(test)]
2831mod tests {
2832    use super::{
2833        u16_from_be_slice, DnsAddress, DnsHostInfo, DnsIncoming, DnsOutPacket, DnsOutgoing,
2834        DnsPointer, DnsTxt, RRType, CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
2835        FLAGS_TC, MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MSG_HEADER_LEN,
2836    };
2837    use crate::InterfaceId;
2838    use std::collections::HashMap;
2839    use std::net::{IpAddr, Ipv4Addr};
2840
2841    /// The `is_ipv4` argument of `to_packets`. IPv6 has the smaller of the two
2842    /// absolute ceilings, so it is the stricter one to encode for.
2843    const IPV6: bool = false;
2844
2845    /// Found by fuzzing the packet parser.
2846    ///
2847    /// An HINFO record with RDLENGTH 0 placed at the very end of a message left
2848    /// `read_char_string` with no length octet to read, and it indexed one byte
2849    /// past the packet.
2850    #[test]
2851    fn test_hinfo_char_string_at_end_of_packet() {
2852        let mut data = Vec::new();
2853
2854        // Header: one authority record, and a query (so the TTL is not rewritten).
2855        data.extend_from_slice(&0x0087u16.to_be_bytes()); // id
2856        data.extend_from_slice(&0x0084u16.to_be_bytes()); // flags: a query
2857        data.extend_from_slice(&0u16.to_be_bytes()); // 0 questions
2858        data.extend_from_slice(&0u16.to_be_bytes()); // 0 answers
2859        data.extend_from_slice(&1u16.to_be_bytes()); // 1 authorities
2860        data.extend_from_slice(&0u16.to_be_bytes()); // 0 additionals
2861
2862        data.push(0); // name: root
2863        data.extend_from_slice(&(RRType::HINFO as u16).to_be_bytes());
2864        data.extend_from_slice(&CLASS_IN.to_be_bytes());
2865        data.extend_from_slice(&0u32.to_be_bytes()); // ttl
2866
2867        // RDLENGTH is 0, so the record — and the message — end here, leaving
2868        // nothing for HINFO's two <character-string> fields.
2869        data.extend_from_slice(&0u16.to_be_bytes()); // rdlength
2870
2871        assert_eq!(data.len(), 23);
2872
2873        let parsed = DnsIncoming::new(data, test_interface_id())
2874            .expect("a truncated HINFO must be skipped, not fail the packet");
2875
2876        // The record is dropped, and nothing is left behind.
2877        assert_eq!(parsed.authorities().len(), 0);
2878    }
2879
2880    #[test]
2881    fn test_dns_outgoing_serialization_empty() {
2882        let out = DnsOutgoing::new(0);
2883        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2884        assert_eq!(packets.len(), 1);
2885        assert_eq!(packets[0].as_bytes(), &[0; 12]);
2886        let expected_names = HashMap::new();
2887        assert_eq!(&packets[0].names, &expected_names);
2888    }
2889
2890    #[test]
2891    fn test_dns_outgoing_serialization_question() {
2892        let mut out = DnsOutgoing::new(0);
2893        out.add_question("123.test", RRType::A);
2894        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2895        assert_eq!(packets.len(), 1);
2896        assert_eq!(
2897            packets[0].as_bytes(),
2898            &[
2899                0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Header
2900                // Payload
2901                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
2902            ]
2903        );
2904        let mut expected_names = HashMap::new();
2905        expected_names.insert("123.test".to_string(), 12);
2906        expected_names.insert("test".to_string(), 16);
2907        assert_eq!(&packets[0].names, &expected_names);
2908    }
2909
2910    #[test]
2911    fn test_dns_outgoing_serialization_question_with_authority() {
2912        let mut out = DnsOutgoing::new(0);
2913        out.add_question("123.test", RRType::ANY);
2914        out.add_authority(Box::new(DnsTxt::new(
2915            "124.test",
2916            CLASS_IN,
2917            0x00112233,
2918            b"help".to_vec(),
2919        )));
2920        out.add_authority(Box::new(DnsHostInfo::new(
2921            "124.test",
2922            RRType::CNAME,
2923            CLASS_IN,
2924            0x00112233,
2925            "arm".to_string(),
2926            "linux".to_string(),
2927        )));
2928        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2929        assert_eq!(packets.len(), 1);
2930        assert_eq!(
2931            packets[0].as_bytes(),
2932            &[
2933                0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, // Header
2934                // Payload
2935                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 255, 0, 1, 3, 49, 50, 52, 192, 16, 0,
2936                16, 0, 1, 0, 17, 34, 51, 0, 4, 104, 101, 108, 112, 192, 26, 0, 5, 0, 1, 0, 17, 34,
2937                51, 0, 8, 97, 114, 109, 108, 105, 110, 117, 120,
2938            ]
2939        );
2940        let mut expected_names = HashMap::new();
2941        expected_names.insert("123.test".to_string(), 12);
2942        expected_names.insert("test".to_string(), 16);
2943        expected_names.insert("124.test".to_string(), 26);
2944        assert_eq!(&packets[0].names, &expected_names);
2945    }
2946
2947    #[test]
2948    fn test_dns_outgoing_serialization_additional_answer() {
2949        let mut out = DnsOutgoing::new(0);
2950        out.add_additional_answer(DnsAddress::new(
2951            "test.local",
2952            RRType::A,
2953            CLASS_IN | CLASS_CACHE_FLUSH,
2954            0xdead_beef,
2955            IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
2956            InterfaceId::default(),
2957        ));
2958        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2959        assert_eq!(packets.len(), 1);
2960        assert_eq!(
2961            packets[0].as_bytes(),
2962            &[
2963                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // Header
2964                // Payload
2965                4, 116, 101, 115, 116, 5, 108, 111, 99, 97, 108, 0, 0, 1, 128, 1, 222, 173, 190,
2966                239, 0, 4, 127, 0, 0, 1,
2967            ]
2968        );
2969        let mut expected_names = HashMap::new();
2970        expected_names.insert("test.local".to_string(), 12);
2971        expected_names.insert("local".to_string(), 17);
2972        assert_eq!(&packets[0].names, &expected_names);
2973    }
2974
2975    #[test]
2976    fn test_dns_outgoing_serialization_answer_at_time() {
2977        let mut out = DnsOutgoing::new(0);
2978        out.add_answer_at_time(
2979            DnsPointer::new(
2980                "test",
2981                RRType::PTR,
2982                CLASS_IN,
2983                0xaaaa5555,
2984                "test-service".to_string(),
2985            ),
2986            0,
2987        );
2988        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2989        assert_eq!(packets.len(), 1);
2990        assert_eq!(
2991            packets[0].as_bytes(),
2992            &[
2993                0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // Header
2994                // Payload
2995                4, 116, 101, 115, 116, 0, 0, 12, 0, 1, 170, 170, 85, 85, 0, 14, 12, 116, 101, 115,
2996                116, 45, 115, 101, 114, 118, 105, 99, 101, 0,
2997            ]
2998        );
2999
3000        let mut out = DnsOutgoing::new(0);
3001        out.add_answer_at_time(
3002            DnsPointer::new(
3003                "test",
3004                RRType::CNAME,
3005                CLASS_IN,
3006                0xaaaa5555,
3007                "test-service.local".to_string(),
3008            ),
3009            0,
3010        );
3011        out.add_answer_at_time(
3012            DnsPointer::new(
3013                "test",
3014                RRType::AAAA,
3015                CLASS_IN,
3016                0xffffffff,
3017                "test-service.local".to_string(),
3018            ),
3019            0,
3020        );
3021        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3022        assert_eq!(packets.len(), 1);
3023        assert_eq!(
3024            packets[0].as_bytes(),
3025            &[
3026                0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, // Header
3027                // Payload
3028                4, 116, 101, 115, 116, 0, 0, 5, 0, 1, 170, 170, 85, 85, 0, 20, 12, 116, 101, 115,
3029                116, 45, 115, 101, 114, 118, 105, 99, 101, 5, 108, 111, 99, 97, 108, 0, 192, 12, 0,
3030                28, 0, 1, 255, 255, 255, 255, 0, 2, 192, 28,
3031            ]
3032        );
3033        let mut expected_names = HashMap::new();
3034        expected_names.insert("test".to_string(), 12);
3035        expected_names.insert("test-service.local".to_string(), 28);
3036        expected_names.insert("local".to_string(), 41);
3037        assert_eq!(&packets[0].names, &expected_names);
3038    }
3039
3040    /// A question whose name has a label longer than 63 bytes cannot be
3041    /// encoded. It must be skipped, not panic. (Note the question count in the
3042    /// header must reflect the questions actually written.)
3043    #[test]
3044    fn test_dns_outgoing_question_label_too_long() {
3045        let long_label = "a".repeat(64);
3046        let mut out = DnsOutgoing::new(0);
3047        out.add_question(&format!("{long_label}.local"), RRType::PTR);
3048        out.add_question("123.test", RRType::A);
3049
3050        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3051        assert_eq!(packets.len(), 1);
3052        assert_eq!(
3053            packets[0].as_bytes(),
3054            &[
3055                0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // Header: 1 question
3056                // Payload: only "123.test" made it in.
3057                3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
3058            ]
3059        );
3060
3061        // The rolled back name must not leave a stale compression offset behind.
3062        let mut expected_names = HashMap::new();
3063        expected_names.insert("123.test".to_string(), 12);
3064        expected_names.insert("test".to_string(), 16);
3065        assert_eq!(&packets[0].names, &expected_names);
3066    }
3067
3068    /// A record whose rdata carries an unencodable name (here a PTR alias) is
3069    /// dropped as a whole, leaving the rest of the packet intact.
3070    #[test]
3071    fn test_dns_outgoing_record_label_too_long() {
3072        let long_label = "a".repeat(64);
3073        let mut out = DnsOutgoing::new(0);
3074        out.add_answer_at_time(
3075            DnsPointer::new(
3076                "_test._tcp.local.",
3077                RRType::PTR,
3078                CLASS_IN,
3079                0,
3080                format!("{long_label}._test._tcp.local."),
3081            ),
3082            0,
3083        );
3084        out.add_answer_at_time(
3085            DnsPointer::new(
3086                "_test._tcp.local.",
3087                RRType::PTR,
3088                CLASS_IN,
3089                0,
3090                "ok._test._tcp.local.".to_string(),
3091            ),
3092            0,
3093        );
3094
3095        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3096        assert_eq!(packets.len(), 1);
3097
3098        // Header answer count is 1: the first answer was dropped.
3099        assert_eq!(&packets[0].as_bytes()[6..8], &[0, 1]);
3100
3101        // Re-parsing must succeed and yield only the good answer.
3102        let incoming = DnsIncoming::new(
3103            packets[0].as_bytes().to_vec(),
3104            InterfaceId {
3105                name: "test".to_string(),
3106                index: 1,
3107            },
3108        )
3109        .unwrap();
3110        assert_eq!(incoming.answers().len(), 1);
3111    }
3112
3113    /// A name learned from the network can hold a label that ends with a
3114    /// backslash, which escapes the following label separator. Unescaping such
3115    /// a name on the way out merges two 63-byte labels into a 127-byte one.
3116    /// This used to panic the daemon thread. See issue #483.
3117    #[test]
3118    fn test_incoming_name_with_merged_labels_does_not_panic() {
3119        // A query with one question: "aa..a\" + "bb..b", 63 bytes each.
3120        let mut data: Vec<u8> = vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0];
3121        data.push(63);
3122        data.extend(vec![b'a'; 62]);
3123        data.push(b'\\');
3124        data.push(63);
3125        data.extend(vec![b'b'; 63]);
3126        data.push(0);
3127        data.extend([0, 12, 0, 1]); // PTR, IN
3128
3129        let incoming = DnsIncoming::new(
3130            data,
3131            InterfaceId {
3132                name: "test".to_string(),
3133                index: 1,
3134            },
3135        )
3136        .unwrap();
3137        let name = incoming.questions()[0].entry.name.clone();
3138
3139        // The two labels merged: the trailing backslash escaped the separator.
3140        assert!(name.starts_with("aaa"));
3141        assert!(name.contains("\\.bbb"));
3142
3143        // Re-emitting it must drop the question rather than panic.
3144        let mut out = DnsOutgoing::new(0);
3145        out.add_question(&name, RRType::PTR);
3146        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3147        assert_eq!(packets.len(), 1);
3148        assert_eq!(packets[0].as_bytes(), &[0; MSG_HEADER_LEN]);
3149    }
3150
3151    /// A pointer that points into the name currently being read is a loop:
3152    /// following it re-reads the same labels and arrives at the same pointer
3153    /// again. `read_name` must reject such a name instead of hanging.
3154    #[test]
3155    fn test_read_name_pointer_loop_is_rejected() {
3156        // A response with one PTR record. Its name starts at offset 12 and is
3157        // encoded as: label "local", label "_x", then a pointer back to 12,
3158        // i.e. to the "local" label of this very name.
3159        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 1, 0, 0, 0, 0];
3160        data.extend_from_slice(&[5, b'l', b'o', b'c', b'a', b'l']); // offset 12
3161        data.extend_from_slice(&[2, b'_', b'x']); // offset 18
3162        data.extend_from_slice(&[0xC0, 12]); // offset 21: pointer to 12
3163        data.extend_from_slice(&[0, 12, 0, 1]); // PTR, IN
3164        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3165        data.extend_from_slice(&[0, 2]); // RDLENGTH
3166        data.extend_from_slice(&[0xC0, 12]); // RDATA: pointer to 12
3167
3168        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3169    }
3170
3171    /// A legal name that follows a pointer backwards and then meets a second
3172    /// pointer whose target sits *after* the start of the name being read, yet
3173    /// still strictly *before* that second pointer's own position.
3174    ///
3175    /// Such a message probably never appears in reality, but it still has to parse.
3176    /// Reading the answer's name walks: 700 -> 640 -> 62-byte label -> 703 ->
3177    /// 702 -> zero byte, name complete.
3178    #[test]
3179    fn test_read_name_pointer_after_backward_jump() {
3180        /// Appends a question: one label of `label_len` 'a' bytes, PTR, IN.
3181        fn push_question(data: &mut Vec<u8>, label_len: usize) {
3182            data.push(label_len as u8);
3183            data.extend(vec![b'a'; label_len]);
3184            data.push(0); // end of the name
3185            data.extend_from_slice(&[0, 12]); // QTYPE: PTR
3186            data.extend_from_slice(&[0, 1]); // QCLASS: IN
3187        }
3188
3189        let mut data: Vec<u8> = vec![
3190            0, 0, // ID
3191            0, 0, // flags: a query
3192            0, 11, // 11 questions
3193            0, 1, // 1 answer
3194            0, 0, 0, 0, // no authorities, no additionals
3195        ];
3196
3197        // Questions #1 to #10, 66 bytes each: 12 + 660 = 672.
3198        for _ in 0..10 {
3199            push_question(&mut data, 60);
3200        }
3201        assert_eq!(data.len(), 672);
3202
3203        // Question #11, 28 bytes, so that the answer record starts at 700.
3204        push_question(&mut data, 22);
3205        assert_eq!(data.len(), 700);
3206
3207        // Plant the label length inside question #10's label.
3208        data[640] = 62;
3209
3210        // The answer record.
3211        data.extend_from_slice(&[0xC2, 0x80]); // 700: name: pointer to 640
3212        data.extend_from_slice(&[0x00, 0xC2]); // 702: TYPE, unknown type 194
3213        data.extend_from_slice(&[0xBE, 0x01]); // 704: CLASS. 703..705 is a pointer to 702
3214        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3215        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3216
3217        // Both pointers point backwards from where they are.
3218        assert_eq!(u16_from_be_slice(&data[700..702]) ^ 0xC000, 640);
3219        assert_eq!(u16_from_be_slice(&data[703..705]) ^ 0xC000, 702);
3220
3221        let incoming = DnsIncoming::new(data, test_interface_id())
3222            .expect("a name whose pointers all point backwards must parse");
3223        assert_eq!(incoming.questions().len(), 11);
3224
3225        // The answer's type is unknown to us, so the record itself is skipped.
3226        assert_eq!(incoming.answers().len(), 0);
3227    }
3228
3229    /// Two pointers at offsets 23 and 25 that target each other (23 -> 25 ->
3230    /// 23). Both sit below offset 27, where the name starts.
3231    ///
3232    /// `follow_pointer` requires each target to be strictly below the
3233    /// pointer's *own* position. A cycle always contains at least one
3234    /// non-backward hop, so this rule breaks every cycle.
3235    #[test]
3236    fn test_read_name_mutual_pointers_are_rejected() {
3237        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3238
3239        // Answer #1: the root name, then an unknown type, so its RDATA is skipped.
3240        data.push(0); // 12: the root name
3241        data.extend_from_slice(&[0x00, 0xC2]); // 13: TYPE: unknown type 194
3242        data.extend_from_slice(&[0x00, 0x01]); // 15: CLASS: IN
3243        data.extend_from_slice(&[0, 0, 0, 120]); // 17: TTL
3244        data.extend_from_slice(&[0x00, 0x04]); // 21: RDLENGTH
3245        data.extend_from_slice(&[0xC0, 25]); // 23: RDATA: pointer to 25
3246        data.extend_from_slice(&[0xC0, 23]); // 25: RDATA: pointer to 23
3247        assert_eq!(data.len(), 27);
3248
3249        // Answer #2, whose name points into that RDATA.
3250        data.extend_from_slice(&[0xC0, 23]); // 27: name: pointer to 23
3251        data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); // TYPE, CLASS
3252        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3253        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3254
3255        // Every pointer targets an offset below the start of the name at 27.
3256        assert_eq!(u16_from_be_slice(&data[27..29]) ^ 0xC000, 23);
3257        assert_eq!(u16_from_be_slice(&data[23..25]) ^ 0xC000, 25);
3258        assert_eq!(u16_from_be_slice(&data[25..27]) ^ 0xC000, 23);
3259
3260        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3261    }
3262
3263    /// A label whose read carries the cursor onto a pointer that jumps back to
3264    /// that same label. Every pointer here points backwards from its own
3265    /// position, so no comparison of offsets rejects it: the cycle is broken
3266    /// only by the name growing past [`MAX_NAME_BYTES`].
3267    #[test]
3268    fn test_read_name_label_cycle_is_rejected() {
3269        let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3270
3271        // Answer #1, again an unknown type so that its RDATA is skipped.
3272        data.push(0); // 12: the root name
3273        data.extend_from_slice(&[0x00, 0xC2]); // 13: TYPE: unknown type 194
3274        data.extend_from_slice(&[0x00, 0x01]); // 15: CLASS: IN
3275        data.extend_from_slice(&[0, 0, 0, 120]); // 17: TTL
3276        data.extend_from_slice(&[0x00, 0x07]); // 21: RDLENGTH
3277        data.push(0x04); // 23: RDATA: a label of 4 bytes, ending at 28
3278        data.extend_from_slice(b"aaaa"); // 24
3279        data.extend_from_slice(&[0xC0, 23]); // 28: RDATA: pointer to 23
3280        assert_eq!(data.len(), 30);
3281
3282        // Answer #2, whose name enters the cycle.
3283        data.extend_from_slice(&[0xC0, 23]); // 30: name: pointer to 23
3284        data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); // TYPE, CLASS
3285        data.extend_from_slice(&[0, 0, 0, 120]); // TTL
3286        data.extend_from_slice(&[0, 0]); // RDLENGTH: no RDATA
3287
3288        // Reading the label at 23 leaves the cursor on the pointer at 28, which
3289        // points backwards from 28 and lands back on the label.
3290        assert_eq!(u16_from_be_slice(&data[28..30]) ^ 0xC000, 23);
3291        assert_eq!(u16_from_be_slice(&data[30..32]) ^ 0xC000, 23);
3292
3293        assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3294    }
3295
3296    /// A real `_miio._udp.local.` response captured behind an avahi mDNS
3297    /// reflector (see issue #468). It has 5 answers, one of which is an NSEC
3298    /// whose Next Domain Name is a compression pointer to its own offset (a
3299    /// self-reference, offset 121 -> 121). That one record is malformed, but
3300    /// the other four (PTR, A, SRV, TXT) are fine, and lenient parsers such as
3301    /// tcpdump decode the whole packet.
3302    ///
3303    /// The parser must skip only the malformed NSEC and keep the good records,
3304    /// rather than discarding the entire message.
3305    #[test]
3306    fn test_malformed_nsec_record_is_skipped() {
3307        let data: Vec<u8> = vec![
3308            0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x5f,
3309            0x6d, 0x69, 0x69, 0x6f, 0x04, 0x5f, 0x75, 0x64, 0x70, 0x05, 0x6c, 0x6f, 0x63, 0x61,
3310            0x6c, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x24, 0x21, 0x64,
3311            0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d, 0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70,
3312            0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d, 0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30,
3313            0x35, 0x32, 0x34, 0x37, 0xc0, 0x0c, 0x21, 0x64, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d,
3314            0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70, 0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d,
3315            0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30, 0x35, 0x32, 0x34, 0x37, 0x00, 0x00,
3316            0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x09, 0xc0, 0x79, 0x00, 0x05, 0x40,
3317            0x00, 0x00, 0x00, 0x00, 0xc0, 0x4c, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78,
3318            0x00, 0x04, 0x0a, 0x2a, 0x02, 0x32, 0xc0, 0x28, 0x00, 0x21, 0x80, 0x01, 0x00, 0x00,
3319            0x00, 0x78, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x31, 0xc0, 0x4c, 0xc0, 0x28,
3320            0x00, 0x10, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x0e, 0x70, 0x61, 0x74,
3321            0x68, 0x3d, 0x2f, 0x6d, 0x79, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
3322        ];
3323
3324        // The offending record: the NSEC's Next Domain Name at offset 121 is a
3325        // pointer to offset 121 (itself).
3326        assert_eq!(u16_from_be_slice(&data[121..123]) ^ 0xC000, 121);
3327
3328        let incoming = DnsIncoming::new(data, test_interface_id())
3329            .expect("one malformed record must not fail the whole packet");
3330
3331        // Four of the five records survive; only the NSEC is dropped.
3332        assert_eq!(incoming.answers().len(), 4);
3333        assert!(
3334            !incoming
3335                .answers()
3336                .iter()
3337                .any(|r| r.get_type() == RRType::NSEC),
3338            "the malformed NSEC record must be skipped"
3339        );
3340    }
3341
3342    fn test_interface_id() -> InterfaceId {
3343        InterfaceId {
3344            name: "test".to_string(),
3345            index: 1,
3346        }
3347    }
3348
3349    /// The "flags" field of a finished packet.
3350    fn packet_flags(packet: &DnsOutPacket) -> u16 {
3351        let bytes = packet.as_bytes();
3352        u16::from_be_bytes([bytes[2], bytes[3]])
3353    }
3354
3355    fn ptr_answer(index: usize) -> DnsPointer {
3356        DnsPointer::new(
3357            "_spill._tcp.local.",
3358            RRType::PTR,
3359            CLASS_IN,
3360            4500,
3361            format!("instance-{index:04}._spill._tcp.local."),
3362        )
3363    }
3364
3365    /// Re-parses each packet and returns the total number of answers found, which
3366    /// checks the header counts against what each packet actually holds.
3367    fn parsed_answer_count(packets: &[DnsOutPacket]) -> usize {
3368        packets
3369            .iter()
3370            .map(|packet: &DnsOutPacket| {
3371                let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id())
3372                    .expect("each packet must parse on its own");
3373                assert!(
3374                    !parsed.answers().is_empty(),
3375                    "a spilled packet must not be empty"
3376                );
3377                parsed.answers().len()
3378            })
3379            .sum()
3380    }
3381
3382    /// A response too big for one packet spills into more packets. Every record
3383    /// must survive: before, records that did not fit were silently dropped.
3384    #[test]
3385    fn test_dns_outgoing_response_spills_into_packets() {
3386        const ANSWER_COUNT: usize = 100;
3387
3388        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3389        for i in 0..ANSWER_COUNT {
3390            out.add_answer_at_time(ptr_answer(i), 0);
3391        }
3392
3393        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3394        assert!(
3395            packets.len() > 1,
3396            "{} answers should not fit in one packet",
3397            ANSWER_COUNT
3398        );
3399
3400        for packet in &packets {
3401            assert!(
3402                packet.size() <= MAX_PKT_DEFAULT,
3403                "packet of {} bytes exceeds the limit",
3404                packet.size()
3405            );
3406
3407            // A multi-packet response is a series of independent responses: unlike
3408            // a query's known answers, it does not use the TC bit.
3409            assert_eq!(packet_flags(packet) & FLAGS_TC, 0);
3410        }
3411
3412        assert_eq!(parsed_answer_count(&packets), ANSWER_COUNT);
3413    }
3414
3415    /// RFC 6762 section 7.2: a querier sending known answers in more than one
3416    /// packet sets the TC bit in every packet but the last.
3417    #[test]
3418    fn test_dns_outgoing_query_truncation_bit() {
3419        let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
3420        out.add_question("_spill._tcp.local.", RRType::PTR);
3421        for i in 0..100 {
3422            out.add_answer_box(Box::new(ptr_answer(i)));
3423        }
3424
3425        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3426        assert!(
3427            packets.len() > 1,
3428            "known answers should not fit in one packet"
3429        );
3430
3431        let (last, rest) = packets.split_last().expect("at least one packet");
3432        for packet in rest {
3433            assert_ne!(
3434                packet_flags(packet) & FLAGS_TC,
3435                0,
3436                "a packet with more known answers to follow must set TC"
3437            );
3438        }
3439        assert_eq!(
3440            packet_flags(last) & FLAGS_TC,
3441            0,
3442            "the last packet must not set TC"
3443        );
3444
3445        // The question goes in the first packet only, and no answer is lost.
3446        assert_eq!(packets[0].as_bytes()[4..6], 1u16.to_be_bytes());
3447        for packet in rest.iter().skip(1) {
3448            assert_eq!(packet.as_bytes()[4..6], [0, 0]);
3449        }
3450        assert_eq!(parsed_answer_count(&packets), 100);
3451    }
3452
3453    /// RFC 6762 section 17: a record too large for one MTU-sized packet is sent
3454    /// alone in an oversized packet, rather than dropped. It must be alone, since
3455    /// a fragmented packet "MUST NOT contain more than one resource record".
3456    #[test]
3457    fn test_dns_outgoing_oversized_record_sent_alone() {
3458        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3459        out.add_answer_at_time(ptr_answer(0), 0);
3460        out.add_answer_at_time(
3461            DnsTxt::new("big._spill._tcp.local.", CLASS_IN, 4500, vec![b'x'; 2000]),
3462            0,
3463        );
3464        out.add_answer_at_time(ptr_answer(1), 0);
3465
3466        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3467        assert_eq!(packets.len(), 3, "the big record needs a packet to itself");
3468
3469        assert!(packets[0].size() <= MAX_PKT_DEFAULT);
3470        assert!(
3471            packets[1].size() > MAX_PKT_DEFAULT,
3472            "the oversized record must not be dropped"
3473        );
3474        // Still small enough that the send path will let it out.
3475        assert!(packets[1].size() <= MAX_PKT_ABSOLUTE_IPV6);
3476        assert!(packets[2].size() <= MAX_PKT_DEFAULT);
3477
3478        // One record per packet here, the middle one being the big TXT.
3479        let parsed = DnsIncoming::new(packets[1].as_bytes().to_vec(), test_interface_id()).unwrap();
3480        assert_eq!(parsed.answers().len(), 1);
3481        assert_eq!(parsed.answers()[0].get_name(), "big._spill._tcp.local.");
3482        assert_eq!(parsed_answer_count(&packets), 3);
3483    }
3484
3485    /// A record over the RFC 6762 section 17 ceiling could not go out on the wire
3486    /// even in a packet of its own, so it is dropped while its neighbors survive.
3487    #[test]
3488    fn test_dns_outgoing_record_over_absolute_ceiling_dropped() {
3489        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3490        out.add_answer_at_time(ptr_answer(0), 0);
3491        out.add_answer_at_time(
3492            DnsTxt::new(
3493                "huge._spill._tcp.local.",
3494                CLASS_IN,
3495                4500,
3496                vec![b'x'; MAX_PKT_ABSOLUTE_IPV6],
3497            ),
3498            0,
3499        );
3500        out.add_answer_at_time(ptr_answer(1), 0);
3501
3502        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3503        for packet in &packets {
3504            assert!(
3505                packet.size() <= MAX_PKT_ABSOLUTE_IPV6,
3506                "an unsendable packet must never be generated"
3507            );
3508        }
3509        assert_eq!(
3510            parsed_answer_count(&packets),
3511            2,
3512            "only the huge record is dropped"
3513        );
3514    }
3515
3516    /// Authorities and additionals spill too, and stay in their own sections.
3517    #[test]
3518    fn test_dns_outgoing_all_sections_spill() {
3519        let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3520        for i in 0..40 {
3521            out.add_answer_at_time(ptr_answer(i), 0);
3522        }
3523        for i in 40..80 {
3524            out.add_authority(Box::new(ptr_answer(i)));
3525        }
3526        for i in 80..120 {
3527            out.add_additional_answer(ptr_answer(i));
3528        }
3529
3530        let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3531        assert!(packets.len() > 1);
3532
3533        let mut answers = 0;
3534        let mut authorities = 0;
3535        let mut additionals = 0;
3536        for packet in &packets {
3537            assert!(packet.size() <= MAX_PKT_DEFAULT);
3538            let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id()).unwrap();
3539            answers += parsed.answers().len();
3540            authorities += parsed.authorities().len();
3541            additionals += parsed.additionals().len();
3542        }
3543
3544        assert_eq!(answers, 40);
3545        assert_eq!(authorities, 40);
3546        assert_eq!(additionals, 40);
3547    }
3548}