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