mdns_sd/
dns_parser.rs

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