trust_dns_resolver/name_server/
name_server.rs

1// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://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::cmp::Ordering;
9use std::fmt::{self, Debug, Formatter};
10use std::pin::Pin;
11use std::sync::Arc;
12use std::time::Instant;
13
14use futures_util::lock::Mutex;
15use futures_util::stream::{once, Stream};
16
17#[cfg(feature = "mdns")]
18use proto::multicast::MDNS_IPV4;
19use proto::xfer::{DnsHandle, DnsRequest, DnsResponse, FirstAnswer};
20use tracing::debug;
21
22use crate::config::{NameServerConfig, ResolverOpts};
23use crate::error::ResolveError;
24use crate::name_server::connection_provider::{ConnectionProvider, GenericConnector};
25use crate::name_server::{NameServerState, NameServerStats};
26#[cfg(feature = "mdns")]
27use proto::multicast::{MdnsClientConnect, MdnsClientStream, MdnsQueryType};
28
29/// This struct is used to create `DnsHandle` with the help of `P`.
30#[derive(Clone)]
31pub struct NameServer<P: ConnectionProvider> {
32    config: NameServerConfig,
33    options: ResolverOpts,
34    client: Arc<Mutex<Option<P::Conn>>>,
35    state: Arc<NameServerState>,
36    stats: Arc<NameServerStats>,
37    connection_provider: P,
38}
39
40/// Specifies the details of a remote NameServer used for lookups
41pub type GenericNameServer<R> = NameServer<GenericConnector<R>>;
42
43impl<P> Debug for NameServer<P>
44where
45    P: ConnectionProvider + Send,
46{
47    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
48        write!(f, "config: {:?}, options: {:?}", self.config, self.options)
49    }
50}
51
52impl<P> NameServer<P>
53where
54    P: ConnectionProvider + Send,
55{
56    /// Construct a new Nameserver with the configuration and options. The connection provider will create UDP and TCP sockets
57    pub fn new(config: NameServerConfig, options: ResolverOpts, connection_provider: P) -> Self {
58        Self {
59            config,
60            options,
61            client: Arc::new(Mutex::new(None)),
62            state: Arc::new(NameServerState::init(None)),
63            stats: Arc::new(NameServerStats::default()),
64            connection_provider,
65        }
66    }
67
68    #[doc(hidden)]
69    pub fn from_conn(
70        config: NameServerConfig,
71        options: ResolverOpts,
72        client: P::Conn,
73        connection_provider: P,
74    ) -> Self {
75        Self {
76            config,
77            options,
78            client: Arc::new(Mutex::new(Some(client))),
79            state: Arc::new(NameServerState::init(None)),
80            stats: Arc::new(NameServerStats::default()),
81            connection_provider,
82        }
83    }
84
85    #[cfg(test)]
86    #[allow(dead_code)]
87    pub(crate) fn is_connected(&self) -> bool {
88        !self.state.is_failed()
89            && if let Some(client) = self.client.try_lock() {
90                client.is_some()
91            } else {
92                // assuming that if someone has it locked it will be or is connected
93                true
94            }
95    }
96
97    /// This will return a mutable client to allows for sending messages.
98    ///
99    /// If the connection is in a failed state, then this will establish a new connection
100    async fn connected_mut_client(&mut self) -> Result<P::Conn, ResolveError> {
101        let mut client = self.client.lock().await;
102
103        // if this is in a failure state
104        if self.state.is_failed() || client.is_none() {
105            debug!("reconnecting: {:?}", self.config);
106
107            // TODO: we need the local EDNS options
108            self.state.reinit(None);
109
110            let new_client = Box::pin(
111                self.connection_provider
112                    .new_connection(&self.config, &self.options),
113            )
114            .await?;
115
116            // establish a new connection
117            *client = Some(new_client);
118        } else {
119            debug!("existing connection: {:?}", self.config);
120        }
121
122        Ok((*client)
123            .clone()
124            .expect("bad state, client should be connected"))
125    }
126
127    async fn inner_send<R: Into<DnsRequest> + Unpin + Send + 'static>(
128        mut self,
129        request: R,
130    ) -> Result<DnsResponse, ResolveError> {
131        let mut client = self.connected_mut_client().await?;
132        let now = Instant::now();
133        let response = client.send(request).first_answer().await;
134        let rtt = now.elapsed();
135
136        match response {
137            Ok(response) => {
138                // Record the measured latency.
139                self.stats.record_rtt(rtt);
140
141                // First evaluate if the message succeeded.
142                let response =
143                    ResolveError::from_response(response, self.config.trust_negative_responses)?;
144
145                // TODO: consider making message::take_edns...
146                let remote_edns = response.extensions().clone();
147
148                // take the remote edns options and store them
149                self.state.establish(remote_edns);
150
151                Ok(response)
152            }
153            Err(error) => {
154                debug!("name_server connection failure: {}", error);
155
156                // this transitions the state to failure
157                self.state.fail(Instant::now());
158
159                // record the failure
160                self.stats.record_connection_failure();
161
162                // These are connection failures, not lookup failures, that is handled in the resolver layer
163                Err(error)
164            }
165        }
166    }
167
168    /// Specifies that this NameServer will treat negative responses as permanent failures and will not retry
169    pub fn trust_nx_responses(&self) -> bool {
170        self.config.trust_negative_responses
171    }
172}
173
174impl<P> DnsHandle for NameServer<P>
175where
176    P: ConnectionProvider + Clone,
177{
178    type Response = Pin<Box<dyn Stream<Item = Result<DnsResponse, ResolveError>> + Send>>;
179    type Error = ResolveError;
180
181    fn is_verifying_dnssec(&self) -> bool {
182        self.options.validate
183    }
184
185    // TODO: there needs to be some way of customizing the connection based on EDNS options from the server side...
186    fn send<R: Into<DnsRequest> + Unpin + Send + 'static>(&mut self, request: R) -> Self::Response {
187        let this = self.clone();
188        // if state is failed, return future::err(), unless retry delay expired..
189        Box::pin(once(this.inner_send(request)))
190    }
191}
192
193impl<P> Ord for NameServer<P>
194where
195    P: ConnectionProvider + Send,
196{
197    /// Custom implementation of Ord for NameServer which incorporates the performance of the connection into it's ranking
198    fn cmp(&self, other: &Self) -> Ordering {
199        // if they are literally equal, just return
200        if self == other {
201            return Ordering::Equal;
202        }
203
204        self.stats.cmp(&other.stats)
205    }
206}
207
208impl<P> PartialOrd for NameServer<P>
209where
210    P: ConnectionProvider + Send,
211{
212    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
213        Some(self.cmp(other))
214    }
215}
216
217impl<P> PartialEq for NameServer<P>
218where
219    P: ConnectionProvider + Send,
220{
221    /// NameServers are equal if the config (connection information) are equal
222    fn eq(&self, other: &Self) -> bool {
223        self.config == other.config
224    }
225}
226
227impl<P> Eq for NameServer<P> where P: ConnectionProvider + Send {}
228
229// TODO: once IPv6 is better understood, also make this a binary keep.
230#[cfg(feature = "mdns")]
231pub(crate) fn mdns_nameserver<P>(
232    options: ResolverOpts,
233    conn_provider: P,
234    trust_negative_responses: bool,
235) -> GenericNameServer<P>
236where
237    P: ConnectionProvider,
238{
239    let config = NameServerConfig {
240        socket_addr: *MDNS_IPV4,
241        protocol: Protocol::Mdns,
242        tls_dns_name: None,
243        trust_negative_responses,
244        #[cfg(feature = "dns-over-rustls")]
245        tls_config: None,
246        bind_addr: None,
247    };
248    GenericNameServer::new_with_provider(config, options, conn_provider)
249}
250
251#[cfg(test)]
252#[cfg(feature = "tokio-runtime")]
253mod tests {
254    use std::net::{IpAddr, Ipv4Addr, SocketAddr};
255    use std::time::Duration;
256
257    use futures_util::{future, FutureExt};
258    use tokio::runtime::Runtime;
259
260    use proto::op::{Query, ResponseCode};
261    use proto::rr::{Name, RecordType};
262    use proto::xfer::{DnsHandle, DnsRequestOptions, FirstAnswer};
263
264    use super::*;
265    use crate::config::Protocol;
266    use crate::name_server::TokioConnectionProvider;
267
268    #[test]
269    fn test_name_server() {
270        //env_logger::try_init().ok();
271
272        let config = NameServerConfig {
273            socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)), 53),
274            protocol: Protocol::Udp,
275            tls_dns_name: None,
276            trust_negative_responses: false,
277            #[cfg(feature = "dns-over-rustls")]
278            tls_config: None,
279            bind_addr: None,
280        };
281        let io_loop = Runtime::new().unwrap();
282        let name_server = future::lazy(|_| {
283            GenericNameServer::new(
284                config,
285                ResolverOpts::default(),
286                TokioConnectionProvider::default(),
287            )
288        });
289
290        let name = Name::parse("www.example.com.", None).unwrap();
291        let response = io_loop
292            .block_on(name_server.then(|mut name_server| {
293                name_server
294                    .lookup(
295                        Query::query(name.clone(), RecordType::A),
296                        DnsRequestOptions::default(),
297                    )
298                    .first_answer()
299            }))
300            .expect("query failed");
301        assert_eq!(response.response_code(), ResponseCode::NoError);
302    }
303
304    #[test]
305    fn test_failed_name_server() {
306        let options = ResolverOpts {
307            timeout: Duration::from_millis(1), // this is going to fail, make it fail fast...
308            ..ResolverOpts::default()
309        };
310        let config = NameServerConfig {
311            socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 252)), 252),
312            protocol: Protocol::Udp,
313            tls_dns_name: None,
314            trust_negative_responses: false,
315            #[cfg(feature = "dns-over-rustls")]
316            tls_config: None,
317            bind_addr: None,
318        };
319        let io_loop = Runtime::new().unwrap();
320        let name_server = future::lazy(|_| {
321            GenericNameServer::new(config, options, TokioConnectionProvider::default())
322        });
323
324        let name = Name::parse("www.example.com.", None).unwrap();
325        assert!(io_loop
326            .block_on(name_server.then(|mut name_server| {
327                name_server
328                    .lookup(
329                        Query::query(name.clone(), RecordType::A),
330                        DnsRequestOptions::default(),
331                    )
332                    .first_answer()
333            }))
334            .is_err());
335    }
336}