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