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