Skip to main content

trust_dns_resolver/
config.rs

1// Copyright 2015-2017 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
8//! Configuration for a resolver
9#![allow(clippy::use_self)]
10
11use std::fmt;
12use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
13use std::ops::{Deref, DerefMut};
14use std::time::Duration;
15
16#[cfg(feature = "dns-over-rustls")]
17use std::sync::Arc;
18
19use proto::rr::Name;
20#[cfg(feature = "dns-over-rustls")]
21use rustls::ClientConfig;
22
23#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
24use serde::{
25    de::{Deserialize as DeserializeT, Deserializer},
26    ser::{Serialize as SerializeT, Serializer},
27};
28
29/// Configuration for the upstream nameservers to use for resolution
30#[derive(Clone, Debug, PartialEq, Eq)]
31#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
32pub struct ResolverConfig {
33    // base search domain
34    #[cfg_attr(feature = "serde-config", serde(default))]
35    domain: Option<Name>,
36    // search domains
37    #[cfg_attr(feature = "serde-config", serde(default))]
38    search: Vec<Name>,
39    // nameservers to use for resolution.
40    name_servers: NameServerConfigGroup,
41}
42
43impl ResolverConfig {
44    /// Creates a new empty configuration
45    pub fn new() -> Self {
46        Self {
47            // TODO: this should get the hostname and use the basename as the default
48            domain: None,
49            search: vec![],
50            name_servers: NameServerConfigGroup::new(),
51        }
52    }
53
54    /// Creates a default configuration, using `8.8.8.8`, `8.8.4.4` and `2001:4860:4860::8888`, `2001:4860:4860::8844` (thank you, Google).
55    ///
56    /// Please see Google's [privacy statement](https://developers.google.com/speed/public-dns/privacy) for important information about what they track, many ISP's track similar information in DNS. To use the system configuration see: `Resolver::from_system_conf` and `AsyncResolver::from_system_conf`
57    ///
58    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
59    pub fn google() -> Self {
60        Self {
61            // TODO: this should get the hostname and use the basename as the default
62            domain: None,
63            search: vec![],
64            name_servers: NameServerConfigGroup::google(),
65        }
66    }
67
68    /// Creates a default configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare).
69    ///
70    /// Please see: <https://www.cloudflare.com/dns/>
71    ///
72    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
73    pub fn cloudflare() -> Self {
74        Self {
75            // TODO: this should get the hostname and use the basename as the default
76            domain: None,
77            search: vec![],
78            name_servers: NameServerConfigGroup::cloudflare(),
79        }
80    }
81
82    /// Creates a configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare). This limits the registered connections to just TLS lookups
83    ///
84    /// Please see: <https://www.cloudflare.com/dns/>
85    ///
86    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
87    #[cfg(feature = "dns-over-tls")]
88    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
89    pub fn cloudflare_tls() -> Self {
90        Self {
91            // TODO: this should get the hostname and use the basename as the default
92            domain: None,
93            search: vec![],
94            name_servers: NameServerConfigGroup::cloudflare_tls(),
95        }
96    }
97
98    /// Creates a configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare). This limits the registered connections to just HTTPS lookups
99    ///
100    /// Please see: <https://www.cloudflare.com/dns/>
101    ///
102    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
103    #[cfg(feature = "dns-over-https")]
104    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
105    pub fn cloudflare_https() -> Self {
106        Self {
107            // TODO: this should get the hostname and use the basename as the default
108            domain: None,
109            search: vec![],
110            name_servers: NameServerConfigGroup::cloudflare_https(),
111        }
112    }
113
114    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings (thank you, Quad9).
115    ///
116    /// Please see: <https://www.quad9.net/faq/>
117    ///
118    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
119    pub fn quad9() -> Self {
120        Self {
121            // TODO: this should get the hostname and use the basename as the default
122            domain: None,
123            search: vec![],
124            name_servers: NameServerConfigGroup::quad9(),
125        }
126    }
127
128    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings. This limits the registered connections to just TLS lookups
129    ///
130    /// Please see: <https://www.quad9.net/faq/>
131    ///
132    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
133    #[cfg(feature = "dns-over-tls")]
134    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
135    pub fn quad9_tls() -> Self {
136        Self {
137            // TODO: this should get the hostname and use the basename as the default
138            domain: None,
139            search: vec![],
140            name_servers: NameServerConfigGroup::quad9_tls(),
141        }
142    }
143
144    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings. This limits the registered connections to just HTTPS lookups
145    ///
146    /// Please see: <https://www.quad9.net/faq/>
147    ///
148    /// NameServerConfigGroups can be combined to use a set of different providers, see `NameServerConfigGroup` and `ResolverConfig::from_parts`
149    #[cfg(feature = "dns-over-https")]
150    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
151    pub fn quad9_https() -> Self {
152        Self {
153            // TODO: this should get the hostname and use the basename as the default
154            domain: None,
155            search: vec![],
156            name_servers: NameServerConfigGroup::quad9_https(),
157        }
158    }
159
160    /// Create a ResolverConfig with all parts specified
161    ///
162    /// # Arguments
163    ///
164    /// * `domain` - domain of the entity querying results. If the `Name` being looked up is not an FQDN, then this is the first part appended to attempt a lookup. `ndots` in the `ResolverOption` does take precedence over this.
165    /// * `search` - additional search domains that are attempted if the `Name` is not found in `domain`, defaults to `vec![]`
166    /// * `name_servers` - set of name servers to use for lookups, defaults are Google: `8.8.8.8`, `8.8.4.4` and `2001:4860:4860::8888`, `2001:4860:4860::8844`
167    pub fn from_parts<G: Into<NameServerConfigGroup>>(
168        domain: Option<Name>,
169        search: Vec<Name>,
170        name_servers: G,
171    ) -> Self {
172        Self {
173            domain,
174            search,
175            name_servers: name_servers.into(),
176        }
177    }
178
179    /// Returns the local domain
180    ///
181    /// By default any names will be appended to all non-fully-qualified-domain names, and searched for after any ndots rules
182    pub fn domain(&self) -> Option<&Name> {
183        self.domain.as_ref()
184    }
185
186    /// Set the domain of the entity querying results.
187    pub fn set_domain(&mut self, domain: Name) {
188        self.domain = Some(domain.clone());
189        self.search = vec![domain];
190    }
191
192    /// Returns the search domains
193    ///
194    /// These will be queried after any local domain and then in the order of the set of search domains
195    pub fn search(&self) -> &[Name] {
196        &self.search
197    }
198
199    /// Add a search domain
200    pub fn add_search(&mut self, search: Name) {
201        self.search.push(search)
202    }
203
204    // TODO: consider allowing options per NameServer... like different timeouts?
205    /// Add the configuration for a name server
206    pub fn add_name_server(&mut self, name_server: NameServerConfig) {
207        self.name_servers.push(name_server);
208    }
209
210    /// Returns a reference to the name servers
211    pub fn name_servers(&self) -> &[NameServerConfig] {
212        &self.name_servers
213    }
214
215    /// return the associated TlsClientConfig
216    #[cfg(feature = "dns-over-rustls")]
217    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
218    pub fn client_config(&self) -> &Option<TlsClientConfig> {
219        &self.name_servers.1
220    }
221
222    /// adds the `rustls::ClientConf` for every configured NameServer
223    /// of the Resolver.
224    ///
225    /// ```
226    /// use std::sync::Arc;
227    ///
228    /// use rustls::{ClientConfig, ProtocolVersion, RootCertStore, OwnedTrustAnchor};
229    /// use trust_dns_resolver::config::ResolverConfig;
230    /// use webpki_roots;
231    ///
232    /// let mut root_store = RootCertStore::empty();
233    /// root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| {
234    ///     OwnedTrustAnchor::from_subject_spki_name_constraints(
235    ///         ta.subject,
236    ///         ta.spki,
237    ///         ta.name_constraints,
238    ///     )
239    /// }));
240    ///
241    /// let mut client_config = ClientConfig::builder()
242    ///     .with_safe_default_cipher_suites()
243    ///     .with_safe_default_kx_groups()
244    ///     .with_protocol_versions(&[&rustls::version::TLS12])
245    ///     .unwrap()
246    ///     .with_root_certificates(root_store)
247    ///     .with_no_client_auth();
248    ///
249    /// let mut resolver_config = ResolverConfig::quad9_tls();
250    /// resolver_config.set_tls_client_config(Arc::new(client_config));
251    /// ```
252    #[cfg(feature = "dns-over-rustls")]
253    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
254    pub fn set_tls_client_config(&mut self, client_config: Arc<ClientConfig>) {
255        self.name_servers = self.name_servers.clone().with_client_config(client_config);
256    }
257}
258
259impl Default for ResolverConfig {
260    /// Creates a default configuration, using `8.8.8.8`, `8.8.4.4` and `2001:4860:4860::8888`, `2001:4860:4860::8844` (thank you, Google).
261    ///
262    /// Please see Google's [privacy statement](https://developers.google.com/speed/public-dns/privacy) for important information about what they track, many ISP's track similar information in DNS. To use the system configuration see: `Resolver::from_system_conf` and `AsyncResolver::from_system_conf`
263    fn default() -> Self {
264        Self::google()
265    }
266}
267
268/// The protocol on which a NameServer should be communicated with
269#[derive(Clone, Copy, Debug, Eq, PartialEq)]
270#[cfg_attr(
271    feature = "serde-config",
272    derive(Serialize, Deserialize),
273    serde(rename_all = "lowercase")
274)]
275#[non_exhaustive]
276pub enum Protocol {
277    /// UDP is the traditional DNS port, this is generally the correct choice
278    Udp,
279    /// TCP can be used for large queries, but not all NameServers support it
280    Tcp,
281    /// Tls for DNS over TLS
282    #[cfg(feature = "dns-over-tls")]
283    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
284    Tls,
285    /// Https for DNS over HTTPS
286    #[cfg(feature = "dns-over-https")]
287    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
288    Https,
289    /// QUIC for DNS over QUIC
290    #[cfg(feature = "dns-over-quic")]
291    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-quic")))]
292    Quic,
293    /// mDNS protocol for performing multicast lookups
294    #[cfg(feature = "mdns")]
295    #[cfg_attr(docsrs, doc(cfg(feature = "mdns")))]
296    Mdns,
297}
298
299impl fmt::Display for Protocol {
300    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301        let protocol = match self {
302            Self::Udp => "udp",
303            Self::Tcp => "tcp",
304            #[cfg(feature = "dns-over-tls")]
305            Self::Tls => "tls",
306            #[cfg(feature = "dns-over-https")]
307            Self::Https => "https",
308            #[cfg(feature = "dns-over-quic")]
309            Self::Quic => "quic",
310            #[cfg(feature = "mdns")]
311            Self::Mdns => "mdns",
312        };
313
314        f.write_str(protocol)
315    }
316}
317
318impl Protocol {
319    /// Returns true if this is a datagram oriented protocol, e.g. UDP
320    pub fn is_datagram(self) -> bool {
321        match self {
322            Self::Udp => true,
323            Self::Tcp => false,
324            #[cfg(feature = "dns-over-tls")]
325            Self::Tls => false,
326            #[cfg(feature = "dns-over-https")]
327            Self::Https => false,
328            // TODO: if you squint, this is true...
329            #[cfg(feature = "dns-over-quic")]
330            Self::Quic => true,
331            #[cfg(feature = "mdns")]
332            Self::Mdns => true,
333        }
334    }
335
336    /// Returns true if this is a stream oriented protocol, e.g. TCP
337    pub fn is_stream(self) -> bool {
338        !self.is_datagram()
339    }
340
341    /// Is this an encrypted protocol, i.e. TLS or HTTPS
342    pub fn is_encrypted(self) -> bool {
343        match self {
344            Self::Udp => false,
345            Self::Tcp => false,
346            #[cfg(feature = "dns-over-tls")]
347            Self::Tls => true,
348            #[cfg(feature = "dns-over-https")]
349            Self::Https => true,
350            #[cfg(feature = "dns-over-quic")]
351            Self::Quic => true,
352            #[cfg(feature = "mdns")]
353            Self::Mdns => false,
354        }
355    }
356}
357
358impl Default for Protocol {
359    /// Default protocol should be UDP, which is supported by all DNS servers
360    fn default() -> Self {
361        Self::Udp
362    }
363}
364
365/// a compatibility wrapper around rustls
366/// ClientConfig
367#[cfg(feature = "dns-over-rustls")]
368#[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
369#[derive(Clone)]
370pub struct TlsClientConfig(pub Arc<ClientConfig>);
371
372#[cfg(feature = "dns-over-rustls")]
373impl std::cmp::PartialEq for TlsClientConfig {
374    fn eq(&self, other: &Self) -> bool {
375        Arc::ptr_eq(&self.0, &other.0)
376    }
377}
378
379#[cfg(feature = "dns-over-rustls")]
380impl std::cmp::Eq for TlsClientConfig {}
381
382#[cfg(feature = "dns-over-rustls")]
383impl std::fmt::Debug for TlsClientConfig {
384    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385        write!(f, "rustls client config")
386    }
387}
388
389/// Configuration for the NameServer
390#[derive(Clone, Debug, Eq, PartialEq)]
391#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
392pub struct NameServerConfig {
393    /// The address which the DNS NameServer is registered at.
394    pub socket_addr: SocketAddr,
395    /// The protocol to use when communicating with the NameServer.
396    #[cfg_attr(feature = "serde-config", serde(default))]
397    pub protocol: Protocol,
398    /// SPKI name, only relevant for TLS connections
399    #[cfg_attr(feature = "serde-config", serde(default))]
400    pub tls_dns_name: Option<String>,
401    /// Whether to trust `NXDOMAIN` responses from upstream nameservers.
402    ///
403    /// When this is `true`, and an empty `NXDOMAIN` response is received, the
404    /// query will not be retried against other configured name servers.
405    ///
406    /// (On an empty `NoError` response, or a response with any other error
407    /// response code, the query will still be retried regardless of this
408    /// configuration setting.)
409    ///
410    /// Defaults to false.
411    #[cfg_attr(feature = "serde-config", serde(default))]
412    pub trust_nx_responses: bool,
413    #[cfg(feature = "dns-over-rustls")]
414    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
415    #[cfg_attr(feature = "serde-config", serde(skip))]
416    /// optional configuration for the tls client
417    pub tls_config: Option<TlsClientConfig>,
418    /// The client address (IP and port) to use for connecting to the server.
419    pub bind_addr: Option<SocketAddr>,
420    /// The number of errors kept by this server to save for debugging purposes.
421    ///
422    /// May be retrieved, along with other information, using
423    /// [`NameServer::stats`](crate::name_server::NameServer::stats).
424    pub num_retained_errors: usize,
425}
426
427impl NameServerConfig {
428    /// Constructs a Nameserver configuration with some basic defaults
429    pub fn new(socket_addr: SocketAddr, protocol: Protocol) -> Self {
430        Self {
431            socket_addr,
432            protocol,
433            trust_nx_responses: true,
434            tls_dns_name: None,
435            #[cfg(feature = "dns-over-rustls")]
436            tls_config: None,
437            bind_addr: None,
438            num_retained_errors: 0,
439        }
440    }
441}
442
443impl fmt::Display for NameServerConfig {
444    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445        write!(f, "{}:", self.protocol)?;
446
447        if let Some(ref tls_dns_name) = self.tls_dns_name {
448            write!(f, "{}@", tls_dns_name)?;
449        }
450
451        write!(f, "{}", self.socket_addr)
452    }
453}
454
455/// A set of name_servers to associate with a [`ResolverConfig`].
456#[derive(Clone, Debug, Eq, PartialEq)]
457#[cfg_attr(
458    all(feature = "serde-config", not(feature = "dns-over-rustls")),
459    derive(Serialize, Deserialize)
460)]
461pub struct NameServerConfigGroup(
462    Vec<NameServerConfig>,
463    #[cfg(feature = "dns-over-rustls")] Option<TlsClientConfig>,
464);
465
466#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
467impl SerializeT for NameServerConfigGroup {
468    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
469    where
470        S: Serializer,
471    {
472        self.0.serialize(serializer)
473    }
474}
475
476#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
477impl<'de> DeserializeT<'de> for NameServerConfigGroup {
478    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
479    where
480        D: Deserializer<'de>,
481    {
482        Vec::deserialize(deserializer).map(|nameservers| Self(nameservers, None))
483    }
484}
485
486impl NameServerConfigGroup {
487    /// Creates a new `NameServerConfigGroup` with a default size of 2
488    pub fn new() -> Self {
489        // this might be a nice opportunity for SmallVec
490        //   most name_server configs will be 2.
491        Self::with_capacity(2)
492    }
493
494    /// Creates a new `NameServiceConfigGroup` with the specified capacity
495    pub fn with_capacity(capacity: usize) -> Self {
496        Self(
497            Vec::with_capacity(capacity),
498            #[cfg(feature = "dns-over-rustls")]
499            None,
500        )
501    }
502
503    /// Returns the inner vec of configs
504    pub fn into_inner(self) -> Vec<NameServerConfig> {
505        self.0
506    }
507
508    /// Configure a NameServer address and port
509    ///
510    /// This will create UDP and TCP connections, using the same port.
511    pub fn from_ips_clear(ips: &[IpAddr], port: u16, trust_nx_responses: bool) -> Self {
512        let mut name_servers = Self::with_capacity(ips.len());
513
514        for ip in ips {
515            let udp = NameServerConfig {
516                socket_addr: SocketAddr::new(*ip, port),
517                protocol: Protocol::Udp,
518                tls_dns_name: None,
519                trust_nx_responses,
520                #[cfg(feature = "dns-over-rustls")]
521                tls_config: None,
522                bind_addr: None,
523                num_retained_errors: 0,
524            };
525            let tcp = NameServerConfig {
526                socket_addr: SocketAddr::new(*ip, port),
527                protocol: Protocol::Tcp,
528                tls_dns_name: None,
529                trust_nx_responses,
530                #[cfg(feature = "dns-over-rustls")]
531                tls_config: None,
532                bind_addr: None,
533                num_retained_errors: 0,
534            };
535
536            name_servers.push(udp);
537            name_servers.push(tcp);
538        }
539
540        name_servers
541    }
542
543    #[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))]
544    fn from_ips_encrypted(
545        ips: &[IpAddr],
546        port: u16,
547        tls_dns_name: String,
548        protocol: Protocol,
549        trust_nx_responses: bool,
550    ) -> Self {
551        assert!(protocol.is_encrypted());
552
553        let mut name_servers = Self::with_capacity(ips.len());
554
555        for ip in ips {
556            let config = NameServerConfig {
557                socket_addr: SocketAddr::new(*ip, port),
558                protocol,
559                tls_dns_name: Some(tls_dns_name.clone()),
560                trust_nx_responses,
561                #[cfg(feature = "dns-over-rustls")]
562                tls_config: None,
563                bind_addr: None,
564            };
565
566            name_servers.push(config);
567        }
568
569        name_servers
570    }
571
572    /// Configure a NameServer address and port for DNS-over-TLS
573    ///
574    /// This will create a TLS connections.
575    #[cfg(feature = "dns-over-tls")]
576    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
577    pub fn from_ips_tls(
578        ips: &[IpAddr],
579        port: u16,
580        tls_dns_name: String,
581        trust_nx_responses: bool,
582    ) -> Self {
583        Self::from_ips_encrypted(ips, port, tls_dns_name, Protocol::Tls, trust_nx_responses)
584    }
585
586    /// Configure a NameServer address and port for DNS-over-HTTPS
587    ///
588    /// This will create a HTTPS connections.
589    #[cfg(feature = "dns-over-https")]
590    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
591    pub fn from_ips_https(
592        ips: &[IpAddr],
593        port: u16,
594        tls_dns_name: String,
595        trust_nx_responses: bool,
596    ) -> Self {
597        Self::from_ips_encrypted(ips, port, tls_dns_name, Protocol::Https, trust_nx_responses)
598    }
599
600    /// Creates a default configuration, using `8.8.8.8`, `8.8.4.4` and `2001:4860:4860::8888`, `2001:4860:4860::8844` (thank you, Google).
601    ///
602    /// Please see Google's [privacy statement](https://developers.google.com/speed/public-dns/privacy) for important information about what they track, many ISP's track similar information in DNS. To use the system configuration see: `Resolver::from_system_conf` and `AsyncResolver::from_system_conf`
603    pub fn google() -> Self {
604        Self::from_ips_clear(GOOGLE_IPS, 53, true)
605    }
606
607    /// Creates a default configuration, using `8.8.8.8`, `8.8.4.4` and `2001:4860:4860::8888`, `2001:4860:4860::8844` (thank you, Google). This limits the registered connections to just HTTPS lookups
608    ///
609    /// Please see Google's [privacy statement](https://developers.google.com/speed/public-dns/privacy) for important information about what they track, many ISP's track similar information in DNS. To use the system configuration see: `Resolver::from_system_conf` and `AsyncResolver::from_system_conf`
610    #[cfg(feature = "dns-over-https")]
611    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
612    pub fn google_https() -> Self {
613        Self::from_ips_https(GOOGLE_IPS, 443, "dns.google".to_string(), true)
614    }
615
616    /// Creates a default configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare).
617    ///
618    /// Please see: <https://www.cloudflare.com/dns/>
619    pub fn cloudflare() -> Self {
620        Self::from_ips_clear(CLOUDFLARE_IPS, 53, true)
621    }
622
623    /// Creates a configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare). This limits the registered connections to just TLS lookups
624    ///
625    /// Please see: <https://www.cloudflare.com/dns/>
626    #[cfg(feature = "dns-over-tls")]
627    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
628    pub fn cloudflare_tls() -> Self {
629        Self::from_ips_tls(CLOUDFLARE_IPS, 853, "cloudflare-dns.com".to_string(), true)
630    }
631
632    /// Creates a configuration, using `1.1.1.1`, `1.0.0.1` and `2606:4700:4700::1111`, `2606:4700:4700::1001` (thank you, Cloudflare). This limits the registered connections to just HTTPS lookups
633    ///
634    /// Please see: <https://www.cloudflare.com/dns/>
635    #[cfg(feature = "dns-over-https")]
636    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
637    pub fn cloudflare_https() -> Self {
638        Self::from_ips_https(CLOUDFLARE_IPS, 443, "cloudflare-dns.com".to_string(), true)
639    }
640
641    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings (thank you, Quad9).
642    ///
643    /// Please see: <https://www.quad9.net/faq/>
644    pub fn quad9() -> Self {
645        Self::from_ips_clear(QUAD9_IPS, 53, true)
646    }
647
648    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings. This limits the registered connections to just TLS lookups
649    ///
650    /// Please see: <https://www.quad9.net/faq/>
651    #[cfg(feature = "dns-over-tls")]
652    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
653    pub fn quad9_tls() -> Self {
654        Self::from_ips_tls(QUAD9_IPS, 853, "dns.quad9.net".to_string(), true)
655    }
656
657    /// Creates a configuration, using `9.9.9.9`, `149.112.112.112` and `2620:fe::fe`, `2620:fe::fe:9`, the "secure" variants of the quad9 settings. This limits the registered connections to just HTTPS lookups
658    ///
659    /// Please see: <https://www.quad9.net/faq/>
660    #[cfg(feature = "dns-over-https")]
661    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
662    pub fn quad9_https() -> Self {
663        Self::from_ips_https(QUAD9_IPS, 443, "dns.quad9.net".to_string(), true)
664    }
665
666    /// Merges this set of [`NameServerConfig`]s with the other
667    ///
668    /// ```
669    /// use std::net::{SocketAddr, Ipv4Addr};
670    /// use trust_dns_resolver::config::NameServerConfigGroup;
671    ///
672    /// let mut group = NameServerConfigGroup::google();
673    /// group.merge(NameServerConfigGroup::cloudflare());
674    /// group.merge(NameServerConfigGroup::quad9());
675    ///
676    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(8, 8, 8, 8).into(), 53)));
677    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(1, 1, 1, 1).into(), 53)));
678    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(9, 9, 9, 9).into(), 53)));
679    /// ```
680    pub fn merge(&mut self, mut other: Self) {
681        #[cfg(not(feature = "dns-over-rustls"))]
682        {
683            self.append(&mut other);
684        }
685        #[cfg(feature = "dns-over-rustls")]
686        {
687            self.0.append(&mut other);
688        }
689    }
690
691    /// add a [`rustls::ClientConfig`]
692    #[cfg(feature = "dns-over-rustls")]
693    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
694    pub fn with_client_config(self, client_config: Arc<ClientConfig>) -> Self {
695        Self(self.0, Some(TlsClientConfig(client_config)))
696    }
697
698    /// Sets the client address (IP and port) to connect from on all name servers.
699    pub fn with_bind_addr(mut self, bind_addr: Option<SocketAddr>) -> Self {
700        for server in &mut self.0 {
701            server.bind_addr = bind_addr;
702        }
703        self
704    }
705}
706
707impl Default for NameServerConfigGroup {
708    fn default() -> Self {
709        Self::new()
710    }
711}
712
713impl Deref for NameServerConfigGroup {
714    type Target = Vec<NameServerConfig>;
715    fn deref(&self) -> &Self::Target {
716        &self.0
717    }
718}
719
720impl DerefMut for NameServerConfigGroup {
721    fn deref_mut(&mut self) -> &mut Self::Target {
722        &mut self.0
723    }
724}
725
726impl From<Vec<NameServerConfig>> for NameServerConfigGroup {
727    fn from(configs: Vec<NameServerConfig>) -> Self {
728        #[cfg(not(feature = "dns-over-rustls"))]
729        {
730            Self(configs)
731        }
732        #[cfg(feature = "dns-over-rustls")]
733        {
734            Self(configs, None)
735        }
736    }
737}
738
739/// The lookup ip strategy
740#[derive(Debug, Clone, Copy, PartialEq, Eq)]
741#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
742pub enum LookupIpStrategy {
743    /// Only query for A (Ipv4) records
744    Ipv4Only,
745    /// Only query for AAAA (Ipv6) records
746    Ipv6Only,
747    /// Query for A and AAAA in parallel
748    Ipv4AndIpv6,
749    /// Query for Ipv6 if that fails, query for Ipv4
750    Ipv6thenIpv4,
751    /// Query for Ipv4 if that fails, query for Ipv6 (default)
752    Ipv4thenIpv6,
753}
754
755impl Default for LookupIpStrategy {
756    /// Returns [`LookupIpStrategy::Ipv4thenIpv6`] as the default.
757    fn default() -> Self {
758        Self::Ipv4thenIpv6
759    }
760}
761
762/// The strategy for establishing the query order of name servers in a pool.
763#[derive(Debug, Clone, Copy, PartialEq, Eq)]
764#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
765pub enum ServerOrderingStrategy {
766    /// Servers are ordered based on collected query statistics. The ordering
767    /// may vary over time.
768    QueryStatistics,
769    /// The order provided to the resolver is used. The ordering does not vary
770    /// over time.
771    UserProvidedOrder,
772}
773
774impl Default for ServerOrderingStrategy {
775    /// Returns [`ServerOrderingStrategy::QueryStatistics`] as the default.
776    fn default() -> Self {
777        Self::QueryStatistics
778    }
779}
780
781/// Configuration for the Resolver
782#[derive(Debug, Clone, Copy, Eq, PartialEq)]
783#[cfg_attr(
784    feature = "serde-config",
785    derive(Serialize, Deserialize),
786    serde(default)
787)]
788#[allow(dead_code)] // TODO: remove after all params are supported
789#[non_exhaustive]
790pub struct ResolverOpts {
791    /// Sets the number of dots that must appear (unless it's a final dot representing the root)
792    ///  before a query is assumed to include the TLD. The default is one, which means that `www`
793    ///  would never be assumed to be a TLD, and would always be appended to either the search
794    pub ndots: usize,
795    /// Specify the timeout for a request. Defaults to 5 seconds
796    pub timeout: Duration,
797    /// Number of retries after lookup failure before giving up. Defaults to 2
798    pub attempts: usize,
799    /// Rotate through the resource records in the response (if there is more than one for a given name)
800    pub rotate: bool,
801    /// Validate the names in the response, not implemented don't really see the point unless you need to support
802    ///  badly configured DNS
803    pub check_names: bool,
804    /// Enable edns, for larger records
805    pub edns0: bool,
806    /// Use DNSSec to validate the request
807    pub validate: bool,
808    /// The ip_strategy for the Resolver to use when lookup Ipv4 or Ipv6 addresses
809    pub ip_strategy: LookupIpStrategy,
810    /// Cache size is in number of records (some records can be large)
811    pub cache_size: usize,
812    /// Check /ect/hosts file before dns requery (only works for unix like OS)
813    pub use_hosts_file: bool,
814    /// Optional minimum TTL for positive responses.
815    ///
816    /// If this is set, any positive responses with a TTL lower than this value will have a TTL of
817    /// `positive_min_ttl` instead. Otherwise, this will default to 0 seconds.
818    pub positive_min_ttl: Option<Duration>,
819    /// Optional minimum TTL for negative (`NXDOMAIN`) responses.
820    ///
821    /// If this is set, any negative responses with a TTL lower than this value will have a TTL of
822    /// `negative_min_ttl` instead. Otherwise, this will default to 0 seconds.
823    pub negative_min_ttl: Option<Duration>,
824    /// Optional maximum TTL for positive responses.
825    ///
826    /// If this is set, any positive responses with a TTL higher than this value will have a TTL of
827    /// `positive_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
828    ///
829    /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
830    pub positive_max_ttl: Option<Duration>,
831    /// Optional maximum TTL for negative (`NXDOMAIN`) responses.
832    ///
833    /// If this is set, any negative responses with a TTL higher than this value will have a TTL of
834    /// `negative_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
835    ///
836    /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
837    pub negative_max_ttl: Option<Duration>,
838    /// Number of concurrent requests per query
839    ///
840    /// Where more than one nameserver is configured, this configures the resolver to send queries
841    /// to a number of servers in parallel. Defaults to 2; 0 or 1 will execute requests serially.
842    pub num_concurrent_reqs: usize,
843    /// Preserve all intermediate records in the lookup response, suchas CNAME records
844    pub preserve_intermediates: bool,
845    /// Try queries over TCP if they fail over UDP.
846    pub try_tcp_on_error: bool,
847    /// The server ordering strategy that the resolver should use.
848    pub server_ordering_strategy: ServerOrderingStrategy,
849    /// Request upstream recursive resolvers to not perform any recursion.
850    ///
851    /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
852    pub recursion_desired: bool,
853    /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
854    pub authentic_data: bool,
855}
856
857impl Default for ResolverOpts {
858    /// Default values for the Resolver configuration.
859    ///
860    /// This follows the resolv.conf defaults as defined in the [Linux man pages](http://man7.org/linux/man-pages/man5/resolv.conf.5.html)
861    fn default() -> Self {
862        Self {
863            ndots: 1,
864            timeout: Duration::from_secs(5),
865            attempts: 2,
866            rotate: false,
867            check_names: true,
868            edns0: false,
869            validate: false,
870            ip_strategy: LookupIpStrategy::default(),
871            cache_size: 32,
872            use_hosts_file: true,
873            positive_min_ttl: None,
874            negative_min_ttl: None,
875            positive_max_ttl: None,
876            negative_max_ttl: None,
877            num_concurrent_reqs: 2,
878
879            // Defaults to `true` to match the behavior of dig and nslookup.
880            preserve_intermediates: true,
881
882            try_tcp_on_error: false,
883            server_ordering_strategy: ServerOrderingStrategy::default(),
884            recursion_desired: true,
885            authentic_data: false,
886        }
887    }
888}
889
890/// IP addresses for Google Public DNS
891pub const GOOGLE_IPS: &[IpAddr] = &[
892    IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
893    IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
894    IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
895    IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
896];
897
898/// IP addresses for Cloudflare's 1.1.1.1 DNS service
899pub const CLOUDFLARE_IPS: &[IpAddr] = &[
900    IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
901    IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
902    IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
903    IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
904];
905
906/// IP address for the Quad9 DNS service
907pub const QUAD9_IPS: &[IpAddr] = &[
908    IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
909    IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
910    IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
911    IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0x00fe, 0x0009)),
912];