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 /// The number of errors kept by this server to save for debugging purposes.
421 ///
422 /// May be retrieved, along with other information, using
423 /// [`NameServer::stats`](crate::name_server::NameServer::stats).
424 pub num_retained_errors: usize,
425}
426
427impl NameServerConfig {
428 /// Constructs a Nameserver configuration with some basic defaults
429 pub fn new(socket_addr: SocketAddr, protocol: Protocol) -> Self {
430 Self {
431 socket_addr,
432 protocol,
433 trust_nx_responses: true,
434 tls_dns_name: None,
435 #[cfg(feature = "dns-over-rustls")]
436 tls_config: None,
437 bind_addr: None,
438 num_retained_errors: 0,
439 }
440 }
441}
442
443impl fmt::Display for NameServerConfig {
444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 write!(f, "{}:", self.protocol)?;
446
447 if let Some(ref tls_dns_name) = self.tls_dns_name {
448 write!(f, "{}@", tls_dns_name)?;
449 }
450
451 write!(f, "{}", self.socket_addr)
452 }
453}
454
455/// A set of name_servers to associate with a [`ResolverConfig`].
456#[derive(Clone, Debug, Eq, PartialEq)]
457#[cfg_attr(
458 all(feature = "serde-config", not(feature = "dns-over-rustls")),
459 derive(Serialize, Deserialize)
460)]
461pub struct NameServerConfigGroup(
462 Vec<NameServerConfig>,
463 #[cfg(feature = "dns-over-rustls")] Option<TlsClientConfig>,
464);
465
466#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
467impl SerializeT for NameServerConfigGroup {
468 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
469 where
470 S: Serializer,
471 {
472 self.0.serialize(serializer)
473 }
474}
475
476#[cfg(all(feature = "serde-config", feature = "dns-over-rustls"))]
477impl<'de> DeserializeT<'de> for NameServerConfigGroup {
478 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
479 where
480 D: Deserializer<'de>,
481 {
482 Vec::deserialize(deserializer).map(|nameservers| Self(nameservers, None))
483 }
484}
485
486impl NameServerConfigGroup {
487 /// Creates a new `NameServerConfigGroup` with a default size of 2
488 pub fn new() -> Self {
489 // this might be a nice opportunity for SmallVec
490 // most name_server configs will be 2.
491 Self::with_capacity(2)
492 }
493
494 /// Creates a new `NameServiceConfigGroup` with the specified capacity
495 pub fn with_capacity(capacity: usize) -> Self {
496 Self(
497 Vec::with_capacity(capacity),
498 #[cfg(feature = "dns-over-rustls")]
499 None,
500 )
501 }
502
503 /// Returns the inner vec of configs
504 pub fn into_inner(self) -> Vec<NameServerConfig> {
505 self.0
506 }
507
508 /// Configure a NameServer address and port
509 ///
510 /// This will create UDP and TCP connections, using the same port.
511 pub fn from_ips_clear(ips: &[IpAddr], port: u16, trust_nx_responses: bool) -> Self {
512 let mut name_servers = Self::with_capacity(ips.len());
513
514 for ip in ips {
515 let udp = NameServerConfig {
516 socket_addr: SocketAddr::new(*ip, port),
517 protocol: Protocol::Udp,
518 tls_dns_name: None,
519 trust_nx_responses,
520 #[cfg(feature = "dns-over-rustls")]
521 tls_config: None,
522 bind_addr: None,
523 num_retained_errors: 0,
524 };
525 let tcp = NameServerConfig {
526 socket_addr: SocketAddr::new(*ip, port),
527 protocol: Protocol::Tcp,
528 tls_dns_name: None,
529 trust_nx_responses,
530 #[cfg(feature = "dns-over-rustls")]
531 tls_config: None,
532 bind_addr: None,
533 num_retained_errors: 0,
534 };
535
536 name_servers.push(udp);
537 name_servers.push(tcp);
538 }
539
540 name_servers
541 }
542
543 #[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))]
544 fn from_ips_encrypted(
545 ips: &[IpAddr],
546 port: u16,
547 tls_dns_name: String,
548 protocol: Protocol,
549 trust_nx_responses: bool,
550 ) -> Self {
551 assert!(protocol.is_encrypted());
552
553 let mut name_servers = Self::with_capacity(ips.len());
554
555 for ip in ips {
556 let config = NameServerConfig {
557 socket_addr: SocketAddr::new(*ip, port),
558 protocol,
559 tls_dns_name: Some(tls_dns_name.clone()),
560 trust_nx_responses,
561 #[cfg(feature = "dns-over-rustls")]
562 tls_config: None,
563 bind_addr: None,
564 };
565
566 name_servers.push(config);
567 }
568
569 name_servers
570 }
571
572 /// Configure a NameServer address and port for DNS-over-TLS
573 ///
574 /// This will create a TLS connections.
575 #[cfg(feature = "dns-over-tls")]
576 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
577 pub fn from_ips_tls(
578 ips: &[IpAddr],
579 port: u16,
580 tls_dns_name: String,
581 trust_nx_responses: bool,
582 ) -> Self {
583 Self::from_ips_encrypted(ips, port, tls_dns_name, Protocol::Tls, trust_nx_responses)
584 }
585
586 /// Configure a NameServer address and port for DNS-over-HTTPS
587 ///
588 /// This will create a HTTPS connections.
589 #[cfg(feature = "dns-over-https")]
590 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
591 pub fn from_ips_https(
592 ips: &[IpAddr],
593 port: u16,
594 tls_dns_name: String,
595 trust_nx_responses: bool,
596 ) -> Self {
597 Self::from_ips_encrypted(ips, port, tls_dns_name, Protocol::Https, trust_nx_responses)
598 }
599
600 /// 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).
601 ///
602 /// 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`
603 pub fn google() -> Self {
604 Self::from_ips_clear(GOOGLE_IPS, 53, true)
605 }
606
607 /// 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
608 ///
609 /// 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`
610 #[cfg(feature = "dns-over-https")]
611 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
612 pub fn google_https() -> Self {
613 Self::from_ips_https(GOOGLE_IPS, 443, "dns.google".to_string(), true)
614 }
615
616 /// 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).
617 ///
618 /// Please see: <https://www.cloudflare.com/dns/>
619 pub fn cloudflare() -> Self {
620 Self::from_ips_clear(CLOUDFLARE_IPS, 53, true)
621 }
622
623 /// 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
624 ///
625 /// Please see: <https://www.cloudflare.com/dns/>
626 #[cfg(feature = "dns-over-tls")]
627 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
628 pub fn cloudflare_tls() -> Self {
629 Self::from_ips_tls(CLOUDFLARE_IPS, 853, "cloudflare-dns.com".to_string(), true)
630 }
631
632 /// 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
633 ///
634 /// Please see: <https://www.cloudflare.com/dns/>
635 #[cfg(feature = "dns-over-https")]
636 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
637 pub fn cloudflare_https() -> Self {
638 Self::from_ips_https(CLOUDFLARE_IPS, 443, "cloudflare-dns.com".to_string(), true)
639 }
640
641 /// 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).
642 ///
643 /// Please see: <https://www.quad9.net/faq/>
644 pub fn quad9() -> Self {
645 Self::from_ips_clear(QUAD9_IPS, 53, true)
646 }
647
648 /// 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
649 ///
650 /// Please see: <https://www.quad9.net/faq/>
651 #[cfg(feature = "dns-over-tls")]
652 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-tls")))]
653 pub fn quad9_tls() -> Self {
654 Self::from_ips_tls(QUAD9_IPS, 853, "dns.quad9.net".to_string(), true)
655 }
656
657 /// 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
658 ///
659 /// Please see: <https://www.quad9.net/faq/>
660 #[cfg(feature = "dns-over-https")]
661 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-https")))]
662 pub fn quad9_https() -> Self {
663 Self::from_ips_https(QUAD9_IPS, 443, "dns.quad9.net".to_string(), true)
664 }
665
666 /// Merges this set of [`NameServerConfig`]s with the other
667 ///
668 /// ```
669 /// use std::net::{SocketAddr, Ipv4Addr};
670 /// use trust_dns_resolver::config::NameServerConfigGroup;
671 ///
672 /// let mut group = NameServerConfigGroup::google();
673 /// group.merge(NameServerConfigGroup::cloudflare());
674 /// group.merge(NameServerConfigGroup::quad9());
675 ///
676 /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(8, 8, 8, 8).into(), 53)));
677 /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(1, 1, 1, 1).into(), 53)));
678 /// assert!(group.iter().any(|c| c.socket_addr == SocketAddr::new(Ipv4Addr::new(9, 9, 9, 9).into(), 53)));
679 /// ```
680 pub fn merge(&mut self, mut other: Self) {
681 #[cfg(not(feature = "dns-over-rustls"))]
682 {
683 self.append(&mut other);
684 }
685 #[cfg(feature = "dns-over-rustls")]
686 {
687 self.0.append(&mut other);
688 }
689 }
690
691 /// add a [`rustls::ClientConfig`]
692 #[cfg(feature = "dns-over-rustls")]
693 #[cfg_attr(docsrs, doc(cfg(feature = "dns-over-rustls")))]
694 pub fn with_client_config(self, client_config: Arc<ClientConfig>) -> Self {
695 Self(self.0, Some(TlsClientConfig(client_config)))
696 }
697
698 /// Sets the client address (IP and port) to connect from on all name servers.
699 pub fn with_bind_addr(mut self, bind_addr: Option<SocketAddr>) -> Self {
700 for server in &mut self.0 {
701 server.bind_addr = bind_addr;
702 }
703 self
704 }
705}
706
707impl Default for NameServerConfigGroup {
708 fn default() -> Self {
709 Self::new()
710 }
711}
712
713impl Deref for NameServerConfigGroup {
714 type Target = Vec<NameServerConfig>;
715 fn deref(&self) -> &Self::Target {
716 &self.0
717 }
718}
719
720impl DerefMut for NameServerConfigGroup {
721 fn deref_mut(&mut self) -> &mut Self::Target {
722 &mut self.0
723 }
724}
725
726impl From<Vec<NameServerConfig>> for NameServerConfigGroup {
727 fn from(configs: Vec<NameServerConfig>) -> Self {
728 #[cfg(not(feature = "dns-over-rustls"))]
729 {
730 Self(configs)
731 }
732 #[cfg(feature = "dns-over-rustls")]
733 {
734 Self(configs, None)
735 }
736 }
737}
738
739/// The lookup ip strategy
740#[derive(Debug, Clone, Copy, PartialEq, Eq)]
741#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
742pub enum LookupIpStrategy {
743 /// Only query for A (Ipv4) records
744 Ipv4Only,
745 /// Only query for AAAA (Ipv6) records
746 Ipv6Only,
747 /// Query for A and AAAA in parallel
748 Ipv4AndIpv6,
749 /// Query for Ipv6 if that fails, query for Ipv4
750 Ipv6thenIpv4,
751 /// Query for Ipv4 if that fails, query for Ipv6 (default)
752 Ipv4thenIpv6,
753}
754
755impl Default for LookupIpStrategy {
756 /// Returns [`LookupIpStrategy::Ipv4thenIpv6`] as the default.
757 fn default() -> Self {
758 Self::Ipv4thenIpv6
759 }
760}
761
762/// The strategy for establishing the query order of name servers in a pool.
763#[derive(Debug, Clone, Copy, PartialEq, Eq)]
764#[cfg_attr(feature = "serde-config", derive(Serialize, Deserialize))]
765pub enum ServerOrderingStrategy {
766 /// Servers are ordered based on collected query statistics. The ordering
767 /// may vary over time.
768 QueryStatistics,
769 /// The order provided to the resolver is used. The ordering does not vary
770 /// over time.
771 UserProvidedOrder,
772}
773
774impl Default for ServerOrderingStrategy {
775 /// Returns [`ServerOrderingStrategy::QueryStatistics`] as the default.
776 fn default() -> Self {
777 Self::QueryStatistics
778 }
779}
780
781/// Configuration for the Resolver
782#[derive(Debug, Clone, Copy, Eq, PartialEq)]
783#[cfg_attr(
784 feature = "serde-config",
785 derive(Serialize, Deserialize),
786 serde(default)
787)]
788#[allow(dead_code)] // TODO: remove after all params are supported
789#[non_exhaustive]
790pub struct ResolverOpts {
791 /// Sets the number of dots that must appear (unless it's a final dot representing the root)
792 /// before a query is assumed to include the TLD. The default is one, which means that `www`
793 /// would never be assumed to be a TLD, and would always be appended to either the search
794 pub ndots: usize,
795 /// Specify the timeout for a request. Defaults to 5 seconds
796 pub timeout: Duration,
797 /// Number of retries after lookup failure before giving up. Defaults to 2
798 pub attempts: usize,
799 /// Rotate through the resource records in the response (if there is more than one for a given name)
800 pub rotate: bool,
801 /// Validate the names in the response, not implemented don't really see the point unless you need to support
802 /// badly configured DNS
803 pub check_names: bool,
804 /// Enable edns, for larger records
805 pub edns0: bool,
806 /// Use DNSSec to validate the request
807 pub validate: bool,
808 /// The ip_strategy for the Resolver to use when lookup Ipv4 or Ipv6 addresses
809 pub ip_strategy: LookupIpStrategy,
810 /// Cache size is in number of records (some records can be large)
811 pub cache_size: usize,
812 /// Check /ect/hosts file before dns requery (only works for unix like OS)
813 pub use_hosts_file: bool,
814 /// Optional minimum TTL for positive responses.
815 ///
816 /// If this is set, any positive responses with a TTL lower than this value will have a TTL of
817 /// `positive_min_ttl` instead. Otherwise, this will default to 0 seconds.
818 pub positive_min_ttl: Option<Duration>,
819 /// Optional minimum TTL for negative (`NXDOMAIN`) responses.
820 ///
821 /// If this is set, any negative responses with a TTL lower than this value will have a TTL of
822 /// `negative_min_ttl` instead. Otherwise, this will default to 0 seconds.
823 pub negative_min_ttl: Option<Duration>,
824 /// Optional maximum TTL for positive responses.
825 ///
826 /// If this is set, any positive responses with a TTL higher than this value will have a TTL of
827 /// `positive_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
828 ///
829 /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
830 pub positive_max_ttl: Option<Duration>,
831 /// Optional maximum TTL for negative (`NXDOMAIN`) responses.
832 ///
833 /// If this is set, any negative responses with a TTL higher than this value will have a TTL of
834 /// `negative_max_ttl` instead. Otherwise, this will default to [`MAX_TTL`] seconds.
835 ///
836 /// [`MAX_TTL`]: ../dns_lru/const.MAX_TTL.html
837 pub negative_max_ttl: Option<Duration>,
838 /// Number of concurrent requests per query
839 ///
840 /// Where more than one nameserver is configured, this configures the resolver to send queries
841 /// to a number of servers in parallel. Defaults to 2; 0 or 1 will execute requests serially.
842 pub num_concurrent_reqs: usize,
843 /// Preserve all intermediate records in the lookup response, suchas CNAME records
844 pub preserve_intermediates: bool,
845 /// Try queries over TCP if they fail over UDP.
846 pub try_tcp_on_error: bool,
847 /// The server ordering strategy that the resolver should use.
848 pub server_ordering_strategy: ServerOrderingStrategy,
849 /// Request upstream recursive resolvers to not perform any recursion.
850 ///
851 /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
852 pub recursion_desired: bool,
853 /// This is true by default, disabling this is useful for requesting single records, but may prevent successful resolution.
854 pub authentic_data: bool,
855}
856
857impl Default for ResolverOpts {
858 /// Default values for the Resolver configuration.
859 ///
860 /// This follows the resolv.conf defaults as defined in the [Linux man pages](http://man7.org/linux/man-pages/man5/resolv.conf.5.html)
861 fn default() -> Self {
862 Self {
863 ndots: 1,
864 timeout: Duration::from_secs(5),
865 attempts: 2,
866 rotate: false,
867 check_names: true,
868 edns0: false,
869 validate: false,
870 ip_strategy: LookupIpStrategy::default(),
871 cache_size: 32,
872 use_hosts_file: true,
873 positive_min_ttl: None,
874 negative_min_ttl: None,
875 positive_max_ttl: None,
876 negative_max_ttl: None,
877 num_concurrent_reqs: 2,
878
879 // Defaults to `true` to match the behavior of dig and nslookup.
880 preserve_intermediates: true,
881
882 try_tcp_on_error: false,
883 server_ordering_strategy: ServerOrderingStrategy::default(),
884 recursion_desired: true,
885 authentic_data: false,
886 }
887 }
888}
889
890/// IP addresses for Google Public DNS
891pub const GOOGLE_IPS: &[IpAddr] = &[
892 IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
893 IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
894 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
895 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
896];
897
898/// IP addresses for Cloudflare's 1.1.1.1 DNS service
899pub const CLOUDFLARE_IPS: &[IpAddr] = &[
900 IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
901 IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
902 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
903 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
904];
905
906/// IP address for the Quad9 DNS service
907pub const QUAD9_IPS: &[IpAddr] = &[
908 IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
909 IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
910 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
911 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0x00fe, 0x0009)),
912];