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];