Skip to main content

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::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
13use std::path::PathBuf;
14use std::sync::Arc;
15use std::time::Duration;
16#[cfg(all(
17    feature = "recursor",
18    feature = "toml",
19    feature = "serde",
20    any(feature = "__tls", feature = "__quic")
21))]
22use std::{fs, io};
23
24use ipnet::IpNet;
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27use tracing::warn;
28#[cfg(all(
29    feature = "recursor",
30    feature = "toml",
31    feature = "serde",
32    any(feature = "__tls", feature = "__quic")
33))]
34use tracing::{debug, info};
35
36#[cfg(all(
37    feature = "recursor",
38    feature = "toml",
39    feature = "serde",
40    any(feature = "__tls", feature = "__quic")
41))]
42use crate::name_server_pool::NameServerTransportState;
43#[cfg(any(feature = "__https", feature = "__h3"))]
44use crate::net::http::DEFAULT_DNS_QUERY_PATH;
45use crate::net::xfer::Protocol;
46use crate::proto::access_control::{AccessControlSet, AccessControlSetBuilder};
47use crate::proto::op::DEFAULT_MAX_PAYLOAD_LEN;
48use crate::proto::rr::Name;
49
50/// Configuration for the upstream nameservers to use for resolution.
51///
52/// The `Default` implementation of this struct will be removed in a future version. Use
53/// [`Self::from_name_servers()`] instead. Note that a `ResolverConfig` with no name servers will
54/// produce a nonfunctional resolver.
55#[non_exhaustive]
56#[derive(Clone, Debug, Default)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58pub struct ResolverConfig {
59    /// Base search domain
60    #[cfg_attr(feature = "serde", serde(default))]
61    pub domain: Option<Name>,
62    /// Search domains
63    #[cfg_attr(feature = "serde", serde(default))]
64    pub search: Vec<Name>,
65    /// Name servers to use for resolution
66    pub name_servers: Vec<NameServerConfig>,
67}
68
69impl ResolverConfig {
70    /// Create a new `ResolverConfig` from [`ServerGroup`] configuration.
71    ///
72    /// Connects via UDP and TCP.
73    pub fn udp_and_tcp(config: &ServerGroup<'_>) -> Self {
74        Self {
75            // TODO: this should get the hostname and use the basename as the default
76            domain: None,
77            search: vec![],
78            name_servers: config.udp_and_tcp().collect(),
79        }
80    }
81
82    /// Create a new `ResolverConfig` from [`ServerGroup`] configuration.
83    ///
84    /// Only connects via TLS.
85    #[cfg(feature = "__tls")]
86    pub fn tls(config: &ServerGroup<'_>) -> Self {
87        Self {
88            // TODO: this should get the hostname and use the basename as the default
89            domain: None,
90            search: vec![],
91            name_servers: config.tls().collect(),
92        }
93    }
94
95    /// Create a new `ResolverConfig` from [`ServerGroup`] configuration.
96    ///
97    /// Only connects via HTTPS (HTTP/2).
98    #[cfg(feature = "__https")]
99    pub fn https(config: &ServerGroup<'_>) -> Self {
100        Self {
101            // TODO: this should get the hostname and use the basename as the default
102            domain: None,
103            search: vec![],
104            name_servers: config.https().collect(),
105        }
106    }
107
108    /// Create a new `ResolverConfig` from [`ServerGroup`] configuration.
109    ///
110    /// Only connects via QUIC.
111    #[cfg(feature = "__quic")]
112    pub fn quic(config: &ServerGroup<'_>) -> Self {
113        Self {
114            // TODO: this should get the hostname and use the basename as the default
115            domain: None,
116            search: vec![],
117            name_servers: config.quic().collect(),
118        }
119    }
120
121    /// Create a new `ResolverConfig` from [`ServerGroup`] configuration.
122    ///
123    /// Only connects via HTTP/3.
124    #[cfg(feature = "__h3")]
125    pub fn h3(config: &ServerGroup<'_>) -> 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: config.h3().collect(),
131        }
132    }
133
134    /// Create a ResolverConfig with all parts specified
135    ///
136    /// # Arguments
137    ///
138    /// * `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.
139    /// * `search` - additional search domains that are attempted if the `Name` is not found in `domain`, defaults to `vec![]`
140    /// * `name_servers` - set of name servers to use for lookups
141    pub fn from_parts(
142        domain: Option<Name>,
143        search: Vec<Name>,
144        name_servers: Vec<NameServerConfig>,
145    ) -> Self {
146        Self {
147            domain,
148            search,
149            name_servers,
150        }
151    }
152
153    /// Create a ResolverConfig from a list of name server configurations.
154    ///
155    /// No base domain for relative names will be set, and no additional search domains will be set.
156    pub fn from_name_servers(name_servers: Vec<NameServerConfig>) -> Self {
157        Self::from_parts(None, vec![], name_servers)
158    }
159
160    /// Take the `domain`, `search`, and `name_servers` from the config.
161    pub fn into_parts(self) -> (Option<Name>, Vec<Name>, Vec<NameServerConfig>) {
162        (self.domain, self.search, self.name_servers)
163    }
164
165    /// Returns the local domain
166    ///
167    /// By default any names will be appended to all non-fully-qualified-domain names, and searched for after any ndots rules
168    pub fn domain(&self) -> Option<&Name> {
169        self.domain.as_ref()
170    }
171
172    /// Set the domain of the entity querying results.
173    pub fn set_domain(&mut self, domain: Name) {
174        self.domain = Some(domain.clone());
175        self.search = vec![domain];
176    }
177
178    /// Returns the search domains
179    ///
180    /// These will be queried after any local domain and then in the order of the set of search domains
181    pub fn search(&self) -> &[Name] {
182        &self.search
183    }
184
185    /// Add a search domain
186    pub fn add_search(&mut self, search: Name) {
187        self.search.push(search)
188    }
189
190    // TODO: consider allowing options per NameServer... like different timeouts?
191    /// Add the configuration for a name server
192    pub fn add_name_server(&mut self, name_server: NameServerConfig) {
193        self.name_servers.push(name_server);
194    }
195
196    /// Returns a reference to the name servers
197    pub fn name_servers(&self) -> &[NameServerConfig] {
198        &self.name_servers
199    }
200}
201
202/// Configuration for the NameServer
203#[derive(Clone, Debug)]
204#[cfg_attr(
205    feature = "serde",
206    derive(Serialize, Deserialize),
207    serde(deny_unknown_fields)
208)]
209#[non_exhaustive]
210pub struct NameServerConfig {
211    /// The address which the DNS NameServer is registered at.
212    pub ip: IpAddr,
213    /// Whether to trust `NXDOMAIN` responses from upstream nameservers.
214    ///
215    /// When this is `true`, and an empty `NXDOMAIN` response with an empty answers set is
216    /// received, the query will not be retried against other configured name servers.
217    ///
218    /// (On a response with any other error response code, the query will still be retried
219    /// regardless of this configuration setting.)
220    ///
221    /// Defaults to `true`.
222    #[cfg_attr(feature = "serde", serde(default = "default_trust_negative_responses"))]
223    pub trust_negative_responses: bool,
224    /// Connection protocols configured for this server.
225    pub connections: Vec<ConnectionConfig>,
226}
227
228impl NameServerConfig {
229    /// Constructs a nameserver configuration with a UDP and TCP connections
230    pub fn udp_and_tcp(ip: IpAddr) -> Self {
231        Self {
232            ip,
233            trust_negative_responses: true,
234            connections: vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
235        }
236    }
237
238    /// Constructs a nameserver configuration with a single UDP connection
239    pub fn udp(ip: IpAddr) -> Self {
240        Self {
241            ip,
242            trust_negative_responses: true,
243            connections: vec![ConnectionConfig::udp()],
244        }
245    }
246
247    /// Constructs a nameserver configuration with a single TCP connection
248    pub fn tcp(ip: IpAddr) -> Self {
249        Self {
250            ip,
251            trust_negative_responses: true,
252            connections: vec![ConnectionConfig::tcp()],
253        }
254    }
255
256    /// Constructs a nameserver configuration with a single TLS connection
257    #[cfg(feature = "__tls")]
258    pub fn tls(ip: IpAddr, server_name: Arc<str>) -> Self {
259        Self {
260            ip,
261            trust_negative_responses: true,
262            connections: vec![ConnectionConfig::tls(server_name)],
263        }
264    }
265
266    /// Constructs a nameserver configuration with a single HTTP/2 connection
267    #[cfg(feature = "__https")]
268    pub fn https(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
269        Self {
270            ip,
271            trust_negative_responses: true,
272            connections: vec![ConnectionConfig::https(server_name, path)],
273        }
274    }
275
276    /// Constructs a nameserver configuration with a single QUIC connection
277    #[cfg(feature = "__quic")]
278    pub fn quic(ip: IpAddr, server_name: Arc<str>) -> Self {
279        Self {
280            ip,
281            trust_negative_responses: true,
282            connections: vec![ConnectionConfig::quic(server_name)],
283        }
284    }
285
286    /// Constructs a nameserver configuration with a single HTTP/3 connection
287    #[cfg(feature = "__h3")]
288    pub fn h3(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
289        Self {
290            ip,
291            trust_negative_responses: true,
292            connections: vec![ConnectionConfig::h3(server_name, path)],
293        }
294    }
295
296    /// Constructs a nameserver configuration for opportunistic encryption.
297    ///
298    /// This will include configurations for plaintext UDP/TCP as well as DNS-over-TLS and/or
299    /// DNS-over-QUIC depending on feature flag support.
300    ///
301    /// Notably, the TLS and QUIC configurations will **not** verify peer certificates, in
302    /// keeping with RFC 9539's requirement. See [RFC 9539 §4.6.3.4] for more information.
303    ///
304    /// [RFC 9539 §4.6.3.4]: https://www.rfc-editor.org/rfc/rfc9539.html#section-4.6.3.4
305    #[cfg(any(feature = "__tls", feature = "__quic"))]
306    pub fn opportunistic_encryption(ip: IpAddr) -> Self {
307        Self {
308            ip,
309            trust_negative_responses: true,
310            connections: vec![
311                ConnectionConfig::udp(),
312                ConnectionConfig::tcp(),
313                #[cfg(feature = "__tls")]
314                ConnectionConfig::tls(Arc::from(ip.to_string())),
315                #[cfg(feature = "__quic")]
316                ConnectionConfig::quic(Arc::from(ip.to_string())),
317            ],
318        }
319    }
320
321    /// Create a new [`NameServerConfig`] from its constituent parts.
322    pub fn new(
323        ip: IpAddr,
324        trust_negative_responses: bool,
325        connections: Vec<ConnectionConfig>,
326    ) -> Self {
327        Self {
328            ip,
329            trust_negative_responses,
330            connections,
331        }
332    }
333}
334
335#[cfg(feature = "serde")]
336fn default_trust_negative_responses() -> bool {
337    true
338}
339
340/// Configuration for a connection to a nameserver
341#[derive(Clone, Debug)]
342#[cfg_attr(feature = "serde", derive(Serialize))]
343#[non_exhaustive]
344pub struct ConnectionConfig {
345    /// The remote port to connect to
346    pub port: u16,
347    /// The protocol to use for the connection
348    pub protocol: ProtocolConfig,
349    /// The client address (IP and port) to use for connecting to the server
350    pub bind_addr: Option<SocketAddr>,
351}
352
353impl ConnectionConfig {
354    /// Constructs a new ConnectionConfig for UDP
355    pub fn udp() -> Self {
356        Self::new(ProtocolConfig::Udp)
357    }
358
359    /// Constructs a new ConnectionConfig for TCP
360    pub fn tcp() -> Self {
361        Self::new(ProtocolConfig::Tcp)
362    }
363
364    /// Constructs a new ConnectionConfig for TLS
365    #[cfg(feature = "__tls")]
366    pub fn tls(server_name: Arc<str>) -> Self {
367        Self::new(ProtocolConfig::Tls { server_name })
368    }
369
370    /// Constructs a new ConnectionConfig for HTTPS (HTTP/2)
371    #[cfg(feature = "__https")]
372    pub fn https(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
373        Self::new(ProtocolConfig::Https {
374            server_name,
375            path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
376        })
377    }
378
379    /// Constructs a new ConnectionConfig for QUIC
380    #[cfg(feature = "__quic")]
381    pub fn quic(server_name: Arc<str>) -> Self {
382        Self::new(ProtocolConfig::Quic { server_name })
383    }
384
385    /// Constructs a new ConnectionConfig for HTTP/3
386    #[cfg(feature = "__h3")]
387    pub fn h3(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
388        Self::new(ProtocolConfig::H3 {
389            server_name,
390            path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
391            disable_grease: false,
392        })
393    }
394
395    /// Constructs a new ConnectionConfig with the specified [`ProtocolConfig`].
396    pub fn new(protocol: ProtocolConfig) -> Self {
397        Self {
398            port: protocol.default_port(),
399            protocol,
400            bind_addr: None,
401        }
402    }
403}
404
405#[cfg(feature = "serde")]
406impl<'de> Deserialize<'de> for ConnectionConfig {
407    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
408        #[derive(Deserialize)]
409        #[serde(deny_unknown_fields)]
410        struct OptionalParts {
411            #[serde(default)]
412            port: Option<u16>,
413            protocol: ProtocolConfig,
414            #[serde(default)]
415            bind_addr: Option<SocketAddr>,
416        }
417
418        let parts = OptionalParts::deserialize(deserializer)?;
419        Ok(Self {
420            port: parts.port.unwrap_or_else(|| parts.protocol.default_port()),
421            protocol: parts.protocol,
422            bind_addr: parts.bind_addr,
423        })
424    }
425}
426
427/// Protocol configuration
428#[allow(missing_docs)]
429#[derive(Clone, Debug, Default, PartialEq)]
430#[cfg_attr(
431    feature = "serde",
432    derive(Serialize, Deserialize),
433    serde(deny_unknown_fields, rename_all = "snake_case", tag = "type")
434)]
435pub enum ProtocolConfig {
436    #[default]
437    Udp,
438    Tcp,
439    #[cfg(feature = "__tls")]
440    Tls {
441        /// The server name to use in the TLS handshake.
442        server_name: Arc<str>,
443    },
444    #[cfg(feature = "__https")]
445    Https {
446        /// The server name to use in the TLS handshake.
447        server_name: Arc<str>,
448        /// The path (or endpoint) to use for the DNS query.
449        path: Arc<str>,
450    },
451    #[cfg(feature = "__quic")]
452    Quic {
453        /// The server name to use in the TLS handshake.
454        server_name: Arc<str>,
455    },
456    #[cfg(feature = "__h3")]
457    H3 {
458        /// The server name to use in the TLS handshake.
459        server_name: Arc<str>,
460        /// The path (or endpoint) to use for the DNS query.
461        path: Arc<str>,
462        /// Whether to disable sending "grease"
463        #[cfg_attr(feature = "serde", serde(default))]
464        disable_grease: bool,
465    },
466}
467
468impl ProtocolConfig {
469    /// Get the [`Protocol`] for this [`ProtocolConfig`].
470    pub fn to_protocol(&self) -> Protocol {
471        match self {
472            ProtocolConfig::Udp => Protocol::Udp,
473            ProtocolConfig::Tcp => Protocol::Tcp,
474            #[cfg(feature = "__tls")]
475            ProtocolConfig::Tls { .. } => Protocol::Tls,
476            #[cfg(feature = "__https")]
477            ProtocolConfig::Https { .. } => Protocol::Https,
478            #[cfg(feature = "__quic")]
479            ProtocolConfig::Quic { .. } => Protocol::Quic,
480            #[cfg(feature = "__h3")]
481            ProtocolConfig::H3 { .. } => Protocol::H3,
482        }
483    }
484
485    /// Default port for the protocol.
486    pub fn default_port(&self) -> u16 {
487        match self {
488            ProtocolConfig::Udp => 53,
489            ProtocolConfig::Tcp => 53,
490            #[cfg(feature = "__tls")]
491            ProtocolConfig::Tls { .. } => 853,
492            #[cfg(feature = "__https")]
493            ProtocolConfig::Https { .. } => 443,
494            #[cfg(feature = "__quic")]
495            ProtocolConfig::Quic { .. } => 853,
496            #[cfg(feature = "__h3")]
497            ProtocolConfig::H3 { .. } => 443,
498        }
499    }
500}
501
502/// Configuration for the Resolver
503#[derive(Debug, Clone)]
504#[cfg_attr(
505    feature = "serde",
506    derive(Serialize, Deserialize),
507    serde(default, deny_unknown_fields)
508)]
509#[non_exhaustive]
510pub struct ResolverOpts {
511    /// Sets the number of dots that must appear (unless it's a final dot representing the root)
512    ///  before a query is assumed to include the TLD. The default is one, which means that `www`
513    ///  would never be assumed to be a TLD, and would always be appended to either the search
514    #[cfg_attr(feature = "serde", serde(default = "default_ndots"))]
515    pub ndots: usize,
516    /// Specify the timeout for a request. Defaults to 5 seconds
517    #[cfg_attr(
518        feature = "serde",
519        serde(default = "default_timeout", with = "duration")
520    )]
521    pub timeout: Duration,
522    /// Number of retries after lookup failure before giving up. Defaults to 2
523    #[cfg_attr(feature = "serde", serde(default = "default_attempts"))]
524    pub attempts: usize,
525    /// Enable edns, for larger records
526    pub edns0: bool,
527    /// Use DNSSEC to validate the request
528    #[cfg(feature = "__dnssec")]
529    pub validate: bool,
530    /// The strategy for the Resolver to use when looking up host IP addresses
531    pub ip_strategy: LookupIpStrategy,
532    /// Cache size is in number of responses (some responses can be large)
533    #[cfg_attr(feature = "serde", serde(default = "default_cache_size"))]
534    pub cache_size: u64,
535    /// Check /etc/hosts file before dns requery (only works for unix like OS)
536    pub use_hosts_file: ResolveHosts,
537    /// Optional minimum TTL for positive responses.
538    ///
539    /// If this is set, any positive responses with a TTL lower than this value will have a TTL of
540    /// `positive_min_ttl` instead. Otherwise, this will default to 0 seconds.
541    #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
542    pub positive_min_ttl: Option<Duration>,
543    /// Optional minimum TTL for negative (`NXDOMAIN`) responses.
544    ///
545    /// If this is set, any negative responses with a TTL lower than this value will have a TTL of
546    /// `negative_min_ttl` instead. Otherwise, this will default to 0 seconds.
547    #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
548    pub negative_min_ttl: Option<Duration>,
549    /// Optional maximum TTL for positive responses.
550    ///
551    /// If this is set, any positive responses with a TTL higher than this value will have a TTL of
552    /// `positive_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`](crate::MAX_TTL) seconds.
553    #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
554    pub positive_max_ttl: Option<Duration>,
555    /// Optional maximum TTL for negative (`NXDOMAIN`) responses.
556    ///
557    /// If this is set, any negative responses with a TTL higher than this value will have a TTL of
558    /// `negative_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`](crate::MAX_TTL) seconds.
559    #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
560    pub negative_max_ttl: Option<Duration>,
561    /// Number of concurrent requests per query
562    ///
563    /// Where more than one nameserver is configured, this configures the resolver to send queries
564    /// to a number of servers in parallel. Defaults to 2; 0 or 1 will execute requests serially.
565    #[cfg_attr(feature = "serde", serde(default = "default_num_concurrent_reqs"))]
566    pub num_concurrent_reqs: usize,
567    /// Maximum number of active (in-flight) requests per multiplexed connection.
568    ///
569    /// This limits how many DNS queries can be simultaneously pending on a single
570    /// connection to an upstream nameserver. When the limit is reached, new requests
571    /// will return a busy error.
572    ///
573    /// Defaults to 32. Higher values allow more parallelism but consume more memory.
574    #[cfg_attr(feature = "serde", serde(default = "default_max_active_requests"))]
575    pub max_active_requests: usize,
576    /// Preserve all intermediate records in the lookup response, such as CNAME records
577    #[cfg_attr(feature = "serde", serde(default = "default_preserve_intermediates"))]
578    pub preserve_intermediates: bool,
579    /// Try queries over TCP if they fail over UDP.
580    pub try_tcp_on_error: bool,
581    /// The server ordering strategy that the resolver should use.
582    pub server_ordering_strategy: ServerOrderingStrategy,
583    /// Request upstream recursive resolvers to not perform any recursion.
584    ///
585    /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
586    #[cfg_attr(feature = "serde", serde(default = "default_recursion_desired"))]
587    pub recursion_desired: bool,
588    /// Local UDP ports to avoid when making outgoing queries
589    pub avoid_local_udp_ports: Arc<HashSet<u16>>,
590    /// Request UDP bind ephemeral ports directly from the OS
591    ///
592    /// Boolean parameter to specify whether to use the operating system's standard UDP port
593    /// selection logic instead of Hickory's logic to securely select a random source port. We do
594    /// not recommend using this option unless absolutely necessary, as the operating system may
595    /// select ephemeral ports from a smaller range than Hickory, which can make response poisoning
596    /// attacks easier to conduct. Some operating systems (notably, Windows) might display a
597    /// user-prompt to allow a Hickory-specified port to be used, and setting this option will
598    /// prevent those prompts from being displayed. If os_port_selection is true, avoid_local_udp_ports
599    /// will be ignored.
600    pub os_port_selection: bool,
601    /// Enable case randomization.
602    ///
603    /// Randomize the case of letters in query names, and require that responses preserve the case
604    /// of the query name, in order to mitigate spoofing attacks. This is only applied over UDP.
605    ///
606    /// This implements the mechanism described in
607    /// [draft-vixie-dnsext-dns0x20-00](https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00).
608    pub case_randomization: bool,
609    /// Path to a DNSSEC trust anchor file.
610    ///
611    /// If this is provided, `validate` will automatically be set to `true`, enabling DNSSEC validation.
612    pub trust_anchor: Option<PathBuf>,
613    /// Exceptions to `deny_answer_addresses`. Networks listed here will be allowed, even if the IP address
614    /// matches a network in `deny_answer_addresses`.
615    pub allow_answers: Vec<IpNet>,
616    /// Networks listed here will be removed from any answers returned by an upstream server.
617    pub deny_answers: Vec<IpNet>,
618    /// Configure the EDNS UDP payload size used in queries.
619    ///
620    /// See [DnsRequestOptions::edns_payload_len][crate::proto::op::DnsRequestOptions::edns_payload_len].
621    #[cfg_attr(feature = "serde", serde(default = "default_edns_payload_len"))]
622    pub edns_payload_len: u16,
623    /// Report the IP of the name server for query result metrics.
624    ///
625    /// When `false`, metrics are aggregated under a static "aggregate" address label to avoid
626    /// cardinality blowup. For this reason, you might want to leave this disabled when querying a
627    /// large or unbounded set of DNS servers.
628    #[cfg_attr(feature = "serde", serde(default))]
629    #[cfg(feature = "metrics")]
630    pub enable_per_name_server_metrics: bool,
631}
632
633impl ResolverOpts {
634    pub(crate) fn answer_address_filter(&self) -> AccessControlSet {
635        let name = "resolver_answer_filter";
636        AccessControlSetBuilder::new(name)
637            .allow(self.allow_answers.iter())
638            .deny(self.deny_answers.iter())
639            .build()
640            .inspect_err(|err| warn!("{err}"))
641            .unwrap_or_else(|_| AccessControlSet::empty(name))
642    }
643}
644
645impl Default for ResolverOpts {
646    /// Default values for the Resolver configuration.
647    ///
648    /// This follows the resolv.conf defaults as defined in the [Linux man pages](https://man7.org/linux/man-pages/man5/resolv.conf.5.html)
649    fn default() -> Self {
650        Self {
651            ndots: default_ndots(),
652            timeout: default_timeout(),
653            attempts: default_attempts(),
654            edns0: true,
655            #[cfg(feature = "__dnssec")]
656            validate: false,
657            ip_strategy: LookupIpStrategy::default(),
658            cache_size: default_cache_size(),
659            use_hosts_file: ResolveHosts::default(),
660            positive_min_ttl: None,
661            negative_min_ttl: None,
662            positive_max_ttl: None,
663            negative_max_ttl: None,
664            num_concurrent_reqs: default_num_concurrent_reqs(),
665            max_active_requests: default_max_active_requests(),
666
667            // Defaults to `true` to match the behavior of dig and nslookup.
668            preserve_intermediates: default_preserve_intermediates(),
669
670            try_tcp_on_error: false,
671            server_ordering_strategy: ServerOrderingStrategy::default(),
672            recursion_desired: default_recursion_desired(),
673            avoid_local_udp_ports: Arc::default(),
674            os_port_selection: false,
675            case_randomization: false,
676            trust_anchor: None,
677            allow_answers: vec![],
678            deny_answers: vec![],
679            edns_payload_len: default_edns_payload_len(),
680            #[cfg(feature = "metrics")]
681            enable_per_name_server_metrics: false,
682        }
683    }
684}
685
686fn default_ndots() -> usize {
687    1
688}
689
690fn default_timeout() -> Duration {
691    Duration::from_secs(5)
692}
693
694fn default_attempts() -> usize {
695    2
696}
697
698fn default_cache_size() -> u64 {
699    8_192
700}
701
702fn default_num_concurrent_reqs() -> usize {
703    2
704}
705
706fn default_max_active_requests() -> usize {
707    32
708}
709
710fn default_preserve_intermediates() -> bool {
711    true
712}
713
714fn default_recursion_desired() -> bool {
715    true
716}
717
718fn default_edns_payload_len() -> u16 {
719    DEFAULT_MAX_PAYLOAD_LEN
720}
721
722/// The lookup ip strategy
723#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
725pub enum LookupIpStrategy {
726    /// Only query for A (Ipv4) records
727    Ipv4Only,
728    /// Only query for AAAA (Ipv6) records
729    Ipv6Only,
730    /// Query for A and AAAA in parallel, ordering A before AAAA
731    Ipv4AndIpv6,
732    /// Query for AAAA and A in parallel, ordering AAAA before A
733    #[default]
734    Ipv6AndIpv4,
735    /// Query for Ipv6 if that fails, query for Ipv4
736    Ipv6thenIpv4,
737    /// Query for Ipv4 if that fails, query for Ipv6 (default)
738    Ipv4thenIpv6,
739}
740
741/// The strategy for establishing the query order of name servers in a pool.
742#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
743#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
744#[non_exhaustive]
745pub enum ServerOrderingStrategy {
746    /// Servers are ordered based on collected query statistics. The ordering
747    /// may vary over time.
748    #[default]
749    QueryStatistics,
750    /// The order provided to the resolver is used. The ordering does not vary
751    /// over time.
752    UserProvidedOrder,
753    /// The order of servers is rotated in a round-robin fashion. This is useful for
754    /// load balancing and ensuring that all servers are used evenly.
755    RoundRobin,
756}
757
758/// Whether the system hosts file should be respected by the resolver.
759#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
760#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
761pub enum ResolveHosts {
762    /// Always attempt to look up IP addresses from the system hosts file.
763    /// If the hostname cannot be found, query the DNS.
764    Always,
765    /// The DNS will always be queried.
766    Never,
767    /// Use local resolver configurations only when this resolver is not used in
768    /// a DNS forwarder. This is the default.
769    #[default]
770    Auto,
771}
772
773/// Configuration for enabling RFC 9539 opportunistic encryption.
774///
775/// Controls how a recursive resolver probes name servers to discover if they support
776/// encrypted transports.
777#[derive(Debug, Clone, Default, Eq, PartialEq)]
778#[cfg_attr(
779    feature = "serde",
780    derive(Serialize, Deserialize),
781    serde(rename_all = "snake_case")
782)]
783#[non_exhaustive]
784pub enum OpportunisticEncryption {
785    /// Opportunistic encryption will not be performed.
786    #[default]
787    Disabled,
788    /// Opportunistic encryption will be performed.
789    #[cfg(any(feature = "__tls", feature = "__quic"))]
790    Enabled {
791        /// Configuration parameters for opportunistic encryption.
792        #[cfg_attr(feature = "serde", serde(flatten))]
793        config: OpportunisticEncryptionConfig,
794    },
795}
796
797impl OpportunisticEncryption {
798    #[cfg(all(
799        feature = "recursor",
800        feature = "toml",
801        feature = "serde",
802        any(feature = "__tls", feature = "__quic")
803    ))]
804    pub(super) fn persisted_state(&self) -> Result<Option<NameServerTransportState>, String> {
805        let OpportunisticEncryption::Enabled {
806            config:
807                OpportunisticEncryptionConfig {
808                    persistence: Some(OpportunisticEncryptionPersistence { path, .. }),
809                    ..
810                },
811        } = self
812        else {
813            return Ok(None);
814        };
815
816        let state = match fs::read_to_string(path) {
817            Ok(toml_content) => toml::from_str(&toml_content).map_err(|e| {
818                format!(
819                    "failed to parse opportunistic encryption state TOML file: {file_path}: {e}",
820                    file_path = path.display()
821                )
822            })?,
823            Err(e) if e.kind() == io::ErrorKind::NotFound => {
824                info!(
825                    state_file = %path.display(),
826                    "no pre-existing opportunistic encryption state TOML file, starting with default state",
827                );
828                NameServerTransportState::default()
829            }
830            Err(e) => {
831                return Err(format!(
832                    "failed to read opportunistic encryption state TOML file: {file_path}: {e}",
833                    file_path = path.display()
834                ));
835            }
836        };
837
838        debug!(
839            path = %path.display(),
840            nameserver_count = state.nameserver_count(),
841            "loaded opportunistic encryption state"
842        );
843
844        Ok(Some(state))
845    }
846
847    /// Returns true if opportunistic encryption is enabled.
848    pub fn is_enabled(&self) -> bool {
849        match self {
850            Self::Disabled => false,
851            #[cfg(any(feature = "__tls", feature = "__quic"))]
852            Self::Enabled { .. } => true,
853        }
854    }
855
856    /// Returns the maximum number of concurrent probes if opportunistic encrypt is enabled.
857    pub fn max_concurrent_probes(&self) -> Option<u8> {
858        match self {
859            Self::Disabled => None,
860            #[cfg(any(feature = "__tls", feature = "__quic"))]
861            Self::Enabled { config, .. } => Some(config.max_concurrent_probes),
862        }
863    }
864}
865
866/// Configuration parameters for opportunistic encryption.
867#[derive(Debug, Clone, Eq, PartialEq)]
868#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
869#[cfg_attr(feature = "serde", serde(default, deny_unknown_fields))]
870pub struct OpportunisticEncryptionConfig {
871    /// How long the recursive resolver remembers a successful encrypted transport connection.
872    #[cfg_attr(
873        feature = "serde",
874        serde(default = "default_persistence_period", with = "duration")
875    )]
876    pub persistence_period: Duration,
877
878    /// How long the recursive resolver remembers a failed encrypted transport connection.
879    #[cfg_attr(
880        feature = "serde",
881        serde(default = "default_damping_period", with = "duration")
882    )]
883    pub damping_period: Duration,
884
885    /// Maximum number of concurrent opportunistic encryption probes.
886    #[cfg_attr(feature = "serde", serde(default = "default_max_concurrent_probes"))]
887    pub max_concurrent_probes: u8,
888
889    /// Optional configuration for persistence of opportunistic encryption probe state.
890    pub persistence: Option<OpportunisticEncryptionPersistence>,
891}
892
893impl Default for OpportunisticEncryptionConfig {
894    fn default() -> Self {
895        Self {
896            persistence_period: default_persistence_period(),
897            damping_period: default_damping_period(),
898            max_concurrent_probes: default_max_concurrent_probes(),
899            persistence: None,
900        }
901    }
902}
903
904/// The RFC 9539 suggested default for the resolver persistence period.
905fn default_persistence_period() -> Duration {
906    Duration::from_secs(60 * 60 * 24 * 3) // 3 days
907}
908
909/// The RFC 9539 suggested default for the resolver damping period.
910fn default_damping_period() -> Duration {
911    Duration::from_secs(24 * 60 * 60) // 1 day
912}
913
914/// A conservative default for the maximum number of in-flight opportunistic probe requests.
915fn default_max_concurrent_probes() -> u8 {
916    10
917}
918
919#[derive(Debug, Clone, Eq, PartialEq)]
920#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
921#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
922/// Configuration for persistence of opportunistic encryption probe state.
923pub struct OpportunisticEncryptionPersistence {
924    /// Path to a TOML state file that may be used for saving/loading opportunistic encryption state.
925    pub path: PathBuf,
926
927    /// Interval after which opportunistic encryption state is periodically saved to `path`.
928    #[cfg_attr(
929        feature = "serde",
930        serde(default = "default_save_interval", with = "duration")
931    )]
932    pub save_interval: Duration,
933}
934
935#[cfg(feature = "serde")]
936fn default_save_interval() -> Duration {
937    Duration::from_secs(60 * 10) // 10 minutes
938}
939
940/// Google Public DNS configuration.
941///
942/// Please see Google's [privacy statement](https://developers.google.com/speed/public-dns/privacy)
943/// for important information about what they track, many ISP's track similar information in DNS.
944/// To use the system configuration see: `Resolver::from_system_conf`.
945pub const GOOGLE: ServerGroup<'static> = ServerGroup {
946    ips: &[
947        IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
948        IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
949        IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
950        IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
951    ],
952    server_name: "dns.google",
953    path: "/dns-query",
954};
955
956/// Cloudflare's 1.1.1.1 DNS service configuration.
957///
958/// See <https://www.cloudflare.com/dns/> for more information.
959pub const CLOUDFLARE: ServerGroup<'static> = ServerGroup {
960    ips: &[
961        IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
962        IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
963        IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
964        IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
965    ],
966    server_name: "cloudflare-dns.com",
967    path: "/dns-query",
968};
969
970/// The Quad9 DNS service configuration.
971///
972/// See <https://www.quad9.net/faq/> for more information.
973pub const QUAD9: ServerGroup<'static> = ServerGroup {
974    ips: &[
975        IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
976        IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
977        IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
978        IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x0009)),
979    ],
980    server_name: "dns.quad9.net",
981    path: "/dns-query",
982};
983
984/// A group of DNS servers.
985#[derive(Clone, Copy, Debug)]
986pub struct ServerGroup<'a> {
987    /// IP addresses of the DNS servers in this group.
988    pub ips: &'a [IpAddr],
989    /// The TLS server name to use for servers.
990    pub server_name: &'a str,
991    /// The query path to use for HTTP queries.
992    pub path: &'a str,
993}
994
995impl<'a> ServerGroup<'a> {
996    /// Create an iterator with `NameServerConfig` for each IP address in the group.
997    pub fn udp_and_tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
998        self.ips.iter().map(|&ip| {
999            NameServerConfig::new(
1000                ip,
1001                true,
1002                vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
1003            )
1004        })
1005    }
1006
1007    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1008    pub fn udp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1009        self.ips
1010            .iter()
1011            .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::udp()]))
1012    }
1013
1014    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1015    pub fn tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1016        self.ips
1017            .iter()
1018            .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::tcp()]))
1019    }
1020
1021    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1022    #[cfg(feature = "__tls")]
1023    pub fn tls(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1024        let this = *self;
1025        self.ips.iter().map(move |&ip| {
1026            NameServerConfig::new(
1027                ip,
1028                true,
1029                vec![ConnectionConfig::tls(Arc::from(this.server_name))],
1030            )
1031        })
1032    }
1033
1034    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1035    #[cfg(feature = "__https")]
1036    pub fn https(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1037        let this = *self;
1038        self.ips.iter().map(move |&ip| {
1039            NameServerConfig::new(
1040                ip,
1041                true,
1042                vec![ConnectionConfig::https(
1043                    Arc::from(this.server_name),
1044                    Some(Arc::from(this.path)),
1045                )],
1046            )
1047        })
1048    }
1049
1050    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1051    #[cfg(feature = "__quic")]
1052    pub fn quic(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1053        let this = *self;
1054        self.ips.iter().map(move |&ip| {
1055            NameServerConfig::new(
1056                ip,
1057                true,
1058                vec![ConnectionConfig::quic(Arc::from(this.server_name))],
1059            )
1060        })
1061    }
1062
1063    /// Create an iterator with `NameServerConfig` for each IP address in the group.
1064    #[cfg(feature = "__h3")]
1065    pub fn h3(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1066        let this = *self;
1067        self.ips.iter().map(move |&ip| {
1068            NameServerConfig::new(
1069                ip,
1070                true,
1071                vec![ConnectionConfig::h3(
1072                    Arc::from(this.server_name),
1073                    Some(Arc::from(this.path)),
1074                )],
1075            )
1076        })
1077    }
1078}
1079
1080#[cfg(feature = "serde")]
1081pub(crate) mod duration {
1082    use std::time::Duration;
1083
1084    use serde::{Deserialize, Deserializer, Serialize, Serializer};
1085
1086    /// This is an alternate serialization function for a [`Duration`] that emits a single number,
1087    /// representing the number of seconds, instead of a struct with `secs` and `nanos` fields.
1088    pub(super) fn serialize<S: Serializer>(
1089        duration: &Duration,
1090        serializer: S,
1091    ) -> Result<S::Ok, S::Error> {
1092        duration.as_secs().serialize(serializer)
1093    }
1094
1095    /// This is an alternate deserialization function for a [`Duration`] that expects a single number,
1096    /// representing the number of seconds, instead of a struct with `secs` and `nanos` fields.
1097    pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1098        deserializer: D,
1099    ) -> Result<Duration, D::Error> {
1100        Ok(Duration::from_secs(u64::deserialize(deserializer)?))
1101    }
1102}
1103
1104#[cfg(feature = "serde")]
1105pub(crate) mod duration_opt {
1106    use std::time::Duration;
1107
1108    use serde::{Deserialize, Deserializer, Serialize, Serializer};
1109
1110    /// This is an alternate serialization function for an optional [`Duration`] that emits a single
1111    /// number, representing the number of seconds, instead of a struct with `secs` and `nanos` fields.
1112    pub(super) fn serialize<S: Serializer>(
1113        duration: &Option<Duration>,
1114        serializer: S,
1115    ) -> Result<S::Ok, S::Error> {
1116        struct Wrapper<'a>(&'a Duration);
1117
1118        impl Serialize for Wrapper<'_> {
1119            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1120                super::duration::serialize(self.0, serializer)
1121            }
1122        }
1123
1124        match duration {
1125            Some(duration) => serializer.serialize_some(&Wrapper(duration)),
1126            None => serializer.serialize_none(),
1127        }
1128    }
1129
1130    /// This is an alternate deserialization function for an optional [`Duration`] that expects a single
1131    /// number, representing the number of seconds, instead of a struct with `secs` and `nanos` fields.
1132    pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1133        deserializer: D,
1134    ) -> Result<Option<Duration>, D::Error> {
1135        Ok(Option::<u64>::deserialize(deserializer)?.map(Duration::from_secs))
1136    }
1137}
1138
1139#[cfg(all(test, feature = "serde"))]
1140mod tests {
1141    use super::*;
1142
1143    #[cfg(feature = "serde")]
1144    #[test]
1145    fn default_opts() {
1146        let code = ResolverOpts::default();
1147        let json = serde_json::from_str::<ResolverOpts>("{}").unwrap();
1148        assert_eq!(code.ndots, json.ndots);
1149        assert_eq!(code.timeout, json.timeout);
1150        assert_eq!(code.attempts, json.attempts);
1151        assert_eq!(code.edns0, json.edns0);
1152        #[cfg(feature = "__dnssec")]
1153        assert_eq!(code.validate, json.validate);
1154        assert_eq!(code.ip_strategy, json.ip_strategy);
1155        assert_eq!(code.cache_size, json.cache_size);
1156        assert_eq!(code.use_hosts_file, json.use_hosts_file);
1157        assert_eq!(code.positive_min_ttl, json.positive_min_ttl);
1158        assert_eq!(code.negative_min_ttl, json.negative_min_ttl);
1159        assert_eq!(code.positive_max_ttl, json.positive_max_ttl);
1160        assert_eq!(code.negative_max_ttl, json.negative_max_ttl);
1161        assert_eq!(code.num_concurrent_reqs, json.num_concurrent_reqs);
1162        assert_eq!(code.preserve_intermediates, json.preserve_intermediates);
1163        assert_eq!(code.try_tcp_on_error, json.try_tcp_on_error);
1164        assert_eq!(code.recursion_desired, json.recursion_desired);
1165        assert_eq!(code.server_ordering_strategy, json.server_ordering_strategy);
1166        assert_eq!(code.avoid_local_udp_ports, json.avoid_local_udp_ports);
1167        assert_eq!(code.os_port_selection, json.os_port_selection);
1168        assert_eq!(code.case_randomization, json.case_randomization);
1169        assert_eq!(code.trust_anchor, json.trust_anchor);
1170        #[cfg(feature = "metrics")]
1171        assert_eq!(
1172            code.enable_per_name_server_metrics,
1173            json.enable_per_name_server_metrics
1174        );
1175    }
1176}