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