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