hickory_server/authority/
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 std::iter::once;
9
10use crate::proto::{
11    error::*,
12    op::{
13        message::{self, EmitAndCount},
14        Edns, Header, LowerQuery, Message, MessageType, OpCode, ResponseCode,
15    },
16    rr::Record,
17    serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder},
18};
19
20/// A Message which captures the data from an inbound request
21#[derive(Debug, PartialEq)]
22pub struct MessageRequest {
23    header: Header,
24    query: WireQuery,
25    answers: Vec<Record>,
26    name_servers: Vec<Record>,
27    additionals: Vec<Record>,
28    sig0: Vec<Record>,
29    edns: Option<Edns>,
30}
31
32impl MessageRequest {
33    /// Return the request header
34    pub fn header(&self) -> &Header {
35        &self.header
36    }
37
38    /// see `Header::id()`
39    pub fn id(&self) -> u16 {
40        self.header.id()
41    }
42
43    /// see `Header::message_type()`
44    pub fn message_type(&self) -> MessageType {
45        self.header.message_type()
46    }
47
48    /// see `Header::op_code()`
49    pub fn op_code(&self) -> OpCode {
50        self.header.op_code()
51    }
52
53    /// see `Header::authoritative()`
54    pub fn authoritative(&self) -> bool {
55        self.header.authoritative()
56    }
57
58    /// see `Header::truncated()`
59    pub fn truncated(&self) -> bool {
60        self.header.truncated()
61    }
62
63    /// see `Header::recursion_desired()`
64    pub fn recursion_desired(&self) -> bool {
65        self.header.recursion_desired()
66    }
67
68    /// see `Header::recursion_available()`
69    pub fn recursion_available(&self) -> bool {
70        self.header.recursion_available()
71    }
72
73    /// see `Header::authentic_data()`
74    pub fn authentic_data(&self) -> bool {
75        self.header.authentic_data()
76    }
77
78    /// see `Header::checking_disabled()`
79    pub fn checking_disabled(&self) -> bool {
80        self.header.checking_disabled()
81    }
82
83    /// # Return value
84    ///
85    /// The `ResponseCode`, if this is an EDNS message then this will join the section from the OPT
86    ///  record to create the EDNS `ResponseCode`
87    pub fn response_code(&self) -> ResponseCode {
88        self.header.response_code()
89    }
90
91    /// ```text
92    /// Question        Carries the query name and other query parameters.
93    /// ```
94    pub fn query(&self) -> &LowerQuery {
95        &self.query.query
96    }
97
98    /// ```text
99    /// Answer          Carries RRs which directly answer the query.
100    /// ```
101    pub fn answers(&self) -> &[Record] {
102        &self.answers
103    }
104
105    /// ```text
106    /// Authority       Carries RRs which describe other authoritative servers.
107    ///                 May optionally carry the SOA RR for the authoritative
108    ///                 data in the answer section.
109    /// ```
110    pub fn name_servers(&self) -> &[Record] {
111        &self.name_servers
112    }
113
114    /// ```text
115    /// Additional      Carries RRs which may be helpful in using the RRs in the
116    ///                 other sections.
117    /// ```
118    pub fn additionals(&self) -> &[Record] {
119        &self.additionals
120    }
121
122    /// [RFC 6891, EDNS(0) Extensions, April 2013](https://tools.ietf.org/html/rfc6891#section-6.1.1)
123    ///
124    /// ```text
125    /// 6.1.1.  Basic Elements
126    ///
127    ///  An OPT pseudo-RR (sometimes called a meta-RR) MAY be added to the
128    ///  additional data section of a request.
129    ///
130    ///  The OPT RR has RR type 41.
131    ///
132    ///  If an OPT record is present in a received request, compliant
133    ///  responders MUST include an OPT record in their respective responses.
134    ///
135    ///  An OPT record does not carry any DNS data.  It is used only to
136    ///  contain control information pertaining to the question-and-answer
137    ///  sequence of a specific transaction.  OPT RRs MUST NOT be cached,
138    ///  forwarded, or stored in or loaded from zone files.
139    ///
140    ///  The OPT RR MAY be placed anywhere within the additional data section.
141    ///  When an OPT RR is included within any DNS message, it MUST be the
142    ///  only OPT RR in that message.  If a query message with more than one
143    ///  OPT RR is received, a FORMERR (RCODE=1) MUST be returned.  The
144    ///  placement flexibility for the OPT RR does not override the need for
145    ///  the TSIG or SIG(0) RRs to be the last in the additional section
146    ///  whenever they are present.
147    /// ```
148    /// # Return value
149    ///
150    /// Returns the EDNS record if it was found in the additional section.
151    pub fn edns(&self) -> Option<&Edns> {
152        self.edns.as_ref()
153    }
154
155    /// Any SIG0 records for signed messages
156    pub fn sig0(&self) -> &[Record] {
157        &self.sig0
158    }
159
160    /// # Return value
161    ///
162    /// the max payload value as it's defined in the EDNS section.
163    pub fn max_payload(&self) -> u16 {
164        let max_size = self.edns.as_ref().map_or(512, Edns::max_payload);
165        if max_size < 512 {
166            512
167        } else {
168            max_size
169        }
170    }
171
172    /// # Return value
173    ///
174    /// the version as defined in the EDNS record
175    pub fn version(&self) -> u8 {
176        self.edns.as_ref().map_or(0, Edns::version)
177    }
178
179    /// Returns the original query received from the client
180    pub(crate) fn raw_query(&self) -> &WireQuery {
181        &self.query
182    }
183}
184
185impl<'q> BinDecodable<'q> for MessageRequest {
186    // TODO: generify this with Message?
187    /// Reads a MessageRequest from the decoder
188    fn read(decoder: &mut BinDecoder<'q>) -> ProtoResult<Self> {
189        let mut header = Header::read(decoder)?;
190
191        let mut try_parse_rest = move || {
192            // get all counts before header moves
193            let query_count = header.query_count() as usize;
194            let answer_count = header.answer_count() as usize;
195            let name_server_count = header.name_server_count() as usize;
196            let additional_count = header.additional_count() as usize;
197
198            let queries = Queries::read(decoder, query_count)?;
199            let query = queries.try_into_query()?;
200            let (answers, _, _) = Message::read_records(decoder, answer_count, false)?;
201            let (name_servers, _, _) = Message::read_records(decoder, name_server_count, false)?;
202            let (additionals, edns, sig0) = Message::read_records(decoder, additional_count, true)?;
203
204            // need to grab error code from EDNS (which might have a higher value)
205            if let Some(edns) = &edns {
206                let high_response_code = edns.rcode_high();
207                header.merge_response_code(high_response_code);
208            }
209
210            Ok(Self {
211                header,
212                query,
213                answers,
214                name_servers,
215                additionals,
216                sig0,
217                edns,
218            })
219        };
220
221        match try_parse_rest() {
222            Ok(message) => Ok(message),
223            Err(e) => Err(ProtoErrorKind::FormError {
224                header,
225                error: Box::new(e),
226            }
227            .into()),
228        }
229    }
230}
231
232/// A set of Queries with the associated serialized data
233#[derive(Debug, PartialEq, Eq)]
234pub struct Queries {
235    queries: Vec<LowerQuery>,
236    original: Box<[u8]>,
237}
238
239impl Queries {
240    fn read_queries(decoder: &mut BinDecoder<'_>, count: usize) -> ProtoResult<Vec<LowerQuery>> {
241        let mut queries = Vec::with_capacity(count);
242        for _ in 0..count {
243            queries.push(LowerQuery::read(decoder)?);
244        }
245        Ok(queries)
246    }
247
248    /// Read queries from a decoder
249    pub fn read(decoder: &mut BinDecoder<'_>, num_queries: usize) -> ProtoResult<Self> {
250        let queries_start = decoder.index();
251        let queries = Self::read_queries(decoder, num_queries)?;
252        let original = decoder
253            .slice_from(queries_start)?
254            .to_vec()
255            .into_boxed_slice();
256
257        Ok(Self { queries, original })
258    }
259
260    /// return the number of queries in the request
261    pub fn len(&self) -> usize {
262        self.queries.len()
263    }
264
265    /// Returns true if there are no queries
266    pub fn is_empty(&self) -> bool {
267        self.queries.is_empty()
268    }
269
270    /// returns the bytes as they were seen from the Client
271    pub fn as_bytes(&self) -> &[u8] {
272        self.original.as_ref()
273    }
274
275    pub(crate) fn as_emit_and_count(&self) -> QueriesEmitAndCount<'_> {
276        QueriesEmitAndCount {
277            length: self.queries.len(),
278            // We don't generally support more than one query, but this will at least give us one
279            // cache entry.
280            first_query: self.queries.first(),
281            cached_serialized: self.original.as_ref(),
282        }
283    }
284
285    /// Performs a validation that this set of Queries is one and only one Query
286    pub(crate) fn try_into_query(mut self) -> Result<WireQuery, ProtoError> {
287        let count = self.queries.len();
288        if count == 1 {
289            let query = self.queries.pop().expect("should have been at least one");
290
291            Ok(WireQuery {
292                query,
293                original: self.original,
294            })
295        } else {
296            Err(ProtoErrorKind::BadQueryCount(count).into())
297        }
298    }
299}
300
301/// A query with the original bytes stored from the query
302#[derive(Debug, PartialEq)]
303pub(crate) struct WireQuery {
304    query: LowerQuery,
305    original: Box<[u8]>,
306}
307
308impl WireQuery {
309    pub(crate) fn as_emit_and_count(&self) -> QueriesEmitAndCount<'_> {
310        QueriesEmitAndCount {
311            length: 1,
312            first_query: Some(&self.query),
313            cached_serialized: self.original.as_ref(),
314        }
315    }
316}
317
318pub(crate) struct QueriesEmitAndCount<'q> {
319    /// Number of queries in this segment
320    length: usize,
321    /// Use the first query, if it exists, to pre-populate the string compression cache
322    first_query: Option<&'q LowerQuery>,
323    /// The cached rendering of the original (wire-format) queries
324    cached_serialized: &'q [u8],
325}
326
327impl EmitAndCount for QueriesEmitAndCount<'_> {
328    fn emit(&mut self, encoder: &mut BinEncoder<'_>) -> ProtoResult<usize> {
329        let original_offset = encoder.offset();
330        encoder.emit_vec(self.cached_serialized)?;
331        if !encoder.is_canonical_names() {
332            if let Some(query) = self.first_query {
333                encoder.store_label_pointer(
334                    original_offset,
335                    original_offset + query.original().name().len(),
336                )
337            }
338        }
339        Ok(self.length)
340    }
341}
342
343impl BinEncodable for MessageRequest {
344    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
345        message::emit_message_parts(
346            &self.header,
347            // we emit the queries, not the raw bytes, in order to guarantee canonical form
348            //   in cases where that's necessary, like SIG0 validation
349            &mut once(&self.query.query),
350            &mut self.answers.iter(),
351            &mut self.name_servers.iter(),
352            &mut self.additionals.iter(),
353            self.edns.as_ref(),
354            &self.sig0,
355            encoder,
356        )?;
357
358        Ok(())
359    }
360}
361
362/// A type which represents an MessageRequest for dynamic Update.
363pub trait UpdateRequest {
364    /// Id of the Message
365    fn id(&self) -> u16;
366
367    /// Zone being updated, this should be the query of a Message
368    fn zone(&self) -> &LowerQuery;
369
370    /// Prerequisites map to the answers of a Message
371    fn prerequisites(&self) -> &[Record];
372
373    /// Records to update map to the name_servers of a Message
374    fn updates(&self) -> &[Record];
375
376    /// Additional records
377    fn additionals(&self) -> &[Record];
378
379    /// SIG0 records for verifying the Message
380    fn sig0(&self) -> &[Record];
381}
382
383impl UpdateRequest for MessageRequest {
384    fn id(&self) -> u16 {
385        Self::id(self)
386    }
387
388    fn zone(&self) -> &LowerQuery {
389        self.query()
390    }
391
392    fn prerequisites(&self) -> &[Record] {
393        self.answers()
394    }
395
396    fn updates(&self) -> &[Record] {
397        self.name_servers()
398    }
399
400    fn additionals(&self) -> &[Record] {
401        self.additionals()
402    }
403
404    fn sig0(&self) -> &[Record] {
405        self.sig0()
406    }
407}