domain 0.12.0

A DNS library for Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
//! DNS message headers.

use core::fmt;

use crate::new::edns::EdnsRecord;
use crate::utils::dst::UnsizedCopy;

use super::build::{BuildInMessage, NameCompressor};
use super::parse::MessageParser;
use super::wire::{
    AsBytes, BuildBytes, ParseBytes, ParseBytesZC, SplitBytes, SplitBytesZC,
    TruncationError, U16,
};
use super::{Question, Record};

//----------- Message --------------------------------------------------------

/// A DNS message.
#[derive(AsBytes, BuildBytes, ParseBytesZC, UnsizedCopy)]
#[repr(C, packed)]
pub struct Message {
    /// The message header.
    pub header: Header,

    /// The message contents.
    pub contents: [u8],
}

//--- Inspection

impl Message {
    /// Represent this as a mutable byte sequence.
    ///
    /// Given `&mut self`, it is already possible to individually modify the
    /// message header and contents; since neither has invalid instances, it
    /// is safe to represent the entire object as mutable bytes.
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        // SAFETY:
        // - 'Self' has no padding bytes and no interior mutability.
        // - Its size in memory is exactly 'size_of_val(self)'.
        unsafe {
            core::slice::from_raw_parts_mut(
                self as *mut Self as *mut u8,
                core::mem::size_of_val(self),
            )
        }
    }
}

//--- Parsing

impl Message {
    /// Parse the questions and records in this message.
    ///
    /// This returns a fallible iterator of [`MessageItem`]s.
    pub const fn parse(&self) -> MessageParser<'_> {
        MessageParser::for_message(self)
    }
}

//--- Interaction

impl Message {
    /// Truncate the contents of this message to the given size.
    ///
    /// The returned value will have a `contents` field of the given size.
    pub fn truncate(&self, size: usize) -> &Self {
        let bytes = &self.as_bytes()[..12 + size];
        // SAFETY: 'bytes' is at least 12 bytes, making it a valid 'Message'.
        unsafe { Self::parse_bytes_by_ref(bytes).unwrap_unchecked() }
    }

    /// Truncate the contents of this message to the given size, mutably.
    ///
    /// The returned value will have a `contents` field of the given size.
    pub fn truncate_mut(&mut self, size: usize) -> &mut Self {
        let bytes = &mut self.as_bytes_mut()[..12 + size];
        // SAFETY: 'bytes' is at least 12 bytes, making it a valid 'Message'.
        unsafe { Self::parse_bytes_in(bytes).unwrap_unchecked() }
    }

    /// Truncate the contents of this message to the given size, by pointer.
    ///
    /// The returned value will have a `contents` field of the given size.
    ///
    /// # Safety
    ///
    /// This method uses `pointer::offset()`: `self` must be "derived from a
    /// pointer to some allocated object". There must be at least 12 bytes
    /// between `self` and the end of that allocated object. A reference to
    /// `Message` will always result in a pointer satisfying this.
    pub unsafe fn truncate_ptr(this: *mut Message, size: usize) -> *mut Self {
        // Extract the metadata from 'this'. We know it's slice metadata.
        //
        // SAFETY: '[()]' is a zero-sized type and references to it can be
        // created from arbitrary pointers, since every pointer is valid for
        // zero-sized reads.
        let len = unsafe { &*(this as *mut [()]) }.len();
        // Replicate the range check performed by normal indexing operations.
        debug_assert!(size <= len);
        core::ptr::slice_from_raw_parts_mut(this.cast::<u8>(), size)
            as *mut Self
    }
}

//--- Cloning

#[cfg(feature = "alloc")]
impl Clone for alloc::boxed::Box<Message> {
    fn clone(&self) -> Self {
        (*self).unsized_copy_into()
    }
}

//----------- Header ---------------------------------------------------------

/// A DNS message header.
#[derive(
    Copy,
    Clone,
    Debug,
    Hash,
    AsBytes,
    BuildBytes,
    ParseBytes,
    ParseBytesZC,
    SplitBytes,
    SplitBytesZC,
    UnsizedCopy,
)]
#[repr(C)]
pub struct Header {
    /// A unique identifier for the message.
    pub id: U16,

    /// Properties of the message.
    pub flags: HeaderFlags,

    /// Counts of objects in the message.
    pub counts: SectionCounts,
}

//--- Formatting

impl fmt::Display for Header {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} of ID {:04X} ({})",
            self.flags,
            self.id.get(),
            self.counts
        )
    }
}

//----------- HeaderFlags ----------------------------------------------------

/// DNS message header flags.
///
/// This 16-bit field provides information about the containing DNS message.
/// Its contents define the purpose of the message, e.g. whether it is a query
/// or a response. Due to its small size, it doesn't cover everything; the
/// OPT record may provide additional information, if it is present.
///
/// # Specification
///
// TODO: Update regularly.
//
/// The header field has been updated by several RFCs and the interpretation
/// of its bits has changed in some places. The following is a collection of
/// the relevant RFC notes; it is up-to-date as of *2025-04-03*.
///
/// The descriptions here are specific to the `QUERY` opcode, which is by far
/// the most common. Other opcodes can change the interpretation of the bits
/// here.
///
/// ```text
///   15   14   13   12   11   10    9    8
/// +----+----+----+----+----+----+----+----+
/// | QR |       OPCODE      | AA | TC | RD |  } MSB
/// +----+----+----+----+----+----+----+----+
/// | RA |    | AD | CD |       RCODE       |  } LSB
/// +----+----+----+----+----+----+----+----+
///    7    6    5    4    3    2    1    0
/// ```
///
/// Here is a short description of each field.
///
/// - `QR` (Query or Response): set if and only if the message is a response.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// - `OPCODE`: the specific operation requested by the DNS client.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// - `AA`: whether the DNS server is authoritative for the primary answer.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// - `TC`: whether the response is truncated (due to channel limitations).
///
///   Specified by [RFC 1035, section 4.1.1]. Behaviour clarified by [RFC
///   2181, section 9]. Behaviour for DNSSEC servers specified by [RFC 4035,
///   section 3.1].
///
/// - `RD`: whether the DNS client wishes for a recursively resolved answer.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// - `RA`: whether the DNS server supports recursive resolution.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// - `AD`: whether the DNS server has authenticated the answer.
///
///   Defined by [RFC 2535, section 6.1]. Behaviour for authoritative name
///   servers specified by [RFC 4035, section 3.1.6]. Behaviour for recursive
///   name servers specified by [RFC 4035, section 3.2.3] and updated by [RFC
///   6840, section 5.8]. Behaviour for DNS clients specified by [RFC 6840,
///   section 5.7].
///
/// - `CD`: whether the DNS server should avoid authenticating the answer.
///
///   Defined by [RFC 2535, section 6.1]. Behaviour for authoritative name
///   servers specified by [RFC 4035, section 3.1.6]. Behaviour for recursive
///   name servers specified by [RFC 4035, section 3.2.2] and updated by [RFC
///   6840, section 5.9].
///
/// - `RCODE`: the response status of the DNS server.
///
///   Specified by [RFC 1035, section 4.1.1].
///
/// [RFC 1035, section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
/// [RFC 2181, section 9]: https://datatracker.ietf.org/doc/html/rfc2181#section-9
/// [RFC 2535, section 6.1]: https://datatracker.ietf.org/doc/html/rfc2535#section-6.1
/// [RFC 4035, section 3.1]: https://datatracker.ietf.org/doc/html/rfc4035#section-3.1
/// [RFC 4035, section 3.1.6]: https://datatracker.ietf.org/doc/html/rfc4035#section-3.1.6
/// [RFC 4035, section 3.2.2]: https://datatracker.ietf.org/doc/html/rfc4035#section-3.2.2
/// [RFC 4035, section 3.2.3]: https://datatracker.ietf.org/doc/html/rfc4035#section-3.2.3
/// [RFC 6840, section 5.7]: https://datatracker.ietf.org/doc/html/rfc6840#section-5.7
/// [RFC 6840, section 5.8]: https://datatracker.ietf.org/doc/html/rfc6840#section-5.8
/// [RFC 6840, section 5.9]: https://datatracker.ietf.org/doc/html/rfc6840#section-5.9
#[derive(
    Copy,
    Clone,
    Default,
    Hash,
    AsBytes,
    BuildBytes,
    ParseBytes,
    ParseBytesZC,
    SplitBytes,
    SplitBytesZC,
    UnsizedCopy,
)]
#[repr(transparent)]
pub struct HeaderFlags {
    /// The raw flag bits.
    inner: U16,
}

//--- Interaction

impl HeaderFlags {
    /// Get the specified flag bit.
    const fn get_flag(&self, pos: u32) -> bool {
        self.inner.get() & (1 << pos) != 0
    }

    /// Set the specified flag bit.
    fn set_flag(&mut self, pos: u32, value: bool) -> &mut Self {
        self.inner &= !(1 << pos);
        self.inner |= (value as u16) << pos;
        self
    }

    /// The raw flags bits.
    pub const fn bits(&self) -> u16 {
        self.inner.get()
    }

    /// The QR bit.
    pub const fn qr(&self) -> bool {
        self.get_flag(15)
    }

    /// Set the QR bit.
    pub fn set_qr(&mut self, value: bool) -> &mut Self {
        self.set_flag(15, value)
    }

    /// The OPCODE field.
    pub const fn opcode(&self) -> u8 {
        (self.inner.get() >> 11) as u8 & 0xF
    }

    /// Set the OPCODE field.
    pub fn set_opcode(&mut self, value: u8) -> &mut Self {
        debug_assert!(value < 16);
        self.inner &= !(0xF << 11);
        self.inner |= (value as u16) << 11;
        self
    }

    /// The AA bit.
    pub fn aa(&self) -> bool {
        self.get_flag(10)
    }

    /// Set the AA bit.
    pub fn set_aa(&mut self, value: bool) -> &mut Self {
        self.set_flag(10, value)
    }

    /// The TC bit.
    pub fn tc(&self) -> bool {
        self.get_flag(9)
    }

    /// Set the TC bit.
    pub fn set_tc(&mut self, value: bool) -> &mut Self {
        self.set_flag(9, value)
    }

    /// The RD bit.
    pub fn rd(&self) -> bool {
        self.get_flag(8)
    }

    /// Set the RD bit.
    pub fn set_rd(&mut self, value: bool) -> &mut Self {
        self.set_flag(8, value)
    }

    /// The RA bit.
    pub fn ra(&self) -> bool {
        self.get_flag(7)
    }

    /// Set the RA bit.
    pub fn set_ra(&mut self, value: bool) -> &mut Self {
        self.set_flag(7, value)
    }

    /// The AD bit.
    pub fn ad(&self) -> bool {
        self.get_flag(5)
    }

    /// Set the AD bit.
    pub fn set_ad(&mut self, value: bool) -> &mut Self {
        self.set_flag(5, value)
    }

    /// The CD bit.
    pub fn cd(&self) -> bool {
        self.get_flag(4)
    }

    /// Set the CD bit.
    pub fn set_cd(&mut self, value: bool) -> &mut Self {
        self.set_flag(4, value)
    }

    /// The RCODE field.
    pub const fn rcode(&self) -> u8 {
        self.inner.get() as u8 & 0xF
    }

    /// Set the RCODE field.
    pub fn set_rcode(&mut self, value: u8) -> &mut Self {
        debug_assert!(value < 16);
        self.inner &= !0xF;
        self.inner |= value as u16;
        self
    }
}

//--- Formatting

impl fmt::Debug for HeaderFlags {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("HeaderFlags")
            .field("qr", &self.qr())
            .field("opcode", &self.opcode())
            .field("aa", &self.aa())
            .field("tc", &self.tc())
            .field("rd", &self.rd())
            .field("ra", &self.ra())
            .field("rcode", &self.rcode())
            .field("bits", &self.bits())
            .finish()
    }
}

impl fmt::Display for HeaderFlags {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if !self.qr() {
            if self.rd() {
                f.write_str("recursive ")?;
            }
            write!(f, "query (opcode {})", self.opcode())?;
            if self.cd() {
                f.write_str(" (checking disabled)")?;
            }
        } else {
            if self.ad() {
                f.write_str("authentic ")?;
            }
            if self.aa() {
                f.write_str("authoritative ")?;
            }
            if self.rd() && self.ra() {
                f.write_str("recursive ")?;
            }
            write!(f, "response (rcode {})", self.rcode())?;
        }

        if self.tc() {
            f.write_str(" (message truncated)")?;
        }

        Ok(())
    }
}

//----------- SectionCounts --------------------------------------------------

/// Counts of objects in a DNS message.
#[derive(
    Copy,
    Clone,
    Debug,
    Default,
    PartialEq,
    Eq,
    Hash,
    AsBytes,
    BuildBytes,
    ParseBytes,
    ParseBytesZC,
    SplitBytes,
    SplitBytesZC,
    UnsizedCopy,
)]
#[repr(C)]
pub struct SectionCounts {
    /// The number of questions in the message.
    pub questions: U16,

    /// The number of answer records in the message.
    pub answers: U16,

    /// The number of name server records in the message.
    pub authorities: U16,

    /// The number of additional records in the message.
    pub additionals: U16,
}

//--- Interaction

impl SectionCounts {
    /// Represent these counts as an array.
    pub fn as_array(&self) -> &[U16; 4] {
        // SAFETY: 'SectionCounts' has the same layout as '[U16; 4]'.
        unsafe { core::mem::transmute(self) }
    }

    /// Represent these counts as a mutable array.
    pub fn as_array_mut(&mut self) -> &mut [U16; 4] {
        // SAFETY: 'SectionCounts' has the same layout as '[U16; 4]'.
        unsafe { core::mem::transmute(self) }
    }
}

//--- Formatting

impl fmt::Display for SectionCounts {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut some = false;

        for (num, single, many) in [
            (self.questions.get(), "question", "questions"),
            (self.answers.get(), "answer", "answers"),
            (self.authorities.get(), "authority", "authorities"),
            (self.additionals.get(), "additional", "additionals"),
        ] {
            // Add a comma if we have printed something before.
            if some && num > 0 {
                f.write_str(", ")?;
            }

            // Print a count of this section.
            match num {
                0 => {}
                1 => write!(f, "1 {single}")?,
                n => write!(f, "{n} {many}")?,
            }

            some |= num > 0;
        }

        if !some {
            f.write_str("empty")?;
        }

        Ok(())
    }
}

//----------- MessageItem ----------------------------------------------------

/// A question or a record.
///
/// This is useful for building and parsing the contents of a [`Message`]
/// ergonomically and efficiently. An iterator of [`MessageItem`]s can be
/// retrieved using [`Message::parse()`].
#[derive(Clone, Debug)]
pub enum MessageItem<N, RD, ED> {
    /// A question.
    Question(Question<N>),

    /// An answer record.
    Answer(Record<N, RD>),

    /// An authority record.
    Authority(Record<N, RD>),

    /// An additional record.
    ///
    /// This does not include EDNS records.
    Additional(Record<N, RD>),

    /// An EDNS record.
    ///
    /// This is a record in the additional section. It uses a distinct type
    /// as the class and TTL fields of the record are interpreted differently.
    Edns(EdnsRecord<ED>),
}

//--- Transformation

impl<N, RD, ED> MessageItem<N, RD, ED> {
    /// Transform this type's generic parameters.
    pub fn transform<NN, NRD, NED>(
        self,
        name_map: impl FnOnce(N) -> NN,
        rdata_map: impl FnOnce(RD) -> NRD,
        edata_map: impl FnOnce(ED) -> NED,
    ) -> MessageItem<NN, NRD, NED> {
        match self {
            Self::Question(this) => {
                MessageItem::Question(this.transform(name_map))
            }
            Self::Answer(this) => {
                MessageItem::Answer(this.transform(name_map, rdata_map))
            }
            Self::Authority(this) => {
                MessageItem::Authority(this.transform(name_map, rdata_map))
            }
            Self::Additional(this) => {
                MessageItem::Additional(this.transform(name_map, rdata_map))
            }
            Self::Edns(this) => MessageItem::Edns(this.transform(edata_map)),
        }
    }

    /// Transform this type's generic parameters by reference.
    pub fn transform_ref<'a, NN, NRD, NED>(
        &'a self,
        name_map: impl FnOnce(&'a N) -> NN,
        rdata_map: impl FnOnce(&'a RD) -> NRD,
        edata_map: impl FnOnce(&'a ED) -> NED,
    ) -> MessageItem<NN, NRD, NED> {
        match self {
            Self::Question(this) => {
                MessageItem::Question(this.transform_ref(name_map))
            }
            Self::Answer(this) => {
                MessageItem::Answer(this.transform_ref(name_map, rdata_map))
            }
            Self::Authority(this) => MessageItem::Authority(
                this.transform_ref(name_map, rdata_map),
            ),
            Self::Additional(this) => MessageItem::Additional(
                this.transform_ref(name_map, rdata_map),
            ),
            Self::Edns(this) => {
                MessageItem::Edns(this.transform_ref(edata_map))
            }
        }
    }
}

//--- Equality

impl<N, RD, LED, RED> PartialEq<MessageItem<N, RD, RED>>
    for MessageItem<N, RD, LED>
where
    N: PartialEq,
    RD: PartialEq,
    LED: PartialEq<RED>,
{
    fn eq(&self, other: &MessageItem<N, RD, RED>) -> bool {
        match (self, other) {
            (MessageItem::Question(l), MessageItem::Question(r)) => l == r,
            (MessageItem::Answer(l), MessageItem::Answer(r)) => l == r,
            (MessageItem::Authority(l), MessageItem::Authority(r)) => l == r,
            (MessageItem::Additional(l), MessageItem::Additional(r)) => {
                l == r
            }
            (MessageItem::Edns(l), MessageItem::Edns(r)) => l == r,
            _ => false,
        }
    }
}

impl<N: Eq, RD: Eq, ED: Eq> Eq for MessageItem<N, RD, ED> {}

//--- Building into DNS messages

impl<N, RD, ED> BuildInMessage for MessageItem<N, RD, ED>
where
    N: BuildInMessage,
    RD: BuildInMessage,
    ED: BuildBytes,
{
    fn build_in_message(
        &self,
        contents: &mut [u8],
        start: usize,
        compressor: &mut NameCompressor,
    ) -> Result<usize, TruncationError> {
        match self {
            Self::Question(i) => {
                i.build_in_message(contents, start, compressor)
            }
            Self::Answer(i) => {
                i.build_in_message(contents, start, compressor)
            }
            Self::Authority(i) => {
                i.build_in_message(contents, start, compressor)
            }
            Self::Additional(i) => {
                i.build_in_message(contents, start, compressor)
            }
            Self::Edns(i) => i.build_in_message(contents, start, compressor),
        }
    }
}

//--- Building into bytes

impl<N, RD, ED> BuildBytes for MessageItem<N, RD, ED>
where
    N: BuildBytes,
    RD: BuildBytes,
    ED: BuildBytes,
{
    fn build_bytes<'b>(
        &self,
        bytes: &'b mut [u8],
    ) -> Result<&'b mut [u8], TruncationError> {
        match self {
            Self::Question(this) => this.build_bytes(bytes),
            Self::Answer(this) => this.build_bytes(bytes),
            Self::Authority(this) => this.build_bytes(bytes),
            Self::Additional(this) => this.build_bytes(bytes),
            Self::Edns(this) => this.build_bytes(bytes),
        }
    }

    fn built_bytes_size(&self) -> usize {
        match self {
            Self::Question(this) => this.built_bytes_size(),
            Self::Answer(this) => this.built_bytes_size(),
            Self::Authority(this) => this.built_bytes_size(),
            Self::Additional(this) => this.built_bytes_size(),
            Self::Edns(this) => this.built_bytes_size(),
        }
    }
}