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 = "toml",
18 feature = "serde",
19 any(feature = "__tls", feature = "__quic")
20))]
21use std::{fs, io};
22
23use ipnet::IpNet;
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26use tracing::warn;
27#[cfg(all(
28 feature = "toml",
29 feature = "serde",
30 any(feature = "__tls", feature = "__quic")
31))]
32use tracing::{debug, info};
33
34#[cfg(all(
35 feature = "toml",
36 feature = "serde",
37 any(feature = "__tls", feature = "__quic")
38))]
39use crate::name_server_pool::NameServerTransportState;
40#[cfg(any(feature = "__https", feature = "__h3"))]
41use crate::net::http::DEFAULT_DNS_QUERY_PATH;
42use crate::net::xfer::Protocol;
43use crate::proto::access_control::{AccessControlSet, AccessControlSetBuilder};
44use crate::proto::op::DEFAULT_MAX_PAYLOAD_LEN;
45use crate::proto::rr::Name;
46
47#[non_exhaustive]
53#[derive(Clone, Debug, Default)]
54#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
55pub struct ResolverConfig {
56 #[cfg_attr(feature = "serde", serde(default))]
58 pub domain: Option<Name>,
59 #[cfg_attr(feature = "serde", serde(default))]
61 pub search: Vec<Name>,
62 pub name_servers: Vec<NameServerConfig>,
64}
65
66impl ResolverConfig {
67 pub fn udp_and_tcp(config: &ServerGroup<'_>) -> Self {
71 Self {
72 domain: None,
74 search: vec![],
75 name_servers: config.udp_and_tcp().collect(),
76 }
77 }
78
79 #[cfg(feature = "__tls")]
83 pub fn tls(config: &ServerGroup<'_>) -> Self {
84 Self {
85 domain: None,
87 search: vec![],
88 name_servers: config.tls().collect(),
89 }
90 }
91
92 #[cfg(feature = "__https")]
96 pub fn https(config: &ServerGroup<'_>) -> Self {
97 Self {
98 domain: None,
100 search: vec![],
101 name_servers: config.https().collect(),
102 }
103 }
104
105 #[cfg(feature = "__quic")]
109 pub fn quic(config: &ServerGroup<'_>) -> Self {
110 Self {
111 domain: None,
113 search: vec![],
114 name_servers: config.quic().collect(),
115 }
116 }
117
118 #[cfg(feature = "__h3")]
122 pub fn h3(config: &ServerGroup<'_>) -> Self {
123 Self {
124 domain: None,
126 search: vec![],
127 name_servers: config.h3().collect(),
128 }
129 }
130
131 pub fn from_parts(
139 domain: Option<Name>,
140 search: Vec<Name>,
141 name_servers: Vec<NameServerConfig>,
142 ) -> Self {
143 Self {
144 domain,
145 search,
146 name_servers,
147 }
148 }
149
150 pub fn from_name_servers(name_servers: Vec<NameServerConfig>) -> Self {
154 Self::from_parts(None, vec![], name_servers)
155 }
156
157 pub fn into_parts(self) -> (Option<Name>, Vec<Name>, Vec<NameServerConfig>) {
159 (self.domain, self.search, self.name_servers)
160 }
161
162 pub fn domain(&self) -> Option<&Name> {
166 self.domain.as_ref()
167 }
168
169 pub fn set_domain(&mut self, domain: Name) {
171 self.domain = Some(domain.clone());
172 self.search = vec![domain];
173 }
174
175 pub fn search(&self) -> &[Name] {
179 &self.search
180 }
181
182 pub fn add_search(&mut self, search: Name) {
184 self.search.push(search)
185 }
186
187 pub fn add_name_server(&mut self, name_server: NameServerConfig) {
190 self.name_servers.push(name_server);
191 }
192
193 pub fn name_servers(&self) -> &[NameServerConfig] {
195 &self.name_servers
196 }
197}
198
199#[derive(Clone, Debug)]
201#[cfg_attr(
202 feature = "serde",
203 derive(Serialize, Deserialize),
204 serde(deny_unknown_fields)
205)]
206#[non_exhaustive]
207pub struct NameServerConfig {
208 pub ip: IpAddr,
210 #[cfg_attr(feature = "serde", serde(default = "default_trust_negative_responses"))]
220 pub trust_negative_responses: bool,
221 pub connections: Vec<ConnectionConfig>,
223}
224
225impl NameServerConfig {
226 pub fn udp_and_tcp(ip: IpAddr) -> Self {
228 Self {
229 ip,
230 trust_negative_responses: true,
231 connections: vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
232 }
233 }
234
235 pub fn udp(ip: IpAddr) -> Self {
237 Self {
238 ip,
239 trust_negative_responses: true,
240 connections: vec![ConnectionConfig::udp()],
241 }
242 }
243
244 pub fn tcp(ip: IpAddr) -> Self {
246 Self {
247 ip,
248 trust_negative_responses: true,
249 connections: vec![ConnectionConfig::tcp()],
250 }
251 }
252
253 #[cfg(feature = "__tls")]
255 pub fn tls(ip: IpAddr, server_name: Arc<str>) -> Self {
256 Self {
257 ip,
258 trust_negative_responses: true,
259 connections: vec![ConnectionConfig::tls(server_name)],
260 }
261 }
262
263 #[cfg(feature = "__https")]
265 pub fn https(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
266 Self {
267 ip,
268 trust_negative_responses: true,
269 connections: vec![ConnectionConfig::https(server_name, path)],
270 }
271 }
272
273 #[cfg(feature = "__quic")]
275 pub fn quic(ip: IpAddr, server_name: Arc<str>) -> Self {
276 Self {
277 ip,
278 trust_negative_responses: true,
279 connections: vec![ConnectionConfig::quic(server_name)],
280 }
281 }
282
283 #[cfg(feature = "__h3")]
285 pub fn h3(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
286 Self {
287 ip,
288 trust_negative_responses: true,
289 connections: vec![ConnectionConfig::h3(server_name, path)],
290 }
291 }
292
293 #[cfg(any(feature = "__tls", feature = "__quic"))]
303 pub fn opportunistic_encryption(ip: IpAddr) -> Self {
304 Self {
305 ip,
306 trust_negative_responses: true,
307 connections: vec![
308 ConnectionConfig::udp(),
309 ConnectionConfig::tcp(),
310 #[cfg(feature = "__tls")]
311 ConnectionConfig::tls(Arc::from(ip.to_string())),
312 #[cfg(feature = "__quic")]
313 ConnectionConfig::quic(Arc::from(ip.to_string())),
314 ],
315 }
316 }
317
318 pub fn new(
320 ip: IpAddr,
321 trust_negative_responses: bool,
322 connections: Vec<ConnectionConfig>,
323 ) -> Self {
324 Self {
325 ip,
326 trust_negative_responses,
327 connections,
328 }
329 }
330}
331
332#[cfg(feature = "serde")]
333fn default_trust_negative_responses() -> bool {
334 true
335}
336
337#[derive(Clone, Debug)]
339#[cfg_attr(feature = "serde", derive(Serialize))]
340#[non_exhaustive]
341pub struct ConnectionConfig {
342 pub port: u16,
344 pub protocol: ProtocolConfig,
346 pub bind_addr: Option<SocketAddr>,
348}
349
350impl ConnectionConfig {
351 pub fn udp() -> Self {
353 Self::new(ProtocolConfig::Udp)
354 }
355
356 pub fn tcp() -> Self {
358 Self::new(ProtocolConfig::Tcp)
359 }
360
361 #[cfg(feature = "__tls")]
363 pub fn tls(server_name: Arc<str>) -> Self {
364 Self::new(ProtocolConfig::Tls { server_name })
365 }
366
367 #[cfg(feature = "__https")]
369 pub fn https(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
370 Self::new(ProtocolConfig::Https {
371 server_name,
372 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
373 })
374 }
375
376 #[cfg(feature = "__quic")]
378 pub fn quic(server_name: Arc<str>) -> Self {
379 Self::new(ProtocolConfig::Quic { server_name })
380 }
381
382 #[cfg(feature = "__h3")]
384 pub fn h3(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
385 Self::new(ProtocolConfig::H3 {
386 server_name,
387 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
388 disable_grease: false,
389 })
390 }
391
392 pub fn new(protocol: ProtocolConfig) -> Self {
394 Self {
395 port: protocol.default_port(),
396 protocol,
397 bind_addr: None,
398 }
399 }
400}
401
402#[cfg(feature = "serde")]
403impl<'de> Deserialize<'de> for ConnectionConfig {
404 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
405 #[derive(Deserialize)]
406 #[serde(deny_unknown_fields)]
407 struct OptionalParts {
408 #[serde(default)]
409 port: Option<u16>,
410 protocol: ProtocolConfig,
411 #[serde(default)]
412 bind_addr: Option<SocketAddr>,
413 }
414
415 let parts = OptionalParts::deserialize(deserializer)?;
416 Ok(Self {
417 port: parts.port.unwrap_or_else(|| parts.protocol.default_port()),
418 protocol: parts.protocol,
419 bind_addr: parts.bind_addr,
420 })
421 }
422}
423
424#[allow(missing_docs)]
426#[derive(Clone, Debug, Default, PartialEq)]
427#[cfg_attr(
428 feature = "serde",
429 derive(Serialize, Deserialize),
430 serde(deny_unknown_fields, rename_all = "snake_case", tag = "type")
431)]
432pub enum ProtocolConfig {
433 #[default]
434 Udp,
435 Tcp,
436 #[cfg(feature = "__tls")]
437 Tls {
438 server_name: Arc<str>,
440 },
441 #[cfg(feature = "__https")]
442 Https {
443 server_name: Arc<str>,
445 path: Arc<str>,
447 },
448 #[cfg(feature = "__quic")]
449 Quic {
450 server_name: Arc<str>,
452 },
453 #[cfg(feature = "__h3")]
454 H3 {
455 server_name: Arc<str>,
457 path: Arc<str>,
459 #[cfg_attr(feature = "serde", serde(default))]
461 disable_grease: bool,
462 },
463}
464
465impl ProtocolConfig {
466 pub fn to_protocol(&self) -> Protocol {
468 match self {
469 ProtocolConfig::Udp => Protocol::Udp,
470 ProtocolConfig::Tcp => Protocol::Tcp,
471 #[cfg(feature = "__tls")]
472 ProtocolConfig::Tls { .. } => Protocol::Tls,
473 #[cfg(feature = "__https")]
474 ProtocolConfig::Https { .. } => Protocol::Https,
475 #[cfg(feature = "__quic")]
476 ProtocolConfig::Quic { .. } => Protocol::Quic,
477 #[cfg(feature = "__h3")]
478 ProtocolConfig::H3 { .. } => Protocol::H3,
479 }
480 }
481
482 pub fn default_port(&self) -> u16 {
484 match self {
485 ProtocolConfig::Udp => 53,
486 ProtocolConfig::Tcp => 53,
487 #[cfg(feature = "__tls")]
488 ProtocolConfig::Tls { .. } => 853,
489 #[cfg(feature = "__https")]
490 ProtocolConfig::Https { .. } => 443,
491 #[cfg(feature = "__quic")]
492 ProtocolConfig::Quic { .. } => 853,
493 #[cfg(feature = "__h3")]
494 ProtocolConfig::H3 { .. } => 443,
495 }
496 }
497}
498
499#[derive(Debug, Clone)]
501#[cfg_attr(
502 feature = "serde",
503 derive(Serialize, Deserialize),
504 serde(default, deny_unknown_fields)
505)]
506#[non_exhaustive]
507pub struct ResolverOpts {
508 #[cfg_attr(feature = "serde", serde(default = "default_ndots"))]
512 pub ndots: usize,
513 #[cfg_attr(
515 feature = "serde",
516 serde(default = "default_timeout", with = "duration")
517 )]
518 pub timeout: Duration,
519 #[cfg_attr(feature = "serde", serde(default = "default_attempts"))]
521 pub attempts: usize,
522 pub edns0: bool,
524 #[cfg(feature = "__dnssec")]
526 pub validate: bool,
527 pub ip_strategy: LookupIpStrategy,
529 #[cfg_attr(feature = "serde", serde(default = "default_cache_size"))]
531 pub cache_size: u64,
532 pub use_hosts_file: ResolveHosts,
534 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
539 pub positive_min_ttl: Option<Duration>,
540 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
545 pub negative_min_ttl: Option<Duration>,
546 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
551 pub positive_max_ttl: Option<Duration>,
552 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
557 pub negative_max_ttl: Option<Duration>,
558 #[cfg_attr(feature = "serde", serde(default = "default_num_concurrent_reqs"))]
563 pub num_concurrent_reqs: usize,
564 #[cfg_attr(feature = "serde", serde(default = "default_max_active_requests"))]
572 pub max_active_requests: usize,
573 #[cfg_attr(feature = "serde", serde(default = "default_preserve_intermediates"))]
575 pub preserve_intermediates: bool,
576 pub try_tcp_on_error: bool,
578 pub server_ordering_strategy: ServerOrderingStrategy,
580 #[cfg_attr(feature = "serde", serde(default = "default_recursion_desired"))]
584 pub recursion_desired: bool,
585 pub avoid_local_udp_ports: Arc<HashSet<u16>>,
587 pub os_port_selection: bool,
598 pub case_randomization: bool,
606 pub trust_anchor: Option<PathBuf>,
610 pub allow_answers: Vec<IpNet>,
613 pub deny_answers: Vec<IpNet>,
615 #[cfg_attr(feature = "serde", serde(default = "default_edns_payload_len"))]
619 pub edns_payload_len: u16,
620 #[cfg_attr(feature = "serde", serde(default))]
626 #[cfg(feature = "metrics")]
627 pub enable_per_name_server_metrics: bool,
628}
629
630impl ResolverOpts {
631 pub(crate) fn answer_address_filter(&self) -> AccessControlSet {
632 let name = "resolver_answer_filter";
633 AccessControlSetBuilder::new(name)
634 .allow(self.allow_answers.iter())
635 .deny(self.deny_answers.iter())
636 .build()
637 .inspect_err(|err| warn!("{err}"))
638 .unwrap_or_else(|_| AccessControlSet::empty(name))
639 }
640}
641
642impl Default for ResolverOpts {
643 fn default() -> Self {
647 Self {
648 ndots: default_ndots(),
649 timeout: default_timeout(),
650 attempts: default_attempts(),
651 edns0: true,
652 #[cfg(feature = "__dnssec")]
653 validate: false,
654 ip_strategy: LookupIpStrategy::default(),
655 cache_size: default_cache_size(),
656 use_hosts_file: ResolveHosts::default(),
657 positive_min_ttl: None,
658 negative_min_ttl: None,
659 positive_max_ttl: None,
660 negative_max_ttl: None,
661 num_concurrent_reqs: default_num_concurrent_reqs(),
662 max_active_requests: default_max_active_requests(),
663
664 preserve_intermediates: default_preserve_intermediates(),
666
667 try_tcp_on_error: false,
668 server_ordering_strategy: ServerOrderingStrategy::default(),
669 recursion_desired: default_recursion_desired(),
670 avoid_local_udp_ports: Arc::default(),
671 os_port_selection: false,
672 case_randomization: false,
673 trust_anchor: None,
674 allow_answers: vec![],
675 deny_answers: vec![],
676 edns_payload_len: default_edns_payload_len(),
677 #[cfg(feature = "metrics")]
678 enable_per_name_server_metrics: false,
679 }
680 }
681}
682
683fn default_ndots() -> usize {
684 1
685}
686
687fn default_timeout() -> Duration {
688 Duration::from_secs(5)
689}
690
691fn default_attempts() -> usize {
692 2
693}
694
695fn default_cache_size() -> u64 {
696 8_192
697}
698
699fn default_num_concurrent_reqs() -> usize {
700 2
701}
702
703fn default_max_active_requests() -> usize {
704 32
705}
706
707fn default_preserve_intermediates() -> bool {
708 true
709}
710
711fn default_recursion_desired() -> bool {
712 true
713}
714
715fn default_edns_payload_len() -> u16 {
716 DEFAULT_MAX_PAYLOAD_LEN
717}
718
719#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
721#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
722pub enum LookupIpStrategy {
723 Ipv4Only,
725 Ipv6Only,
727 Ipv4AndIpv6,
729 #[default]
731 Ipv6AndIpv4,
732 Ipv6thenIpv4,
734 Ipv4thenIpv6,
736}
737
738#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
740#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
741#[non_exhaustive]
742pub enum ServerOrderingStrategy {
743 #[default]
746 QueryStatistics,
747 UserProvidedOrder,
750 RoundRobin,
753}
754
755#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
757#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
758pub enum ResolveHosts {
759 Always,
762 Never,
764 #[default]
767 Auto,
768}
769
770#[derive(Debug, Clone, Default, Eq, PartialEq)]
775#[cfg_attr(
776 feature = "serde",
777 derive(Serialize, Deserialize),
778 serde(rename_all = "snake_case")
779)]
780#[non_exhaustive]
781pub enum OpportunisticEncryption {
782 #[default]
784 Disabled,
785 #[cfg(any(feature = "__tls", feature = "__quic"))]
787 Enabled {
788 #[cfg_attr(feature = "serde", serde(flatten))]
790 config: OpportunisticEncryptionConfig,
791 },
792}
793
794impl OpportunisticEncryption {
795 #[cfg(all(
796 feature = "toml",
797 feature = "serde",
798 any(feature = "__tls", feature = "__quic")
799 ))]
800 pub(super) fn persisted_state(&self) -> Result<Option<NameServerTransportState>, String> {
801 let OpportunisticEncryption::Enabled {
802 config:
803 OpportunisticEncryptionConfig {
804 persistence: Some(OpportunisticEncryptionPersistence { path, .. }),
805 ..
806 },
807 } = self
808 else {
809 return Ok(None);
810 };
811
812 let state = match fs::read_to_string(path) {
813 Ok(toml_content) => toml::from_str(&toml_content).map_err(|e| {
814 format!(
815 "failed to parse opportunistic encryption state TOML file: {file_path}: {e}",
816 file_path = path.display()
817 )
818 })?,
819 Err(e) if e.kind() == io::ErrorKind::NotFound => {
820 info!(
821 state_file = %path.display(),
822 "no pre-existing opportunistic encryption state TOML file, starting with default state",
823 );
824 NameServerTransportState::default()
825 }
826 Err(e) => {
827 return Err(format!(
828 "failed to read opportunistic encryption state TOML file: {file_path}: {e}",
829 file_path = path.display()
830 ));
831 }
832 };
833
834 debug!(
835 path = %path.display(),
836 nameserver_count = state.nameserver_count(),
837 "loaded opportunistic encryption state"
838 );
839
840 Ok(Some(state))
841 }
842
843 pub fn is_enabled(&self) -> bool {
845 match self {
846 Self::Disabled => false,
847 #[cfg(any(feature = "__tls", feature = "__quic"))]
848 Self::Enabled { .. } => true,
849 }
850 }
851
852 pub fn max_concurrent_probes(&self) -> Option<u8> {
854 match self {
855 Self::Disabled => None,
856 #[cfg(any(feature = "__tls", feature = "__quic"))]
857 Self::Enabled { config, .. } => Some(config.max_concurrent_probes),
858 }
859 }
860}
861
862#[derive(Debug, Clone, Eq, PartialEq)]
864#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
865#[cfg_attr(feature = "serde", serde(default, deny_unknown_fields))]
866pub struct OpportunisticEncryptionConfig {
867 #[cfg_attr(
869 feature = "serde",
870 serde(default = "default_persistence_period", with = "duration")
871 )]
872 pub persistence_period: Duration,
873
874 #[cfg_attr(
876 feature = "serde",
877 serde(default = "default_damping_period", with = "duration")
878 )]
879 pub damping_period: Duration,
880
881 #[cfg_attr(feature = "serde", serde(default = "default_max_concurrent_probes"))]
883 pub max_concurrent_probes: u8,
884
885 pub persistence: Option<OpportunisticEncryptionPersistence>,
887}
888
889impl Default for OpportunisticEncryptionConfig {
890 fn default() -> Self {
891 Self {
892 persistence_period: default_persistence_period(),
893 damping_period: default_damping_period(),
894 max_concurrent_probes: default_max_concurrent_probes(),
895 persistence: None,
896 }
897 }
898}
899
900fn default_persistence_period() -> Duration {
902 Duration::from_secs(60 * 60 * 24 * 3) }
904
905fn default_damping_period() -> Duration {
907 Duration::from_secs(24 * 60 * 60) }
909
910fn default_max_concurrent_probes() -> u8 {
912 10
913}
914
915#[derive(Debug, Clone, Eq, PartialEq)]
916#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
917#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
918pub struct OpportunisticEncryptionPersistence {
920 pub path: PathBuf,
922
923 #[cfg_attr(
925 feature = "serde",
926 serde(default = "default_save_interval", with = "duration")
927 )]
928 pub save_interval: Duration,
929}
930
931#[cfg(feature = "serde")]
932fn default_save_interval() -> Duration {
933 Duration::from_secs(60 * 10) }
935
936pub const GOOGLE: ServerGroup<'static> = ServerGroup {
942 ips: &[
943 IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
944 IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
945 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
946 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
947 ],
948 server_name: "dns.google",
949 path: "/dns-query",
950};
951
952pub const CLOUDFLARE: ServerGroup<'static> = ServerGroup {
956 ips: &[
957 IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
958 IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
959 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
960 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
961 ],
962 server_name: "cloudflare-dns.com",
963 path: "/dns-query",
964};
965
966pub const QUAD9: ServerGroup<'static> = ServerGroup {
970 ips: &[
971 IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
972 IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
973 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
974 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x0009)),
975 ],
976 server_name: "dns.quad9.net",
977 path: "/dns-query",
978};
979
980#[derive(Clone, Copy, Debug)]
982pub struct ServerGroup<'a> {
983 pub ips: &'a [IpAddr],
985 pub server_name: &'a str,
987 pub path: &'a str,
989}
990
991impl<'a> ServerGroup<'a> {
992 pub fn udp_and_tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
994 self.ips.iter().map(|&ip| {
995 NameServerConfig::new(
996 ip,
997 true,
998 vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
999 )
1000 })
1001 }
1002
1003 pub fn udp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1005 self.ips
1006 .iter()
1007 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::udp()]))
1008 }
1009
1010 pub fn tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1012 self.ips
1013 .iter()
1014 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::tcp()]))
1015 }
1016
1017 #[cfg(feature = "__tls")]
1019 pub fn tls(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1020 let this = *self;
1021 self.ips.iter().map(move |&ip| {
1022 NameServerConfig::new(
1023 ip,
1024 true,
1025 vec![ConnectionConfig::tls(Arc::from(this.server_name))],
1026 )
1027 })
1028 }
1029
1030 #[cfg(feature = "__https")]
1032 pub fn https(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1033 let this = *self;
1034 self.ips.iter().map(move |&ip| {
1035 NameServerConfig::new(
1036 ip,
1037 true,
1038 vec![ConnectionConfig::https(
1039 Arc::from(this.server_name),
1040 Some(Arc::from(this.path)),
1041 )],
1042 )
1043 })
1044 }
1045
1046 #[cfg(feature = "__quic")]
1048 pub fn quic(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1049 let this = *self;
1050 self.ips.iter().map(move |&ip| {
1051 NameServerConfig::new(
1052 ip,
1053 true,
1054 vec![ConnectionConfig::quic(Arc::from(this.server_name))],
1055 )
1056 })
1057 }
1058
1059 #[cfg(feature = "__h3")]
1061 pub fn h3(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1062 let this = *self;
1063 self.ips.iter().map(move |&ip| {
1064 NameServerConfig::new(
1065 ip,
1066 true,
1067 vec![ConnectionConfig::h3(
1068 Arc::from(this.server_name),
1069 Some(Arc::from(this.path)),
1070 )],
1071 )
1072 })
1073 }
1074}
1075
1076#[cfg(feature = "serde")]
1077pub(crate) mod duration {
1078 use std::time::Duration;
1079
1080 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1081
1082 pub(super) fn serialize<S: Serializer>(
1085 duration: &Duration,
1086 serializer: S,
1087 ) -> Result<S::Ok, S::Error> {
1088 duration.as_secs().serialize(serializer)
1089 }
1090
1091 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1094 deserializer: D,
1095 ) -> Result<Duration, D::Error> {
1096 Ok(Duration::from_secs(u64::deserialize(deserializer)?))
1097 }
1098}
1099
1100#[cfg(feature = "serde")]
1101pub(crate) mod duration_opt {
1102 use std::time::Duration;
1103
1104 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1105
1106 pub(super) fn serialize<S: Serializer>(
1109 duration: &Option<Duration>,
1110 serializer: S,
1111 ) -> Result<S::Ok, S::Error> {
1112 struct Wrapper<'a>(&'a Duration);
1113
1114 impl Serialize for Wrapper<'_> {
1115 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1116 super::duration::serialize(self.0, serializer)
1117 }
1118 }
1119
1120 match duration {
1121 Some(duration) => serializer.serialize_some(&Wrapper(duration)),
1122 None => serializer.serialize_none(),
1123 }
1124 }
1125
1126 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1129 deserializer: D,
1130 ) -> Result<Option<Duration>, D::Error> {
1131 Ok(Option::<u64>::deserialize(deserializer)?.map(Duration::from_secs))
1132 }
1133}
1134
1135#[cfg(all(test, feature = "serde"))]
1136mod tests {
1137 use super::*;
1138
1139 #[cfg(feature = "serde")]
1140 #[test]
1141 fn default_opts() {
1142 let code = ResolverOpts::default();
1143 let json = serde_json::from_str::<ResolverOpts>("{}").unwrap();
1144 assert_eq!(code.ndots, json.ndots);
1145 assert_eq!(code.timeout, json.timeout);
1146 assert_eq!(code.attempts, json.attempts);
1147 assert_eq!(code.edns0, json.edns0);
1148 #[cfg(feature = "__dnssec")]
1149 assert_eq!(code.validate, json.validate);
1150 assert_eq!(code.ip_strategy, json.ip_strategy);
1151 assert_eq!(code.cache_size, json.cache_size);
1152 assert_eq!(code.use_hosts_file, json.use_hosts_file);
1153 assert_eq!(code.positive_min_ttl, json.positive_min_ttl);
1154 assert_eq!(code.negative_min_ttl, json.negative_min_ttl);
1155 assert_eq!(code.positive_max_ttl, json.positive_max_ttl);
1156 assert_eq!(code.negative_max_ttl, json.negative_max_ttl);
1157 assert_eq!(code.num_concurrent_reqs, json.num_concurrent_reqs);
1158 assert_eq!(code.preserve_intermediates, json.preserve_intermediates);
1159 assert_eq!(code.try_tcp_on_error, json.try_tcp_on_error);
1160 assert_eq!(code.recursion_desired, json.recursion_desired);
1161 assert_eq!(code.server_ordering_strategy, json.server_ordering_strategy);
1162 assert_eq!(code.avoid_local_udp_ports, json.avoid_local_udp_ports);
1163 assert_eq!(code.os_port_selection, json.os_port_selection);
1164 assert_eq!(code.case_randomization, json.case_randomization);
1165 assert_eq!(code.trust_anchor, json.trust_anchor);
1166 #[cfg(feature = "metrics")]
1167 assert_eq!(
1168 code.enable_per_name_server_metrics,
1169 json.enable_per_name_server_metrics
1170 );
1171 }
1172}