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}
348
349impl fmt::Display for Protocol {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        let protocol = match self {
352            Self::Udp => "udp",
353            Self::Tcp => "tcp",
354            #[cfg(feature = "dns-over-tls")]
355            Self::Tls => "tls",
356            #[cfg(feature = "dns-over-https")]
357            Self::Https => "https",
358            #[cfg(feature = "dns-over-quic")]
359            Self::Quic => "quic",
360            #[cfg(feature = "dns-over-h3")]
361            Self::H3 => "h3",
362        };
363
364        f.write_str(protocol)
365    }
366}
367
368impl Protocol {
369    /// Returns true if this is a datagram oriented protocol, e.g. UDP
370    pub fn is_datagram(self) -> bool {
371        match self {
372            Self::Udp => true,
373            Self::Tcp => false,
374            #[cfg(feature = "dns-over-tls")]
375            Self::Tls => false,
376            #[cfg(feature = "dns-over-https")]
377            Self::Https => false,
378            // TODO: if you squint, this is true...
379            #[cfg(feature = "dns-over-quic")]
380            Self::Quic => true,
381            #[cfg(feature = "dns-over-h3")]
382            Self::H3 => true,
383        }
384    }
385
386    /// Returns true if this is a stream oriented protocol, e.g. TCP
387    pub fn is_stream(self) -> bool {
388        !self.is_datagram()
389    }
390
391    /// Is this an encrypted protocol, i.e. TLS or HTTPS
392    pub fn is_encrypted(self) -> bool {
393        match self {
394            Self::Udp => false,
395            Self::Tcp => false,
396            #[cfg(feature = "dns-over-tls")]
397            Self::Tls => true,
398            #[cfg(feature = "dns-over-https")]
399            Self::Https => true,
400            #[cfg(feature = "dns-over-quic")]
401            Self::Quic => true,
402            #[cfg(feature = "dns-over-h3")]
403            Self::H3 => true,
404        }
405    }
406}
407
408impl Default for Protocol {
409    /// Default protocol should be UDP, which is supported by all DNS servers
410    fn default() -> Self {
411        Self::Udp
412    }
413}
414
415/// a compatibility wrapper around rustls
416/// ClientConfig
417#[cfg(feature = "dns-over-rustls")]
418#[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
419#[derive(Clone)]
420pub struct TlsClientConfig(pub Arc<ClientConfig>);
421
422#[cfg(feature = "dns-over-rustls")]
423impl std::cmp::PartialEq for TlsClientConfig {
424    fn eq(&self, other: &Self) -> bool {
425        Arc::ptr_eq(&self.0, &other.0)
426    }
427}
428
429#[cfg(feature = "dns-over-rustls")]
430impl std::cmp::Eq for TlsClientConfig {}
431
432#[cfg(feature = "dns-over-rustls")]
433impl std::fmt::Debug for TlsClientConfig {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(f, "rustls client config")
436    }
437}
438
439/// Configuration for the NameServer
440#[derive(Clone, Debug, Eq, PartialEq)]
441#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
442pub struct NameServerConfig {
443    /// The address which the DNS NameServer is registered at.
444    pub socket_addr: SocketAddr,
445    /// The protocol to use when communicating with the NameServer.
446    #[cfg_attr(feature = "serde-config", serde(default))]
447    pub protocol: Protocol,
448    /// SPKI name, only relevant for TLS connections
449    #[cfg_attr(feature = "serde-config", serde(default))]
450    pub tls_dns_name: Option<String>,
451    /// Whether to trust `NXDOMAIN` responses from upstream nameservers.
452    ///
453    /// When this is `true`, and an empty `NXDOMAIN` response or `NOERROR`
454    /// with an empty answers set is received, the
455    /// query will not be retried against other configured name servers if
456    /// the response has the Authoritative flag set.
457    ///
458    /// (On a response with any other error
459    /// response code, the query will still be retried regardless of this
460    /// configuration setting.)
461    ///
462    /// Defaults to false.
463    #[cfg_attr(feature = "serde-config", serde(default))]
464    pub trust_negative_responses: bool,
465    #[cfg(feature = "dns-over-rustls")]
466    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
467    #[cfg_attr(feature = "serde-config", serde(skip))]
468    /// Optional configuration for the TLS client.
469    ///
470    /// The correct ALPN for the corresponding protocol is automatically
471    /// inserted if none was specificed.
472    pub tls_config: Option<TlsClientConfig>,
473    /// The client address (IP and port) to use for connecting to the server.
474    pub bind_addr: Option<SocketAddr>,
475}
476
477impl NameServerConfig {
478    /// Constructs a Nameserver configuration with some basic defaults
479    pub fn new(socket_addr: SocketAddr, protocol: Protocol) -> Self {
480        Self {
481            socket_addr,
482            protocol,
483            trust_negative_responses: true,
484            tls_dns_name: None,
485            #[cfg(feature = "dns-over-rustls")]
486            tls_config: None,
487            bind_addr: None,
488        }
489    }
490}
491
492impl fmt::Display for NameServerConfig {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        write!(f, "{}:", self.protocol)?;
495
496        if let Some(ref tls_dns_name) = self.tls_dns_name {
497            write!(f, "{tls_dns_name}@")?;
498        }
499
500        write!(f, "{}", self.socket_addr)
501    }
502}
503
504/// A set of name_servers to associate with a [`ResolverConfig`].
505#[derive(Clone, Debug, Eq, PartialEq)]
506#[cfg_attr(
507    all(feature = "serde-config", not(feature = "dns-over-rustls")),
508    derive(Serialize, Deserialize)
509)]
510pub struct NameServerConfigGroup(
511    Vec<NameServerConfig>,
512    #[cfg(feature = "dns-over-rustls")] Option<TlsClientConfig>,
513);
514
515#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
516impl SerializeT for NameServerConfigGroup {
517    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
518    where
519        S: Serializer,
520    {
521        self.0.serialize(serializer)
522    }
523}
524
525#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
526impl<'de> DeserializeT<'de> for NameServerConfigGroup {
527    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
528    where
529        D: Deserializer<'de>,
530    {
531        Vec::deserialize(deserializer).map(|nameservers| Self(nameservers, None))
532    }
533}
534
535impl NameServerConfigGroup {
536    /// Creates a new `NameServerConfigGroup` with a default size of 2
537    pub fn new() -> Self {
538        // this might be a nice opportunity for SmallVec
539        //   most name_server configs will be 2.
540        Self::with_capacity(2)
541    }
542
543    /// Creates a new `NameServiceConfigGroup` with the specified capacity
544    pub fn with_capacity(capacity: usize) -> Self {
545        Self(
546            Vec::with_capacity(capacity),
547            #[cfg(feature = "dns-over-rustls")]
548            None,
549        )
550    }
551
552    /// Returns the inner vec of configs
553    pub fn into_inner(self) -> Vec<NameServerConfig> {
554        self.0
555    }
556
557    /// Configure a NameServer address and port
558    ///
559    /// This will create UDP and TCP connections, using the same port.
560    pub fn from_ips_clear(ips: &[IpAddr], port: u16, trust_negative_responses: bool) -> Self {
561        let mut name_servers = Self::with_capacity(ips.len());
562
563        for ip in ips {
564            let udp = NameServerConfig {
565                socket_addr: SocketAddr::new(*ip, port),
566                protocol: Protocol::Udp,
567                tls_dns_name: None,
568                trust_negative_responses,
569                #[cfg(feature = "dns-over-rustls")]
570                tls_config: None,
571                bind_addr: None,
572            };
573            let tcp = NameServerConfig {
574                socket_addr: SocketAddr::new(*ip, port),
575                protocol: Protocol::Tcp,
576                tls_dns_name: None,
577                trust_negative_responses,
578                #[cfg(feature = "dns-over-rustls")]
579                tls_config: None,
580                bind_addr: None,
581            };
582
583            name_servers.push(udp);
584            name_servers.push(tcp);
585        }
586
587        name_servers
588    }
589
590    #[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))]
591    fn from_ips_encrypted(
592        ips: &[IpAddr],
593        port: u16,
594        tls_dns_name: String,
595        protocol: Protocol,
596        trust_negative_responses: bool,
597    ) -> Self {
598        assert!(protocol.is_encrypted());
599
600        let mut name_servers = Self::with_capacity(ips.len());
601
602        for ip in ips {
603            let config = NameServerConfig {
604                socket_addr: SocketAddr::new(*ip, port),
605                protocol,
606                tls_dns_name: Some(tls_dns_name.clone()),
607                trust_negative_responses,
608                #[cfg(feature = "dns-over-rustls")]
609                tls_config: None,
610                bind_addr: None,
611            };
612
613            name_servers.push(config);
614        }
615
616        name_servers
617    }
618
619    /// Configure a NameServer address and port for DNS-over-TLS
620    ///
621    /// This will create a TLS connections.
622    #[cfg(feature = "dns-over-tls")]
623    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
624    pub fn from_ips_tls(
625        ips: &[IpAddr],
626        port: u16,
627        tls_dns_name: String,
628        trust_negative_responses: bool,
629    ) -> Self {
630        Self::from_ips_encrypted(
631            ips,
632            port,
633            tls_dns_name,
634            Protocol::Tls,
635            trust_negative_responses,
636        )
637    }
638
639    /// Configure a NameServer address and port for DNS-over-HTTPS
640    ///
641    /// This will create a HTTPS connections.
642    #[cfg(feature = "dns-over-https")]
643    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
644    pub fn from_ips_https(
645        ips: &[IpAddr],
646        port: u16,
647        tls_dns_name: String,
648        trust_negative_responses: bool,
649    ) -> Self {
650        Self::from_ips_encrypted(
651            ips,
652            port,
653            tls_dns_name,
654            Protocol::Https,
655            trust_negative_responses,
656        )
657    }
658
659    /// Configure a NameServer address and port for DNS-over-QUIC
660    ///
661    /// This will create a QUIC connections.
662    #[cfg(feature = "dns-over-quic")]
663    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-quic")))]
664    pub fn from_ips_quic(
665        ips: &[IpAddr],
666        port: u16,
667        tls_dns_name: String,
668        trust_negative_responses: bool,
669    ) -> Self {
670        Self::from_ips_encrypted(
671            ips,
672            port,
673            tls_dns_name,
674            Protocol::Quic,
675            trust_negative_responses,
676        )
677    }
678
679    /// Configure a NameServer address and port for DNS-over-HTTP/3
680    ///
681    /// This will create a HTTP/3 connection.
682    #[cfg(feature = "dns-over-h3")]
683    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-h3")))]
684    pub fn from_ips_h3(
685        ips: &[IpAddr],
686        port: u16,
687        tls_dns_name: String,
688        trust_negative_responses: bool,
689    ) -> Self {
690        Self::from_ips_encrypted(
691            ips,
692            port,
693            tls_dns_name,
694            Protocol::H3,
695            trust_negative_responses,
696        )
697    }
698
699    /// 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).
700    ///
701    /// 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`
702    pub fn google() -> Self {
703        Self::from_ips_clear(GOOGLE_IPS, 53, true)
704    }
705
706    /// 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
707    ///
708    /// 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`
709    #[cfg(feature = "dns-over-tls")]
710    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
711    pub fn google_tls() -> Self {
712        Self::from_ips_tls(GOOGLE_IPS, 853, "dns.google".to_string(), true)
713    }
714
715    /// 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
716    ///
717    /// 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`
718    #[cfg(feature = "dns-over-https")]
719    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
720    pub fn google_https() -> Self {
721        Self::from_ips_https(GOOGLE_IPS, 443, "dns.google".to_string(), true)
722    }
723
724    /// 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
725    ///
726    /// 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`
727    #[cfg(feature = "dns-over-h3")]
728    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-h3")))]
729    pub fn google_h3() -> Self {
730        Self::from_ips_h3(GOOGLE_IPS, 443, "dns.google".to_string(), true)
731    }
732
733    /// 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).
734    ///
735    /// Please see: <https://www.cloudflare.com/dns/>
736    pub fn cloudflare() -> Self {
737        Self::from_ips_clear(CLOUDFLARE_IPS, 53, true)
738    }
739
740    /// 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
741    ///
742    /// Please see: <https://www.cloudflare.com/dns/>
743    #[cfg(feature = "dns-over-tls")]
744    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
745    pub fn cloudflare_tls() -> Self {
746        Self::from_ips_tls(CLOUDFLARE_IPS, 853, "cloudflare-dns.com".to_string(), true)
747    }
748
749    /// 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
750    ///
751    /// Please see: <https://www.cloudflare.com/dns/>
752    #[cfg(feature = "dns-over-https")]
753    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
754    pub fn cloudflare_https() -> Self {
755        Self::from_ips_https(CLOUDFLARE_IPS, 443, "cloudflare-dns.com".to_string(), true)
756    }
757
758    /// 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).
759    ///
760    /// Please see: <https://www.quad9.net/faq/>
761    pub fn quad9() -> Self {
762        Self::from_ips_clear(QUAD9_IPS, 53, true)
763    }
764
765    /// 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
766    ///
767    /// Please see: <https://www.quad9.net/faq/>
768    #[cfg(feature = "dns-over-tls")]
769    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
770    pub fn quad9_tls() -> Self {
771        Self::from_ips_tls(QUAD9_IPS, 853, "dns.quad9.net".to_string(), true)
772    }
773
774    /// 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
775    ///
776    /// Please see: <https://www.quad9.net/faq/>
777    #[cfg(feature = "dns-over-https")]
778    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
779    pub fn quad9_https() -> Self {
780        Self::from_ips_https(QUAD9_IPS, 443, "dns.quad9.net".to_string(), true)
781    }
782
783    /// Merges this set of [`NameServerConfig`]s with the other
784    ///
785    /// ```
786    /// use std::net::{SocketAddr, Ipv4Addr};
787    /// use hickory_resolver::config::NameServerConfigGroup;
788    ///
789    /// let mut group = NameServerConfigGroup::google();
790    /// group.merge(NameServerConfigGroup::cloudflare());
791    /// group.merge(NameServerConfigGroup::quad9());
792    ///
793    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(8, 8, 8, 8).into(), 53)));
794    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(1, 1, 1, 1).into(), 53)));
795    /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(9, 9, 9, 9).into(), 53)));
796    /// ```
797    pub fn merge(&mut self, mut other: Self) {
798        #[cfg(not(feature = "dns-over-rustls"))]
799        {
800            self.append(&mut other);
801        }
802        #[cfg(feature = "dns-over-rustls")]
803        {
804            self.0.append(&mut other);
805        }
806    }
807
808    /// add a [`rustls::ClientConfig`]
809    #[cfg(feature = "dns-over-rustls")]
810    #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
811    pub fn with_client_config(self, client_config: Arc<ClientConfig>) -> Self {
812        Self(self.0, Some(TlsClientConfig(client_config)))
813    }
814
815    /// Sets the client address (IP and port) to connect from on all name servers.
816    pub fn with_bind_addr(mut self, bind_addr: Option<SocketAddr>) -> Self {
817        for server in &mut self.0 {
818            server.bind_addr = bind_addr;
819        }
820        self
821    }
822}
823
824impl Default for NameServerConfigGroup {
825    fn default() -> Self {
826        Self::new()
827    }
828}
829
830impl Deref for NameServerConfigGroup {
831    type Target = Vec<NameServerConfig>;
832    fn deref(&self) -> &Self::Target {
833        &self.0
834    }
835}
836
837impl DerefMut for NameServerConfigGroup {
838    fn deref_mut(&mut self) -> &mut Self::Target {
839        &mut self.0
840    }
841}
842
843impl From<Vec<NameServerConfig>> for NameServerConfigGroup {
844    fn from(configs: Vec<NameServerConfig>) -> Self {
845        #[cfg(not(feature = "dns-over-rustls"))]
846        {
847            Self(configs)
848        }
849        #[cfg(feature = "dns-over-rustls")]
850        {
851            Self(configs, None)
852        }
853    }
854}
855
856/// The lookup ip strategy
857#[derive(Debug, Clone, Copy, PartialEq, Eq)]
858#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
859pub enum LookupIpStrategy {
860    /// Only query for A (Ipv4) records
861    Ipv4Only,
862    /// Only query for AAAA (Ipv6) records
863    Ipv6Only,
864    /// Query for A and AAAA in parallel
865    Ipv4AndIpv6,
866    /// Query for Ipv6 if that fails, query for Ipv4
867    Ipv6thenIpv4,
868    /// Query for Ipv4 if that fails, query for Ipv6 (default)
869    Ipv4thenIpv6,
870}
871
872impl Default for LookupIpStrategy {
873    /// Returns [`LookupIpStrategy::Ipv4thenIpv6`] as the default.
874    fn default() -> Self {
875        Self::Ipv4thenIpv6
876    }
877}
878
879/// The strategy for establishing the query order of name servers in a pool.
880#[derive(Debug, Clone, Copy, PartialEq, Eq)]
881#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
882pub enum ServerOrderingStrategy {
883    /// Servers are ordered based on collected query statistics. The ordering
884    /// may vary over time.
885    QueryStatistics,
886    /// The order provided to the resolver is used. The ordering does not vary
887    /// over time.
888    UserProvidedOrder,
889}
890
891impl Default for ServerOrderingStrategy {
892    /// Returns [`ServerOrderingStrategy::QueryStatistics`] as the default.
893    fn default() -> Self {
894        Self::QueryStatistics
895    }
896}
897
898/// Configuration for the Resolver
899#[derive(Debug, Clone, Eq, PartialEq)]
900#[cfg_attr(
901    feature = "serde-config",
902    derive(Serialize, Deserialize),
903    serde(default)
904)]
905#[allow(missing_copy_implementations)]
906#[non_exhaustive]
907pub struct ResolverOpts {
908    /// Sets the number of dots that must appear (unless it's a final dot representing the root)
909    ///  before a query is assumed to include the TLD. The default is one, which means that `www`
910    ///  would never be assumed to be a TLD, and would always be appended to either the search
911    pub ndots: usize,
912    /// Specify the timeout for a request. Defaults to 5 seconds
913    pub timeout: Duration,
914    /// Number of retries after lookup failure before giving up. Defaults to 2
915    pub attempts: usize,
916    /// Rotate through the resource records in the response (if there is more than one for a given name)
917    pub rotate: bool,
918    /// Validate the names in the response, not implemented don't really see the point unless you need to support
919    ///  badly configured DNS
920    pub check_names: bool,
921    /// Enable edns, for larger records
922    pub edns0: bool,
923    /// Use DNSSEC to validate the request
924    pub validate: bool,
925    /// The ip_strategy for the Resolver to use when lookup Ipv4 or Ipv6 addresses
926    pub ip_strategy: LookupIpStrategy,
927    /// Cache size is in number of records (some records can be large)
928    pub cache_size: usize,
929    /// Check /ect/hosts file before dns requery (only works for unix like OS)
930    pub use_hosts_file: bool,
931    /// Optional minimum TTL for positive responses.
932    ///
933    /// If this is set, any positive responses with a TTL lower than this value will have a TTL of
934    /// `positive_min_ttl` instead. Otherwise, this will default to 0 seconds.
935    pub positive_min_ttl: Option<Duration>,
936    /// Optional minimum TTL for negative (`NXDOMAIN`) responses.
937    ///
938    /// If this is set, any negative responses with a TTL lower than this value will have a TTL of
939    /// `negative_min_ttl` instead. Otherwise, this will default to 0 seconds.
940    pub negative_min_ttl: Option<Duration>,
941    /// Optional maximum TTL for positive responses.
942    ///
943    /// If this is set, any positive responses with a TTL higher than this value will have a TTL of
944    /// `positive_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
945    ///
946    /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
947    pub positive_max_ttl: Option<Duration>,
948    /// Optional maximum TTL for negative (`NXDOMAIN`) responses.
949    ///
950    /// If this is set, any negative responses with a TTL higher than this value will have a TTL of
951    /// `negative_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
952    ///
953    /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
954    pub negative_max_ttl: Option<Duration>,
955    /// Number of concurrent requests per query
956    ///
957    /// Where more than one nameserver is configured, this configures the resolver to send queries
958    /// to a number of servers in parallel. Defaults to 2; 0 or 1 will execute requests serially.
959    pub num_concurrent_reqs: usize,
960    /// Preserve all intermediate records in the lookup response, such as CNAME records
961    pub preserve_intermediates: bool,
962    /// Try queries over TCP if they fail over UDP.
963    pub try_tcp_on_error: bool,
964    /// The server ordering strategy that the resolver should use.
965    pub server_ordering_strategy: ServerOrderingStrategy,
966    /// Request upstream recursive resolvers to not perform any recursion.
967    ///
968    /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
969    pub recursion_desired: bool,
970    /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
971    pub authentic_data: bool,
972    /// Shuffle DNS servers before each query.
973    pub shuffle_dns_servers: bool,
974}
975
976impl Default for ResolverOpts {
977    /// Default values for the Resolver configuration.
978    ///
979    /// This follows the resolv.conf defaults as defined in the [Linux man pages](https://man7.org/linux/man-pages/man5/resolv.conf.5.html)
980    fn default() -> Self {
981        Self {
982            ndots: 1,
983            timeout: Duration::from_secs(5),
984            attempts: 2,
985            rotate: false,
986            check_names: true,
987            edns0: false,
988            validate: false,
989            ip_strategy: LookupIpStrategy::default(),
990            cache_size: 32,
991            use_hosts_file: true,
992            positive_min_ttl: None,
993            negative_min_ttl: None,
994            positive_max_ttl: None,
995            negative_max_ttl: None,
996            num_concurrent_reqs: 2,
997
998            // Defaults to `true` to match the behavior of dig and nslookup.
999            preserve_intermediates: true,
1000
1001            try_tcp_on_error: false,
1002            server_ordering_strategy: ServerOrderingStrategy::default(),
1003            recursion_desired: true,
1004            authentic_data: false,
1005            shuffle_dns_servers: false,
1006        }
1007    }
1008}
1009
1010/// IP addresses for Google Public DNS
1011pub const GOOGLE_IPS: &[IpAddr] = &[
1012    IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
1013    IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
1014    IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
1015    IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
1016];
1017
1018/// IP addresses for Cloudflare's 1.1.1.1 DNS service
1019pub const CLOUDFLARE_IPS: &[IpAddr] = &[
1020    IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
1021    IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
1022    IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
1023    IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
1024];
1025
1026/// IP address for the Quad9 DNS service
1027pub const QUAD9_IPS: &[IpAddr] = &[
1028    IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
1029    IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
1030    IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
1031    IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0x00fe, 0x0009)),
1032];