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]
49#[derive(Clone, Debug, Default)]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51pub struct ResolverConfig {
52 #[cfg_attr(feature = "serde", serde(default))]
54 pub domain: Option<Name>,
55 #[cfg_attr(feature = "serde", serde(default))]
57 pub search: Vec<Name>,
58 pub name_servers: Vec<NameServerConfig>,
60}
61
62impl ResolverConfig {
63 pub fn udp_and_tcp(config: &ServerGroup<'_>) -> Self {
67 Self {
68 domain: None,
70 search: vec![],
71 name_servers: config.udp_and_tcp().collect(),
72 }
73 }
74
75 #[cfg(feature = "__tls")]
79 pub fn tls(config: &ServerGroup<'_>) -> Self {
80 Self {
81 domain: None,
83 search: vec![],
84 name_servers: config.tls().collect(),
85 }
86 }
87
88 #[cfg(feature = "__https")]
92 pub fn https(config: &ServerGroup<'_>) -> Self {
93 Self {
94 domain: None,
96 search: vec![],
97 name_servers: config.https().collect(),
98 }
99 }
100
101 #[cfg(feature = "__quic")]
105 pub fn quic(config: &ServerGroup<'_>) -> Self {
106 Self {
107 domain: None,
109 search: vec![],
110 name_servers: config.quic().collect(),
111 }
112 }
113
114 #[cfg(feature = "__h3")]
118 pub fn h3(config: &ServerGroup<'_>) -> Self {
119 Self {
120 domain: None,
122 search: vec![],
123 name_servers: config.h3().collect(),
124 }
125 }
126
127 pub fn from_parts(
135 domain: Option<Name>,
136 search: Vec<Name>,
137 name_servers: Vec<NameServerConfig>,
138 ) -> Self {
139 Self {
140 domain,
141 search,
142 name_servers,
143 }
144 }
145
146 pub fn into_parts(self) -> (Option<Name>, Vec<Name>, Vec<NameServerConfig>) {
148 (self.domain, self.search, self.name_servers)
149 }
150
151 pub fn domain(&self) -> Option<&Name> {
155 self.domain.as_ref()
156 }
157
158 pub fn set_domain(&mut self, domain: Name) {
160 self.domain = Some(domain.clone());
161 self.search = vec![domain];
162 }
163
164 pub fn search(&self) -> &[Name] {
168 &self.search
169 }
170
171 pub fn add_search(&mut self, search: Name) {
173 self.search.push(search)
174 }
175
176 pub fn add_name_server(&mut self, name_server: NameServerConfig) {
179 self.name_servers.push(name_server);
180 }
181
182 pub fn name_servers(&self) -> &[NameServerConfig] {
184 &self.name_servers
185 }
186}
187
188#[derive(Clone, Debug)]
190#[cfg_attr(
191 feature = "serde",
192 derive(Serialize, Deserialize),
193 serde(deny_unknown_fields)
194)]
195#[non_exhaustive]
196pub struct NameServerConfig {
197 pub ip: IpAddr,
199 #[cfg_attr(feature = "serde", serde(default = "default_trust_negative_responses"))]
209 pub trust_negative_responses: bool,
210 pub connections: Vec<ConnectionConfig>,
212}
213
214impl NameServerConfig {
215 pub fn udp_and_tcp(ip: IpAddr) -> Self {
217 Self {
218 ip,
219 trust_negative_responses: true,
220 connections: vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
221 }
222 }
223
224 pub fn udp(ip: IpAddr) -> Self {
226 Self {
227 ip,
228 trust_negative_responses: true,
229 connections: vec![ConnectionConfig::udp()],
230 }
231 }
232
233 pub fn tcp(ip: IpAddr) -> Self {
235 Self {
236 ip,
237 trust_negative_responses: true,
238 connections: vec![ConnectionConfig::tcp()],
239 }
240 }
241
242 #[cfg(feature = "__tls")]
244 pub fn tls(ip: IpAddr, server_name: Arc<str>) -> Self {
245 Self {
246 ip,
247 trust_negative_responses: true,
248 connections: vec![ConnectionConfig::tls(server_name)],
249 }
250 }
251
252 #[cfg(feature = "__https")]
254 pub fn https(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
255 Self {
256 ip,
257 trust_negative_responses: true,
258 connections: vec![ConnectionConfig::https(server_name, path)],
259 }
260 }
261
262 #[cfg(feature = "__quic")]
264 pub fn quic(ip: IpAddr, server_name: Arc<str>) -> Self {
265 Self {
266 ip,
267 trust_negative_responses: true,
268 connections: vec![ConnectionConfig::quic(server_name)],
269 }
270 }
271
272 #[cfg(feature = "__h3")]
274 pub fn h3(ip: IpAddr, server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
275 Self {
276 ip,
277 trust_negative_responses: true,
278 connections: vec![ConnectionConfig::h3(server_name, path)],
279 }
280 }
281
282 #[cfg(any(feature = "__tls", feature = "__quic"))]
292 pub fn opportunistic_encryption(ip: IpAddr) -> Self {
293 Self {
294 ip,
295 trust_negative_responses: true,
296 connections: vec![
297 ConnectionConfig::udp(),
298 ConnectionConfig::tcp(),
299 #[cfg(feature = "__tls")]
300 ConnectionConfig::tls(Arc::from(ip.to_string())),
301 #[cfg(feature = "__quic")]
302 ConnectionConfig::quic(Arc::from(ip.to_string())),
303 ],
304 }
305 }
306
307 pub fn new(
309 ip: IpAddr,
310 trust_negative_responses: bool,
311 connections: Vec<ConnectionConfig>,
312 ) -> Self {
313 Self {
314 ip,
315 trust_negative_responses,
316 connections,
317 }
318 }
319}
320
321#[cfg(feature = "serde")]
322fn default_trust_negative_responses() -> bool {
323 true
324}
325
326#[derive(Clone, Debug)]
328#[cfg_attr(feature = "serde", derive(Serialize))]
329#[non_exhaustive]
330pub struct ConnectionConfig {
331 pub port: u16,
333 pub protocol: ProtocolConfig,
335 pub bind_addr: Option<SocketAddr>,
337}
338
339impl ConnectionConfig {
340 pub fn udp() -> Self {
342 Self::new(ProtocolConfig::Udp)
343 }
344
345 pub fn tcp() -> Self {
347 Self::new(ProtocolConfig::Tcp)
348 }
349
350 #[cfg(feature = "__tls")]
352 pub fn tls(server_name: Arc<str>) -> Self {
353 Self::new(ProtocolConfig::Tls { server_name })
354 }
355
356 #[cfg(feature = "__https")]
358 pub fn https(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
359 Self::new(ProtocolConfig::Https {
360 server_name,
361 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
362 })
363 }
364
365 #[cfg(feature = "__quic")]
367 pub fn quic(server_name: Arc<str>) -> Self {
368 Self::new(ProtocolConfig::Quic { server_name })
369 }
370
371 #[cfg(feature = "__h3")]
373 pub fn h3(server_name: Arc<str>, path: Option<Arc<str>>) -> Self {
374 Self::new(ProtocolConfig::H3 {
375 server_name,
376 path: path.unwrap_or_else(|| Arc::from(DEFAULT_DNS_QUERY_PATH)),
377 disable_grease: false,
378 })
379 }
380
381 pub fn new(protocol: ProtocolConfig) -> Self {
383 Self {
384 port: protocol.default_port(),
385 protocol,
386 bind_addr: None,
387 }
388 }
389}
390
391#[cfg(feature = "serde")]
392impl<'de> Deserialize<'de> for ConnectionConfig {
393 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
394 #[derive(Deserialize)]
395 #[serde(deny_unknown_fields)]
396 struct OptionalParts {
397 #[serde(default)]
398 port: Option<u16>,
399 protocol: ProtocolConfig,
400 #[serde(default)]
401 bind_addr: Option<SocketAddr>,
402 }
403
404 let parts = OptionalParts::deserialize(deserializer)?;
405 Ok(Self {
406 port: parts.port.unwrap_or_else(|| parts.protocol.default_port()),
407 protocol: parts.protocol,
408 bind_addr: parts.bind_addr,
409 })
410 }
411}
412
413#[allow(missing_docs)]
415#[derive(Clone, Debug, Default, PartialEq)]
416#[cfg_attr(
417 feature = "serde",
418 derive(Serialize, Deserialize),
419 serde(deny_unknown_fields, rename_all = "snake_case", tag = "type")
420)]
421pub enum ProtocolConfig {
422 #[default]
423 Udp,
424 Tcp,
425 #[cfg(feature = "__tls")]
426 Tls {
427 server_name: Arc<str>,
429 },
430 #[cfg(feature = "__https")]
431 Https {
432 server_name: Arc<str>,
434 path: Arc<str>,
436 },
437 #[cfg(feature = "__quic")]
438 Quic {
439 server_name: Arc<str>,
441 },
442 #[cfg(feature = "__h3")]
443 H3 {
444 server_name: Arc<str>,
446 path: Arc<str>,
448 #[cfg_attr(feature = "serde", serde(default))]
450 disable_grease: bool,
451 },
452}
453
454impl ProtocolConfig {
455 pub fn to_protocol(&self) -> Protocol {
457 match self {
458 ProtocolConfig::Udp => Protocol::Udp,
459 ProtocolConfig::Tcp => Protocol::Tcp,
460 #[cfg(feature = "__tls")]
461 ProtocolConfig::Tls { .. } => Protocol::Tls,
462 #[cfg(feature = "__https")]
463 ProtocolConfig::Https { .. } => Protocol::Https,
464 #[cfg(feature = "__quic")]
465 ProtocolConfig::Quic { .. } => Protocol::Quic,
466 #[cfg(feature = "__h3")]
467 ProtocolConfig::H3 { .. } => Protocol::H3,
468 }
469 }
470
471 pub fn default_port(&self) -> u16 {
473 match self {
474 ProtocolConfig::Udp => 53,
475 ProtocolConfig::Tcp => 53,
476 #[cfg(feature = "__tls")]
477 ProtocolConfig::Tls { .. } => 853,
478 #[cfg(feature = "__https")]
479 ProtocolConfig::Https { .. } => 443,
480 #[cfg(feature = "__quic")]
481 ProtocolConfig::Quic { .. } => 853,
482 #[cfg(feature = "__h3")]
483 ProtocolConfig::H3 { .. } => 443,
484 }
485 }
486}
487
488#[derive(Debug, Clone)]
490#[cfg_attr(
491 feature = "serde",
492 derive(Serialize, Deserialize),
493 serde(default, deny_unknown_fields)
494)]
495#[non_exhaustive]
496pub struct ResolverOpts {
497 #[cfg_attr(feature = "serde", serde(default = "default_ndots"))]
501 pub ndots: usize,
502 #[cfg_attr(
504 feature = "serde",
505 serde(default = "default_timeout", with = "duration")
506 )]
507 pub timeout: Duration,
508 #[cfg_attr(feature = "serde", serde(default = "default_attempts"))]
510 pub attempts: usize,
511 pub edns0: bool,
513 #[cfg(feature = "__dnssec")]
515 pub validate: bool,
516 pub ip_strategy: LookupIpStrategy,
518 #[cfg_attr(feature = "serde", serde(default = "default_cache_size"))]
520 pub cache_size: u64,
521 pub use_hosts_file: ResolveHosts,
523 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
528 pub positive_min_ttl: Option<Duration>,
529 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
534 pub negative_min_ttl: Option<Duration>,
535 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
540 pub positive_max_ttl: Option<Duration>,
541 #[cfg_attr(feature = "serde", serde(with = "duration_opt"))]
546 pub negative_max_ttl: Option<Duration>,
547 #[cfg_attr(feature = "serde", serde(default = "default_num_concurrent_reqs"))]
552 pub num_concurrent_reqs: usize,
553 #[cfg_attr(feature = "serde", serde(default = "default_max_active_requests"))]
561 pub max_active_requests: usize,
562 #[cfg_attr(feature = "serde", serde(default = "default_preserve_intermediates"))]
564 pub preserve_intermediates: bool,
565 pub try_tcp_on_error: bool,
567 pub server_ordering_strategy: ServerOrderingStrategy,
569 #[cfg_attr(feature = "serde", serde(default = "default_recursion_desired"))]
573 pub recursion_desired: bool,
574 pub avoid_local_udp_ports: Arc<HashSet<u16>>,
576 pub os_port_selection: bool,
587 pub case_randomization: bool,
595 pub trust_anchor: Option<PathBuf>,
599 pub allow_answers: Vec<IpNet>,
602 pub deny_answers: Vec<IpNet>,
604 #[cfg_attr(feature = "serde", serde(default = "default_edns_payload_len"))]
608 pub edns_payload_len: u16,
609}
610
611impl ResolverOpts {
612 pub(crate) fn answer_address_filter(&self) -> AccessControlSet {
613 let name = "resolver_answer_filter";
614 AccessControlSetBuilder::new(name)
615 .allow(self.allow_answers.iter())
616 .deny(self.deny_answers.iter())
617 .build()
618 .inspect_err(|err| warn!("{err}"))
619 .unwrap_or_else(|_| AccessControlSet::empty(name))
620 }
621}
622
623impl Default for ResolverOpts {
624 fn default() -> Self {
628 Self {
629 ndots: default_ndots(),
630 timeout: default_timeout(),
631 attempts: default_attempts(),
632 edns0: true,
633 #[cfg(feature = "__dnssec")]
634 validate: false,
635 ip_strategy: LookupIpStrategy::default(),
636 cache_size: default_cache_size(),
637 use_hosts_file: ResolveHosts::default(),
638 positive_min_ttl: None,
639 negative_min_ttl: None,
640 positive_max_ttl: None,
641 negative_max_ttl: None,
642 num_concurrent_reqs: default_num_concurrent_reqs(),
643 max_active_requests: default_max_active_requests(),
644
645 preserve_intermediates: default_preserve_intermediates(),
647
648 try_tcp_on_error: false,
649 server_ordering_strategy: ServerOrderingStrategy::default(),
650 recursion_desired: default_recursion_desired(),
651 avoid_local_udp_ports: Arc::default(),
652 os_port_selection: false,
653 case_randomization: false,
654 trust_anchor: None,
655 allow_answers: vec![],
656 deny_answers: vec![],
657 edns_payload_len: default_edns_payload_len(),
658 }
659 }
660}
661
662fn default_ndots() -> usize {
663 1
664}
665
666fn default_timeout() -> Duration {
667 Duration::from_secs(5)
668}
669
670fn default_attempts() -> usize {
671 2
672}
673
674fn default_cache_size() -> u64 {
675 8_192
676}
677
678fn default_num_concurrent_reqs() -> usize {
679 2
680}
681
682fn default_max_active_requests() -> usize {
683 32
684}
685
686fn default_preserve_intermediates() -> bool {
687 true
688}
689
690fn default_recursion_desired() -> bool {
691 true
692}
693
694fn default_edns_payload_len() -> u16 {
695 DEFAULT_MAX_PAYLOAD_LEN
696}
697
698#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
700#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
701pub enum LookupIpStrategy {
702 Ipv4Only,
704 Ipv6Only,
706 Ipv4AndIpv6,
708 #[default]
710 Ipv6AndIpv4,
711 Ipv6thenIpv4,
713 Ipv4thenIpv6,
715}
716
717#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
719#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
720#[non_exhaustive]
721pub enum ServerOrderingStrategy {
722 #[default]
725 QueryStatistics,
726 UserProvidedOrder,
729 RoundRobin,
732}
733
734#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
736#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
737pub enum ResolveHosts {
738 Always,
741 Never,
743 #[default]
746 Auto,
747}
748
749#[derive(Debug, Clone, Default, Eq, PartialEq)]
754#[cfg_attr(
755 feature = "serde",
756 derive(Serialize, Deserialize),
757 serde(rename_all = "snake_case")
758)]
759#[non_exhaustive]
760pub enum OpportunisticEncryption {
761 #[default]
763 Disabled,
764 #[cfg(any(feature = "__tls", feature = "__quic"))]
766 Enabled {
767 #[cfg_attr(feature = "serde", serde(flatten))]
769 config: OpportunisticEncryptionConfig,
770 },
771}
772
773impl OpportunisticEncryption {
774 #[cfg(all(
775 feature = "toml",
776 feature = "serde",
777 any(feature = "__tls", feature = "__quic")
778 ))]
779 pub(super) fn persisted_state(&self) -> Result<Option<NameServerTransportState>, String> {
780 let OpportunisticEncryption::Enabled {
781 config:
782 OpportunisticEncryptionConfig {
783 persistence: Some(OpportunisticEncryptionPersistence { path, .. }),
784 ..
785 },
786 } = self
787 else {
788 return Ok(None);
789 };
790
791 let state = match fs::read_to_string(path) {
792 Ok(toml_content) => toml::from_str(&toml_content).map_err(|e| {
793 format!(
794 "failed to parse opportunistic encryption state TOML file: {file_path}: {e}",
795 file_path = path.display()
796 )
797 })?,
798 Err(e) if e.kind() == io::ErrorKind::NotFound => {
799 info!(
800 state_file = %path.display(),
801 "no pre-existing opportunistic encryption state TOML file, starting with default state",
802 );
803 NameServerTransportState::default()
804 }
805 Err(e) => {
806 return Err(format!(
807 "failed to read opportunistic encryption state TOML file: {file_path}: {e}",
808 file_path = path.display()
809 ));
810 }
811 };
812
813 debug!(
814 path = %path.display(),
815 nameserver_count = state.nameserver_count(),
816 "loaded opportunistic encryption state"
817 );
818
819 Ok(Some(state))
820 }
821
822 pub fn is_enabled(&self) -> bool {
824 match self {
825 Self::Disabled => false,
826 #[cfg(any(feature = "__tls", feature = "__quic"))]
827 Self::Enabled { .. } => true,
828 }
829 }
830
831 pub fn max_concurrent_probes(&self) -> Option<u8> {
833 match self {
834 Self::Disabled => None,
835 #[cfg(any(feature = "__tls", feature = "__quic"))]
836 Self::Enabled { config, .. } => Some(config.max_concurrent_probes),
837 }
838 }
839}
840
841#[derive(Debug, Clone, Eq, PartialEq)]
843#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
844#[cfg_attr(feature = "serde", serde(default, deny_unknown_fields))]
845pub struct OpportunisticEncryptionConfig {
846 #[cfg_attr(
848 feature = "serde",
849 serde(default = "default_persistence_period", with = "duration")
850 )]
851 pub persistence_period: Duration,
852
853 #[cfg_attr(
855 feature = "serde",
856 serde(default = "default_damping_period", with = "duration")
857 )]
858 pub damping_period: Duration,
859
860 #[cfg_attr(feature = "serde", serde(default = "default_max_concurrent_probes"))]
862 pub max_concurrent_probes: u8,
863
864 pub persistence: Option<OpportunisticEncryptionPersistence>,
866}
867
868impl Default for OpportunisticEncryptionConfig {
869 fn default() -> Self {
870 Self {
871 persistence_period: default_persistence_period(),
872 damping_period: default_damping_period(),
873 max_concurrent_probes: default_max_concurrent_probes(),
874 persistence: None,
875 }
876 }
877}
878
879fn default_persistence_period() -> Duration {
881 Duration::from_secs(60 * 60 * 24 * 3) }
883
884fn default_damping_period() -> Duration {
886 Duration::from_secs(24 * 60 * 60) }
888
889fn default_max_concurrent_probes() -> u8 {
891 10
892}
893
894#[derive(Debug, Clone, Eq, PartialEq)]
895#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
896#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
897pub struct OpportunisticEncryptionPersistence {
899 pub path: PathBuf,
901
902 #[cfg_attr(
904 feature = "serde",
905 serde(default = "default_save_interval", with = "duration")
906 )]
907 pub save_interval: Duration,
908}
909
910#[cfg(feature = "serde")]
911fn default_save_interval() -> Duration {
912 Duration::from_secs(60 * 10) }
914
915pub const GOOGLE: ServerGroup<'static> = ServerGroup {
921 ips: &[
922 IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
923 IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)),
924 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888)),
925 IpAddr::V6(Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8844)),
926 ],
927 server_name: "dns.google",
928 path: "/dns-query",
929};
930
931pub const CLOUDFLARE: ServerGroup<'static> = ServerGroup {
935 ips: &[
936 IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
937 IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)),
938 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1111)),
939 IpAddr::V6(Ipv6Addr::new(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x1001)),
940 ],
941 server_name: "cloudflare-dns.com",
942 path: "/dns-query",
943};
944
945pub const QUAD9: ServerGroup<'static> = ServerGroup {
949 ips: &[
950 IpAddr::V4(Ipv4Addr::new(9, 9, 9, 9)),
951 IpAddr::V4(Ipv4Addr::new(149, 112, 112, 112)),
952 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x00fe)),
953 IpAddr::V6(Ipv6Addr::new(0x2620, 0x00fe, 0, 0, 0, 0, 0, 0x0009)),
954 ],
955 server_name: "dns.quad9.net",
956 path: "/dns-query",
957};
958
959#[derive(Clone, Copy, Debug)]
961pub struct ServerGroup<'a> {
962 pub ips: &'a [IpAddr],
964 pub server_name: &'a str,
966 pub path: &'a str,
968}
969
970impl<'a> ServerGroup<'a> {
971 pub fn udp_and_tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
973 self.ips.iter().map(|&ip| {
974 NameServerConfig::new(
975 ip,
976 true,
977 vec![ConnectionConfig::udp(), ConnectionConfig::tcp()],
978 )
979 })
980 }
981
982 pub fn udp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
984 self.ips
985 .iter()
986 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::udp()]))
987 }
988
989 pub fn tcp(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
991 self.ips
992 .iter()
993 .map(|&ip| NameServerConfig::new(ip, true, vec![ConnectionConfig::tcp()]))
994 }
995
996 #[cfg(feature = "__tls")]
998 pub fn tls(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
999 let this = *self;
1000 self.ips.iter().map(move |&ip| {
1001 NameServerConfig::new(
1002 ip,
1003 true,
1004 vec![ConnectionConfig::tls(Arc::from(this.server_name))],
1005 )
1006 })
1007 }
1008
1009 #[cfg(feature = "__https")]
1011 pub fn https(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1012 let this = *self;
1013 self.ips.iter().map(move |&ip| {
1014 NameServerConfig::new(
1015 ip,
1016 true,
1017 vec![ConnectionConfig::https(
1018 Arc::from(this.server_name),
1019 Some(Arc::from(this.path)),
1020 )],
1021 )
1022 })
1023 }
1024
1025 #[cfg(feature = "__quic")]
1027 pub fn quic(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1028 let this = *self;
1029 self.ips.iter().map(move |&ip| {
1030 NameServerConfig::new(
1031 ip,
1032 true,
1033 vec![ConnectionConfig::quic(Arc::from(this.server_name))],
1034 )
1035 })
1036 }
1037
1038 #[cfg(feature = "__h3")]
1040 pub fn h3(&self) -> impl Iterator<Item = NameServerConfig> + 'a {
1041 let this = *self;
1042 self.ips.iter().map(move |&ip| {
1043 NameServerConfig::new(
1044 ip,
1045 true,
1046 vec![ConnectionConfig::h3(
1047 Arc::from(this.server_name),
1048 Some(Arc::from(this.path)),
1049 )],
1050 )
1051 })
1052 }
1053}
1054
1055#[cfg(feature = "serde")]
1056pub(crate) mod duration {
1057 use std::time::Duration;
1058
1059 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1060
1061 pub(super) fn serialize<S: Serializer>(
1064 duration: &Duration,
1065 serializer: S,
1066 ) -> Result<S::Ok, S::Error> {
1067 duration.as_secs().serialize(serializer)
1068 }
1069
1070 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1073 deserializer: D,
1074 ) -> Result<Duration, D::Error> {
1075 Ok(Duration::from_secs(u64::deserialize(deserializer)?))
1076 }
1077}
1078
1079#[cfg(feature = "serde")]
1080pub(crate) mod duration_opt {
1081 use std::time::Duration;
1082
1083 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1084
1085 pub(super) fn serialize<S: Serializer>(
1088 duration: &Option<Duration>,
1089 serializer: S,
1090 ) -> Result<S::Ok, S::Error> {
1091 struct Wrapper<'a>(&'a Duration);
1092
1093 impl Serialize for Wrapper<'_> {
1094 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1095 super::duration::serialize(self.0, serializer)
1096 }
1097 }
1098
1099 match duration {
1100 Some(duration) => serializer.serialize_some(&Wrapper(duration)),
1101 None => serializer.serialize_none(),
1102 }
1103 }
1104
1105 pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
1108 deserializer: D,
1109 ) -> Result<Option<Duration>, D::Error> {
1110 Ok(Option::<u64>::deserialize(deserializer)?.map(Duration::from_secs))
1111 }
1112}
1113
1114#[cfg(all(test, feature = "serde"))]
1115mod tests {
1116 use super::*;
1117
1118 #[cfg(feature = "serde")]
1119 #[test]
1120 fn default_opts() {
1121 let code = ResolverOpts::default();
1122 let json = serde_json::from_str::<ResolverOpts>("{}").unwrap();
1123 assert_eq!(code.ndots, json.ndots);
1124 assert_eq!(code.timeout, json.timeout);
1125 assert_eq!(code.attempts, json.attempts);
1126 assert_eq!(code.edns0, json.edns0);
1127 #[cfg(feature = "__dnssec")]
1128 assert_eq!(code.validate, json.validate);
1129 assert_eq!(code.ip_strategy, json.ip_strategy);
1130 assert_eq!(code.cache_size, json.cache_size);
1131 assert_eq!(code.use_hosts_file, json.use_hosts_file);
1132 assert_eq!(code.positive_min_ttl, json.positive_min_ttl);
1133 assert_eq!(code.negative_min_ttl, json.negative_min_ttl);
1134 assert_eq!(code.positive_max_ttl, json.positive_max_ttl);
1135 assert_eq!(code.negative_max_ttl, json.negative_max_ttl);
1136 assert_eq!(code.num_concurrent_reqs, json.num_concurrent_reqs);
1137 assert_eq!(code.preserve_intermediates, json.preserve_intermediates);
1138 assert_eq!(code.try_tcp_on_error, json.try_tcp_on_error);
1139 assert_eq!(code.recursion_desired, json.recursion_desired);
1140 assert_eq!(code.server_ordering_strategy, json.server_ordering_strategy);
1141 assert_eq!(code.avoid_local_udp_ports, json.avoid_local_udp_ports);
1142 assert_eq!(code.os_port_selection, json.os_port_selection);
1143 assert_eq!(code.case_randomization, json.case_randomization);
1144 assert_eq!(code.trust_anchor, json.trust_anchor);
1145 }
1146}