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