Coverage Report

Created: 2026-07-25 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hickory-dns/crates/proto/src/op/header.rs
Line
Count
Source
1
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
2
//
3
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4
// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5
// https://opensource.org/licenses/MIT>, at your option. This file may not be
6
// copied, modified, or distributed except according to those terms.
7
8
//! Message metadata
9
10
#[cfg(test)]
11
use alloc::vec::Vec;
12
use core::{
13
    convert::From,
14
    fmt,
15
    ops::{Deref, DerefMut},
16
};
17
18
#[cfg(feature = "serde")]
19
use serde::{Deserialize, Serialize};
20
21
use crate::{
22
    error::*,
23
    op::{op_code::OpCode, response_code::ResponseCode},
24
    serialize::binary::*,
25
};
26
27
/// Metadata for the `Message` struct.
28
///
29
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
30
///
31
/// ```text
32
/// 4.1.1. Header section format
33
///
34
/// The header contains the following fields
35
///
36
///                                    1  1  1  1  1  1
37
///      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
38
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
39
///     |                      ID                       |
40
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
41
///     |QR|   Opcode  |AA|TC|RD|RA|ZZ|AD|CD|   RCODE   |  /// AD and CD from RFC4035
42
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
43
///     |                    QDCOUNT / ZCOUNT           |
44
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
45
///     |                    ANCOUNT / PRCOUNT          |
46
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
47
///     |                    NSCOUNT / UPCOUNT          |
48
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
49
///     |                    ARCOUNT / ADCOUNT          |
50
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
51
///
52
/// where
53
///
54
/// Z               Reserved for future use.  Must be zero in all queries
55
///                 and responses.
56
///
57
/// ```
58
///
59
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Hash)]
60
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
61
pub struct Header {
62
    /// The message metadata (ID, flags, response and op code)
63
    #[cfg_attr(feature = "serde", serde(flatten))]
64
    pub metadata: Metadata,
65
    /// Record counts for the message, for use during encoding/decoding
66
    #[cfg_attr(feature = "serde", serde(flatten))]
67
    pub counts: HeaderCounts,
68
}
69
70
impl BinEncodable for Header {
71
6.66k
    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
72
        // Id
73
6.66k
        self.id.emit(encoder)?;
74
75
        // IsQuery, OpCode, Authoritative, Truncation, RecursionDesired
76
6.66k
        let mut q_opcd_a_t_r = if let MessageType::Response = self.message_type {
77
1.45k
            0x80
78
        } else {
79
5.20k
            0x00
80
        };
81
6.66k
        q_opcd_a_t_r |= u8::from(self.op_code) << 3;
82
6.66k
        q_opcd_a_t_r |= if self.authoritative { 0x4 } else { 0x0 };
83
6.66k
        q_opcd_a_t_r |= if self.truncation { 0x2 } else { 0x0 };
84
6.66k
        q_opcd_a_t_r |= if self.recursion_desired { 0x1 } else { 0x0 };
85
6.66k
        q_opcd_a_t_r.emit(encoder)?;
86
87
        // IsRecursionAvailable, Triple 0's, ResponseCode
88
6.66k
        let mut r_z_ad_cd_rcod = if self.recursion_available {
89
1.04k
            0b1000_0000
90
        } else {
91
5.62k
            0b0000_0000
92
        };
93
6.66k
        r_z_ad_cd_rcod |= if self.authentic_data {
94
2.22k
            0b0010_0000
95
        } else {
96
4.44k
            0b0000_0000
97
        };
98
6.66k
        r_z_ad_cd_rcod |= if self.checking_disabled {
99
2.32k
            0b0001_0000
100
        } else {
101
4.34k
            0b0000_0000
102
        };
103
6.66k
        r_z_ad_cd_rcod |= self.response_code.low();
104
6.66k
        r_z_ad_cd_rcod.emit(encoder)?;
105
106
6.66k
        self.counts.queries.emit(encoder)?;
107
6.66k
        self.counts.answers.emit(encoder)?;
108
6.66k
        self.counts.authorities.emit(encoder)?;
109
6.66k
        self.counts.additionals.emit(encoder)?;
110
111
6.66k
        Ok(())
112
6.66k
    }
113
}
114
115
impl<'r> BinDecodable<'r> for Header {
116
17.7k
    fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
117
17.7k
        let id = decoder.read_u16()?.unverified(/*it is valid for this to be any u16*/);
118
119
17.6k
        let q_opcd_a_t_r = decoder.pop()?.unverified(/*used as a bitfield, this is safe*/);
120
        // if the first bit is set
121
17.6k
        let message_type = if (0b1000_0000 & q_opcd_a_t_r) == 0b1000_0000 {
122
3.69k
            MessageType::Response
123
        } else {
124
13.9k
            MessageType::Query
125
        };
126
        // the 4bit opcode, masked and then shifted right 3bits for the u8...
127
17.6k
        let op_code = OpCode::from_u8((0b0111_1000 & q_opcd_a_t_r) >> 3);
128
17.6k
        let authoritative = (0b0000_0100 & q_opcd_a_t_r) == 0b0000_0100;
129
17.6k
        let truncation = (0b0000_0010 & q_opcd_a_t_r) == 0b0000_0010;
130
17.6k
        let recursion_desired = (0b0000_0001 & q_opcd_a_t_r) == 0b0000_0001;
131
132
17.6k
        let r_z_ad_cd_rcod = decoder.pop()?.unverified(/*used as a bitfield, this is safe*/); // fail fast...
133
134
17.6k
        let recursion_available = (0b1000_0000 & r_z_ad_cd_rcod) == 0b1000_0000;
135
17.6k
        let authentic_data = (0b0010_0000 & r_z_ad_cd_rcod) == 0b0010_0000;
136
17.6k
        let checking_disabled = (0b0001_0000 & r_z_ad_cd_rcod) == 0b0001_0000;
137
17.6k
        let response_code: u8 = 0b0000_1111 & r_z_ad_cd_rcod;
138
17.6k
        let response_code = ResponseCode::from_low(response_code);
139
140
17.6k
        let metadata = Metadata {
141
17.6k
            id,
142
17.6k
            message_type,
143
17.6k
            op_code,
144
17.6k
            authoritative,
145
17.6k
            truncation,
146
17.6k
            recursion_desired,
147
17.6k
            recursion_available,
148
17.6k
            authentic_data,
149
17.6k
            checking_disabled,
150
17.6k
            response_code,
151
17.6k
        };
152
153
17.6k
        let counts = HeaderCounts {
154
17.6k
            queries: decoder.read_u16()?.unverified(/*this must be verified when reading queries*/),
155
17.6k
            answers: decoder.read_u16()?.unverified(/*this must be verified when reading answers*/),
156
17.6k
            authorities: decoder.read_u16()?.unverified(/*this must be verified when reading answers*/),
157
17.6k
            additionals: decoder.read_u16()?.unverified(/*this must be verified when reading answers*/),
158
        };
159
160
17.6k
        Ok(Self { metadata, counts })
161
17.7k
    }
162
}
163
164
impl EncodedSize for Header {
165
    const LEN: usize = 12;
166
}
167
168
impl Deref for Header {
169
    type Target = Metadata;
170
171
66.6k
    fn deref(&self) -> &Self::Target {
172
66.6k
        &self.metadata
173
66.6k
    }
174
}
175
176
impl DerefMut for Header {
177
0
    fn deref_mut(&mut self) -> &mut Self::Target {
178
0
        &mut self.metadata
179
0
    }
180
}
181
182
/// Message metadata, including the message ID, flags, response code, and op code.
183
#[non_exhaustive]
184
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Hash)]
185
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
186
pub struct Metadata {
187
    /// ```text
188
    /// ID              A 16 bit identifier assigned by the program that
189
    ///                 generates any kind of query.  This identifier is copied
190
    ///                 the corresponding reply and can be used by the requester
191
    ///                 to match up replies to outstanding queries.
192
    /// ```
193
    pub id: u16,
194
    /// ```text
195
    /// QR              A one bit field that specifies whether this message is a
196
    ///                 query (0), or a response (1).
197
    /// ```
198
    pub message_type: MessageType,
199
    /// ```text
200
    /// OPCODE          A four bit field that specifies kind of query in this
201
    ///                 message.  This value is set by the originator of a query
202
    ///                 and copied into the response.  The values are: <see super::op_code>
203
    /// ```
204
    pub op_code: OpCode,
205
    /// ```text
206
    /// AA              Authoritative Answer - this bit is valid in responses,
207
    ///                 and specifies that the responding name server is an
208
    ///                 authority for the domain name in question section.
209
    ///
210
    ///                 Note that the contents of the answer section may have
211
    ///                 multiple owner names because of aliases.  The AA bit
212
    ///                 corresponds to the name which matches the query name, or
213
    ///                 the first owner name in the answer section.
214
    /// ```
215
    pub authoritative: bool,
216
    /// ```text
217
    /// TC              TrunCation - specifies that this message was truncated
218
    ///                 due to length greater than that permitted on the
219
    ///                 transmission channel.
220
    /// ```
221
    pub truncation: bool,
222
    /// ```text
223
    /// RD              Recursion Desired - this bit may be set in a query and
224
    ///                 is copied into the response.  If RD is set, it directs
225
    ///                 the name server to pursue the query recursively.
226
    ///                 Recursive query support is optional.
227
    /// ```
228
    pub recursion_desired: bool,
229
    /// ```text
230
    /// RA              Recursion Available - this be is set or cleared in a
231
    ///                 response, and denotes whether recursive query support is
232
    ///                 available in the name server.
233
    /// ```
234
    pub recursion_available: bool,
235
    /// [RFC 4035, DNSSEC Resource Records, March 2005](https://tools.ietf.org/html/rfc4035#section-3.1.6)
236
    ///
237
    /// ```text
238
    ///
239
    /// 3.1.6.  The AD and CD Bits in an Authoritative Response
240
    ///
241
    ///   The CD and AD bits are designed for use in communication between
242
    ///   security-aware resolvers and security-aware recursive name servers.
243
    ///   These bits are for the most part not relevant to query processing by
244
    ///   security-aware authoritative name servers.
245
    ///
246
    ///   A security-aware name server does not perform signature validation
247
    ///   for authoritative data during query processing, even when the CD bit
248
    ///   is clear.  A security-aware name server SHOULD clear the CD bit when
249
    ///   composing an authoritative response.
250
    ///
251
    ///   A security-aware name server MUST NOT set the AD bit in a response
252
    ///   unless the name server considers all RRsets in the Answer and
253
    ///   Authority sections of the response to be authentic.  A security-aware
254
    ///   name server's local policy MAY consider data from an authoritative
255
    ///   zone to be authentic without further validation.  However, the name
256
    ///   server MUST NOT do so unless the name server obtained the
257
    ///   authoritative zone via secure means (such as a secure zone transfer
258
    ///   mechanism) and MUST NOT do so unless this behavior has been
259
    ///   configured explicitly.
260
    ///
261
    ///   A security-aware name server that supports recursion MUST follow the
262
    ///   rules for the CD and AD bits given in Section 3.2 when generating a
263
    ///   response that involves data obtained via recursion.
264
    /// ```
265
    pub authentic_data: bool,
266
    /// See [`Metadata::authentic_data`] for more information on the CD bit.
267
    pub checking_disabled: bool,
268
    /// ```text
269
    /// RCODE           Response code - this 4 bit field is set as part of
270
    ///                 responses.  The values have the following
271
    ///                 interpretation: <see super::response_code>
272
    /// ```
273
    pub response_code: ResponseCode,
274
}
275
276
impl Metadata {
277
    /// Construct a new `Metadata` with the given `id`, `message_type`, and `op_code`.
278
0
    pub const fn new(id: u16, message_type: MessageType, op_code: OpCode) -> Self {
279
0
        Self {
280
0
            id,
281
0
            message_type,
282
0
            op_code,
283
0
            authoritative: false,
284
0
            truncation: false,
285
0
            recursion_desired: false,
286
0
            recursion_available: false,
287
0
            authentic_data: false,
288
0
            checking_disabled: false,
289
0
            response_code: ResponseCode::NoError,
290
0
        }
291
0
    }
292
293
    /// Construct new metadata based off the request metadata.
294
    ///
295
    /// This copies over the RD (recursion-desired) and CD (checking-disabled),
296
    /// as well as the op_code and id of the request.
297
    ///
298
    /// See <https://datatracker.ietf.org/doc/html/rfc6895#section-2>
299
    ///
300
    /// ```text
301
    /// The AA, TC, RD, RA, and CD bits are each theoretically meaningful
302
    ///    only in queries or only in responses, depending on the bit.  The AD
303
    ///    bit was only meaningful in responses but is expected to have a
304
    ///    separate but related meaning in queries (see Section 5.7 of
305
    ///    [RFC6840]).  Only the RD and CD bits are expected to be copied from
306
    ///    the query to the response; however, some DNS implementations copy all
307
    ///    the query header as the initial value of the response header.  Thus,
308
    ///    any attempt to use a "query" bit with a different meaning in a
309
    ///    response or to define a query meaning for a "response" bit may be
310
    ///    dangerous, given the existing implementation.  Meanings for these
311
    ///    bits may only be assigned by a Standards Action.
312
    /// ```
313
0
    pub fn response_from_request(req: &Self) -> Self {
314
0
        Self {
315
0
            id: req.id,
316
0
            message_type: MessageType::Response,
317
0
            op_code: req.op_code,
318
0
            authoritative: false,
319
0
            truncation: false,
320
0
            recursion_desired: req.recursion_desired,
321
0
            recursion_available: false,
322
0
            authentic_data: false,
323
0
            checking_disabled: req.checking_disabled,
324
0
            response_code: ResponseCode::default(),
325
0
        }
326
0
    }
327
328
    /// A method to get all header flags (useful for Display purposes)
329
0
    pub fn flags(&self) -> Flags {
330
0
        Flags {
331
0
            authoritative: self.authoritative,
332
0
            authentic_data: self.authentic_data,
333
0
            checking_disabled: self.checking_disabled,
334
0
            recursion_available: self.recursion_available,
335
0
            recursion_desired: self.recursion_desired,
336
0
            truncation: self.truncation,
337
0
        }
338
0
    }
339
340
    /// This combines the high and low response code values to form the complete ResponseCode from the EDNS record.
341
    ///   The existing high order bits will be overwritten (if set), and `high_response_code` will be merge with
342
    ///   the existing low order bits.
343
    ///
344
    /// This is intended for use during decoding.
345
    #[doc(hidden)]
346
1.95k
    pub fn merge_response_code(&mut self, high_response_code: u8) {
347
1.95k
        self.response_code = ResponseCode::from(high_response_code, self.response_code.low());
348
1.95k
    }
349
}
350
351
impl fmt::Display for Metadata {
352
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
353
0
        write!(
354
0
            f,
355
0
            "{id}:{message_type}:{flags}:{code:?}:{op_code}",
356
            id = self.id,
357
            message_type = self.message_type,
358
0
            flags = self.flags(),
359
            code = self.response_code,
360
            op_code = self.op_code,
361
        )
362
0
    }
363
}
364
365
/// Tracks the counts of the records in the Message.
366
///
367
/// This is only used internally during serialization.
368
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Eq, Hash)]
369
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
370
pub struct HeaderCounts {
371
    /// The number of queries in the Message
372
    pub queries: u16,
373
    /// The number of answer records in the Message
374
    pub answers: u16,
375
    /// The number of authority records in the Message
376
    pub authorities: u16,
377
    /// The number of additional records in the Message
378
    pub additionals: u16,
379
}
380
381
/// Message types are either Query (also Update) or Response
382
#[derive(Debug, PartialEq, Eq, PartialOrd, Copy, Clone, Hash)]
383
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
384
pub enum MessageType {
385
    /// Queries are Client requests, these are either Queries or Updates
386
    Query,
387
    /// Response message from the Server or upstream Resolver
388
    Response,
389
}
390
391
impl fmt::Display for MessageType {
392
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
393
0
        let s = match self {
394
0
            Self::Query => "QUERY",
395
0
            Self::Response => "RESPONSE",
396
        };
397
398
0
        f.write_str(s)
399
0
    }
400
}
401
402
/// All the flags of the request/response header
403
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
404
pub struct Flags {
405
    authoritative: bool,
406
    truncation: bool,
407
    recursion_desired: bool,
408
    recursion_available: bool,
409
    authentic_data: bool,
410
    checking_disabled: bool,
411
}
412
413
/// We are following the `dig` commands display format for the header flags
414
///
415
/// Example: "RD,AA,RA;" is Recursion-Desired, Authoritative-Answer, Recursion-Available.
416
impl fmt::Display for Flags {
417
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
418
        const SEPARATOR: &str = ",";
419
420
0
        let flags = [
421
0
            (self.recursion_desired, "RD"),
422
0
            (self.checking_disabled, "CD"),
423
0
            (self.truncation, "TC"),
424
0
            (self.authoritative, "AA"),
425
0
            (self.recursion_available, "RA"),
426
0
            (self.authentic_data, "AD"),
427
0
        ];
428
429
0
        let mut iter = flags
430
0
            .iter()
431
0
            .cloned()
432
0
            .filter_map(|(flag, s)| if flag { Some(s) } else { None });
433
434
        // print first without a separator, then print the rest.
435
0
        if let Some(s) = iter.next() {
436
0
            f.write_str(s)?
437
0
        }
438
0
        for s in iter {
439
0
            f.write_str(SEPARATOR)?;
440
0
            f.write_str(s)?;
441
        }
442
443
0
        Ok(())
444
0
    }
445
}
446
447
#[cfg(test)]
448
mod tests {
449
    use super::*;
450
451
    #[test]
452
    fn test_parse() {
453
        let byte_vec = vec![
454
            0x01, 0x10, 0xAA, 0x83, // 0b1010 1010 1000 0011
455
            0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
456
        ];
457
458
        let mut decoder = BinDecoder::new(&byte_vec);
459
460
        let expect = Header {
461
            metadata: Metadata {
462
                id: 0x0110,
463
                message_type: MessageType::Response,
464
                op_code: OpCode::Update,
465
                authoritative: false,
466
                truncation: true,
467
                recursion_desired: false,
468
                recursion_available: true,
469
                authentic_data: false,
470
                checking_disabled: false,
471
                response_code: ResponseCode::NXDomain,
472
            },
473
            counts: HeaderCounts {
474
                queries: 0x8877,
475
                answers: 0x6655,
476
                authorities: 0x4433,
477
                additionals: 0x2211,
478
            },
479
        };
480
481
        let got = Header::read(&mut decoder).unwrap();
482
483
        assert_eq!(got, expect);
484
    }
485
486
    #[test]
487
    fn test_write() {
488
        let header = Header {
489
            metadata: Metadata {
490
                id: 0x0110,
491
                message_type: MessageType::Response,
492
                op_code: OpCode::Update,
493
                authoritative: false,
494
                truncation: true,
495
                recursion_desired: false,
496
                recursion_available: true,
497
                authentic_data: false,
498
                checking_disabled: false,
499
                response_code: ResponseCode::NXDomain,
500
            },
501
            counts: HeaderCounts {
502
                queries: 0x8877,
503
                answers: 0x6655,
504
                authorities: 0x4433,
505
                additionals: 0x2211,
506
            },
507
        };
508
509
        let expect = vec![
510
            0x01, 0x10, 0xAA, 0x83, // 0b1010 1010 1000 0011
511
            0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
512
        ];
513
514
        let mut bytes = Vec::with_capacity(512);
515
        {
516
            let mut encoder = BinEncoder::new(&mut bytes);
517
            header.emit(&mut encoder).unwrap();
518
        }
519
520
        assert_eq!(bytes, expect);
521
    }
522
}