Skip to main content

hickory_proto/op/
header.rs

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