Skip to main content

hickory_server/zone_handler/
message_request.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
8use crate::{
9    proto::{
10        ProtoError,
11        op::{Edns, EmitAndCount, Header, LowerQuery, Message, Metadata, emit_message_parts},
12        rr::{Record, rdata::TSIG},
13        serialize::binary::{
14            BinDecodable, BinDecoder, BinEncodable, BinEncoder, DecodeError, NameEncoding,
15        },
16    },
17    zone_handler::LookupError,
18};
19
20/// A Message which captures the data from an inbound request
21#[derive(Debug, PartialEq)]
22pub struct MessageRequest {
23    /// Metadata from the message header
24    pub metadata: Metadata,
25    /// Query name and other query parameters
26    pub queries: Queries,
27    /// Records which directly answer the query
28    pub answers: Vec<Record>,
29    /// Records with describe other authoritative servers
30    ///
31    /// May optionally carry the SOA record for the authoritative data in the answer section.
32    pub authorities: Vec<Record>,
33    /// Records which may be helpful in using the records in the other sections
34    pub additionals: Vec<Record>,
35    /// TSIG signature for the message, if any
36    pub signature: Option<Box<Record<TSIG>>>,
37    /// [RFC 6891, EDNS(0) Extensions, April 2013](https://tools.ietf.org/html/rfc6891#section-6.1.1)
38    ///
39    /// ```text
40    /// 6.1.1.  Basic Elements
41    ///
42    ///  An OPT pseudo-RR (sometimes called a meta-RR) MAY be added to the
43    ///  additional data section of a request.
44    ///
45    ///  The OPT RR has RR type 41.
46    ///
47    ///  If an OPT record is present in a received request, compliant
48    ///  responders MUST include an OPT record in their respective responses.
49    ///
50    ///  An OPT record does not carry any DNS data.  It is used only to
51    ///  contain control information pertaining to the question-and-answer
52    ///  sequence of a specific transaction.  OPT RRs MUST NOT be cached,
53    ///  forwarded, or stored in or loaded from Zone Files.
54    ///
55    ///  The OPT RR MAY be placed anywhere within the additional data section.
56    ///  When an OPT RR is included within any DNS message, it MUST be the
57    ///  only OPT RR in that message.  If a query message with more than one
58    ///  OPT RR is received, a FORMERR (RCODE=1) MUST be returned.  The
59    ///  placement flexibility for the OPT RR does not override the need for
60    ///  the TSIG or SIG(0) RRs to be the last in the additional section
61    ///  whenever they are present.
62    /// ```
63    /// # Return value
64    ///
65    /// Optionally returns a reference to EDNS OPT pseudo-RR
66    pub edns: Option<Edns>,
67}
68
69impl MessageRequest {
70    // TODO: generify this with Message?
71    /// Reads a MessageRequest from the decoder
72    pub(crate) fn read(decoder: &mut BinDecoder<'_>, header: Header) -> Result<Self, DecodeError> {
73        let Header {
74            mut metadata,
75            counts,
76        } = header;
77        let queries = Queries::read(decoder, counts.queries as usize)?;
78        let (answers, _, _) =
79            Message::read_records(decoder, counts.answers as usize, false, metadata.op_code)?;
80        let (authorities, _, _) = Message::read_records(
81            decoder,
82            counts.authorities as usize,
83            false,
84            metadata.op_code,
85        )?;
86        let (additionals, edns, signature) =
87            Message::read_records(decoder, counts.additionals as usize, true, metadata.op_code)?;
88
89        // need to grab error code from EDNS (which might have a higher value)
90        if let Some(edns) = &edns {
91            let high_response_code = edns.rcode_high();
92            metadata.merge_response_code(high_response_code);
93        }
94
95        Ok(Self {
96            metadata,
97            queries,
98            answers,
99            authorities,
100            additionals,
101            signature,
102            edns,
103        })
104    }
105
106    /// Construct a mock MessageRequest for testing purposes
107    ///
108    /// The unspecified fields are left empty.
109    #[cfg(any(test, feature = "testing"))]
110    pub fn mock(metadata: Metadata, query: impl Into<LowerQuery>) -> Self {
111        Self {
112            metadata,
113            queries: Queries::new(vec![query.into()]),
114            answers: Vec::new(),
115            authorities: Vec::new(),
116            additionals: Vec::new(),
117            signature: None,
118            edns: None,
119        }
120    }
121
122    /// # Return value
123    ///
124    /// the max payload value as it's defined in the EDNS OPT pseudo-RR.
125    pub fn max_payload(&self) -> u16 {
126        let max_size = self.edns.as_ref().map_or(512, Edns::max_payload);
127        if max_size < 512 { 512 } else { max_size }
128    }
129
130    /// # Return value
131    ///
132    /// the version as defined in the EDNS record
133    pub fn version(&self) -> u8 {
134        self.edns.as_ref().map_or(0, Edns::version)
135    }
136}
137
138/// A set of Queries with the associated serialized data
139#[derive(Debug, PartialEq, Eq)]
140pub struct Queries {
141    queries: Vec<LowerQuery>,
142    original: Box<[u8]>,
143}
144
145impl Queries {
146    /// Construct a mock Queries object for a given query for testing purposes
147    #[cfg(any(test, feature = "testing"))]
148    pub fn new(query: Vec<LowerQuery>) -> Self {
149        let mut encoded = Vec::new();
150        let mut encoder = BinEncoder::new(&mut encoded);
151        for q in query.iter() {
152            q.emit(&mut encoder).unwrap();
153        }
154        Self {
155            queries: query,
156            original: encoded.into_boxed_slice(),
157        }
158    }
159
160    /// Read queries from a decoder
161    pub fn read(decoder: &mut BinDecoder<'_>, num_queries: usize) -> Result<Self, DecodeError> {
162        let queries_start = decoder.index();
163        let mut queries = Vec::with_capacity(num_queries);
164        for _ in 0..num_queries {
165            queries.push(LowerQuery::read(decoder)?);
166        }
167
168        let original = decoder
169            .slice_from(queries_start)?
170            .to_vec()
171            .into_boxed_slice();
172
173        Ok(Self { queries, original })
174    }
175
176    /// return the number of queries in the request
177    pub fn len(&self) -> usize {
178        self.queries.len()
179    }
180
181    /// Returns true if there are no queries
182    pub fn is_empty(&self) -> bool {
183        self.queries.is_empty()
184    }
185
186    /// Returns the queries from the request
187    pub fn queries(&self) -> &[LowerQuery] {
188        &self.queries
189    }
190
191    /// returns the bytes as they were seen from the Client
192    pub fn as_bytes(&self) -> &[u8] {
193        self.original.as_ref()
194    }
195
196    pub(crate) fn as_emit_and_count(&self) -> QueriesEmitAndCount<'_> {
197        QueriesEmitAndCount {
198            length: self.queries.len(),
199            // We don't generally support more than one query, but this will at least give us one
200            // cache entry.
201            first_query: self.queries.first(),
202            cached_serialized: self.original.as_ref(),
203        }
204    }
205
206    /// Validate that this set of Queries contains exactly one Query, and return a reference to the
207    /// `LowerQuery` if so.
208    pub(crate) fn try_as_query(&self) -> Result<&LowerQuery, LookupError> {
209        let count = self.queries.len();
210        if count != 1 {
211            return Err(LookupError::BadQueryCount(count));
212        }
213        Ok(&self.queries[0])
214    }
215
216    /// Construct an empty set of queries
217    pub(crate) fn empty() -> Self {
218        Self {
219            queries: Vec::new(),
220            original: (*b"").into(),
221        }
222    }
223}
224
225pub(crate) struct QueriesEmitAndCount<'q> {
226    /// Number of queries in this segment
227    length: usize,
228    /// Use the first query, if it exists, to pre-populate the string compression cache
229    first_query: Option<&'q LowerQuery>,
230    /// The cached rendering of the original (wire-format) queries
231    cached_serialized: &'q [u8],
232}
233
234impl EmitAndCount for QueriesEmitAndCount<'_> {
235    fn emit(&mut self, encoder: &mut BinEncoder<'_>) -> Result<usize, ProtoError> {
236        let original_offset = encoder.offset();
237        encoder.emit_vec(self.cached_serialized)?;
238        if matches!(encoder.name_encoding(), NameEncoding::Compressed) && self.first_query.is_some()
239        {
240            encoder.store_label_pointer(
241                original_offset,
242                original_offset + self.cached_serialized.len(),
243            )
244        }
245        Ok(self.length)
246    }
247}
248
249impl BinEncodable for MessageRequest {
250    fn emit(&self, encoder: &mut BinEncoder<'_>) -> Result<(), ProtoError> {
251        emit_message_parts(
252            &self.metadata,
253            // we emit the queries, not the raw bytes, in order to guarantee canonical form
254            //   in cases where that's necessary, like SIG0 validation
255            &mut self.queries.queries.iter(),
256            &mut self.answers.iter(),
257            &mut self.authorities.iter(),
258            &mut self.additionals.iter(),
259            self.edns.as_ref(),
260            self.signature.as_deref(),
261            encoder,
262        )?;
263
264        Ok(())
265    }
266}
267
268/// A type which represents an MessageRequest for dynamic Update.
269pub trait UpdateRequest {
270    /// Id of the Message
271    fn id(&self) -> u16;
272
273    /// Zone being updated, this should be the query of a Message
274    fn zone(&self) -> Result<&LowerQuery, LookupError>;
275
276    /// Prerequisites map to the Answer section of a Message
277    fn prerequisites(&self) -> &[Record];
278
279    /// Records to update map to the Authority section of a Message
280    fn updates(&self) -> &[Record];
281
282    /// Additional records
283    fn additionals(&self) -> &[Record];
284
285    /// Signature for verifying the Message
286    fn signature(&self) -> Option<&Record<TSIG>>;
287}
288
289impl UpdateRequest for MessageRequest {
290    fn id(&self) -> u16 {
291        self.metadata.id
292    }
293
294    fn zone(&self) -> Result<&LowerQuery, LookupError> {
295        // RFC 2136 says "the Zone Section is allowed to contain exactly one record."
296        self.queries.try_as_query()
297    }
298
299    fn prerequisites(&self) -> &[Record] {
300        &self.answers
301    }
302
303    fn updates(&self) -> &[Record] {
304        &self.authorities
305    }
306
307    fn additionals(&self) -> &[Record] {
308        &self.additionals
309    }
310
311    fn signature(&self) -> Option<&Record<TSIG>> {
312        self.signature.as_deref()
313    }
314}