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}