1#![allow(clippy::use_self)]
10
11use std::collections::HashSet;
12use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
13use std::path::PathBuf;
14use std::sync::Arc;
15use std::time::Duration;
16#[cfg(all(
17 feature = "recursor",
18 feature = "toml",
19 feature = "serde",
20 any(feature = "__tls", feature = "__quic")
21))]
22use std::{fs, io};
23
24use ipnet::IpNet;
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27use tracing::warn;
28#[cfg(all(
29 feature = "recursor",
30 feature = "toml",
31 feature = "serde",
32 any(feature = "__tls", feature = "__quic")
33))]
34use tracing::{debug, info};
35
36#[cfg(all(
37 feature = "recursor",
38 feature = "toml",
39 feature = "serde",
40 any(feature = "__tls", feature = "__quic")
41))]
42use crate::name_server_pool::NameServerTransportState;
43#[cfg(any(feature = "__https", feature = "__h3"))]
44use crate::net::http::DEFAULT_DNS_QUERY_PATH;
45use crate::net::xfer::Protocol;
46use crate::proto::access_control::{AccessControlSet, AccessControlSetBuilder};
47use crate::proto::op::DEFAULT_MAX_PAYLOAD_LEN;
48use crate::proto::rr::Name;
49
50#[non_exhaustive]
56#[derive(Clone, Debug, Default)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58pub struct ResolverConfig {
59 #[cfg_attr(feature = "serde", serde(default))]
61 pub domain: Option<Name>,
62 #[cfg_attr(feature = "serde", serde(default))]
64 pub search: Vec<Name>,
65 pub name_servers: Vec<NameServerConfig>,
67}
68
69impl ResolverConfig {
70 pub fn udp_and_tcp(config: &ServerGroup<'_>) -> Self {
74 Self {
75 domain: None,
77 search: vec![],
78 name_servers: config.udp_and_tcp().collect(),
79 }
80 }
81
82 #[cfg(feature = "__tls")]
86 pub fn tls(config: &ServerGroup<'_>) -> Self {
87 Self {
88 domain: None,
90 search: vec![],
91 name_servers: config.tls().collect(),
92 }
93 }
94
95 #[cfg(feature = "__https")]
99 pub fn https(config: &ServerGroup<'_>) -> Self {
100 Self {
101 domain: None,
103 search: vec![],
104 name_servers: config.https().collect(),
105 }
106 }
107
108 #[cfg(feature = "__quic")]
112 pub fn quic(config: &ServerGroup<'_>) -> Self {
113 Self {
114 domain: None,
116 search: vec![],
117 name_servers: config.quic().collect(),
118 }
119 }
120
121 #[cfg(feature = "__h3")]
125 pub fn h3(config: &ServerGroup<'_>) -> Self {
126 Self {
127 domain: None,
129 search: vec![],
130 name_servers: config.h3().collect(),
131 }
132 }
133
134 pub fn from_parts(
142 domain: Option<Name>,
143 search: Vec<Name>,
144 name_servers: Vec<NameServerConfig>,
145 ) -> Self {
146 Self {
147 domain,
148 search,
149 name_servers,
150 }
151 }
152
153 pub fn from_name_servers(name_servers: Vec<NameServerConfig>) -> Self {
157 Self::from_parts(None, vec![], name_servers)
158 }
159
160 pub fn into_parts(self) -> (Option<Name>, Vec<Name>, Vec<NameServerConfig>) {
162 (self.domain, self.search, self.name_servers)
163 }
164
165 pub fn domain(&self) -> Option<&Name> {
169 self.domain.as_ref()
170 }
171
172 pub fn set_domain(&mut self, domain: Name) {
174 self.domain = Some(domain.clone());
175 self.search = vec![domain];
176 }
177
178 pub fn search(&self) -> &[Name] {
182 &self.search
183 }
184
185 pub fn add_search(&mut self, search: Name) {
187 self.search.push(search)
188 }
189
190 pub fn add_name_server(&mut self, name_server: NameServerConfig) {
193 self.name_servers.push(name_server);
194 }
195
196 pub fn name_servers(&self) -> &[NameServerConfig] {
198 &self.name_servers
199 }
200}
201
202#[derive(Clone, Debug)]
204#[cfg_attr(
205 feature = "serde",
206 derive(Serialize, Deserialize),
207 serde(deny_unknown_fields)
208)]
209#[non_exhaustive]
210pub struct NameServerConfig {
211 pub ip: IpAddr,
213 #[cfg_attr(feature = "serde", serde(default = "default_trust_negative_responses"))]
223 pub trust_negative_responses: bool,
224 pub connections: Vec<ConnectionConfig>,
226}
227
228impl NameServerConfig {
229 pub fn udp_and_tcp(ip: IpAddr) -> Self {
231 Self {
232 ip,
233 trust_negative_responses: true,
234 connections: vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
235 }
236 }
237
238 pub fn udp(ip: IpAddr) -> Self {
240 Self {
241 ip,
242 trust_negative_responses: true,
243 connections: vec![ConnectionConfig::udp()],
244 }
245 }
246
247 pub fn tcp(ip: IpAddr) -> Self {
249 Self {
250 ip,
251 trust_negative_responses: true,
252 connections: vec![ConnectionConfig::tcp()],
253 }
254 }
255
256 #[cfg(feature = "__tls")]
258 pub fn tls(ip: IpAddr, server_name: Arc<str>) -> Self {
259 Self {
260 ip,
261 trust_negative_responses: true,
262 connections: vec![ConnectionConfig::tls(server_name)],
263 }
264 }
265
266 #[cfg(feature = "__https")]
268 pub fn https(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
269 Self {
270 ip,
271 trust_negative_responses: true,
272 connections: vec![ConnectionConfig::https(server_name, path)],
273 }
274 }
275
276 #[cfg(feature = "__quic")]
278 pub fn quic(ip: IpAddr, server_name: Arc<str>) -> Self {
279 Self {
280 ip,
281 trust_negative_responses: true,
282 connections: vec![ConnectionConfig::quic(server_name)],
283 }
284 }
285
286 #[cfg(feature = "__h3")]
288 pub fn h3(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
289 Self {
290 ip,
291 trust_negative_responses: true,
292 connections: vec![ConnectionConfig::h3(server_name, path)],
293 }
294 }
295
296 #[cfg(any(feature = "__tls", feature = "__quic"))]
306 pub fn opportunistic_encryption(ip: IpAddr) -> Self {
307 Self {
308 ip,
309 trust_negative_responses: true,
310 connections: vec![
311 ConnectionConfig::udp(),
312 ConnectionConfig::tcp(),
313 #[cfg(feature = "__tls")]
314 ConnectionConfig::tls(Arc::from(ip.to_string())),
315 #[cfg(feature = "__quic")]
316 ConnectionConfig::quic(Arc::from(ip.to_string())),
317 ],
318 }
319 }
320
321 pub fn new(
323 ip: IpAddr,
324 trust_negative_responses: bool,
325 connections: Vec<ConnectionConfig>,
326 ) -> Self {
327 Self {
328 ip,
329 trust_negative_responses,
330 connections,
331 }
332 }
333}
334
335#[cfg(feature = "serde")]
336fn default_trust_negative_responses() -> bool {
337 true
338}
339
340#[derive(Clone, Debug)]
342#[cfg_attr(feature = "serde", derive(Serialize))]
343#[non_exhaustive]
344pub struct ConnectionConfig {
345 pub port: u16,
347 pub protocol: ProtocolConfig,
349 pub bind_addr: Option<SocketAddr>,
351}
352
353impl ConnectionConfig {
354 pub fn udp() -> Self {
356 Self::new(ProtocolConfig::Udp)
357 }
358
359 pub fn tcp() -> Self {
361 Self::new(ProtocolConfig::Tcp)
362 }
363
364 #[cfg(feature = "__tls")]
366 pub fn tls(server_name: Arc<str>) -> Self {
367 Self::new(ProtocolConfig::Tls { server_name })
368 }
369
370 #[cfg(feature = "__https")]
372 pub fn https(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
373 Self::new(ProtocolConfig::Https {
374 server_name,
375 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
376 })
377 }
378
379 #[cfg(feature = "__quic")]
381 pub fn quic(server_name: Arc<str>) -> Self {
382 Self::new(ProtocolConfig::Quic { server_name })
383 }
384
385 #[cfg(feature = "__h3")]
387 pub fn h3(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
388 Self::new(ProtocolConfig::H3 {
389 server_name,
390 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
391 disable_grease: false,
392 })
393 }
394
395 pub fn new(protocol: ProtocolConfig) -> Self {
397 Self {
398 port: protocol.default_port(),
399 protocol,
400 bind_addr: None,
401 }
402 }
403}
404
405#[cfg(feature = "serde")]
406impl<'de> Deserialize<'de> for ConnectionConfig {
407 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
408 #[derive(Deserialize)]
409 #[serde(deny_unknown_fields)]
410 struct OptionalParts {
411 #[serde(default)]
412 port: Option<u16>,
413 protocol: ProtocolConfig,
414 #[serde(default)]
415 bind_addr: Option<SocketAddr>,
416 }
417
418 let parts = OptionalParts::deserialize(deserializer)?;
419 Ok(Self {
420 port: parts.port.unwrap_or_else(|| parts.protocol.default_port()),
421 protocol: parts.protocol,
422 bind_addr: parts.bind_addr,
423 })
424 }
425}
426
427#[allow(missing_docs)]
429#[derive(Clone, Debug, Default, PartialEq)]
430#[cfg_attr(
431 feature = "serde",
432 derive(Serialize, Deserialize),
433 serde(deny_unknown_fields, rename_all = "snake_case", tag = "type")
434)]
435pub enum ProtocolConfig {
436 #[default]
437 Udp,
438 Tcp,
439 #[cfg(feature = "__tls")]
440 Tls {
441 server_name: Arc<str>,
443 },
444 #[cfg(feature = "__https")]
445 Https {
446 server_name: Arc<str>,
448 path: Arc<str>,
450 },
451 #[cfg(feature = "__quic")]
452 Quic {
453 server_name: Arc<str>,
455 },
456 #[cfg(feature = "__h3")]
457 H3 {
458 server_name: Arc<str>,
460 path: Arc<str>,
462 #[cfg_attr(feature = "serde", serde(default))]
464 disable_grease: bool,
465 },
466}
467
468impl ProtocolConfig {
469 pub fn to_protocol(&self) -> Protocol {
471 match self {
472 ProtocolConfig::Udp => Protocol::Udp,
473 ProtocolConfig::Tcp => Protocol::Tcp,
474 #[cfg(feature = "__tls")]
475 ProtocolConfig::Tls { .. } => Protocol::Tls,
476 #[cfg(feature = "__https")]
477 ProtocolConfig::Https { .. } => Protocol::Https,
478 #[cfg(feature = "__quic")]
479 ProtocolConfig::Quic { .. } => Protocol::Quic,
480 #[cfg(feature = "__h3")]
481 ProtocolConfig::H3 { .. } => Protocol::H3,
482 }
483 }
484
485 pub fn default_port(&self) -> u16 {
487 match self {
488 ProtocolConfig::Udp => 53,
489 ProtocolConfig::Tcp => 53,
490 #[cfg(feature = "__tls")]
491 ProtocolConfig::Tls { .. } => 853,
492 #[cfg(feature = "__https")]
493 ProtocolConfig::Https { .. } => 443,
494 #[cfg(feature = "__quic")]
495 ProtocolConfig::Quic { .. } => 853,
496 #[cfg(feature = "__h3")]
497 ProtocolConfig::H3 { .. } => 443,
498 }
499 }
500}
501
502#[derive(Debug, Clone)]
504#[cfg_attr(
505 feature = "serde",
506 derive(Serialize, Deserialize),
507 serde(default, deny_unknown_fields)
508)]
509#[non_exhaustive]
510pub struct ResolverOpts {
511 #[cfg_attr(feature = "serde", serde(default = "default_ndots"))]
515 pub ndots: usize,
516 #[cfg_attr(
518 feature = "serde",
519 serde(default = "default_timeout", with = "duration")
520 )]
521 pub timeout: Duration,
522 #[cfg_attr(feature = "serde", serde(default = "default_attempts"))]
524 pub attempts: usize,
525 pub edns0: bool,
527 #[cfg(feature = "__dnssec")]
529 pub validate: bool,
530 pub ip_strategy: LookupIpStrategy,
532 #[cfg_attr(feature = "serde", serde(default = "default_cache_size"))]
534 pub cache_size: u64,
535 pub use_hosts_file: ResolveHosts,
537 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
542 pub positive_min_ttl: Option<Duration>,
543 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
548 pub negative_min_ttl: Option<Duration>,
549 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
554 pub positive_max_ttl: Option<Duration>,
555 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
560 pub negative_max_ttl: Option<Duration>,
561 #[cfg_attr(feature = "serde", serde(default = "default_num_concurrent_reqs"))]
566 pub num_concurrent_reqs: usize,
567 #[cfg_attr(feature = "serde", serde(default = "default_max_active_requests"))]
575 pub max_active_requests: usize,
576 #[cfg_attr(feature = "serde", serde(default = "default_preserve_intermediates"))]
578 pub preserve_intermediates: bool,
579 pub try_tcp_on_error: bool,
581 pub server_ordering_strategy: ServerOrderingStrategy,
583 #[cfg_attr(feature = "serde", serde(default = "default_recursion_desired"))]
587 pub recursion_desired: bool,
588 pub avoid_local_udp_ports: Arc<HashSet<u16>>,
590 pub os_port_selection: bool,
601 pub case_randomization: bool,
609 pub trust_anchor: Option<PathBuf>,
613 pub allow_answers: Vec<IpNet>,
616 pub deny_answers: Vec<IpNet>,
618 #[cfg_attr(feature = "serde", serde(default = "default_edns_payload_len"))]
622 pub edns_payload_len: u16,
623 #[cfg_attr(feature = "serde", serde(default))]
629 #[cfg(feature = "metrics")]
630 pub enable_per_name_server_metrics: bool,
631}
632
633impl ResolverOpts {
634 pub(crate) fn answer_address_filter(&self) -> AccessControlSet {
635 let name = "resolver_answer_filter";
636 AccessControlSetBuilder::new(name)
637 .allow(self.allow_answers.iter())
638 .deny(self.deny_answers.iter())
639 .build()
640 .inspect_err(|err| warn!("{err}"))
641 .unwrap_or_else(|_| AccessControlSet::empty(name))
642 }
643}
644
645impl Default for ResolverOpts {
646 fn default() -> Self {
650 Self {
651 ndots: default_ndots(),
652 timeout: default_timeout(),
653 attempts: default_attempts(),
654 edns0: true,
655 #[cfg(feature = "__dnssec")]
656 validate: false,
657 ip_strategy: LookupIpStrategy::default(),
658 cache_size: default_cache_size(),
659 use_hosts_file: ResolveHosts::default(),
660 positive_min_ttl: None,
661 negative_min_ttl: None,
662 positive_max_ttl: None,
663 negative_max_ttl: None,
664 num_concurrent_reqs: default_num_concurrent_reqs(),
665 max_active_requests: default_max_active_requests(),
666
667 preserve_intermediates: default_preserve_intermediates(),
669
670 try_tcp_on_error: false,
671 server_ordering_strategy: ServerOrderingStrategy::default(),
672 recursion_desired: default_recursion_desired(),
673 avoid_local_udp_ports: Arc::default(),
674 os_port_selection: false,
675 case_randomization: false,
676 trust_anchor: None,
677 allow_answers: vec![],
678 deny_answers: vec![],
679 edns_payload_len: default_edns_payload_len(),
680 #[cfg(feature = "metrics")]
681 enable_per_name_server_metrics: false,
682 }
683 }
684}
685
686fn default_ndots() -> usize {
687 1
688}
689
690fn default_timeout() -> Duration {
691 Duration::from_secs(5)
692}
693
694fn default_attempts() -> usize {
695 2
696}
697
698fn default_cache_size() -> u64 {
699 8_192
700}
701
702fn default_num_concurrent_reqs() -> usize {
703 2
704}
705
706fn default_max_active_requests() -> usize {
707 32
708}
709
710fn default_preserve_intermediates() -> bool {
711 true
712}
713
714fn default_recursion_desired() -> bool {
715 true
716}
717
718fn default_edns_payload_len() -> u16 {
719 DEFAULT_MAX_PAYLOAD_LEN
720}
721
722#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
724#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
725pub enum LookupIpStrategy {
726 Ipv4Only,
728 Ipv6Only,
730 Ipv4AndIpv6,
732 #[default]
734 Ipv6AndIpv4,
735 Ipv6thenIpv4,
737 Ipv4thenIpv6,
739}
740
741#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
743#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
744#[non_exhaustive]
745pub enum ServerOrderingStrategy {
746 #[default]
749 QueryStatistics,
750 UserProvidedOrder,
753 RoundRobin,
756}
757
758#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
760#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
761pub enum ResolveHosts {
762 Always,
765 Never,
767 #[default]
770 Auto,
771}
772
773#[derive(Debug, Clone, Default, Eq, PartialEq)]
778#[cfg_attr(
779 feature = "serde",
780 derive(Serialize, Deserialize),
781 serde(rename_all = "snake_case")
782)]
783#[non_exhaustive]
784pub enum OpportunisticEncryption {
785 #[default]
787 Disabled,
788 #[cfg(any(feature = "__tls", feature = "__quic"))]
790 Enabled {
791 #[cfg_attr(feature = "serde", serde(flatten))]
793 config: OpportunisticEncryptionConfig,
794 },
795}
796
797impl OpportunisticEncryption {
798 #[cfg(all(
799 feature = "recursor",
800 feature = "toml",
801 feature = "serde",
802 any(feature = "__tls", feature = "__quic")
803 ))]
804 pub(super) fn persisted_state(&self) -> Result<Option<NameServerTransportState>, String> {
805 let OpportunisticEncryption::Enabled {
806 config:
807 OpportunisticEncryptionConfig {
808 persistence: Some(OpportunisticEncryptionPersistence { path, .. }),
809 ..
810 },
811 } = self
812 else {
813 return Ok(None);
814 };
815
816 let state = match fs::read_to_string(path) {
817 Ok(toml_content) => toml::from_str(&toml_content).map_err(|e| {
818 format!(
819 "failed to parse opportunistic encryption state TOML file: {file_path}: {e}",
820 file_path = path.display()
821 )
822 })?,
823 Err(e) if e.kind() == io::ErrorKind::NotFound => {
824 info!(
825 state_file = %path.display(),
826 "no pre-existing opportunistic encryption state TOML file, starting with default state",
827 );
828 NameServerTransportState::default()
829 }
830 Err(e) => {
831 return Err(format!(
832 "failed to read opportunistic encryption state TOML file: {file_path}: {e}",
833 file_path = path.display()
834 ));
835 }
836 };
837
838 debug!(
839 path = %path.display(),
840 nameserver_count = state.nameserver_count(),
841 "loaded opportunistic encryption state"
842 );
843
844 Ok(Some(state))
845 }
846
847 pub fn is_enabled(&self) -> bool {
849 match self {
850 Self::Disabled => false,
851 #[cfg(any(feature = "__tls", feature = "__quic"))]
852 Self::Enabled { .. } => true,
853 }
854 }
855
856 pub fn max_concurrent_probes(&self) -> Option<u8> {
858 match self {
859 Self::Disabled => None,
860 #[cfg(any(feature = "__tls", feature = "__quic"))]
861 Self::Enabled { config, .. } => Some(config.max_concurrent_probes),
862 }
863 }
864}
865
866#[derive(Debug, Clone, Eq, PartialEq)]
868#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
869#[cfg_attr(feature = "serde", serde(default, deny_unknown_fields))]
870pub struct OpportunisticEncryptionConfig {
871 #[cfg_attr(
873 feature = "serde",
874 serde(default = "default_persistence_period", with = "duration")
875 )]
876 pub persistence_period: Duration,
877
878 #[cfg_attr(
880 feature = "serde",
881 serde(default = "default_damping_period", with = "duration")
882 )]
883 pub damping_period: Duration,
884
885 #[cfg_attr(feature = "serde", serde(default = "default_max_concurrent_probes"))]
887 pub max_concurrent_probes: u8,
888
889 pub persistence: Option<OpportunisticEncryptionPersistence>,
891}
892
893impl Default for OpportunisticEncryptionConfig {
894 fn default() -> Self {
895 Self {
896 persistence_period: default_persistence_period(),
897 damping_period: default_damping_period(),
898 max_concurrent_probes: default_max_concurrent_probes(),
899 persistence: None,
900 }
901 }
902}
903
904fn default_persistence_period() -> Duration {
906 Duration::from_secs(60 * 60 * 24 * 3) }
908
909fn default_damping_period() -> Duration {
911 Duration::from_secs(24 * 60 * 60) }
913
914fn default_max_concurrent_probes() -> u8 {
916 10
917}
918
919#[derive(Debug, Clone, Eq, PartialEq)]
920#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
921#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
922pub struct OpportunisticEncryptionPersistence {
924 pub path: PathBuf,
926
927 #[cfg_attr(
929 feature = "serde",
930 serde(default = "default_save_interval", with = "duration")
931 )]
932 pub save_interval: Duration,
933}
934
935#[cfg(feature = "serde")]
936fn default_save_interval() -> Duration {
937 Duration::from_secs(60 * 10) }
939
940pub const GOOGLE: ServerGroup<'static> = ServerGroup {
946 ips: &[
947 IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
948 IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
949 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
950 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
951 ],
952 server_name: "dns.google",
953 path: "/dns-query",
954};
955
956pub const CLOUDFLARE: ServerGroup<'static> = ServerGroup {
960 ips: &[
961 IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
962 IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
963 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
964 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
965 ],
966 server_name: "cloudflare-dns.com",
967 path: "/dns-query",
968};
969
970pub const QUAD9: ServerGroup<'static> = ServerGroup {
974 ips: &[
975 IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
976 IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
977 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
978 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x0009)),
979 ],
980 server_name: "dns.quad9.net",
981 path: "/dns-query",
982};
983
984#[derive(Clone, Copy, Debug)]
986pub struct ServerGroup<'a> {
987 pub ips: &'a [IpAddr],
989 pub server_name: &'a str,
991 pub path: &'a str,
993}
994
995impl<'a> ServerGroup<'a> {
996 pub fn udp_and_tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
998 self.ips.iter().map(|&ip| {
999 NameServerConfig::new(
1000 ip,
1001 true,
1002 vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
1003 )
1004 })
1005 }
1006
1007 pub fn udp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1009 self.ips
1010 .iter()
1011 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::udp()]))
1012 }
1013
1014 pub fn tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1016 self.ips
1017 .iter()
1018 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::tcp()]))
1019 }
1020
1021 #[cfg(feature = "__tls")]
1023 pub fn tls(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1024 let this = *self;
1025 self.ips.iter().map(move |&ip| {
1026 NameServerConfig::new(
1027 ip,
1028 true,
1029 vec![ConnectionConfig::tls(Arc::from(this.server_name))],
1030 )
1031 })
1032 }
1033
1034 #[cfg(feature = "__https")]
1036 pub fn https(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1037 let this = *self;
1038 self.ips.iter().map(move |&ip| {
1039 NameServerConfig::new(
1040 ip,
1041 true,
1042 vec![ConnectionConfig::https(
1043 Arc::from(this.server_name),
1044 Some(Arc::from(this.path)),
1045 )],
1046 )
1047 })
1048 }
1049
1050 #[cfg(feature = "__quic")]
1052 pub fn quic(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1053 let this = *self;
1054 self.ips.iter().map(move |&ip| {
1055 NameServerConfig::new(
1056 ip,
1057 true,
1058 vec![ConnectionConfig::quic(Arc::from(this.server_name))],
1059 )
1060 })
1061 }
1062
1063 #[cfg(feature = "__h3")]
1065 pub fn h3(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1066 let this = *self;
1067 self.ips.iter().map(move |&ip| {
1068 NameServerConfig::new(
1069 ip,
1070 true,
1071 vec![ConnectionConfig::h3(
1072 Arc::from(this.server_name),
1073 Some(Arc::from(this.path)),
1074 )],
1075 )
1076 })
1077 }
1078}
1079
1080#[cfg(feature = "serde")]
1081pub(crate) mod duration {
1082 use std::time::Duration;
1083
1084 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1085
1086 pub(super) fn serialize<S: Serializer>(
1089 duration: &Duration,
1090 serializer: S,
1091 ) -> Result<S::Ok, S::Error> {
1092 duration.as_secs().serialize(serializer)
1093 }
1094
1095 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1098 deserializer: D,
1099 ) -> Result<Duration, D::Error> {
1100 Ok(Duration::from_secs(u64::deserialize(deserializer)?))
1101 }
1102}
1103
1104#[cfg(feature = "serde")]
1105pub(crate) mod duration_opt {
1106 use std::time::Duration;
1107
1108 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1109
1110 pub(super) fn serialize<S: Serializer>(
1113 duration: &Option<Duration>,
1114 serializer: S,
1115 ) -> Result<S::Ok, S::Error> {
1116 struct Wrapper<'a>(&'a Duration);
1117
1118 impl Serialize for Wrapper<'_> {
1119 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1120 super::duration::serialize(self.0, serializer)
1121 }
1122 }
1123
1124 match duration {
1125 Some(duration) => serializer.serialize_some(&Wrapper(duration)),
1126 None => serializer.serialize_none(),
1127 }
1128 }
1129
1130 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1133 deserializer: D,
1134 ) -> Result<Option<Duration>, D::Error> {
1135 Ok(Option::<u64>::deserialize(deserializer)?.map(Duration::from_secs))
1136 }
1137}
1138
1139#[cfg(all(test, feature = "serde"))]
1140mod tests {
1141 use super::*;
1142
1143 #[cfg(feature = "serde")]
1144 #[test]
1145 fn default_opts() {
1146 let code = ResolverOpts::default();
1147 let json = serde_json::from_str::<ResolverOpts>("{}").unwrap();
1148 assert_eq!(code.ndots, json.ndots);
1149 assert_eq!(code.timeout, json.timeout);
1150 assert_eq!(code.attempts, json.attempts);
1151 assert_eq!(code.edns0, json.edns0);
1152 #[cfg(feature = "__dnssec")]
1153 assert_eq!(code.validate, json.validate);
1154 assert_eq!(code.ip_strategy, json.ip_strategy);
1155 assert_eq!(code.cache_size, json.cache_size);
1156 assert_eq!(code.use_hosts_file, json.use_hosts_file);
1157 assert_eq!(code.positive_min_ttl, json.positive_min_ttl);
1158 assert_eq!(code.negative_min_ttl, json.negative_min_ttl);
1159 assert_eq!(code.positive_max_ttl, json.positive_max_ttl);
1160 assert_eq!(code.negative_max_ttl, json.negative_max_ttl);
1161 assert_eq!(code.num_concurrent_reqs, json.num_concurrent_reqs);
1162 assert_eq!(code.preserve_intermediates, json.preserve_intermediates);
1163 assert_eq!(code.try_tcp_on_error, json.try_tcp_on_error);
1164 assert_eq!(code.recursion_desired, json.recursion_desired);
1165 assert_eq!(code.server_ordering_strategy, json.server_ordering_strategy);
1166 assert_eq!(code.avoid_local_udp_ports, json.avoid_local_udp_ports);
1167 assert_eq!(code.os_port_selection, json.os_port_selection);
1168 assert_eq!(code.case_randomization, json.case_randomization);
1169 assert_eq!(code.trust_anchor, json.trust_anchor);
1170 #[cfg(feature = "metrics")]
1171 assert_eq!(
1172 code.enable_per_name_server_metrics,
1173 json.enable_per_name_server_metrics
1174 );
1175 }
1176}