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