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    /// For testing purposes only.
1498    pub(crate) fn _answers(&self) -> &[(DnsRecordBox, u64)] {
1499        &self.answers
1500    }
1501
1502    pub fn answers_count(&self) -> usize {
1503        self.answers.len()
1504    }
1505
1506    pub fn authorities(&self) -> &[DnsRecordBox] {
1507        &self.authorities
1508    }
1509
1510    pub fn additionals(&self) -> &[DnsRecordBox] {
1511        &self.additionals
1512    }
1513
1514    pub fn known_answer_count(&self) -> i64 {
1515        self.known_answer_count
1516    }
1517
1518    pub fn set_id(&mut self, id: u16) {
1519        self.id = id;
1520    }
1521
1522    pub const fn is_query(&self) -> bool {
1523        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1524    }
1525
1526    const fn is_response(&self) -> bool {
1527        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
1528    }
1529
1530    // Adds an additional answer
1531
1532    // From: RFC 6763, DNS-Based Service Discovery, February 2013
1533
1534    // 12.  DNS Additional Record Generation
1535
1536    //    DNS has an efficiency feature whereby a DNS server may place
1537    //    additional records in the additional section of the DNS message.
1538    //    These additional records are records that the client did not
1539    //    explicitly request, but the server has reasonable grounds to expect
1540    //    that the client might request them shortly, so including them can
1541    //    save the client from having to issue additional queries.
1542
1543    //    This section recommends which additional records SHOULD be generated
1544    //    to improve network efficiency, for both Unicast and Multicast DNS-SD
1545    //    responses.
1546
1547    // 12.1.  PTR Records
1548
1549    //    When including a DNS-SD Service Instance Enumeration or Selective
1550    //    Instance Enumeration (subtype) PTR record in a response packet, the
1551    //    server/responder SHOULD include the following additional records:
1552
1553    //    o  The SRV record(s) named in the PTR rdata.
1554    //    o  The TXT record(s) named in the PTR rdata.
1555    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1556
1557    // 12.2.  SRV Records
1558
1559    //    When including an SRV record in a response packet, the
1560    //    server/responder SHOULD include the following additional records:
1561
1562    //    o  All address records (type "A" and "AAAA") named in the SRV rdata.
1563    pub fn add_additional_answer(&mut self, answer: impl DnsRecordExt + 'static) {
1564        trace!("add_additional_answer: {:?}", &answer);
1565        self.additionals.push(answer.boxed());
1566    }
1567
1568    /// A workaround as Rust doesn't allow us to pass DnsRecordBox in as `impl DnsRecordExt`
1569    pub fn add_answer_box(&mut self, answer_box: DnsRecordBox) {
1570        self.answers.push((answer_box, 0));
1571    }
1572
1573    pub fn add_authority(&mut self, record: DnsRecordBox) {
1574        self.authorities.push(record);
1575    }
1576
1577    /// Returns true if `answer` is added to the outgoing msg.
1578    /// Returns false if `answer` was not added as it expired or suppressed by the incoming `msg`.
1579    pub fn add_answer(
1580        &mut self,
1581        msg: &DnsIncoming,
1582        answer: impl DnsRecordExt + Send + 'static,
1583    ) -> bool {
1584        trace!("Check for add_answer");
1585        if answer.suppressed_by(msg) {
1586            trace!("my answer is suppressed by incoming msg");
1587            self.known_answer_count += 1;
1588            return false;
1589        }
1590
1591        self.add_answer_at_time(answer, 0)
1592    }
1593
1594    /// Returns true if `answer` is added to the outgoing msg.
1595    /// Returns false if the answer is expired `now` hence not added.
1596    /// If `now` is 0, do not check if the answer expires.
1597    pub fn add_answer_at_time(
1598        &mut self,
1599        answer: impl DnsRecordExt + Send + 'static,
1600        now: u64,
1601    ) -> bool {
1602        if now == 0 || !answer.get_record().is_expired(now) {
1603            trace!("add_answer push: {:?}", &answer);
1604            self.answers.push((answer.boxed(), now));
1605            return true;
1606        }
1607        false
1608    }
1609
1610    pub fn add_question(&mut self, name: &str, qtype: RRType) {
1611        let q = DnsQuestion {
1612            entry: DnsEntry::new(name.to_string(), qtype, CLASS_IN),
1613        };
1614        self.questions.push(q);
1615    }
1616
1617    /// Returns a list of actual DNS packet data to be sent on the wire.
1618    pub fn to_data_on_wire(&self) -> Vec<Vec<u8>> {
1619        let packet_list = self.to_packets();
1620        packet_list.iter().map(|p| p.data.concat()).collect()
1621    }
1622
1623    /// Encode self into one or more packets.
1624    pub fn to_packets(&self) -> Vec<DnsOutPacket> {
1625        let mut packet_list = Vec::new();
1626        let mut packet = DnsOutPacket::new();
1627
1628        let mut question_count = self.questions.len() as u16;
1629        let mut answer_count = 0;
1630        let mut auth_count = 0;
1631        let mut addi_count = 0;
1632        let id = if self.multicast { 0 } else { self.id };
1633
1634        for question in self.questions.iter() {
1635            packet.write_question(question);
1636        }
1637
1638        for (answer, time) in self.answers.iter() {
1639            if packet.write_record(answer.as_ref(), *time) {
1640                answer_count += 1;
1641            }
1642        }
1643
1644        for auth in self.authorities.iter() {
1645            auth_count += u16::from(packet.write_record(auth.as_ref(), 0));
1646        }
1647
1648        for addi in self.additionals.iter() {
1649            if packet.write_record(addi.as_ref(), 0) {
1650                addi_count += 1;
1651                continue;
1652            }
1653
1654            // No more processing for response packets.
1655            if self.is_response() {
1656                break;
1657            }
1658
1659            // For query, the current packet exceeds its max size due to known answers,
1660            // need to truncate.
1661
1662            // finish the current packet first.
1663            packet.write_header(
1664                id,
1665                self.flags | FLAGS_TC,
1666                question_count,
1667                answer_count,
1668                auth_count,
1669                addi_count,
1670            );
1671
1672            packet_list.push(packet);
1673
1674            // create a new packet and reset counts.
1675            packet = DnsOutPacket::new();
1676            packet.write_record(addi.as_ref(), 0);
1677
1678            question_count = 0;
1679            answer_count = 0;
1680            auth_count = 0;
1681            addi_count = 1;
1682        }
1683
1684        packet.write_header(
1685            id,
1686            self.flags,
1687            question_count,
1688            answer_count,
1689            auth_count,
1690            addi_count,
1691        );
1692
1693        packet_list.push(packet);
1694        packet_list
1695    }
1696}
1697
1698/// An incoming DNS message. It could be a query or a response.
1699#[derive(Debug)]
1700pub struct DnsIncoming {
1701    offset: usize,
1702    data: Vec<u8>,
1703    questions: Vec<DnsQuestion>,
1704    answers: Vec<DnsRecordBox>,
1705    authorities: Vec<DnsRecordBox>,
1706    additional: Vec<DnsRecordBox>,
1707    id: u16,
1708    flags: u16,
1709    num_questions: u16,
1710    num_answers: u16,
1711    num_authorities: u16,
1712    num_additionals: u16,
1713    interface_id: InterfaceId,
1714}
1715
1716impl DnsIncoming {
1717    pub fn new(data: Vec<u8>, interface_id: InterfaceId) -> Result<Self> {
1718        let mut incoming = Self {
1719            offset: 0,
1720            data,
1721            questions: Vec::new(),
1722            answers: Vec::new(),
1723            authorities: Vec::new(),
1724            additional: Vec::new(),
1725            id: 0,
1726            flags: 0,
1727            num_questions: 0,
1728            num_answers: 0,
1729            num_authorities: 0,
1730            num_additionals: 0,
1731            interface_id,
1732        };
1733
1734        /*
1735        RFC 1035 section 4.1: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1
1736        ...
1737        All communications inside of the domain protocol are carried in a single
1738        format called a message.  The top level format of message is divided
1739        into 5 sections (some of which are empty in certain cases) shown below:
1740
1741            +---------------------+
1742            |        Header       |
1743            +---------------------+
1744            |       Question      | the question for the name server
1745            +---------------------+
1746            |        Answer       | RRs answering the question
1747            +---------------------+
1748            |      Authority      | RRs pointing toward an authority
1749            +---------------------+
1750            |      Additional     | RRs holding additional information
1751            +---------------------+
1752         */
1753        incoming.read_header()?;
1754        incoming.read_questions()?;
1755        incoming.read_answers()?;
1756        incoming.read_authorities()?;
1757        incoming.read_additional()?;
1758
1759        Ok(incoming)
1760    }
1761
1762    pub fn id(&self) -> u16 {
1763        self.id
1764    }
1765
1766    pub fn questions(&self) -> &[DnsQuestion] {
1767        &self.questions
1768    }
1769
1770    pub fn answers(&self) -> &[DnsRecordBox] {
1771        &self.answers
1772    }
1773
1774    pub fn authorities(&self) -> &[DnsRecordBox] {
1775        &self.authorities
1776    }
1777
1778    pub fn additionals(&self) -> &[DnsRecordBox] {
1779        &self.additional
1780    }
1781
1782    pub fn answers_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1783        &mut self.answers
1784    }
1785
1786    pub fn authorities_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1787        &mut self.authorities
1788    }
1789
1790    pub fn additionals_mut(&mut self) -> &mut Vec<DnsRecordBox> {
1791        &mut self.additional
1792    }
1793
1794    pub fn all_records(self) -> impl Iterator<Item = DnsRecordBox> {
1795        self.answers
1796            .into_iter()
1797            .chain(self.authorities)
1798            .chain(self.additional)
1799    }
1800
1801    pub fn num_additionals(&self) -> u16 {
1802        self.num_additionals
1803    }
1804
1805    pub fn num_authorities(&self) -> u16 {
1806        self.num_authorities
1807    }
1808
1809    pub fn num_questions(&self) -> u16 {
1810        self.num_questions
1811    }
1812
1813    pub const fn is_query(&self) -> bool {
1814        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1815    }
1816
1817    pub const fn is_response(&self) -> bool {
1818        (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
1819    }
1820
1821    fn read_header(&mut self) -> Result<()> {
1822        if self.data.len() < MSG_HEADER_LEN {
1823            return Err(e_fmt!(
1824                "DNS incoming: header is too short: {} bytes",
1825                self.data.len()
1826            ));
1827        }
1828
1829        let data = &self.data[0..];
1830        self.id = u16_from_be_slice(&data[..2]);
1831        self.flags = u16_from_be_slice(&data[2..4]);
1832        self.num_questions = u16_from_be_slice(&data[4..6]);
1833        self.num_answers = u16_from_be_slice(&data[6..8]);
1834        self.num_authorities = u16_from_be_slice(&data[8..10]);
1835        self.num_additionals = u16_from_be_slice(&data[10..12]);
1836
1837        self.offset = MSG_HEADER_LEN;
1838
1839        trace!(
1840            "read_header: id {}, {} questions {} answers {} authorities {} additionals",
1841            self.id,
1842            self.num_questions,
1843            self.num_answers,
1844            self.num_authorities,
1845            self.num_additionals
1846        );
1847        Ok(())
1848    }
1849
1850    fn read_questions(&mut self) -> Result<()> {
1851        trace!("read_questions: {}", &self.num_questions);
1852        for i in 0..self.num_questions {
1853            let name = self.read_name()?;
1854
1855            let data = &self.data[self.offset..];
1856            if data.len() < 4 {
1857                return Err(Error::Msg(format!(
1858                    "DNS incoming: question idx {} too short: {}",
1859                    i,
1860                    data.len()
1861                )));
1862            }
1863            let ty = u16_from_be_slice(&data[..2]);
1864            let class = u16_from_be_slice(&data[2..4]);
1865            self.offset += 4;
1866
1867            let Some(rr_type) = RRType::from_u16(ty) else {
1868                return Err(Error::Msg(format!(
1869                    "DNS incoming: question idx {} qtype unknown: {}",
1870                    i, ty
1871                )));
1872            };
1873
1874            self.questions.push(DnsQuestion {
1875                entry: DnsEntry::new(name, rr_type, class),
1876            });
1877        }
1878        Ok(())
1879    }
1880
1881    fn read_answers(&mut self) -> Result<()> {
1882        self.answers = self.read_rr_records(self.num_answers)?;
1883        Ok(())
1884    }
1885
1886    fn read_authorities(&mut self) -> Result<()> {
1887        self.authorities = self.read_rr_records(self.num_authorities)?;
1888        Ok(())
1889    }
1890
1891    fn read_additional(&mut self) -> Result<()> {
1892        self.additional = self.read_rr_records(self.num_additionals)?;
1893        Ok(())
1894    }
1895
1896    /// Decodes a sequence of RR records (in answers, authorities and additionals).
1897    fn read_rr_records(&mut self, count: u16) -> Result<Vec<DnsRecordBox>> {
1898        trace!("read_rr_records: {}", count);
1899        let mut rr_records = Vec::new();
1900
1901        // RFC 1035: https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.1
1902        //
1903        // All RRs have the same top level format shown below:
1904        //                               1  1  1  1  1  1
1905        // 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
1906        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1907        // |                                               |
1908        // /                                               /
1909        // /                      NAME                     /
1910        // |                                               |
1911        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1912        // |                      TYPE                     |
1913        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1914        // |                     CLASS                     |
1915        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1916        // |                      TTL                      |
1917        // |                                               |
1918        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1919        // |                   RDLENGTH                    |
1920        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
1921        // /                     RDATA                     /
1922        // /                                               /
1923        // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1924
1925        // Muse have at least TYPE, CLASS, TTL, RDLENGTH fields: 10 bytes.
1926        const RR_HEADER_REMAIN: usize = 10;
1927
1928        for _ in 0..count {
1929            let name = self.read_name()?;
1930            let slice = &self.data[self.offset..];
1931
1932            if slice.len() < RR_HEADER_REMAIN {
1933                return Err(Error::Msg(format!(
1934                    "read_others: RR '{}' is too short after name: {} bytes",
1935                    &name,
1936                    slice.len()
1937                )));
1938            }
1939
1940            let ty = u16_from_be_slice(&slice[..2]);
1941            let class = u16_from_be_slice(&slice[2..4]);
1942            let mut ttl = u32_from_be_slice(&slice[4..8]);
1943            if ttl == 0 && self.is_response() {
1944                // RFC 6762 section 10.1:
1945                // "...Queriers receiving a Multicast DNS response with a TTL of zero SHOULD
1946                // NOT immediately delete the record from the cache, but instead record
1947                // a TTL of 1 and then delete the record one second later."
1948                // See https://datatracker.ietf.org/doc/html/rfc6762#section-10.1
1949
1950                ttl = 1;
1951            }
1952            let rdata_len = u16_from_be_slice(&slice[8..10]) as usize;
1953            self.offset += RR_HEADER_REMAIN;
1954            let next_offset = self.offset + rdata_len;
1955
1956            // Sanity check for RDATA length.
1957            if next_offset > self.data.len() {
1958                return Err(Error::Msg(format!(
1959                    "RR {name} RDATA length {rdata_len} is invalid: remain data len: {}",
1960                    self.data.len() - self.offset
1961                )));
1962            }
1963
1964            // decode RDATA based on the record type.
1965            let rec: Option<DnsRecordBox> = match RRType::from_u16(ty) {
1966                None => None,
1967
1968                Some(rr_type) => match rr_type {
1969                    RRType::CNAME | RRType::PTR => {
1970                        Some(DnsPointer::new(&name, rr_type, class, ttl, self.read_name()?).boxed())
1971                    }
1972                    RRType::TXT => {
1973                        Some(DnsTxt::new(&name, class, ttl, self.read_vec(rdata_len)?).boxed())
1974                    }
1975                    RRType::SRV => Some(
1976                        DnsSrv::new(
1977                            &name,
1978                            class,
1979                            ttl,
1980                            self.read_u16()?,
1981                            self.read_u16()?,
1982                            self.read_u16()?,
1983                            self.read_name()?,
1984                        )
1985                        .boxed(),
1986                    ),
1987                    RRType::HINFO => Some(
1988                        DnsHostInfo::new(
1989                            &name,
1990                            rr_type,
1991                            class,
1992                            ttl,
1993                            self.read_char_string()?,
1994                            self.read_char_string()?,
1995                        )
1996                        .boxed(),
1997                    ),
1998                    RRType::A => Some(
1999                        DnsAddress::new(
2000                            &name,
2001                            rr_type,
2002                            class,
2003                            ttl,
2004                            self.read_ipv4()?.into(),
2005                            self.interface_id.clone(),
2006                        )
2007                        .boxed(),
2008                    ),
2009                    RRType::AAAA => Some(
2010                        DnsAddress::new(
2011                            &name,
2012                            rr_type,
2013                            class,
2014                            ttl,
2015                            self.read_ipv6()?.into(),
2016                            self.interface_id.clone(),
2017                        )
2018                        .boxed(),
2019                    ),
2020                    RRType::NSEC => Some(
2021                        DnsNSec::new(
2022                            &name,
2023                            class,
2024                            ttl,
2025                            self.read_name()?,
2026                            self.read_type_bitmap()?,
2027                        )
2028                        .boxed(),
2029                    ),
2030                    _ => None,
2031                },
2032            };
2033
2034            if let Some(record) = rec {
2035                trace!("read_rr_records: {:?}", &record);
2036                rr_records.push(record);
2037            } else {
2038                trace!("Unsupported DNS record type: {} name: {}", ty, &name);
2039                self.offset += rdata_len;
2040            }
2041
2042            // sanity check.
2043            if self.offset != next_offset {
2044                return Err(Error::Msg(format!(
2045                    "read_rr_records: decode offset error for RData type {} offset: {} expected offset: {}",
2046                    ty, self.offset, next_offset,
2047                )));
2048            }
2049        }
2050
2051        Ok(rr_records)
2052    }
2053
2054    fn read_char_string(&mut self) -> Result<String> {
2055        let length = self.data[self.offset];
2056        self.offset += 1;
2057        self.read_string(length as usize)
2058    }
2059
2060    fn read_u16(&mut self) -> Result<u16> {
2061        let slice = &self.data[self.offset..];
2062        if slice.len() < U16_SIZE {
2063            return Err(Error::Msg(format!(
2064                "read_u16: slice len is only {}",
2065                slice.len()
2066            )));
2067        }
2068        let num = u16_from_be_slice(&slice[..U16_SIZE]);
2069        self.offset += U16_SIZE;
2070        Ok(num)
2071    }
2072
2073    /// Reads the "Type Bit Map" block for a DNS NSEC record.
2074    fn read_type_bitmap(&mut self) -> Result<Vec<u8>> {
2075        // From RFC 6762: 6.1.  Negative Responses
2076        // https://datatracker.ietf.org/doc/html/rfc6762#section-6.1
2077        //   o The Type Bit Map block number is 0.
2078        //   o The Type Bit Map block length byte is a value in the range 1-32.
2079        //   o The Type Bit Map data is 1-32 bytes, as indicated by length
2080        //     byte.
2081
2082        // Sanity check: at least 2 bytes to read.
2083        if self.data.len() < self.offset + 2 {
2084            return Err(Error::Msg(format!(
2085                "DnsIncoming is too short: {} at NSEC Type Bit Map offset {}",
2086                self.data.len(),
2087                self.offset
2088            )));
2089        }
2090
2091        let block_num = self.data[self.offset];
2092        self.offset += 1;
2093        if block_num != 0 {
2094            return Err(Error::Msg(format!(
2095                "NSEC block number is not 0: {}",
2096                block_num
2097            )));
2098        }
2099
2100        let block_len = self.data[self.offset] as usize;
2101        if !(1..=32).contains(&block_len) {
2102            return Err(Error::Msg(format!(
2103                "NSEC block length must be in the range 1-32: {}",
2104                block_len
2105            )));
2106        }
2107        self.offset += 1;
2108
2109        let end = self.offset + block_len;
2110        if end > self.data.len() {
2111            return Err(Error::Msg(format!(
2112                "NSEC block overflow: {} over RData len {}",
2113                end,
2114                self.data.len()
2115            )));
2116        }
2117        let bitmap = self.data[self.offset..end].to_vec();
2118        self.offset += block_len;
2119
2120        Ok(bitmap)
2121    }
2122
2123    fn read_vec(&mut self, length: usize) -> Result<Vec<u8>> {
2124        if self.data.len() < self.offset + length {
2125            return Err(e_fmt!(
2126                "DNS Incoming: not enough data to read a chunk of data"
2127            ));
2128        }
2129
2130        let v = self.data[self.offset..self.offset + length].to_vec();
2131        self.offset += length;
2132        Ok(v)
2133    }
2134
2135    fn read_ipv4(&mut self) -> Result<Ipv4Addr> {
2136        if self.data.len() < self.offset + 4 {
2137            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV4"));
2138        }
2139
2140        let bytes: [u8; 4] = self.data[self.offset..self.offset + 4]
2141            .try_into()
2142            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV4"))?;
2143        self.offset += bytes.len();
2144        Ok(Ipv4Addr::from(bytes))
2145    }
2146
2147    fn read_ipv6(&mut self) -> Result<Ipv6Addr> {
2148        if self.data.len() < self.offset + 16 {
2149            return Err(e_fmt!("DNS Incoming: not enough data to read an IPV6"));
2150        }
2151
2152        let bytes: [u8; 16] = self.data[self.offset..self.offset + 16]
2153            .try_into()
2154            .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV6"))?;
2155        self.offset += bytes.len();
2156        Ok(Ipv6Addr::from(bytes))
2157    }
2158
2159    fn read_string(&mut self, length: usize) -> Result<String> {
2160        if self.data.len() < self.offset + length {
2161            return Err(e_fmt!("DNS Incoming: not enough data to read a string"));
2162        }
2163
2164        let s = str::from_utf8(&self.data[self.offset..self.offset + length])
2165            .map_err(|e| Error::Msg(e.to_string()))?;
2166        self.offset += length;
2167        Ok(s.to_string())
2168    }
2169
2170    /// Reads a domain name at the current location of `self.data`.
2171    ///
2172    /// See https://datatracker.ietf.org/doc/html/rfc1035#section-3.1 for
2173    /// domain name encoding.
2174    fn read_name(&mut self) -> Result<String> {
2175        let data = &self.data[..];
2176        let start_offset = self.offset;
2177        let mut offset = start_offset;
2178        let mut name = "".to_string();
2179        let mut at_end = false;
2180
2181        // From RFC1035:
2182        // "...Domain names in messages are expressed in terms of a sequence of labels.
2183        // Each label is represented as a one octet length field followed by that
2184        // number of octets."
2185        //
2186        // "...The compression scheme allows a domain name in a message to be
2187        // represented as either:
2188        // - a sequence of labels ending in a zero octet
2189        // - a pointer
2190        // - a sequence of labels ending with a pointer"
2191        loop {
2192            if offset >= data.len() {
2193                return Err(Error::Msg(format!(
2194                    "read_name: offset: {} data len {}. DnsIncoming: {:?}",
2195                    offset,
2196                    data.len(),
2197                    self
2198                )));
2199            }
2200            let length = data[offset];
2201
2202            // From RFC1035:
2203            // "...Since every domain name ends with the null label of
2204            // the root, a domain name is terminated by a length byte of zero."
2205            if length == 0 {
2206                if !at_end {
2207                    self.offset = offset + 1;
2208                }
2209                break; // The end of the name
2210            }
2211
2212            // Check the first 2 bits for possible "Message compression".
2213            match length & 0xC0 {
2214                0x00 => {
2215                    // regular utf8 string with length
2216                    offset += 1;
2217                    let ending = offset + length as usize;
2218
2219                    // Never read beyond the whole data length.
2220                    if ending > data.len() {
2221                        return Err(Error::Msg(format!(
2222                            "read_name: ending {} exceeds data length {}",
2223                            ending,
2224                            data.len()
2225                        )));
2226                    }
2227
2228                    name += str::from_utf8(&data[offset..ending])
2229                        .map_err(|e| Error::Msg(format!("read_name: from_utf8: {}", e)))?;
2230                    name += ".";
2231                    offset += length as usize;
2232                }
2233                0xC0 => {
2234                    // Message compression.
2235                    // See https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4
2236                    let slice = &data[offset..];
2237                    if slice.len() < U16_SIZE {
2238                        return Err(Error::Msg(format!(
2239                            "read_name: u16 slice len is only {}",
2240                            slice.len()
2241                        )));
2242                    }
2243                    let pointer = (u16_from_be_slice(slice) ^ 0xC000) as usize;
2244                    if pointer >= start_offset {
2245                        // Error: could trigger an infinite loop.
2246                        return Err(Error::Msg(format!(
2247                            "Invalid name compression: pointer {} must be less than the start offset {}",
2248                            &pointer, &start_offset
2249                        )));
2250                    }
2251
2252                    // A pointer marks the end of a domain name.
2253                    if !at_end {
2254                        self.offset = offset + U16_SIZE;
2255                        at_end = true;
2256                    }
2257                    offset = pointer;
2258                }
2259                _ => {
2260                    return Err(Error::Msg(format!(
2261                        "Bad name with invalid length: 0x{:x} offset {}, data (so far): {:x?}",
2262                        length,
2263                        offset,
2264                        &data[..offset]
2265                    )));
2266                }
2267            };
2268        }
2269
2270        Ok(name)
2271    }
2272}
2273
2274/// Returns UNIX time in millis
2275fn current_time_millis() -> u64 {
2276    SystemTime::now()
2277        .duration_since(SystemTime::UNIX_EPOCH)
2278        .expect("failed to get current UNIX time")
2279        .as_millis() as u64
2280}
2281
2282const fn u16_from_be_slice(bytes: &[u8]) -> u16 {
2283    let u8_array: [u8; 2] = [bytes[0], bytes[1]];
2284    u16::from_be_bytes(u8_array)
2285}
2286
2287const fn u32_from_be_slice(s: &[u8]) -> u32 {
2288    let u8_array: [u8; 4] = [s[0], s[1], s[2], s[3]];
2289    u32::from_be_bytes(u8_array)
2290}
2291
2292/// Returns the UNIX time in millis at which this record will have expired
2293/// by a certain percentage.
2294const fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
2295    // 'created' is in millis, 'ttl' is in seconds, hence:
2296    // ttl * 1000 * (percent / 100) => ttl * percent * 10
2297    created + (ttl * percent * 10) as u64
2298}