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