hickory_proto/xfer/
dns_handle.rs

1// Copyright 2015-2018 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//! `DnsHandle` types perform conversions of the raw DNS messages before sending the messages on the specified streams.
9use std::error::Error;
10
11use futures_util::stream::Stream;
12use rand;
13use tracing::debug;
14
15use crate::op::{Message, MessageType, OpCode, Query};
16use crate::xfer::{DnsRequest, DnsRequestOptions, DnsResponse, SerialMessage};
17use crate::{error::*, op::Edns};
18
19// TODO: this should be configurable
20// > An EDNS buffer size of 1232 bytes will avoid fragmentation on nearly all current networks.
21// https://dnsflagday.net/2020/
22const MAX_PAYLOAD_LEN: u16 = 1232;
23
24/// Implementations of Sinks for sending DNS messages
25pub trait DnsStreamHandle: 'static + Send {
26    /// Sends a message to the Handle for delivery to the server.
27    fn send(&mut self, buffer: SerialMessage) -> Result<(), ProtoError>;
28}
29
30/// A trait for implementing high level functions of DNS.
31pub trait DnsHandle: 'static + Clone + Send + Sync + Unpin {
32    /// The associated response from the response stream, this should resolve to the Response messages
33    type Response: Stream<Item = Result<DnsResponse, Self::Error>> + Send + Unpin + 'static;
34    /// Error of the response, generally this will be `ProtoError`
35    type Error: From<ProtoError> + Error + Clone + Send + Unpin + 'static;
36
37    /// Only returns true if and only if this DNS handle is validating DNSSEC.
38    ///
39    /// If the DnsHandle impl is wrapping other clients, then the correct option is to delegate the question to the wrapped client.
40    fn is_verifying_dnssec(&self) -> bool {
41        false
42    }
43
44    /// Allow for disabling EDNS
45    fn is_using_edns(&self) -> bool {
46        true
47    }
48
49    /// Send a message via the channel in the client
50    ///
51    /// # Arguments
52    ///
53    /// * `request` - the fully constructed Message to send, note that most implementations of
54    ///               will most likely be required to rewrite the QueryId, do no rely on that as
55    ///               being stable.
56    fn send<R: Into<DnsRequest> + Unpin + Send + 'static>(&self, request: R) -> Self::Response;
57
58    /// A *classic* DNS query
59    ///
60    /// This is identical to `query`, but instead takes a `Query` object.
61    ///
62    /// # Arguments
63    ///
64    /// * `query` - the query to lookup
65    /// * `options` - options to use when constructing the message
66    fn lookup(&self, query: Query, options: DnsRequestOptions) -> Self::Response {
67        debug!("querying: {} {:?}", query.name(), query.query_type());
68        self.send(DnsRequest::new(build_message(query, options), options))
69    }
70}
71
72fn build_message(query: Query, options: DnsRequestOptions) -> Message {
73    // build the message
74    let mut message: Message = Message::new();
75    // TODO: This is not the final ID, it's actually set in the poll method of DNS future
76    //  should we just remove this?
77    let id: u16 = rand::random();
78    message
79        .add_query(query)
80        .set_id(id)
81        .set_message_type(MessageType::Query)
82        .set_op_code(OpCode::Query)
83        .set_recursion_desired(options.recursion_desired);
84
85    // Extended dns
86    if options.use_edns {
87        message
88            .extensions_mut()
89            .get_or_insert_with(Edns::new)
90            .set_max_payload(MAX_PAYLOAD_LEN)
91            .set_version(0);
92    }
93    message
94}