1#![allow(
2 missing_docs,
3 reason = "temporary compatibility adapter preserves the existing browser resolver API"
4)]
5
6use hns_cache::ExpiringLru;
7use hns_core::dns::{
8 DnsEncodeConfig, DnsFlags, DnsHeader, DnsMessage, DnsName, DnsQuestion, RecordType,
9 ResourceRecord, SVCB_PARAM_ALPN, SVCB_PARAM_DOHPATH, SVCB_PARAM_IPV4HINT, SVCB_PARAM_IPV6HINT,
10 SVCB_PARAM_MANDATORY, SVCB_PARAM_PORT, SvcbRecord,
11};
12use hns_core::network::NetworkKind;
13use hns_core::network_policy::{
14 is_browser_blocked_port, is_browser_special_use_host, is_publicly_routable,
15};
16use hns_core::resource::{ResourceError, decode_handshake_resource_records};
17use hns_core::{Hash, Height, NameHash, NameHashError};
18use hns_dane::{TlsaMatching, TlsaRecord, TlsaSelector, TlsaUsage};
19use hns_dnssec::{
20 DnssecChainLink, DnssecChainValidationInput, DnssecStatus, DnssecTime,
21 Nsec3NameErrorValidationInput, Nsec3NoDataValidationInput, NsecNameErrorValidationInput,
22 NsecNoDataValidationInput, RrsigRecord, SignedRrsetValidationInput, validate_dnssec_chain,
23 validate_nsec_name_error, validate_nsec_no_data, validate_nsec3_name_error,
24 validate_nsec3_no_data, validate_rrset_signature, validate_signed_rrset,
25};
26use hns_namespace_resolution::{
27 ClassificationError as NamespaceClassificationError, NamespaceDecision, OriginQuery,
28 ValidationError as NamespaceValidationError,
29};
30use rusqlite::{Connection, OptionalExtension, params};
31use std::collections::{BTreeSet, HashMap};
32use std::io::{Read, Write};
33use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpStream, UdpSocket};
34use std::num::NonZeroUsize;
35use std::path::Path;
36use std::sync::Mutex;
37use std::sync::atomic::{AtomicU16, Ordering};
38use std::time::{Duration, SystemTime, UNIX_EPOCH};
39use thiserror::Error;
40
41const DNS_CLASS_IN: u16 = 1;
42const DNS_OPT_RECORD_TYPE: u16 = 41;
43const DNSSEC_DO_FLAG: u32 = 0x8000;
44const DNS_RCODE_NOERROR: u8 = 0;
45const DNS_RCODE_NXDOMAIN: u8 = 3;
46const DEFAULT_DNS_UDP_PAYLOAD: usize = 1232;
47const DEFAULT_DNS_TCP_MAX_MESSAGE_LEN: usize = 65_535;
48const DEFAULT_DOH_PORT: u16 = 443;
49const DEFAULT_DOH_PATH: &str = "/dns-query";
50const DOH_URI_TEMPLATE_DNS_VARIABLE: &str = "{?dns}";
51const HNSDNS_VERSION: &str = "1";
52const HNSDNS_MAX_TEXT_BYTES: usize = 255;
53const HNSDNS_MAX_TLSA_PINS: usize = 2;
54const MAX_CNAME_CHAIN_LEN: usize = 8;
55static DNS_QUERY_ID: AtomicU16 = AtomicU16::new(0x4d00);
56const ICANN_TLDS: &str = include_str!("icann_tlds.txt");
58
59pub fn browser_icann_tld_snapshot() -> &'static str {
62 ICANN_TLDS
63}
64
65#[derive(Clone, Copy, Debug, Eq, PartialEq)]
66pub enum NameClass {
67 Hns,
68 Icann,
69 Search,
70}
71
72#[derive(Clone, Debug, Eq, Hash, PartialEq)]
73pub struct ResolutionRequest {
74 pub qname: String,
75 pub qtype: u16,
76}
77
78#[derive(Clone, Debug, Eq, PartialEq)]
79pub struct ResolutionAnswer {
80 pub name: DnsName,
81 pub records: Vec<ResourceRecord>,
82 pub secure: bool,
83}
84
85#[derive(Clone, Debug, Eq, PartialEq)]
91pub struct PreparedNamespaceResolution {
92 pub decision: NamespaceDecision,
93 pub selected_answer: Option<ResolutionAnswer>,
94}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
97pub struct ProvenNameRecords {
98 pub root_name: String,
99 pub name_hash: NameHash,
100 pub records: Vec<ResourceRecord>,
101 pub secure: bool,
102 pub exists: bool,
103}
104
105#[derive(Clone, Debug, Eq, PartialEq)]
106pub struct VerifiedResourceValue {
107 pub root_name: String,
108 pub name_hash: NameHash,
109 pub value: Option<Vec<u8>>,
110 pub secure: bool,
111 pub anchor: Option<ResourceValueAnchor>,
112}
113
114#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
115pub struct ResourceValueAnchor {
116 pub tree_root: Hash,
117 pub height: Height,
118}
119
120#[derive(Debug, Error, Eq, PartialEq)]
121pub enum ResolverError {
122 #[error("HNS proof is unavailable")]
123 ProofUnavailable,
124 #[error("HNS name is invalid: {0}")]
125 InvalidName(#[from] NameHashError),
126 #[error("HNS proof payload does not match requested name")]
127 ProofNameMismatch,
128 #[error("HNS name does not exist")]
129 NameNotFound,
130 #[error("local HNS chain is not current enough to determine current name state")]
131 LocalChainNotCurrent,
132 #[error("DNSSEC validation failed")]
133 DnssecFailed,
134 #[error("DNSSEC validation of an HNS P2P relay response failed")]
135 RelayDnssecFailed,
136 #[error("transparent port 53 interception was confirmed")]
137 Port53InterceptionDetected,
138 #[error("HNS resource payload is invalid: {0}")]
139 InvalidResource(#[from] ResourceError),
140 #[error("resolver backend is not implemented")]
141 UnsupportedBackend,
142 #[error("HNS delegation has no usable nameserver address")]
143 NoNameserverAddress,
144 #[error("delegated DNS endpoint is not publicly routable")]
145 NonPublicDnsEndpoint,
146 #[error("authoritative DoH port {0} is blocked by browser network policy")]
147 UnsafeAuthoritativeDohPort(u16),
148 #[error("DNS transport failed: {0}")]
149 DnsTransport(String),
150 #[error("DNS response returned rcode {0}")]
151 DnsResponseCode(u8),
152 #[error("DNS response is invalid")]
153 InvalidDnsResponse,
154 #[error("HNS authoritative DoH discovery record is invalid")]
155 InvalidAuthoritativeDoh,
156 #[error("resolver cache lock is poisoned")]
157 CachePoisoned,
158 #[error("resolver storage error: {0}")]
159 Storage(String),
160 #[error("dual-root namespace input is invalid: {0}")]
161 NamespaceValidation(#[from] NamespaceValidationError),
162 #[error("dual-root namespace classification failed: {0}")]
163 NamespaceClassification(#[from] NamespaceClassificationError),
164 #[error("neither namespace has a usable origin plan")]
165 NamespaceUnavailable,
166}
167
168pub trait Resolver {
169 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError>;
170
171 fn prepare_namespace_resolution(
174 &self,
175 _query: &OriginQuery,
176 ) -> Result<Option<PreparedNamespaceResolution>, ResolverError> {
177 Ok(None)
178 }
179}
180
181pub trait DelegatedResolver {
182 fn resolve_delegated(
183 &self,
184 request: &ResolutionRequest,
185 delegation: &HnsDelegation,
186 ) -> Result<ResolutionAnswer, ResolverError>;
187}
188
189impl<R: Resolver> DelegatedResolver for R {
190 fn resolve_delegated(
191 &self,
192 request: &ResolutionRequest,
193 _delegation: &HnsDelegation,
194 ) -> Result<ResolutionAnswer, ResolverError> {
195 self.resolve(request)
196 }
197}
198
199pub trait HnsProofProvider {
200 fn prove_name(
201 &self,
202 root_name: &str,
203 name_hash: NameHash,
204 ) -> Result<ProvenNameRecords, ResolverError>;
205}
206
207pub trait HnsResourceValueProvider {
208 fn prove_resource_value(
209 &self,
210 root_name: &str,
211 name_hash: NameHash,
212 ) -> Result<VerifiedResourceValue, ResolverError>;
213}
214
215pub struct FailClosedResolver;
216
217pub struct CompositeResolver<H, I> {
218 hns: H,
219 icann: I,
220}
221
222pub struct ProofBackedResolver<P> {
223 proof_provider: P,
224}
225
226pub struct DelegatingResolver<P, D> {
227 proof_provider: P,
228 delegated_resolver: D,
229}
230
231#[derive(Clone, Debug, Eq, PartialEq)]
232pub struct HnsDelegation {
233 pub root_name: String,
234 pub owner: DnsName,
235 pub records: Vec<ResourceRecord>,
236}
237
238#[derive(Clone, Debug, Eq, PartialEq)]
239pub struct AuthoritativeDohEndpoint {
240 pub ns: DnsName,
241 pub host: String,
242 pub connect_addr: IpAddr,
243 pub port: u16,
244 pub path_and_query: String,
245 pub tls_authentication: AuthoritativeDohTlsAuthentication,
246}
247
248#[derive(Clone, Debug, Eq, PartialEq)]
249pub enum AuthoritativeDohTlsAuthentication {
250 WebPki,
251 HnsProofTlsa(Vec<TlsaRecord>),
252}
253
254#[derive(Clone, Copy, Debug, Eq, PartialEq)]
255pub struct DnsEndpointPolicy {
256 pub allow_non_public_addresses: bool,
257 pub allow_unsafe_doh_ports: bool,
258}
259
260impl DnsEndpointPolicy {
261 pub const fn strict() -> Self {
262 Self {
263 allow_non_public_addresses: false,
264 allow_unsafe_doh_ports: false,
265 }
266 }
267
268 pub const fn permissive() -> Self {
269 Self {
270 allow_non_public_addresses: true,
271 allow_unsafe_doh_ports: true,
272 }
273 }
274
275 pub const fn for_network(network: NetworkKind) -> Self {
276 match network {
277 NetworkKind::Mainnet | NetworkKind::Testnet => Self::strict(),
278 NetworkKind::Regtest => Self::permissive(),
279 }
280 }
281}
282
283impl Default for DnsEndpointPolicy {
284 fn default() -> Self {
285 Self::strict()
286 }
287}
288
289#[derive(Clone, Debug, Eq, PartialEq)]
290pub struct UdpTcpDnsTransport {
291 pub timeout: Duration,
292 pub max_udp_response_len: usize,
293 pub max_tcp_message_len: usize,
294 pub endpoint_policy: DnsEndpointPolicy,
295}
296
297pub struct SystemDnssecVerifier;
298
299pub struct AuthoritativeDnssecResolver<T = UdpTcpDnsTransport, V = SystemDnssecVerifier> {
300 transport: T,
301 verifier: V,
302 authoritative_doh_enabled: bool,
303 prefer_authoritative_doh: bool,
304 authoritative_doh_endpoint_cache: Mutex<HashMap<String, Vec<AuthoritativeDohEndpoint>>>,
305}
306
307pub trait DnsTransport {
308 fn endpoint_policy(&self) -> DnsEndpointPolicy {
309 DnsEndpointPolicy::strict()
310 }
311
312 fn exchange_udp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError>;
313
314 fn exchange_tcp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError>;
315
316 fn exchange_doh(
317 &self,
318 _endpoint: &AuthoritativeDohEndpoint,
319 _query: &[u8],
320 ) -> Result<Vec<u8>, ResolverError> {
321 Err(ResolverError::UnsupportedBackend)
322 }
323
324 fn probe_dns_interception(&self) -> DnsInterceptionStatus {
325 DnsInterceptionStatus::NotTested
326 }
327
328 fn dns_interception_status(&self) -> DnsInterceptionStatus {
329 DnsInterceptionStatus::NotTested
330 }
331
332 fn is_recursive_relay(&self) -> bool {
336 false
337 }
338}
339
340#[derive(Clone, Copy, Debug, Eq, PartialEq)]
341pub enum DnsInterceptionStatus {
342 NotTested,
343 NotDetected,
344 Detected,
345 Inconclusive,
346}
347
348pub struct DelegatedDnssecValidation<'a> {
349 pub dnskey_owner: &'a DnsName,
350 pub ds_rrset: &'a [ResourceRecord],
351 pub dnskey_rrset: &'a [ResourceRecord],
352 pub dnskey_rrsig_rrset: &'a [ResourceRecord],
353 pub target_rrset: &'a [ResourceRecord],
354 pub target_rrsig_rrset: &'a [ResourceRecord],
355}
356
357pub struct DelegatedDnssecNoDataValidation<'a> {
358 pub dnskey_owner: &'a DnsName,
359 pub ds_rrset: &'a [ResourceRecord],
360 pub dnskey_rrset: &'a [ResourceRecord],
361 pub dnskey_rrsig_rrset: &'a [ResourceRecord],
362 pub query_name: &'a DnsName,
363 pub query_type: RecordType,
364 pub nsec_rrset: &'a [ResourceRecord],
365 pub nsec_rrsig_rrset: &'a [ResourceRecord],
366 pub nsec3_rrset: &'a [ResourceRecord],
367 pub nsec3_rrsig_rrset: &'a [ResourceRecord],
368}
369
370pub struct DelegatedDnssecNameErrorValidation<'a> {
371 pub dnskey_owner: &'a DnsName,
372 pub ds_rrset: &'a [ResourceRecord],
373 pub dnskey_rrset: &'a [ResourceRecord],
374 pub dnskey_rrsig_rrset: &'a [ResourceRecord],
375 pub query_name: &'a DnsName,
376 pub closest_encloser: &'a DnsName,
377 pub nsec_rrset: &'a [ResourceRecord],
378 pub nsec_rrsig_rrset: &'a [ResourceRecord],
379 pub nsec3_rrset: &'a [ResourceRecord],
380 pub nsec3_rrsig_rrset: &'a [ResourceRecord],
381}
382
383pub struct DelegatedChildDnssecValidation<'a> {
384 pub parent_dnskey_owner: &'a DnsName,
385 pub parent_ds_rrset: &'a [ResourceRecord],
386 pub parent_dnskey_rrset: &'a [ResourceRecord],
387 pub parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
388 pub child_dnskey_owner: &'a DnsName,
389 pub child_ds_rrset: &'a [ResourceRecord],
390 pub child_ds_rrsig_rrset: &'a [ResourceRecord],
391 pub child_dnskey_rrset: &'a [ResourceRecord],
392 pub child_dnskey_rrsig_rrset: &'a [ResourceRecord],
393 pub target_rrset: &'a [ResourceRecord],
394 pub target_rrsig_rrset: &'a [ResourceRecord],
395}
396
397pub struct DelegatedChildDnssecNoDataValidation<'a> {
398 pub parent_dnskey_owner: &'a DnsName,
399 pub parent_ds_rrset: &'a [ResourceRecord],
400 pub parent_dnskey_rrset: &'a [ResourceRecord],
401 pub parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
402 pub child_dnskey_owner: &'a DnsName,
403 pub child_ds_rrset: &'a [ResourceRecord],
404 pub child_ds_rrsig_rrset: &'a [ResourceRecord],
405 pub child_dnskey_rrset: &'a [ResourceRecord],
406 pub child_dnskey_rrsig_rrset: &'a [ResourceRecord],
407 pub query_name: &'a DnsName,
408 pub query_type: RecordType,
409 pub nsec_rrset: &'a [ResourceRecord],
410 pub nsec_rrsig_rrset: &'a [ResourceRecord],
411 pub nsec3_rrset: &'a [ResourceRecord],
412 pub nsec3_rrsig_rrset: &'a [ResourceRecord],
413}
414
415pub struct DelegatedChildDnssecNameErrorValidation<'a> {
416 pub parent_dnskey_owner: &'a DnsName,
417 pub parent_ds_rrset: &'a [ResourceRecord],
418 pub parent_dnskey_rrset: &'a [ResourceRecord],
419 pub parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
420 pub child_dnskey_owner: &'a DnsName,
421 pub child_ds_rrset: &'a [ResourceRecord],
422 pub child_ds_rrsig_rrset: &'a [ResourceRecord],
423 pub child_dnskey_rrset: &'a [ResourceRecord],
424 pub child_dnskey_rrsig_rrset: &'a [ResourceRecord],
425 pub query_name: &'a DnsName,
426 pub closest_encloser: &'a DnsName,
427 pub nsec_rrset: &'a [ResourceRecord],
428 pub nsec_rrsig_rrset: &'a [ResourceRecord],
429 pub nsec3_rrset: &'a [ResourceRecord],
430 pub nsec3_rrsig_rrset: &'a [ResourceRecord],
431}
432
433pub trait DelegatedDnssecVerifier {
434 fn validate_positive_rrset(
435 &self,
436 input: DelegatedDnssecValidation<'_>,
437 ) -> Result<bool, ResolverError>;
438
439 fn validate_no_data(
440 &self,
441 input: DelegatedDnssecNoDataValidation<'_>,
442 ) -> Result<bool, ResolverError>;
443
444 fn validate_name_error(
445 &self,
446 _input: DelegatedDnssecNameErrorValidation<'_>,
447 ) -> Result<bool, ResolverError> {
448 Ok(false)
449 }
450
451 fn validate_child_positive_rrset(
452 &self,
453 input: DelegatedChildDnssecValidation<'_>,
454 ) -> Result<bool, ResolverError>;
455
456 fn validate_child_no_data(
457 &self,
458 input: DelegatedChildDnssecNoDataValidation<'_>,
459 ) -> Result<bool, ResolverError>;
460
461 fn validate_child_name_error(
462 &self,
463 _input: DelegatedChildDnssecNameErrorValidation<'_>,
464 ) -> Result<bool, ResolverError> {
465 Ok(false)
466 }
467}
468
469pub struct ResourceValueProofProvider<P> {
470 value_provider: P,
471}
472
473#[derive(Default)]
474pub struct MemoryResourceValueProvider {
475 values: Mutex<HashMap<(String, NameHash), VerifiedResourceValue>>,
476}
477
478pub struct SqliteResourceValueProvider {
479 connection: Mutex<Connection>,
480}
481
482#[derive(Clone, Debug, Eq, PartialEq)]
483pub struct ResourceValueCacheStats {
484 pub entries: usize,
485 pub value_bytes: usize,
486}
487
488pub struct CachedResolver<R> {
489 inner: R,
490 cache: Mutex<ExpiringLru<ResolutionRequest, CachedResolution>>,
491 ttl: Duration,
492}
493
494#[derive(Clone, Debug, Eq, PartialEq)]
495enum CachedResolution {
496 Answer(ResolutionAnswer),
497 NameNotFound,
498}
499
500impl VerifiedResourceValue {
501 pub fn inclusion(root_name: String, name_hash: NameHash, value: Vec<u8>) -> Self {
502 Self {
503 root_name,
504 name_hash,
505 value: Some(value),
506 secure: true,
507 anchor: None,
508 }
509 }
510
511 pub fn non_inclusion(root_name: String, name_hash: NameHash) -> Self {
512 Self {
513 root_name,
514 name_hash,
515 value: None,
516 secure: true,
517 anchor: None,
518 }
519 }
520
521 pub fn with_anchor(mut self, tree_root: Hash, height: Height) -> Self {
522 self.anchor = Some(ResourceValueAnchor { tree_root, height });
523 self
524 }
525}
526
527impl ProvenNameRecords {
528 pub fn from_resource_value(
529 root_name: String,
530 name_hash: NameHash,
531 value: &[u8],
532 ) -> Result<Self, ResolverError> {
533 let owner =
534 DnsName::from_ascii(&root_name).map_err(|_| ResolverError::UnsupportedBackend)?;
535 let records = decode_handshake_resource_records(&owner, value)?;
536 Ok(Self {
537 root_name,
538 name_hash,
539 records,
540 secure: true,
541 exists: true,
542 })
543 }
544
545 pub fn from_verified_resource_value(
546 verified: VerifiedResourceValue,
547 ) -> Result<Self, ResolverError> {
548 let exists = verified.value.is_some();
549 let records = match verified.value {
550 Some(value) => {
551 let owner = DnsName::from_ascii(&verified.root_name)
552 .map_err(|_| ResolverError::UnsupportedBackend)?;
553 decode_handshake_resource_records(&owner, &value)?
554 }
555 None => Vec::new(),
556 };
557
558 Ok(Self {
559 root_name: verified.root_name,
560 name_hash: verified.name_hash,
561 records,
562 secure: verified.secure,
563 exists,
564 })
565 }
566}
567
568impl Resolver for FailClosedResolver {
569 fn resolve(&self, _request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
570 Err(ResolverError::UnsupportedBackend)
571 }
572}
573
574impl<H, I> CompositeResolver<H, I> {
575 pub fn new(hns: H, icann: I) -> Self {
576 Self { hns, icann }
577 }
578
579 pub fn into_parts(self) -> (H, I) {
580 (self.hns, self.icann)
581 }
582}
583
584impl<H, I> Resolver for CompositeResolver<H, I>
585where
586 H: Resolver,
587 I: Resolver,
588{
589 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
590 match classify_name(&request.qname) {
591 NameClass::Hns => self.hns.resolve(request),
592 NameClass::Icann => self.icann.resolve(request),
593 NameClass::Search => Err(ResolverError::UnsupportedBackend),
594 }
595 }
596}
597
598impl Default for UdpTcpDnsTransport {
599 fn default() -> Self {
600 Self {
601 timeout: Duration::from_secs(3),
602 max_udp_response_len: DEFAULT_DNS_UDP_PAYLOAD,
603 max_tcp_message_len: DEFAULT_DNS_TCP_MAX_MESSAGE_LEN,
604 endpoint_policy: DnsEndpointPolicy::strict(),
605 }
606 }
607}
608
609impl DnsTransport for UdpTcpDnsTransport {
610 fn endpoint_policy(&self) -> DnsEndpointPolicy {
611 self.endpoint_policy
612 }
613
614 fn exchange_udp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
615 validate_dns_server(self.endpoint_policy, server)?;
616 let bind_addr = match server {
617 SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
618 SocketAddr::V6(_) => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
619 };
620 let socket = UdpSocket::bind(bind_addr)
621 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
622 socket
623 .set_read_timeout(Some(self.timeout))
624 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
625 socket
626 .set_write_timeout(Some(self.timeout))
627 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
628 socket
629 .send_to(query, server)
630 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
631
632 let mut response = vec![0u8; self.max_udp_response_len];
633 let (len, source) = socket
634 .recv_from(&mut response)
635 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
636 if source != server {
637 return Err(ResolverError::InvalidDnsResponse);
638 }
639 response.truncate(len);
640 Ok(response)
641 }
642
643 fn exchange_tcp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
644 validate_dns_server(self.endpoint_policy, server)?;
645 if query.len() > u16::MAX as usize {
646 return Err(ResolverError::InvalidDnsResponse);
647 }
648
649 let mut stream = TcpStream::connect_timeout(&server, self.timeout)
650 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
651 stream
652 .set_read_timeout(Some(self.timeout))
653 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
654 stream
655 .set_write_timeout(Some(self.timeout))
656 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
657
658 stream
659 .write_all(&(query.len() as u16).to_be_bytes())
660 .and_then(|_| stream.write_all(query))
661 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
662
663 let mut length = [0u8; 2];
664 stream
665 .read_exact(&mut length)
666 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
667 let length = u16::from_be_bytes(length) as usize;
668 if length > self.max_tcp_message_len {
669 return Err(ResolverError::InvalidDnsResponse);
670 }
671
672 let mut response = vec![0u8; length];
673 stream
674 .read_exact(&mut response)
675 .map_err(|error| ResolverError::DnsTransport(error.to_string()))?;
676 Ok(response)
677 }
678}
679
680impl DelegatedDnssecVerifier for SystemDnssecVerifier {
681 fn validate_positive_rrset(
682 &self,
683 input: DelegatedDnssecValidation<'_>,
684 ) -> Result<bool, ResolverError> {
685 let now = SystemTime::now()
686 .duration_since(UNIX_EPOCH)
687 .map_err(|_| ResolverError::DnssecFailed)?
688 .as_secs();
689 let status = validate_signed_rrset(SignedRrsetValidationInput {
690 dnskey_owner: input.dnskey_owner,
691 ds_rrset: input.ds_rrset,
692 dnskey_rrset: input.dnskey_rrset,
693 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
694 rrset: input.target_rrset,
695 rrsig_rrset: input.target_rrsig_rrset,
696 now: DnssecTime(now),
697 })
698 .map_err(|_| ResolverError::DnssecFailed)?;
699
700 Ok(status == DnssecStatus::Secure)
701 }
702
703 fn validate_no_data(
704 &self,
705 input: DelegatedDnssecNoDataValidation<'_>,
706 ) -> Result<bool, ResolverError> {
707 let now = SystemTime::now()
708 .duration_since(UNIX_EPOCH)
709 .map_err(|_| ResolverError::DnssecFailed)?
710 .as_secs();
711 let now = DnssecTime(now);
712 let dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
713 dnskey_owner: input.dnskey_owner,
714 ds_rrset: input.ds_rrset,
715 dnskey_rrset: input.dnskey_rrset,
716 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
717 rrset: input.dnskey_rrset,
718 rrsig_rrset: input.dnskey_rrsig_rrset,
719 now,
720 })
721 .map_err(|_| ResolverError::DnssecFailed)?;
722 if dnskey_status != DnssecStatus::Secure {
723 return Ok(false);
724 }
725
726 if !input.nsec_rrset.is_empty() {
727 let status = validate_nsec_no_data(NsecNoDataValidationInput {
728 signer_name: input.dnskey_owner,
729 dnskey_rrset: input.dnskey_rrset,
730 query_name: input.query_name,
731 query_type: input.query_type,
732 nsec_rrset: input.nsec_rrset,
733 nsec_rrsig_rrset: input.nsec_rrsig_rrset,
734 now,
735 })
736 .map_err(|_| ResolverError::DnssecFailed)?;
737 if status == DnssecStatus::Secure {
738 return Ok(true);
739 }
740 }
741
742 if !input.nsec3_rrset.is_empty() {
743 let status = validate_nsec3_no_data(Nsec3NoDataValidationInput {
744 signer_name: input.dnskey_owner,
745 dnskey_rrset: input.dnskey_rrset,
746 query_name: input.query_name,
747 query_type: input.query_type,
748 nsec3_rrset: input.nsec3_rrset,
749 nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
750 now,
751 })
752 .map_err(|_| ResolverError::DnssecFailed)?;
753 if status == DnssecStatus::Secure {
754 return Ok(true);
755 }
756 }
757
758 Ok(false)
759 }
760
761 fn validate_name_error(
762 &self,
763 input: DelegatedDnssecNameErrorValidation<'_>,
764 ) -> Result<bool, ResolverError> {
765 let now = SystemTime::now()
766 .duration_since(UNIX_EPOCH)
767 .map_err(|_| ResolverError::DnssecFailed)?
768 .as_secs();
769 let now = DnssecTime(now);
770 let dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
771 dnskey_owner: input.dnskey_owner,
772 ds_rrset: input.ds_rrset,
773 dnskey_rrset: input.dnskey_rrset,
774 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
775 rrset: input.dnskey_rrset,
776 rrsig_rrset: input.dnskey_rrsig_rrset,
777 now,
778 })
779 .map_err(|_| ResolverError::DnssecFailed)?;
780 if dnskey_status != DnssecStatus::Secure {
781 return Ok(false);
782 }
783
784 if !input.nsec_rrset.is_empty() {
785 let status = validate_nsec_name_error(NsecNameErrorValidationInput {
786 signer_name: input.dnskey_owner,
787 dnskey_rrset: input.dnskey_rrset,
788 query_name: input.query_name,
789 closest_encloser: input.closest_encloser,
790 covering_nsec_rrset: input.nsec_rrset,
791 covering_nsec_rrsig_rrset: input.nsec_rrsig_rrset,
792 wildcard_nsec_rrset: input.nsec_rrset,
793 wildcard_nsec_rrsig_rrset: input.nsec_rrsig_rrset,
794 now,
795 })
796 .map_err(|_| ResolverError::DnssecFailed)?;
797 if status == DnssecStatus::Secure {
798 return Ok(true);
799 }
800 }
801
802 if !input.nsec3_rrset.is_empty() {
803 let status = validate_nsec3_name_error(Nsec3NameErrorValidationInput {
804 signer_name: input.dnskey_owner,
805 dnskey_rrset: input.dnskey_rrset,
806 query_name: input.query_name,
807 closest_encloser: input.closest_encloser,
808 closest_encloser_nsec3_rrset: input.nsec3_rrset,
809 closest_encloser_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
810 next_closer_nsec3_rrset: input.nsec3_rrset,
811 next_closer_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
812 wildcard_nsec3_rrset: input.nsec3_rrset,
813 wildcard_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
814 now,
815 })
816 .map_err(|_| ResolverError::DnssecFailed)?;
817 if status == DnssecStatus::Secure {
818 return Ok(true);
819 }
820 }
821
822 Ok(false)
823 }
824
825 fn validate_child_positive_rrset(
826 &self,
827 input: DelegatedChildDnssecValidation<'_>,
828 ) -> Result<bool, ResolverError> {
829 let now = SystemTime::now()
830 .duration_since(UNIX_EPOCH)
831 .map_err(|_| ResolverError::DnssecFailed)?
832 .as_secs();
833 let link = DnssecChainLink {
834 child_dnskey_owner: input.child_dnskey_owner,
835 ds_rrset: input.child_ds_rrset,
836 ds_rrsig_rrset: input.child_ds_rrsig_rrset,
837 child_dnskey_rrset: input.child_dnskey_rrset,
838 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
839 };
840 let status = validate_dnssec_chain(DnssecChainValidationInput {
841 initial_dnskey_owner: input.parent_dnskey_owner,
842 initial_ds_rrset: input.parent_ds_rrset,
843 initial_dnskey_rrset: input.parent_dnskey_rrset,
844 initial_dnskey_rrsig_rrset: input.parent_dnskey_rrsig_rrset,
845 delegation_links: &[link],
846 target_rrset: input.target_rrset,
847 target_rrsig_rrset: input.target_rrsig_rrset,
848 now: DnssecTime(now),
849 })
850 .map_err(|_| ResolverError::DnssecFailed)?;
851
852 Ok(status == DnssecStatus::Secure)
853 }
854
855 fn validate_child_no_data(
856 &self,
857 input: DelegatedChildDnssecNoDataValidation<'_>,
858 ) -> Result<bool, ResolverError> {
859 let now = SystemTime::now()
860 .duration_since(UNIX_EPOCH)
861 .map_err(|_| ResolverError::DnssecFailed)?
862 .as_secs();
863 let now = DnssecTime(now);
864 let parent_dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
865 dnskey_owner: input.parent_dnskey_owner,
866 ds_rrset: input.parent_ds_rrset,
867 dnskey_rrset: input.parent_dnskey_rrset,
868 dnskey_rrsig_rrset: input.parent_dnskey_rrsig_rrset,
869 rrset: input.parent_dnskey_rrset,
870 rrsig_rrset: input.parent_dnskey_rrsig_rrset,
871 now,
872 })
873 .map_err(|_| ResolverError::DnssecFailed)?;
874 if parent_dnskey_status != DnssecStatus::Secure {
875 return Ok(false);
876 }
877
878 let child_ds_status = validate_rrset_signature(
879 input.parent_dnskey_owner,
880 input.parent_dnskey_rrset,
881 input.child_ds_rrset,
882 input.child_ds_rrsig_rrset,
883 now,
884 )
885 .map_err(|_| ResolverError::DnssecFailed)?;
886 if child_ds_status != DnssecStatus::Secure {
887 return Ok(false);
888 }
889
890 let child_dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
891 dnskey_owner: input.child_dnskey_owner,
892 ds_rrset: input.child_ds_rrset,
893 dnskey_rrset: input.child_dnskey_rrset,
894 dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
895 rrset: input.child_dnskey_rrset,
896 rrsig_rrset: input.child_dnskey_rrsig_rrset,
897 now,
898 })
899 .map_err(|_| ResolverError::DnssecFailed)?;
900 if child_dnskey_status != DnssecStatus::Secure {
901 return Ok(false);
902 }
903
904 if !input.nsec_rrset.is_empty() {
905 let status = validate_nsec_no_data(NsecNoDataValidationInput {
906 signer_name: input.child_dnskey_owner,
907 dnskey_rrset: input.child_dnskey_rrset,
908 query_name: input.query_name,
909 query_type: input.query_type,
910 nsec_rrset: input.nsec_rrset,
911 nsec_rrsig_rrset: input.nsec_rrsig_rrset,
912 now,
913 })
914 .map_err(|_| ResolverError::DnssecFailed)?;
915 if status == DnssecStatus::Secure {
916 return Ok(true);
917 }
918 }
919
920 if !input.nsec3_rrset.is_empty() {
921 let status = validate_nsec3_no_data(Nsec3NoDataValidationInput {
922 signer_name: input.child_dnskey_owner,
923 dnskey_rrset: input.child_dnskey_rrset,
924 query_name: input.query_name,
925 query_type: input.query_type,
926 nsec3_rrset: input.nsec3_rrset,
927 nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
928 now,
929 })
930 .map_err(|_| ResolverError::DnssecFailed)?;
931 if status == DnssecStatus::Secure {
932 return Ok(true);
933 }
934 }
935
936 Ok(false)
937 }
938
939 fn validate_child_name_error(
940 &self,
941 input: DelegatedChildDnssecNameErrorValidation<'_>,
942 ) -> Result<bool, ResolverError> {
943 let now = SystemTime::now()
944 .duration_since(UNIX_EPOCH)
945 .map_err(|_| ResolverError::DnssecFailed)?
946 .as_secs();
947 let now = DnssecTime(now);
948 let parent_dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
949 dnskey_owner: input.parent_dnskey_owner,
950 ds_rrset: input.parent_ds_rrset,
951 dnskey_rrset: input.parent_dnskey_rrset,
952 dnskey_rrsig_rrset: input.parent_dnskey_rrsig_rrset,
953 rrset: input.parent_dnskey_rrset,
954 rrsig_rrset: input.parent_dnskey_rrsig_rrset,
955 now,
956 })
957 .map_err(|_| ResolverError::DnssecFailed)?;
958 if parent_dnskey_status != DnssecStatus::Secure {
959 return Ok(false);
960 }
961
962 let child_ds_status = validate_rrset_signature(
963 input.parent_dnskey_owner,
964 input.parent_dnskey_rrset,
965 input.child_ds_rrset,
966 input.child_ds_rrsig_rrset,
967 now,
968 )
969 .map_err(|_| ResolverError::DnssecFailed)?;
970 if child_ds_status != DnssecStatus::Secure {
971 return Ok(false);
972 }
973
974 let child_dnskey_status = validate_signed_rrset(SignedRrsetValidationInput {
975 dnskey_owner: input.child_dnskey_owner,
976 ds_rrset: input.child_ds_rrset,
977 dnskey_rrset: input.child_dnskey_rrset,
978 dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
979 rrset: input.child_dnskey_rrset,
980 rrsig_rrset: input.child_dnskey_rrsig_rrset,
981 now,
982 })
983 .map_err(|_| ResolverError::DnssecFailed)?;
984 if child_dnskey_status != DnssecStatus::Secure {
985 return Ok(false);
986 }
987
988 if !input.nsec_rrset.is_empty() {
989 let status = validate_nsec_name_error(NsecNameErrorValidationInput {
990 signer_name: input.child_dnskey_owner,
991 dnskey_rrset: input.child_dnskey_rrset,
992 query_name: input.query_name,
993 closest_encloser: input.closest_encloser,
994 covering_nsec_rrset: input.nsec_rrset,
995 covering_nsec_rrsig_rrset: input.nsec_rrsig_rrset,
996 wildcard_nsec_rrset: input.nsec_rrset,
997 wildcard_nsec_rrsig_rrset: input.nsec_rrsig_rrset,
998 now,
999 })
1000 .map_err(|_| ResolverError::DnssecFailed)?;
1001 if status == DnssecStatus::Secure {
1002 return Ok(true);
1003 }
1004 }
1005
1006 if !input.nsec3_rrset.is_empty() {
1007 let status = validate_nsec3_name_error(Nsec3NameErrorValidationInput {
1008 signer_name: input.child_dnskey_owner,
1009 dnskey_rrset: input.child_dnskey_rrset,
1010 query_name: input.query_name,
1011 closest_encloser: input.closest_encloser,
1012 closest_encloser_nsec3_rrset: input.nsec3_rrset,
1013 closest_encloser_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
1014 next_closer_nsec3_rrset: input.nsec3_rrset,
1015 next_closer_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
1016 wildcard_nsec3_rrset: input.nsec3_rrset,
1017 wildcard_nsec3_rrsig_rrset: input.nsec3_rrsig_rrset,
1018 now,
1019 })
1020 .map_err(|_| ResolverError::DnssecFailed)?;
1021 if status == DnssecStatus::Secure {
1022 return Ok(true);
1023 }
1024 }
1025
1026 Ok(false)
1027 }
1028}
1029
1030impl<T, V> AuthoritativeDnssecResolver<T, V> {
1031 pub fn new(transport: T, verifier: V) -> Self {
1032 Self {
1033 transport,
1034 verifier,
1035 authoritative_doh_enabled: true,
1036 prefer_authoritative_doh: false,
1037 authoritative_doh_endpoint_cache: Mutex::new(HashMap::new()),
1038 }
1039 }
1040
1041 pub fn with_authoritative_doh_preferred(mut self) -> Self {
1042 self.prefer_authoritative_doh = true;
1043 self
1044 }
1045
1046 pub fn without_authoritative_doh(mut self) -> Self {
1051 self.authoritative_doh_enabled = false;
1052 self.prefer_authoritative_doh = false;
1053 self
1054 }
1055
1056 pub fn into_parts(self) -> (T, V) {
1057 (self.transport, self.verifier)
1058 }
1059
1060 fn authoritative_doh_endpoints(
1061 &self,
1062 delegation: &HnsDelegation,
1063 ) -> Result<Vec<AuthoritativeDohEndpoint>, ResolverError>
1064 where
1065 T: DnsTransport,
1066 V: DelegatedDnssecVerifier,
1067 {
1068 let cache_key = authoritative_doh_cache_key(delegation);
1069 if let Some(cached) = self
1070 .authoritative_doh_endpoint_cache
1071 .lock()
1072 .ok()
1073 .and_then(|cache| cache.get(&cache_key).cloned())
1074 {
1075 return Ok(cached);
1076 }
1077
1078 let endpoints = authoritative_doh_endpoints(&self.transport, &self.verifier, delegation)?;
1079 if let Ok(mut cache) = self.authoritative_doh_endpoint_cache.lock() {
1080 cache.insert(cache_key, endpoints.clone());
1081 }
1082 Ok(endpoints)
1083 }
1084}
1085
1086impl Default for AuthoritativeDnssecResolver {
1087 fn default() -> Self {
1088 Self::new(UdpTcpDnsTransport::default(), SystemDnssecVerifier)
1089 }
1090}
1091
1092impl<T, V> DelegatedResolver for AuthoritativeDnssecResolver<T, V>
1093where
1094 T: DnsTransport,
1095 V: DelegatedDnssecVerifier,
1096{
1097 fn resolve_delegated(
1098 &self,
1099 request: &ResolutionRequest,
1100 delegation: &HnsDelegation,
1101 ) -> Result<ResolutionAnswer, ResolverError> {
1102 if request.qtype == u16::MAX {
1103 return Err(ResolverError::UnsupportedBackend);
1104 }
1105
1106 let request_name =
1107 DnsName::from_ascii(&request.qname).map_err(|_| ResolverError::UnsupportedBackend)?;
1108 let qtype = RecordType::from_code(request.qtype);
1109 let servers = nameserver_addresses(delegation);
1110 if servers.is_empty() {
1111 return Err(ResolverError::NoNameserverAddress);
1112 }
1113
1114 let ds_rrset = records_for(&delegation.records, &delegation.owner, RecordType::Ds);
1115 let mut last_error = None;
1116 if self.authoritative_doh_enabled && self.prefer_authoritative_doh {
1117 match self.authoritative_doh_endpoints(delegation) {
1118 Ok(endpoints) => {
1119 for endpoint in endpoints {
1120 match resolve_delegated_from_doh_endpoint(
1121 &self.transport,
1122 &self.verifier,
1123 &endpoint,
1124 delegation,
1125 &request_name,
1126 qtype,
1127 &ds_rrset,
1128 ) {
1129 Ok(answer) => return Ok(answer),
1130 Err(error) => retain_strongest_resolution_error(&mut last_error, error),
1131 }
1132 }
1133 }
1134 Err(error) => retain_strongest_resolution_error(&mut last_error, error),
1135 }
1136 }
1137
1138 if self.transport.is_recursive_relay() {
1139 let server = servers
1140 .iter()
1141 .copied()
1142 .find(|server| {
1143 validate_dns_server(self.transport.endpoint_policy(), *server).is_ok()
1144 })
1145 .ok_or(ResolverError::NoNameserverAddress)?;
1146 return resolve_delegated_from_server_target(
1147 &self.transport,
1148 &self.verifier,
1149 server,
1150 DnsQueryTarget::Server(server),
1151 delegation,
1152 &request_name,
1153 qtype,
1154 &ds_rrset,
1155 );
1156 } else if self.transport.dns_interception_status() == DnsInterceptionStatus::Detected {
1157 last_error = Some(ResolverError::Port53InterceptionDetected);
1158 } else {
1159 for server in servers {
1160 match resolve_delegated_from_server(
1161 &self.transport,
1162 &self.verifier,
1163 server,
1164 delegation,
1165 &request_name,
1166 qtype,
1167 &ds_rrset,
1168 ) {
1169 Ok(answer) => return Ok(answer),
1170 Err(ResolverError::Port53InterceptionDetected) => {
1171 retain_strongest_resolution_error(
1172 &mut last_error,
1173 ResolverError::Port53InterceptionDetected,
1174 );
1175 break;
1176 }
1177 Err(error) => retain_strongest_resolution_error(&mut last_error, error),
1178 }
1179 }
1180 }
1181
1182 if self.authoritative_doh_enabled && !self.prefer_authoritative_doh {
1183 match self.authoritative_doh_endpoints(delegation) {
1184 Ok(endpoints) => {
1185 for endpoint in endpoints {
1186 match resolve_delegated_from_doh_endpoint(
1187 &self.transport,
1188 &self.verifier,
1189 &endpoint,
1190 delegation,
1191 &request_name,
1192 qtype,
1193 &ds_rrset,
1194 ) {
1195 Ok(answer) => return Ok(answer),
1196 Err(error) => retain_strongest_resolution_error(&mut last_error, error),
1197 }
1198 }
1199 }
1200 Err(error) => retain_strongest_resolution_error(&mut last_error, error),
1201 }
1202 }
1203
1204 self.transport.probe_dns_interception();
1205 Err(last_error.unwrap_or(ResolverError::NoNameserverAddress))
1206 }
1207}
1208
1209fn retain_strongest_resolution_error(
1210 current: &mut Option<ResolverError>,
1211 candidate: ResolverError,
1212) {
1213 let candidate_priority = resolution_error_priority(&candidate);
1214 if current
1215 .as_ref()
1216 .is_none_or(|error| candidate_priority >= resolution_error_priority(error))
1217 {
1218 *current = Some(candidate);
1219 }
1220}
1221
1222fn strongest_resolution_error(first: ResolverError, second: ResolverError) -> ResolverError {
1223 let mut strongest = Some(first);
1224 retain_strongest_resolution_error(&mut strongest, second);
1225 strongest.expect("a seeded strongest resolution error must remain present")
1226}
1227
1228fn resolution_error_priority(error: &ResolverError) -> u8 {
1229 match error {
1230 ResolverError::DnsTransport(_) => 0,
1235 ResolverError::Port53InterceptionDetected => 1,
1236 _ => 2,
1237 }
1238}
1239
1240impl<P> ProofBackedResolver<P> {
1241 pub fn new(proof_provider: P) -> Self {
1242 Self { proof_provider }
1243 }
1244
1245 pub fn into_inner(self) -> P {
1246 self.proof_provider
1247 }
1248}
1249
1250impl<P: HnsProofProvider> Resolver for ProofBackedResolver<P> {
1251 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
1252 let request_name =
1253 DnsName::from_ascii(&request.qname).map_err(|_| ResolverError::UnsupportedBackend)?;
1254 let root_name = hns_root_label(&request.qname)?;
1255 let name_hash = NameHash::from_name(&root_name)?;
1256 let proven = self.proof_provider.prove_name(&root_name, name_hash)?;
1257 if proven.root_name != root_name || proven.name_hash != name_hash || !proven.secure {
1258 return Err(ResolverError::ProofNameMismatch);
1259 }
1260 if !proven.exists {
1261 return Err(ResolverError::NameNotFound);
1262 }
1263
1264 let records = filter_records(proven.records, &request_name, request.qtype);
1265
1266 Ok(ResolutionAnswer {
1267 name: request_name,
1268 records,
1269 secure: true,
1270 })
1271 }
1272}
1273
1274impl<P, D> DelegatingResolver<P, D> {
1275 pub fn new(proof_provider: P, delegated_resolver: D) -> Self {
1276 Self {
1277 proof_provider,
1278 delegated_resolver,
1279 }
1280 }
1281
1282 pub fn into_parts(self) -> (P, D) {
1283 (self.proof_provider, self.delegated_resolver)
1284 }
1285}
1286
1287impl<P, D> Resolver for DelegatingResolver<P, D>
1288where
1289 P: HnsProofProvider,
1290 D: DelegatedResolver,
1291{
1292 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
1293 let request_name =
1294 DnsName::from_ascii(&request.qname).map_err(|_| ResolverError::UnsupportedBackend)?;
1295 let root_name = hns_root_label(&request.qname)?;
1296 let root_owner =
1297 DnsName::from_ascii(&root_name).map_err(|_| ResolverError::UnsupportedBackend)?;
1298 let name_hash = NameHash::from_name(&root_name)?;
1299 let proven = self.proof_provider.prove_name(&root_name, name_hash)?;
1300 if proven.root_name != root_name || proven.name_hash != name_hash || !proven.secure {
1301 return Err(ResolverError::ProofNameMismatch);
1302 }
1303 if !proven.exists {
1304 return Err(ResolverError::NameNotFound);
1305 }
1306 let mut delegation_records = proven.records.clone();
1307
1308 let direct_records =
1309 filter_records(delegation_records.clone(), &request_name, request.qtype);
1310 if (request_name == root_owner && !direct_records.is_empty())
1311 || root_records_answer_request(&request_name, &root_owner, request.qtype)
1312 || !has_owner_record(&delegation_records, &root_owner, RecordType::Ns)
1313 {
1314 return Ok(ResolutionAnswer {
1315 name: request_name.clone(),
1316 records: direct_records,
1317 secure: true,
1318 });
1319 }
1320
1321 hydrate_hns_nameserver_addresses(
1322 &self.proof_provider,
1323 &root_owner,
1324 &mut delegation_records,
1325 )?;
1326 let delegation = HnsDelegation {
1327 root_name: root_name.clone(),
1328 owner: root_owner.clone(),
1329 records: delegation_records.clone(),
1330 };
1331
1332 let has_secure_delegation =
1333 has_owner_record(&delegation_records, &root_owner, RecordType::Ds);
1334 let mut delegated = match self
1335 .delegated_resolver
1336 .resolve_delegated(request, &delegation)
1337 {
1338 Ok(answer) => answer,
1339 Err(ResolverError::NameNotFound) if !has_secure_delegation => {
1340 return Err(ResolverError::DnssecFailed);
1341 }
1342 Err(error) => return Err(error),
1343 };
1344 if !has_secure_delegation {
1345 delegated.secure = false;
1346 return Ok(delegated);
1347 }
1348 if !delegated.secure {
1349 return Err(ResolverError::DnssecFailed);
1350 }
1351
1352 Ok(delegated)
1353 }
1354}
1355
1356fn hydrate_hns_nameserver_addresses<P: HnsProofProvider>(
1357 proof_provider: &P,
1358 delegation_owner: &DnsName,
1359 records: &mut Vec<ResourceRecord>,
1360) -> Result<(), ResolverError> {
1361 let ns_names = records
1362 .iter()
1363 .filter(|record| record.name == *delegation_owner && record.record_type == RecordType::Ns)
1364 .filter_map(record_name_rdata)
1365 .fold(Vec::<DnsName>::new(), |mut names, name| {
1366 if !names.contains(&name) {
1367 names.push(name);
1368 }
1369 names
1370 });
1371
1372 for ns_name in ns_names {
1373 if has_owner_record(records, &ns_name, RecordType::A)
1374 || has_owner_record(records, &ns_name, RecordType::Aaaa)
1375 {
1376 continue;
1377 }
1378
1379 let Some(ns_root) = ns_name.labels().last().cloned() else {
1380 continue;
1381 };
1382 let name_hash = match NameHash::from_name(&ns_root) {
1383 Ok(name_hash) => name_hash,
1384 Err(_) => continue,
1385 };
1386 let proven = match proof_provider.prove_name(&ns_root, name_hash) {
1387 Ok(proven) => proven,
1388 Err(ResolverError::ProofUnavailable) => continue,
1389 Err(error) => return Err(error),
1390 };
1391 if proven.root_name != ns_root || proven.name_hash != name_hash || !proven.secure {
1392 return Err(ResolverError::ProofNameMismatch);
1393 }
1394 if !proven.exists {
1395 continue;
1396 }
1397
1398 records.extend(proven.records.into_iter().filter(|record| {
1399 record.name == ns_name && matches!(record.record_type, RecordType::A | RecordType::Aaaa)
1400 }));
1401 }
1402
1403 Ok(())
1404}
1405
1406impl<P> ResourceValueProofProvider<P> {
1407 pub fn new(value_provider: P) -> Self {
1408 Self { value_provider }
1409 }
1410
1411 pub fn into_inner(self) -> P {
1412 self.value_provider
1413 }
1414}
1415
1416impl<P: HnsResourceValueProvider> HnsProofProvider for ResourceValueProofProvider<P> {
1417 fn prove_name(
1418 &self,
1419 root_name: &str,
1420 name_hash: NameHash,
1421 ) -> Result<ProvenNameRecords, ResolverError> {
1422 let verified = self
1423 .value_provider
1424 .prove_resource_value(root_name, name_hash)?;
1425 if verified.root_name != root_name || verified.name_hash != name_hash || !verified.secure {
1426 return Err(ResolverError::ProofNameMismatch);
1427 }
1428 ProvenNameRecords::from_verified_resource_value(verified)
1429 }
1430}
1431
1432impl MemoryResourceValueProvider {
1433 pub fn new() -> Self {
1434 Self::default()
1435 }
1436
1437 pub fn insert(&self, mut verified: VerifiedResourceValue) -> Result<(), ResolverError> {
1438 let root_name = normalize_verified_root(&verified.root_name)?;
1439 verified = normalize_verified_resource_value(verified)?;
1440 self.values
1441 .lock()
1442 .map_err(|_| ResolverError::CachePoisoned)?
1443 .insert((root_name, verified.name_hash), verified);
1444 Ok(())
1445 }
1446
1447 pub fn len(&self) -> Result<usize, ResolverError> {
1448 Ok(self
1449 .values
1450 .lock()
1451 .map_err(|_| ResolverError::CachePoisoned)?
1452 .len())
1453 }
1454
1455 pub fn is_empty(&self) -> Result<bool, ResolverError> {
1456 Ok(self.len()? == 0)
1457 }
1458}
1459
1460impl SqliteResourceValueProvider {
1461 pub fn open(path: impl AsRef<Path>) -> Result<Self, ResolverError> {
1462 let connection =
1463 Connection::open(path).map_err(|error| ResolverError::Storage(error.to_string()))?;
1464 Self::from_connection(connection)
1465 }
1466
1467 pub fn in_memory() -> Result<Self, ResolverError> {
1468 let connection = Connection::open_in_memory()
1469 .map_err(|error| ResolverError::Storage(error.to_string()))?;
1470 Self::from_connection(connection)
1471 }
1472
1473 pub fn from_connection(connection: Connection) -> Result<Self, ResolverError> {
1474 let provider = Self {
1475 connection: Mutex::new(connection),
1476 };
1477 provider.initialize()?;
1478 Ok(provider)
1479 }
1480
1481 pub fn insert(&self, verified: VerifiedResourceValue) -> Result<(), ResolverError> {
1482 let verified = normalize_verified_resource_value(verified)?;
1483 let value = verified.value.as_deref();
1484 let secure = if verified.secure { 1_i64 } else { 0_i64 };
1485 let proof_tree_root = verified
1486 .anchor
1487 .map(|anchor| anchor.tree_root.as_bytes().as_slice().to_vec());
1488 let proof_height = verified.anchor.map(|anchor| i64::from(anchor.height.0));
1489 self.connection
1490 .lock()
1491 .map_err(|_| ResolverError::CachePoisoned)?
1492 .execute(
1493 "
1494 INSERT INTO verified_resource_values(
1495 root_name,
1496 name_hash,
1497 value,
1498 secure,
1499 proof_tree_root,
1500 proof_height,
1501 updated_at_unix
1502 )
1503 VALUES (?1, ?2, ?3, ?4, ?5, ?6, unixepoch())
1504 ON CONFLICT(root_name, name_hash) DO UPDATE SET
1505 value = excluded.value,
1506 secure = excluded.secure,
1507 proof_tree_root = excluded.proof_tree_root,
1508 proof_height = excluded.proof_height,
1509 updated_at_unix = excluded.updated_at_unix
1510 ",
1511 params![
1512 verified.root_name.as_str(),
1513 verified.name_hash.as_hash().as_bytes().as_slice(),
1514 value,
1515 secure,
1516 proof_tree_root,
1517 proof_height,
1518 ],
1519 )
1520 .map_err(sqlite_error)?;
1521 Ok(())
1522 }
1523
1524 pub fn len(&self) -> Result<usize, ResolverError> {
1525 let count = self
1526 .connection
1527 .lock()
1528 .map_err(|_| ResolverError::CachePoisoned)?
1529 .query_row("SELECT COUNT(*) FROM verified_resource_values", [], |row| {
1530 row.get::<_, i64>(0)
1531 })
1532 .map_err(sqlite_error)?;
1533 usize::try_from(count).map_err(|error| ResolverError::Storage(error.to_string()))
1534 }
1535
1536 pub fn is_empty(&self) -> Result<bool, ResolverError> {
1537 Ok(self.len()? == 0)
1538 }
1539
1540 pub fn stats(&self) -> Result<ResourceValueCacheStats, ResolverError> {
1541 let connection = self
1542 .connection
1543 .lock()
1544 .map_err(|_| ResolverError::CachePoisoned)?;
1545 let (entries, value_bytes) = connection
1546 .query_row(
1547 "
1548 SELECT COUNT(*), COALESCE(SUM(COALESCE(length(value), 0)), 0)
1549 FROM verified_resource_values
1550 ",
1551 [],
1552 |row| {
1553 let entries: i64 = row.get(0)?;
1554 let value_bytes: i64 = row.get(1)?;
1555 Ok((entries, value_bytes))
1556 },
1557 )
1558 .map_err(sqlite_error)?;
1559
1560 Ok(ResourceValueCacheStats {
1561 entries: usize::try_from(entries)
1562 .map_err(|error| ResolverError::Storage(error.to_string()))?,
1563 value_bytes: usize::try_from(value_bytes)
1564 .map_err(|error| ResolverError::Storage(error.to_string()))?,
1565 })
1566 }
1567
1568 pub fn total_value_bytes(&self) -> Result<usize, ResolverError> {
1569 self.stats().map(|stats| stats.value_bytes)
1570 }
1571
1572 pub fn enforce_value_byte_limit(&self, max_bytes: usize) -> Result<usize, ResolverError> {
1573 let mut connection = self
1574 .connection
1575 .lock()
1576 .map_err(|_| ResolverError::CachePoisoned)?;
1577 let transaction = connection.transaction().map_err(sqlite_error)?;
1578 let mut total = total_value_bytes_in(&transaction)?;
1579 let mut removed = 0usize;
1580
1581 while total > max_bytes {
1582 let Some(entry) = oldest_resource_value_entry(&transaction)? else {
1583 break;
1584 };
1585
1586 transaction
1587 .execute(
1588 "
1589 DELETE FROM verified_resource_values
1590 WHERE root_name = ?1 AND name_hash = ?2
1591 ",
1592 params![entry.root_name, entry.name_hash.as_slice()],
1593 )
1594 .map_err(sqlite_error)?;
1595 total = total.saturating_sub(entry.value_bytes);
1596 removed = removed.saturating_add(1);
1597 }
1598
1599 transaction.commit().map_err(sqlite_error)?;
1600 Ok(removed)
1601 }
1602
1603 pub fn anchored_heights(&self) -> Result<Vec<Height>, ResolverError> {
1604 let connection = self
1605 .connection
1606 .lock()
1607 .map_err(|_| ResolverError::CachePoisoned)?;
1608 let mut statement = connection
1609 .prepare(
1610 "
1611 SELECT DISTINCT proof_height
1612 FROM verified_resource_values
1613 WHERE proof_tree_root IS NOT NULL AND proof_height IS NOT NULL
1614 ORDER BY proof_height DESC
1615 ",
1616 )
1617 .map_err(sqlite_error)?;
1618 let heights = statement
1619 .query_map([], |row| row.get::<_, i64>(0))
1620 .map_err(sqlite_error)?
1621 .map(|height| {
1622 let height = height.map_err(sqlite_error)?;
1623 let height = u32::try_from(height)
1624 .map_err(|error| ResolverError::Storage(error.to_string()))?;
1625 Ok(Height(height))
1626 })
1627 .collect::<Result<Vec<_>, ResolverError>>()?;
1628 Ok(heights)
1629 }
1630
1631 pub fn prune_invalid_anchors(
1632 &self,
1633 valid_anchors: &[ResourceValueAnchor],
1634 prune_unanchored: bool,
1635 ) -> Result<usize, ResolverError> {
1636 let valid_anchors = valid_anchors.iter().copied().collect::<BTreeSet<_>>();
1637 let mut connection = self
1638 .connection
1639 .lock()
1640 .map_err(|_| ResolverError::CachePoisoned)?;
1641 let transaction = connection.transaction().map_err(sqlite_error)?;
1642 let entries = resource_value_anchor_entries(&transaction)?;
1643 let mut removed = 0usize;
1644
1645 for entry in entries {
1646 let remove = match entry.anchor {
1647 Some(anchor) => !valid_anchors.contains(&anchor),
1648 None => prune_unanchored,
1649 };
1650 if !remove {
1651 continue;
1652 }
1653
1654 transaction
1655 .execute(
1656 "
1657 DELETE FROM verified_resource_values
1658 WHERE root_name = ?1 AND name_hash = ?2
1659 ",
1660 params![entry.root_name, entry.name_hash.as_slice()],
1661 )
1662 .map_err(sqlite_error)?;
1663 removed = removed.saturating_add(1);
1664 }
1665
1666 transaction.commit().map_err(sqlite_error)?;
1667 Ok(removed)
1668 }
1669
1670 pub fn clear(&self) -> Result<(), ResolverError> {
1671 self.connection
1672 .lock()
1673 .map_err(|_| ResolverError::CachePoisoned)?
1674 .execute("DELETE FROM verified_resource_values", [])
1675 .map_err(sqlite_error)?;
1676 Ok(())
1677 }
1678
1679 pub fn flush(self) -> Result<(), ResolverError> {
1680 let connection = self
1681 .connection
1682 .into_inner()
1683 .map_err(|_| ResolverError::CachePoisoned)?;
1684 connection
1685 .close()
1686 .map_err(|(_, error)| ResolverError::Storage(error.to_string()))
1687 }
1688
1689 fn initialize(&self) -> Result<(), ResolverError> {
1690 let connection = self
1691 .connection
1692 .lock()
1693 .map_err(|_| ResolverError::CachePoisoned)?;
1694 connection
1695 .execute_batch(
1696 "
1697 PRAGMA journal_mode = WAL;
1698 PRAGMA synchronous = NORMAL;
1699 PRAGMA foreign_keys = ON;
1700
1701 CREATE TABLE IF NOT EXISTS verified_resource_values (
1702 root_name TEXT NOT NULL,
1703 name_hash BLOB NOT NULL,
1704 value BLOB,
1705 secure INTEGER NOT NULL,
1706 proof_tree_root BLOB,
1707 proof_height INTEGER,
1708 updated_at_unix INTEGER NOT NULL,
1709 PRIMARY KEY(root_name, name_hash)
1710 );
1711 ",
1712 )
1713 .map_err(sqlite_error)?;
1714 ensure_sqlite_column(&connection, "proof_tree_root", "BLOB")?;
1715 ensure_sqlite_column(&connection, "proof_height", "INTEGER")?;
1716 connection
1717 .execute_batch(
1718 "
1719 CREATE INDEX IF NOT EXISTS verified_resource_values_by_anchor
1720 ON verified_resource_values(proof_height, proof_tree_root);
1721 ",
1722 )
1723 .map_err(sqlite_error)?;
1724 Ok(())
1725 }
1726}
1727
1728impl HnsResourceValueProvider for MemoryResourceValueProvider {
1729 fn prove_resource_value(
1730 &self,
1731 root_name: &str,
1732 name_hash: NameHash,
1733 ) -> Result<VerifiedResourceValue, ResolverError> {
1734 let root_name = normalize_verified_root(root_name)?;
1735 if name_hash != NameHash::from_name(&root_name)? {
1736 return Err(ResolverError::ProofNameMismatch);
1737 }
1738
1739 self.values
1740 .lock()
1741 .map_err(|_| ResolverError::CachePoisoned)?
1742 .get(&(root_name, name_hash))
1743 .cloned()
1744 .ok_or(ResolverError::ProofUnavailable)
1745 }
1746}
1747
1748impl HnsResourceValueProvider for SqliteResourceValueProvider {
1749 fn prove_resource_value(
1750 &self,
1751 root_name: &str,
1752 name_hash: NameHash,
1753 ) -> Result<VerifiedResourceValue, ResolverError> {
1754 let root_name = normalize_verified_root(root_name)?;
1755 if name_hash != NameHash::from_name(&root_name)? {
1756 return Err(ResolverError::ProofNameMismatch);
1757 }
1758
1759 self.connection
1760 .lock()
1761 .map_err(|_| ResolverError::CachePoisoned)?
1762 .query_row(
1763 "
1764 SELECT name_hash, value, secure, proof_tree_root, proof_height
1765 FROM verified_resource_values
1766 WHERE root_name = ?1 AND name_hash = ?2
1767 ",
1768 params![root_name, name_hash.as_hash().as_bytes().as_slice()],
1769 |row| {
1770 let hash_bytes: Vec<u8> = row.get(0)?;
1771 let value: Option<Vec<u8>> = row.get(1)?;
1772 let secure: i64 = row.get(2)?;
1773 let proof_tree_root: Option<Vec<u8>> = row.get(3)?;
1774 let proof_height: Option<i64> = row.get(4)?;
1775 let stored_hash = Hash::from_slice(&hash_bytes).map_err(|error| {
1776 rusqlite::Error::FromSqlConversionFailure(
1777 0,
1778 rusqlite::types::Type::Blob,
1779 Box::new(error),
1780 )
1781 })?;
1782 let anchor = sqlite_anchor(proof_tree_root, proof_height)?;
1783 Ok(VerifiedResourceValue {
1784 root_name: root_name.clone(),
1785 name_hash: NameHash::new(stored_hash),
1786 value,
1787 secure: secure != 0,
1788 anchor,
1789 })
1790 },
1791 )
1792 .optional()
1793 .map_err(sqlite_error)?
1794 .ok_or(ResolverError::ProofUnavailable)
1795 }
1796}
1797
1798impl<R> CachedResolver<R> {
1799 pub fn new(inner: R, max_entries: usize, ttl: Duration) -> Self {
1800 Self {
1801 inner,
1802 cache: Mutex::new(ExpiringLru::new(
1803 NonZeroUsize::new(max_entries).unwrap_or(NonZeroUsize::MIN),
1804 )),
1805 ttl,
1806 }
1807 }
1808
1809 pub fn into_inner(self) -> R {
1810 self.inner
1811 }
1812}
1813
1814impl<R: Resolver> Resolver for CachedResolver<R> {
1815 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
1816 if let Some(cached) = self
1817 .cache
1818 .lock()
1819 .map_err(|_| ResolverError::CachePoisoned)?
1820 .get(request)
1821 {
1822 return cached.into_result();
1823 }
1824
1825 match self.inner.resolve(request) {
1826 Ok(answer) => {
1827 let mut cache = self
1828 .cache
1829 .lock()
1830 .map_err(|_| ResolverError::CachePoisoned)?;
1831 if cache
1832 .insert(
1833 request.clone(),
1834 CachedResolution::Answer(answer.clone()),
1835 self.ttl,
1836 )
1837 .is_err()
1838 {
1839 cache.clear();
1840 }
1841 Ok(answer)
1842 }
1843 Err(ResolverError::NameNotFound) => {
1844 let mut cache = self
1845 .cache
1846 .lock()
1847 .map_err(|_| ResolverError::CachePoisoned)?;
1848 if cache
1849 .insert(request.clone(), CachedResolution::NameNotFound, self.ttl)
1850 .is_err()
1851 {
1852 cache.clear();
1853 }
1854 Err(ResolverError::NameNotFound)
1855 }
1856 Err(error) => Err(error),
1857 }
1858 }
1859}
1860
1861impl CachedResolution {
1862 fn into_result(self) -> Result<ResolutionAnswer, ResolverError> {
1863 match self {
1864 Self::Answer(answer) => Ok(answer),
1865 Self::NameNotFound => Err(ResolverError::NameNotFound),
1866 }
1867 }
1868}
1869
1870fn normalize_verified_root(root_name: &str) -> Result<String, ResolverError> {
1871 hns_root_label(root_name)
1872}
1873
1874fn normalize_verified_resource_value(
1875 mut verified: VerifiedResourceValue,
1876) -> Result<VerifiedResourceValue, ResolverError> {
1877 let root_name = normalize_verified_root(&verified.root_name)?;
1878 if verified.name_hash != NameHash::from_name(&root_name)? {
1879 return Err(ResolverError::ProofNameMismatch);
1880 }
1881
1882 verified.root_name = root_name;
1883 Ok(verified)
1884}
1885
1886struct ResourceValueEntry {
1887 root_name: String,
1888 name_hash: Vec<u8>,
1889 value_bytes: usize,
1890}
1891
1892struct ResourceValueAnchorEntry {
1893 root_name: String,
1894 name_hash: Vec<u8>,
1895 anchor: Option<ResourceValueAnchor>,
1896}
1897
1898fn total_value_bytes_in(connection: &Connection) -> Result<usize, ResolverError> {
1899 let value_bytes = connection
1900 .query_row(
1901 "
1902 SELECT COALESCE(SUM(COALESCE(length(value), 0)), 0)
1903 FROM verified_resource_values
1904 ",
1905 [],
1906 |row| row.get::<_, i64>(0),
1907 )
1908 .map_err(sqlite_error)?;
1909 usize::try_from(value_bytes).map_err(|error| ResolverError::Storage(error.to_string()))
1910}
1911
1912fn oldest_resource_value_entry(
1913 connection: &Connection,
1914) -> Result<Option<ResourceValueEntry>, ResolverError> {
1915 connection
1916 .query_row(
1917 "
1918 SELECT root_name, name_hash, COALESCE(length(value), 0)
1919 FROM verified_resource_values
1920 ORDER BY updated_at_unix ASC, root_name ASC, name_hash ASC
1921 LIMIT 1
1922 ",
1923 [],
1924 |row| {
1925 let root_name: String = row.get(0)?;
1926 let name_hash: Vec<u8> = row.get(1)?;
1927 let value_bytes: i64 = row.get(2)?;
1928 Ok((root_name, name_hash, value_bytes))
1929 },
1930 )
1931 .optional()
1932 .map_err(sqlite_error)?
1933 .map(|(root_name, name_hash, value_bytes)| {
1934 Ok(ResourceValueEntry {
1935 root_name,
1936 name_hash,
1937 value_bytes: usize::try_from(value_bytes)
1938 .map_err(|error| ResolverError::Storage(error.to_string()))?,
1939 })
1940 })
1941 .transpose()
1942}
1943
1944fn resource_value_anchor_entries(
1945 connection: &Connection,
1946) -> Result<Vec<ResourceValueAnchorEntry>, ResolverError> {
1947 let mut statement = connection
1948 .prepare(
1949 "
1950 SELECT root_name, name_hash, proof_tree_root, proof_height
1951 FROM verified_resource_values
1952 ",
1953 )
1954 .map_err(sqlite_error)?;
1955 statement
1956 .query_map([], |row| {
1957 let root_name: String = row.get(0)?;
1958 let name_hash: Vec<u8> = row.get(1)?;
1959 let proof_tree_root: Option<Vec<u8>> = row.get(2)?;
1960 let proof_height: Option<i64> = row.get(3)?;
1961 let anchor = sqlite_anchor(proof_tree_root, proof_height)?;
1962 Ok(ResourceValueAnchorEntry {
1963 root_name,
1964 name_hash,
1965 anchor,
1966 })
1967 })
1968 .map_err(sqlite_error)?
1969 .map(|entry| entry.map_err(sqlite_error))
1970 .collect()
1971}
1972
1973fn sqlite_anchor(
1974 proof_tree_root: Option<Vec<u8>>,
1975 proof_height: Option<i64>,
1976) -> rusqlite::Result<Option<ResourceValueAnchor>> {
1977 match (proof_tree_root, proof_height) {
1978 (Some(root), Some(height)) => {
1979 let tree_root = Hash::from_slice(&root).map_err(|error| {
1980 rusqlite::Error::FromSqlConversionFailure(
1981 2,
1982 rusqlite::types::Type::Blob,
1983 Box::new(error),
1984 )
1985 })?;
1986 let height = u32::try_from(height).map_err(|error| {
1987 rusqlite::Error::FromSqlConversionFailure(
1988 3,
1989 rusqlite::types::Type::Integer,
1990 Box::new(error),
1991 )
1992 })?;
1993 Ok(Some(ResourceValueAnchor {
1994 tree_root,
1995 height: Height(height),
1996 }))
1997 }
1998 _ => Ok(None),
1999 }
2000}
2001
2002fn ensure_sqlite_column(
2003 connection: &Connection,
2004 column: &str,
2005 column_type: &str,
2006) -> Result<(), ResolverError> {
2007 let mut statement = connection
2008 .prepare("PRAGMA table_info(verified_resource_values)")
2009 .map_err(sqlite_error)?;
2010 let columns = statement
2011 .query_map([], |row| row.get::<_, String>(1))
2012 .map_err(sqlite_error)?
2013 .collect::<Result<Vec<_>, _>>()
2014 .map_err(sqlite_error)?;
2015 if columns.iter().any(|existing| existing == column) {
2016 return Ok(());
2017 }
2018
2019 connection
2020 .execute_batch(&format!(
2021 "ALTER TABLE verified_resource_values ADD COLUMN {column} {column_type};"
2022 ))
2023 .map_err(sqlite_error)
2024}
2025
2026fn sqlite_error(error: rusqlite::Error) -> ResolverError {
2027 ResolverError::Storage(error.to_string())
2028}
2029
2030fn filter_records(
2031 records: Vec<ResourceRecord>,
2032 request_name: &DnsName,
2033 qtype: u16,
2034) -> Vec<ResourceRecord> {
2035 if qtype == u16::MAX {
2036 return records;
2037 }
2038
2039 let qtype = RecordType::from_code(qtype);
2040 records
2041 .into_iter()
2042 .filter(|record| record.name == *request_name && record.record_type == qtype)
2043 .collect()
2044}
2045
2046fn root_records_answer_request(request_name: &DnsName, root_owner: &DnsName, qtype: u16) -> bool {
2047 if request_name != root_owner {
2048 return false;
2049 }
2050
2051 if qtype == u16::MAX {
2052 return true;
2053 }
2054
2055 matches!(
2056 RecordType::from_code(qtype),
2057 RecordType::Ds | RecordType::Ns | RecordType::Txt
2058 )
2059}
2060
2061#[derive(Clone, Debug, Eq, PartialEq)]
2062struct AuthoritativeDohTemplate {
2063 ns: DnsName,
2064 host: String,
2065 port: u16,
2066 path_and_query: String,
2067 tls_authentication: AuthoritativeDohTlsAuthentication,
2068}
2069
2070fn key_value_part(part: &str) -> Option<(&str, &str)> {
2071 let (key, value) = part.trim().split_once('=')?;
2072 let key = key.trim();
2073 let value = value.trim();
2074 (!key.is_empty() && !value.is_empty()).then_some((key, value))
2075}
2076
2077fn txt_rdata_strings(rdata: &[u8]) -> Result<Vec<String>, ResolverError> {
2078 let mut cursor = 0usize;
2079 let mut strings = Vec::new();
2080 while cursor < rdata.len() {
2081 let length = *rdata
2082 .get(cursor)
2083 .ok_or(ResolverError::InvalidAuthoritativeDoh)? as usize;
2084 cursor += 1;
2085 let end = cursor
2086 .checked_add(length)
2087 .ok_or(ResolverError::InvalidAuthoritativeDoh)?;
2088 let bytes = rdata
2089 .get(cursor..end)
2090 .ok_or(ResolverError::InvalidAuthoritativeDoh)?;
2091 strings.push(
2092 std::str::from_utf8(bytes)
2093 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)?
2094 .to_owned(),
2095 );
2096 cursor = end;
2097 }
2098 Ok(strings)
2099}
2100
2101fn hnsdns_is_declared(text: &str) -> bool {
2102 text.split(';').any(|part| {
2103 key_value_part(part).is_some_and(|(key, value)| {
2104 key.eq_ignore_ascii_case("hnsdns") && value == HNSDNS_VERSION
2105 })
2106 })
2107}
2108
2109fn authoritative_doh_templates_from_hns(
2110 delegation: &HnsDelegation,
2111) -> Result<Vec<AuthoritativeDohTemplate>, ResolverError> {
2112 let mut templates = Vec::new();
2113 for record in delegation
2114 .records
2115 .iter()
2116 .filter(|record| record.name == delegation.owner && record.record_type == RecordType::Txt)
2117 {
2118 for text in txt_rdata_strings(&record.rdata)? {
2119 let Some(template) = parse_hnsdns_declaration(&text, &delegation.owner)? else {
2120 continue;
2121 };
2122 if !templates.contains(&template) {
2123 templates.push(template);
2124 }
2125 }
2126 }
2127 Ok(templates)
2128}
2129
2130fn parse_hnsdns_declaration(
2131 text: &str,
2132 root_owner: &DnsName,
2133) -> Result<Option<AuthoritativeDohTemplate>, ResolverError> {
2134 if !hnsdns_is_declared(text) {
2135 return Ok(None);
2136 }
2137 if text.len() > HNSDNS_MAX_TEXT_BYTES {
2138 return Err(ResolverError::InvalidAuthoritativeDoh);
2139 }
2140
2141 let mut saw_version = false;
2142 let mut ns = None;
2143 let mut transport = None;
2144 let mut doh_uri = None;
2145 let mut explicit_port = None;
2146 let mut explicit_path = None;
2147 let mut proof_tlsa_records = Vec::new();
2148 for part in text.split(';') {
2149 let (key, value) = key_value_part(part).ok_or(ResolverError::InvalidAuthoritativeDoh)?;
2150 match key.to_ascii_lowercase().as_str() {
2151 "hnsdns" if value == HNSDNS_VERSION => saw_version = true,
2152 "hnsdns" => return Err(ResolverError::InvalidAuthoritativeDoh),
2153 "ns" => {
2154 if ns.is_some() {
2155 return Err(ResolverError::InvalidAuthoritativeDoh);
2156 }
2157 ns = Some(hnsdns_ns_name(root_owner, value)?);
2158 }
2159 "transport" => {
2160 if transport.replace(value.to_ascii_lowercase()).is_some() {
2161 return Err(ResolverError::InvalidAuthoritativeDoh);
2162 }
2163 }
2164 "doh" => {
2165 if doh_uri.replace(parse_doh_uri_template(value)?).is_some() {
2166 return Err(ResolverError::InvalidAuthoritativeDoh);
2167 }
2168 }
2169 "port" => {
2170 let port = value
2171 .parse::<u16>()
2172 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2173 if explicit_port.replace(port).is_some() {
2174 return Err(ResolverError::InvalidAuthoritativeDoh);
2175 }
2176 }
2177 "path" => {
2178 let path = normalize_doh_path(value)?;
2179 if explicit_path.replace(path).is_some() {
2180 return Err(ResolverError::InvalidAuthoritativeDoh);
2181 }
2182 }
2183 "tlsa" => {
2184 let record = parse_hnsdns_tlsa(value)?;
2185 if !proof_tlsa_records.contains(&record) {
2186 if proof_tlsa_records.len() >= HNSDNS_MAX_TLSA_PINS {
2187 return Err(ResolverError::InvalidAuthoritativeDoh);
2188 }
2189 proof_tlsa_records.push(record);
2190 }
2191 }
2192 _ => {}
2193 }
2194 }
2195
2196 if !saw_version || transport.as_deref().is_some_and(|value| value != "doh") {
2197 return Err(ResolverError::InvalidAuthoritativeDoh);
2198 }
2199 let ns = ns.ok_or(ResolverError::InvalidAuthoritativeDoh)?;
2200 let (host, port, path_and_query) = doh_uri.unwrap_or_else(|| {
2201 (
2202 ns.to_string().trim_end_matches('.').to_ascii_lowercase(),
2203 DEFAULT_DOH_PORT,
2204 DEFAULT_DOH_PATH.to_owned(),
2205 )
2206 });
2207 Ok(Some(AuthoritativeDohTemplate {
2208 ns,
2209 host,
2210 port: explicit_port.unwrap_or(port),
2211 path_and_query: explicit_path.unwrap_or(path_and_query),
2212 tls_authentication: if proof_tlsa_records.is_empty() {
2213 AuthoritativeDohTlsAuthentication::WebPki
2214 } else {
2215 AuthoritativeDohTlsAuthentication::HnsProofTlsa(proof_tlsa_records)
2216 },
2217 }))
2218}
2219
2220fn parse_hnsdns_tlsa(value: &str) -> Result<TlsaRecord, ResolverError> {
2221 let fields = value.split(',').map(str::trim).collect::<Vec<_>>();
2222 let [usage, selector, matching, association] = fields.as_slice() else {
2223 return Err(ResolverError::InvalidAuthoritativeDoh);
2224 };
2225 if *usage != "3" || *selector != "1" || *matching != "1" {
2226 return Err(ResolverError::InvalidAuthoritativeDoh);
2227 }
2228 let digest = Hash::from_hex(association).map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2229 Ok(TlsaRecord {
2230 usage: TlsaUsage::DaneEe,
2231 selector: TlsaSelector::SubjectPublicKeyInfo,
2232 matching: TlsaMatching::Sha256,
2233 association_data: digest.into_bytes().to_vec(),
2234 })
2235}
2236
2237fn hnsdns_ns_name(root_owner: &DnsName, value: &str) -> Result<DnsName, ResolverError> {
2238 let value = value.trim().trim_end_matches('.').to_ascii_lowercase();
2239 if value.is_empty() || value == "@" || value.contains('*') {
2240 return Err(ResolverError::InvalidAuthoritativeDoh);
2241 }
2242 let name = DnsName::from_ascii(&value).map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2243 if name.labels().len() == 1 {
2244 DnsName::from_ascii(&format!("{name}.{root_owner}"))
2245 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)
2246 } else {
2247 Ok(name)
2248 }
2249}
2250
2251fn parse_doh_uri_template(value: &str) -> Result<(String, u16, String), ResolverError> {
2252 let value = value.trim();
2253 let remainder = value
2254 .get(..8)
2255 .filter(|scheme| scheme.eq_ignore_ascii_case("https://"))
2256 .and_then(|_| value.get(8..))
2257 .ok_or(ResolverError::InvalidAuthoritativeDoh)?;
2258 if remainder.contains('#')
2259 || remainder
2260 .bytes()
2261 .any(|byte| byte.is_ascii_control() || byte == b' ')
2262 {
2263 return Err(ResolverError::InvalidAuthoritativeDoh);
2264 }
2265 let (authority, raw_path) = remainder
2266 .split_once('/')
2267 .unwrap_or((remainder, DEFAULT_DOH_PATH.trim_start_matches('/')));
2268 if authority.is_empty() || authority.contains('@') {
2269 return Err(ResolverError::InvalidAuthoritativeDoh);
2270 }
2271 let (host, port) = match authority.rsplit_once(':') {
2272 Some((host, port)) if !host.contains(':') => (
2273 host,
2274 port.parse::<u16>()
2275 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)?,
2276 ),
2277 Some(_) => return Err(ResolverError::InvalidAuthoritativeDoh),
2278 None => (authority, DEFAULT_DOH_PORT),
2279 };
2280 let host = normalize_doh_host(host)?;
2281 let path_and_query = normalize_doh_path(&format!("/{raw_path}"))?;
2282 Ok((host, port, path_and_query))
2283}
2284
2285fn normalize_doh_host(host: &str) -> Result<String, ResolverError> {
2286 let host = host.trim().trim_end_matches('.').to_ascii_lowercase();
2287 if host.is_empty()
2288 || host.len() > 253
2289 || host
2290 .bytes()
2291 .any(|byte| byte.is_ascii_control() || matches!(byte, b'/' | b'?' | b'#' | b'@' | b' '))
2292 || DnsName::from_ascii(&host).is_err()
2293 {
2294 return Err(ResolverError::InvalidAuthoritativeDoh);
2295 }
2296 Ok(host)
2297}
2298
2299fn normalize_doh_path(path: &str) -> Result<String, ResolverError> {
2300 let mut path = path.trim();
2301 if let Some(stripped) = path.strip_suffix(DOH_URI_TEMPLATE_DNS_VARIABLE) {
2302 path = stripped;
2303 }
2304 if !path.starts_with('/') {
2305 return Err(ResolverError::InvalidAuthoritativeDoh);
2306 }
2307 if path.is_empty()
2308 || path.contains('#')
2309 || path
2310 .bytes()
2311 .any(|byte| byte.is_ascii_control() || byte == b' ')
2312 {
2313 return Err(ResolverError::InvalidAuthoritativeDoh);
2314 }
2315 Ok(path.to_owned())
2316}
2317
2318fn authoritative_doh_endpoints<T, V>(
2319 transport: &T,
2320 verifier: &V,
2321 delegation: &HnsDelegation,
2322) -> Result<Vec<AuthoritativeDohEndpoint>, ResolverError>
2323where
2324 T: DnsTransport,
2325 V: DelegatedDnssecVerifier,
2326{
2327 let mut endpoints = Vec::new();
2328
2329 let address_map = nameserver_ip_addresses(delegation);
2330 for template in authoritative_doh_templates_from_hns(delegation)? {
2331 for (ns, address) in &address_map {
2332 if *ns != template.ns {
2333 continue;
2334 }
2335 let endpoint = AuthoritativeDohEndpoint {
2336 ns: template.ns.clone(),
2337 host: template.host.clone(),
2338 connect_addr: *address,
2339 port: template.port,
2340 path_and_query: template.path_and_query.clone(),
2341 tls_authentication: template.tls_authentication.clone(),
2342 };
2343 if !endpoints.contains(&endpoint) {
2344 endpoints.push(endpoint);
2345 }
2346 }
2347 }
2348 if !endpoints.is_empty() {
2349 return Ok(endpoints);
2350 }
2351 let ds_rrset = records_for(&delegation.records, &delegation.owner, RecordType::Ds);
2352 if ds_rrset.is_empty() {
2353 return Ok(endpoints);
2354 }
2355 for (ns, address) in address_map {
2356 let server = SocketAddr::new(address, 53);
2357 let service_name = dns_service_binding_name(&ns)?;
2358 let response = match resolve_delegated_from_server(
2359 transport,
2360 verifier,
2361 server,
2362 delegation,
2363 &service_name,
2364 RecordType::Svcb,
2365 &ds_rrset,
2366 ) {
2367 Ok(response) => response,
2368 Err(_) => continue,
2369 };
2370
2371 if !response.secure {
2372 continue;
2373 }
2374 for record in records_for(&response.records, &service_name, RecordType::Svcb) {
2375 let Some(template) = authoritative_doh_template_from_svcb(&ns, &record)? else {
2376 continue;
2377 };
2378 let endpoint = AuthoritativeDohEndpoint {
2379 ns: template.ns,
2380 host: template.host,
2381 connect_addr: address,
2382 port: template.port,
2383 path_and_query: template.path_and_query,
2384 tls_authentication: template.tls_authentication,
2385 };
2386 if !endpoints.contains(&endpoint) {
2387 endpoints.push(endpoint);
2388 }
2389 }
2390 }
2391
2392 Ok(endpoints)
2393}
2394
2395fn authoritative_doh_cache_key(delegation: &HnsDelegation) -> String {
2396 let records = delegation
2397 .records
2398 .iter()
2399 .map(|record| {
2400 format!(
2401 "{}:{}:{}:{}:{:02x?}",
2402 record.name,
2403 record.record_type.code(),
2404 record.class,
2405 record.ttl,
2406 record.rdata,
2407 )
2408 })
2409 .collect::<BTreeSet<_>>()
2410 .into_iter()
2411 .collect::<Vec<_>>()
2412 .join(",");
2413 let servers = nameserver_ip_addresses(delegation)
2414 .into_iter()
2415 .map(|(ns, address)| format!("{ns}@{address}"))
2416 .collect::<BTreeSet<_>>()
2417 .into_iter()
2418 .collect::<Vec<_>>()
2419 .join(",");
2420 format!("{}|{}|{}", delegation.owner, servers, records)
2421}
2422
2423fn dns_service_binding_name(ns: &DnsName) -> Result<DnsName, ResolverError> {
2424 DnsName::from_ascii(&format!("_dns.{ns}")).map_err(|_| ResolverError::InvalidAuthoritativeDoh)
2425}
2426
2427fn authoritative_doh_template_from_svcb(
2428 ns: &DnsName,
2429 record: &ResourceRecord,
2430) -> Result<Option<AuthoritativeDohTemplate>, ResolverError> {
2431 let svcb =
2432 SvcbRecord::from_record(record).map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2433 if svcb.is_alias_mode() || !svcb_mandatory_keys_supported(&svcb) {
2434 return Ok(None);
2435 }
2436
2437 let target = if svcb.target_name == DnsName::root() {
2438 ns.clone()
2439 } else {
2440 svcb.target_name.clone()
2441 };
2442 let alpn_ids = svcb
2443 .alpn_ids()
2444 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2445 if !alpn_ids.iter().any(|id| id.as_slice() == b"h2") {
2446 return Ok(None);
2447 }
2448
2449 let Some(dohpath) = svcb.param(SVCB_PARAM_DOHPATH) else {
2450 return Ok(None);
2451 };
2452 let path_and_query = doh_path_from_svcb_param(dohpath)?;
2453 let port = svcb
2454 .port()
2455 .map_err(|_| ResolverError::InvalidAuthoritativeDoh)?
2456 .unwrap_or(DEFAULT_DOH_PORT);
2457
2458 Ok(Some(AuthoritativeDohTemplate {
2459 ns: ns.clone(),
2460 host: target
2461 .to_string()
2462 .trim_end_matches('.')
2463 .to_ascii_lowercase(),
2464 port,
2465 path_and_query,
2466 tls_authentication: AuthoritativeDohTlsAuthentication::WebPki,
2467 }))
2468}
2469
2470fn svcb_mandatory_keys_supported(svcb: &SvcbRecord) -> bool {
2471 let Some(value) = svcb.param(SVCB_PARAM_MANDATORY) else {
2472 return true;
2473 };
2474 value.chunks_exact(2).all(|chunk| {
2475 let key = u16::from_be_bytes([chunk[0], chunk[1]]);
2476 matches!(
2477 key,
2478 SVCB_PARAM_ALPN
2479 | SVCB_PARAM_PORT
2480 | SVCB_PARAM_IPV4HINT
2481 | SVCB_PARAM_IPV6HINT
2482 | SVCB_PARAM_DOHPATH
2483 )
2484 })
2485}
2486
2487fn doh_path_from_svcb_param(value: &[u8]) -> Result<String, ResolverError> {
2488 let template =
2489 std::str::from_utf8(value).map_err(|_| ResolverError::InvalidAuthoritativeDoh)?;
2490 if !template.contains("dns") {
2491 return Err(ResolverError::InvalidAuthoritativeDoh);
2492 }
2493 normalize_doh_path(template)
2494}
2495
2496fn has_owner_record(records: &[ResourceRecord], owner: &DnsName, record_type: RecordType) -> bool {
2497 records
2498 .iter()
2499 .any(|record| record.name == *owner && record.record_type == record_type)
2500}
2501
2502fn resolve_delegated_from_server<T, V>(
2503 transport: &T,
2504 verifier: &V,
2505 server: SocketAddr,
2506 delegation: &HnsDelegation,
2507 request_name: &DnsName,
2508 qtype: RecordType,
2509 ds_rrset: &[ResourceRecord],
2510) -> Result<ResolutionAnswer, ResolverError>
2511where
2512 T: DnsTransport,
2513 V: DelegatedDnssecVerifier,
2514{
2515 match resolve_delegated_from_server_target(
2516 transport,
2517 verifier,
2518 server,
2519 DnsQueryTarget::Server(server),
2520 delegation,
2521 request_name,
2522 qtype,
2523 ds_rrset,
2524 ) {
2525 Err(ResolverError::DnssecFailed)
2526 if transport.probe_dns_interception() == DnsInterceptionStatus::Detected =>
2527 {
2528 Err(ResolverError::Port53InterceptionDetected)
2529 }
2530 Err(ResolverError::DnssecFailed) => {
2531 match resolve_delegated_from_server_target(
2532 transport,
2533 verifier,
2534 server,
2535 DnsQueryTarget::ServerTcp(server),
2536 delegation,
2537 request_name,
2538 qtype,
2539 ds_rrset,
2540 ) {
2541 Ok(answer) => Ok(answer),
2542 Err(error) => Err(strongest_resolution_error(
2543 ResolverError::DnssecFailed,
2544 error,
2545 )),
2546 }
2547 }
2548 result => result,
2549 }
2550}
2551
2552#[allow(clippy::too_many_arguments)]
2553fn resolve_delegated_from_server_target<T, V>(
2554 transport: &T,
2555 verifier: &V,
2556 server: SocketAddr,
2557 target: DnsQueryTarget<'_>,
2558 delegation: &HnsDelegation,
2559 request_name: &DnsName,
2560 qtype: RecordType,
2561 ds_rrset: &[ResourceRecord],
2562) -> Result<ResolutionAnswer, ResolverError>
2563where
2564 T: DnsTransport,
2565 V: DelegatedDnssecVerifier,
2566{
2567 let target_response = dns_query_target(transport, target, request_name, qtype)?;
2568 let target_rrset = records_for(&target_response.answers, request_name, qtype);
2569
2570 if ds_rrset.is_empty() {
2571 return Ok(ResolutionAnswer {
2572 name: request_name.clone(),
2573 records: target_rrset,
2574 secure: false,
2575 });
2576 }
2577
2578 let dnskey_response =
2579 dns_query_target(transport, target, &delegation.owner, RecordType::Dnskey)?;
2580 let dnskey_rrset = records_for(
2581 &dnskey_response.answers,
2582 &delegation.owner,
2583 RecordType::Dnskey,
2584 );
2585 let dnskey_rrsig_rrset = records_for(
2586 &dnskey_response.answers,
2587 &delegation.owner,
2588 RecordType::Rrsig,
2589 );
2590 if target_response.header.flags.rcode() == DNS_RCODE_NXDOMAIN {
2591 return resolve_secure_name_error(
2592 verifier,
2593 NameErrorResolutionInput {
2594 delegation,
2595 request_name,
2596 ds_rrset,
2597 dnskey_rrset: &dnskey_rrset,
2598 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2599 response: &target_response,
2600 prefix_records: &[],
2601 },
2602 );
2603 }
2604 if let Some(referral) = child_referral(&target_response, &delegation.owner, request_name) {
2605 return resolve_secure_child_referral(
2606 transport,
2607 verifier,
2608 ChildReferralResolutionInput {
2609 parent_delegation: delegation,
2610 referral,
2611 request_name,
2612 qtype,
2613 parent_ds_rrset: ds_rrset,
2614 parent_dnskey_rrset: &dnskey_rrset,
2615 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2616 },
2617 );
2618 }
2619 let target_rrsig_rrset = records_for(&target_response.answers, request_name, RecordType::Rrsig);
2620 if let Some(child_owner) = inline_child_answer_signer(
2621 delegation,
2622 request_name,
2623 &target_rrset,
2624 &target_rrsig_rrset,
2625 qtype,
2626 ) {
2627 return resolve_secure_inline_child_answer(
2628 transport,
2629 verifier,
2630 InlineChildAnswerResolutionInput {
2631 parent_delegation: delegation,
2632 child_owner,
2633 server,
2634 request_name,
2635 parent_ds_rrset: ds_rrset,
2636 parent_dnskey_rrset: &dnskey_rrset,
2637 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2638 target_rrset: &target_rrset,
2639 target_rrsig_rrset: &target_rrsig_rrset,
2640 },
2641 );
2642 }
2643 if target_rrset.is_empty()
2644 && records_for(&target_response.answers, request_name, RecordType::Cname).is_empty()
2645 {
2646 let proof_records = combined_response_records(&target_response);
2647 if let Some(child_owner) =
2648 inline_child_denial_signer(delegation, request_name, &proof_records)
2649 {
2650 return resolve_secure_inline_child_no_data(
2651 transport,
2652 verifier,
2653 InlineChildNoDataResolutionInput {
2654 parent_delegation: delegation,
2655 child_owner,
2656 server,
2657 request_name,
2658 qtype,
2659 parent_ds_rrset: ds_rrset,
2660 parent_dnskey_rrset: &dnskey_rrset,
2661 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2662 response: &target_response,
2663 prefix_records: &[],
2664 },
2665 );
2666 }
2667 return resolve_secure_no_data(
2668 verifier,
2669 NoDataResolutionInput {
2670 delegation,
2671 request_name,
2672 qtype,
2673 ds_rrset,
2674 dnskey_rrset: &dnskey_rrset,
2675 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2676 response: &target_response,
2677 prefix_records: &[],
2678 },
2679 );
2680 }
2681
2682 if dnskey_rrset.is_empty() || dnskey_rrsig_rrset.is_empty() {
2683 return Err(ResolverError::DnssecFailed);
2684 }
2685
2686 resolve_secure_answer_records(SecureAnswerResolutionInput {
2687 transport,
2688 verifier,
2689 target,
2690 delegation,
2691 request_name,
2692 qtype,
2693 ds_rrset,
2694 dnskey_rrset: &dnskey_rrset,
2695 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2696 initial_response: target_response,
2697 })
2698}
2699
2700fn resolve_delegated_from_doh_endpoint<T, V>(
2701 transport: &T,
2702 verifier: &V,
2703 endpoint: &AuthoritativeDohEndpoint,
2704 delegation: &HnsDelegation,
2705 request_name: &DnsName,
2706 qtype: RecordType,
2707 ds_rrset: &[ResourceRecord],
2708) -> Result<ResolutionAnswer, ResolverError>
2709where
2710 T: DnsTransport,
2711 V: DelegatedDnssecVerifier,
2712{
2713 let target_response = dns_query_doh(transport, endpoint, request_name, qtype)?;
2714 let target_rrset = records_for(&target_response.answers, request_name, qtype);
2715
2716 if ds_rrset.is_empty() {
2717 return Ok(ResolutionAnswer {
2718 name: request_name.clone(),
2719 records: target_rrset,
2720 secure: false,
2721 });
2722 }
2723
2724 let dnskey_response =
2725 dns_query_doh(transport, endpoint, &delegation.owner, RecordType::Dnskey)?;
2726 let dnskey_rrset = records_for(
2727 &dnskey_response.answers,
2728 &delegation.owner,
2729 RecordType::Dnskey,
2730 );
2731 let dnskey_rrsig_rrset = records_for(
2732 &dnskey_response.answers,
2733 &delegation.owner,
2734 RecordType::Rrsig,
2735 );
2736 if target_response.header.flags.rcode() == DNS_RCODE_NXDOMAIN {
2737 return resolve_secure_name_error(
2738 verifier,
2739 NameErrorResolutionInput {
2740 delegation,
2741 request_name,
2742 ds_rrset,
2743 dnskey_rrset: &dnskey_rrset,
2744 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2745 response: &target_response,
2746 prefix_records: &[],
2747 },
2748 );
2749 }
2750 if let Some(referral) = child_referral(&target_response, &delegation.owner, request_name) {
2751 return resolve_secure_child_referral(
2752 transport,
2753 verifier,
2754 ChildReferralResolutionInput {
2755 parent_delegation: delegation,
2756 referral,
2757 request_name,
2758 qtype,
2759 parent_ds_rrset: ds_rrset,
2760 parent_dnskey_rrset: &dnskey_rrset,
2761 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2762 },
2763 );
2764 }
2765 let target_rrsig_rrset = records_for(&target_response.answers, request_name, RecordType::Rrsig);
2766 if let Some(child_owner) = inline_child_answer_signer(
2767 delegation,
2768 request_name,
2769 &target_rrset,
2770 &target_rrsig_rrset,
2771 qtype,
2772 ) {
2773 return resolve_secure_inline_child_answer(
2774 transport,
2775 verifier,
2776 InlineChildAnswerResolutionInput {
2777 parent_delegation: delegation,
2778 child_owner,
2779 server: SocketAddr::new(endpoint.connect_addr, endpoint.port),
2780 request_name,
2781 parent_ds_rrset: ds_rrset,
2782 parent_dnskey_rrset: &dnskey_rrset,
2783 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2784 target_rrset: &target_rrset,
2785 target_rrsig_rrset: &target_rrsig_rrset,
2786 },
2787 );
2788 }
2789 if target_rrset.is_empty()
2790 && records_for(&target_response.answers, request_name, RecordType::Cname).is_empty()
2791 {
2792 let proof_records = combined_response_records(&target_response);
2793 if let Some(child_owner) =
2794 inline_child_denial_signer(delegation, request_name, &proof_records)
2795 {
2796 return resolve_secure_inline_child_no_data(
2797 transport,
2798 verifier,
2799 InlineChildNoDataResolutionInput {
2800 parent_delegation: delegation,
2801 child_owner,
2802 server: SocketAddr::new(endpoint.connect_addr, endpoint.port),
2803 request_name,
2804 qtype,
2805 parent_ds_rrset: ds_rrset,
2806 parent_dnskey_rrset: &dnskey_rrset,
2807 parent_dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2808 response: &target_response,
2809 prefix_records: &[],
2810 },
2811 );
2812 }
2813 return resolve_secure_no_data(
2814 verifier,
2815 NoDataResolutionInput {
2816 delegation,
2817 request_name,
2818 qtype,
2819 ds_rrset,
2820 dnskey_rrset: &dnskey_rrset,
2821 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2822 response: &target_response,
2823 prefix_records: &[],
2824 },
2825 );
2826 }
2827
2828 if dnskey_rrset.is_empty() || dnskey_rrsig_rrset.is_empty() {
2829 return Err(ResolverError::DnssecFailed);
2830 }
2831
2832 resolve_secure_answer_records(SecureAnswerResolutionInput {
2833 transport,
2834 verifier,
2835 target: DnsQueryTarget::Doh(endpoint),
2836 delegation,
2837 request_name,
2838 qtype,
2839 ds_rrset,
2840 dnskey_rrset: &dnskey_rrset,
2841 dnskey_rrsig_rrset: &dnskey_rrsig_rrset,
2842 initial_response: target_response,
2843 })
2844}
2845
2846#[derive(Clone, Debug, Eq, PartialEq)]
2847struct ChildReferral {
2848 owner: DnsName,
2849 ds_rrset: Vec<ResourceRecord>,
2850 ds_rrsig_rrset: Vec<ResourceRecord>,
2851 servers: Vec<SocketAddr>,
2852}
2853
2854struct ChildReferralResolutionInput<'a> {
2855 parent_delegation: &'a HnsDelegation,
2856 referral: ChildReferral,
2857 request_name: &'a DnsName,
2858 qtype: RecordType,
2859 parent_ds_rrset: &'a [ResourceRecord],
2860 parent_dnskey_rrset: &'a [ResourceRecord],
2861 parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
2862}
2863
2864struct InlineChildAnswerResolutionInput<'a> {
2865 parent_delegation: &'a HnsDelegation,
2866 child_owner: DnsName,
2867 server: SocketAddr,
2868 request_name: &'a DnsName,
2869 parent_ds_rrset: &'a [ResourceRecord],
2870 parent_dnskey_rrset: &'a [ResourceRecord],
2871 parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
2872 target_rrset: &'a [ResourceRecord],
2873 target_rrsig_rrset: &'a [ResourceRecord],
2874}
2875
2876struct InlineChildNoDataResolutionInput<'a> {
2877 parent_delegation: &'a HnsDelegation,
2878 child_owner: DnsName,
2879 server: SocketAddr,
2880 request_name: &'a DnsName,
2881 qtype: RecordType,
2882 parent_ds_rrset: &'a [ResourceRecord],
2883 parent_dnskey_rrset: &'a [ResourceRecord],
2884 parent_dnskey_rrsig_rrset: &'a [ResourceRecord],
2885 response: &'a DnsMessage,
2886 prefix_records: &'a [ResourceRecord],
2887}
2888
2889struct InlineChildDnssecMaterial {
2890 child_ds_rrset: Vec<ResourceRecord>,
2891 child_ds_rrsig_rrset: Vec<ResourceRecord>,
2892 child_dnskey_rrset: Vec<ResourceRecord>,
2893 child_dnskey_rrsig_rrset: Vec<ResourceRecord>,
2894}
2895
2896fn resolve_secure_child_referral<T, V>(
2897 transport: &T,
2898 verifier: &V,
2899 input: ChildReferralResolutionInput<'_>,
2900) -> Result<ResolutionAnswer, ResolverError>
2901where
2902 T: DnsTransport,
2903 V: DelegatedDnssecVerifier,
2904{
2905 if input.parent_dnskey_rrset.is_empty()
2906 || input.parent_dnskey_rrsig_rrset.is_empty()
2907 || input.referral.ds_rrset.is_empty()
2908 || input.referral.ds_rrsig_rrset.is_empty()
2909 {
2910 return Err(ResolverError::DnssecFailed);
2911 }
2912 if input.referral.servers.is_empty() {
2913 return Err(ResolverError::NoNameserverAddress);
2914 }
2915
2916 if transport.is_recursive_relay() {
2917 let server = input
2918 .referral
2919 .servers
2920 .iter()
2921 .copied()
2922 .find(|server| validate_dns_server(transport.endpoint_policy(), *server).is_ok())
2923 .ok_or(ResolverError::NoNameserverAddress)?;
2924 return resolve_secure_child_from_server(transport, verifier, server, &input);
2925 }
2926
2927 let mut last_error = None;
2928 for &server in &input.referral.servers {
2929 match resolve_secure_child_from_server(transport, verifier, server, &input) {
2930 Ok(answer) => return Ok(answer),
2931 Err(error) => last_error = Some(error),
2932 }
2933 }
2934
2935 Err(last_error.unwrap_or(ResolverError::NoNameserverAddress))
2936}
2937
2938fn resolve_secure_inline_child_answer<T, V>(
2939 transport: &T,
2940 verifier: &V,
2941 input: InlineChildAnswerResolutionInput<'_>,
2942) -> Result<ResolutionAnswer, ResolverError>
2943where
2944 T: DnsTransport,
2945 V: DelegatedDnssecVerifier,
2946{
2947 if input.parent_dnskey_rrset.is_empty()
2948 || input.parent_dnskey_rrsig_rrset.is_empty()
2949 || input.target_rrset.is_empty()
2950 || input.target_rrsig_rrset.is_empty()
2951 {
2952 return Err(ResolverError::DnssecFailed);
2953 }
2954
2955 let child_material =
2956 fetch_inline_child_dnssec_material(transport, input.server, &input.child_owner)?;
2957
2958 let secure = verifier.validate_child_positive_rrset(DelegatedChildDnssecValidation {
2959 parent_dnskey_owner: &input.parent_delegation.owner,
2960 parent_ds_rrset: input.parent_ds_rrset,
2961 parent_dnskey_rrset: input.parent_dnskey_rrset,
2962 parent_dnskey_rrsig_rrset: input.parent_dnskey_rrsig_rrset,
2963 child_dnskey_owner: &input.child_owner,
2964 child_ds_rrset: &child_material.child_ds_rrset,
2965 child_ds_rrsig_rrset: &child_material.child_ds_rrsig_rrset,
2966 child_dnskey_rrset: &child_material.child_dnskey_rrset,
2967 child_dnskey_rrsig_rrset: &child_material.child_dnskey_rrsig_rrset,
2968 target_rrset: input.target_rrset,
2969 target_rrsig_rrset: input.target_rrsig_rrset,
2970 })?;
2971 if !secure {
2972 return Err(ResolverError::DnssecFailed);
2973 }
2974
2975 Ok(ResolutionAnswer {
2976 name: input.request_name.clone(),
2977 records: input.target_rrset.to_vec(),
2978 secure: true,
2979 })
2980}
2981
2982fn resolve_secure_inline_child_no_data<T, V>(
2983 transport: &T,
2984 verifier: &V,
2985 input: InlineChildNoDataResolutionInput<'_>,
2986) -> Result<ResolutionAnswer, ResolverError>
2987where
2988 T: DnsTransport,
2989 V: DelegatedDnssecVerifier,
2990{
2991 if input.parent_dnskey_rrset.is_empty() || input.parent_dnskey_rrsig_rrset.is_empty() {
2992 return Err(ResolverError::DnssecFailed);
2993 }
2994
2995 let child_material =
2996 fetch_inline_child_dnssec_material(transport, input.server, &input.child_owner)?;
2997 let proof_records = combined_response_records(input.response);
2998 let nsec_rrset = records_for(&proof_records, input.request_name, RecordType::Nsec);
2999 let nsec_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3000 let nsec3_rrset = records_of_type(&proof_records, RecordType::Nsec3);
3001 let nsec3_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3002 let secure = verifier.validate_child_no_data(DelegatedChildDnssecNoDataValidation {
3003 parent_dnskey_owner: &input.parent_delegation.owner,
3004 parent_ds_rrset: input.parent_ds_rrset,
3005 parent_dnskey_rrset: input.parent_dnskey_rrset,
3006 parent_dnskey_rrsig_rrset: input.parent_dnskey_rrsig_rrset,
3007 child_dnskey_owner: &input.child_owner,
3008 child_ds_rrset: &child_material.child_ds_rrset,
3009 child_ds_rrsig_rrset: &child_material.child_ds_rrsig_rrset,
3010 child_dnskey_rrset: &child_material.child_dnskey_rrset,
3011 child_dnskey_rrsig_rrset: &child_material.child_dnskey_rrsig_rrset,
3012 query_name: input.request_name,
3013 query_type: input.qtype,
3014 nsec_rrset: &nsec_rrset,
3015 nsec_rrsig_rrset: &nsec_rrsig_rrset,
3016 nsec3_rrset: &nsec3_rrset,
3017 nsec3_rrsig_rrset: &nsec3_rrsig_rrset,
3018 })?;
3019 if !secure {
3020 return Err(ResolverError::DnssecFailed);
3021 }
3022
3023 Ok(ResolutionAnswer {
3024 name: input.request_name.clone(),
3025 records: input.prefix_records.to_vec(),
3026 secure: true,
3027 })
3028}
3029
3030fn fetch_inline_child_dnssec_material<T>(
3031 transport: &T,
3032 server: SocketAddr,
3033 child_owner: &DnsName,
3034) -> Result<InlineChildDnssecMaterial, ResolverError>
3035where
3036 T: DnsTransport,
3037{
3038 let child_ds_response = dns_query(transport, server, child_owner, RecordType::Ds)?;
3039 let child_ds_rrset = records_for(&child_ds_response.answers, child_owner, RecordType::Ds);
3040 let child_ds_rrsig_rrset =
3041 records_for(&child_ds_response.answers, child_owner, RecordType::Rrsig);
3042 let child_dnskey_response = dns_query(transport, server, child_owner, RecordType::Dnskey)?;
3043 let child_dnskey_rrset = records_for(
3044 &child_dnskey_response.answers,
3045 child_owner,
3046 RecordType::Dnskey,
3047 );
3048 let child_dnskey_rrsig_rrset = records_for(
3049 &child_dnskey_response.answers,
3050 child_owner,
3051 RecordType::Rrsig,
3052 );
3053
3054 if child_ds_rrset.is_empty()
3055 || child_ds_rrsig_rrset.is_empty()
3056 || child_dnskey_rrset.is_empty()
3057 || child_dnskey_rrsig_rrset.is_empty()
3058 {
3059 return Err(ResolverError::DnssecFailed);
3060 }
3061
3062 Ok(InlineChildDnssecMaterial {
3063 child_ds_rrset,
3064 child_ds_rrsig_rrset,
3065 child_dnskey_rrset,
3066 child_dnskey_rrsig_rrset,
3067 })
3068}
3069
3070fn resolve_secure_child_from_server<T, V>(
3071 transport: &T,
3072 verifier: &V,
3073 server: SocketAddr,
3074 input: &ChildReferralResolutionInput<'_>,
3075) -> Result<ResolutionAnswer, ResolverError>
3076where
3077 T: DnsTransport,
3078 V: DelegatedDnssecVerifier,
3079{
3080 let child_dnskey_response =
3081 dns_query(transport, server, &input.referral.owner, RecordType::Dnskey)?;
3082 let child_dnskey_rrset = records_for(
3083 &child_dnskey_response.answers,
3084 &input.referral.owner,
3085 RecordType::Dnskey,
3086 );
3087 let child_dnskey_rrsig_rrset = records_for(
3088 &child_dnskey_response.answers,
3089 &input.referral.owner,
3090 RecordType::Rrsig,
3091 );
3092 if child_dnskey_rrset.is_empty() || child_dnskey_rrsig_rrset.is_empty() {
3093 return Err(ResolverError::DnssecFailed);
3094 }
3095
3096 let target_response = dns_query(transport, server, input.request_name, input.qtype)?;
3097 resolve_secure_child_answer_records(ChildSecureAnswerResolutionInput {
3098 transport,
3099 verifier,
3100 server,
3101 referral: input,
3102 child_dnskey_rrset: &child_dnskey_rrset,
3103 child_dnskey_rrsig_rrset: &child_dnskey_rrsig_rrset,
3104 initial_response: target_response,
3105 })
3106}
3107
3108struct ChildSecureAnswerResolutionInput<'a, T, V> {
3109 transport: &'a T,
3110 verifier: &'a V,
3111 server: SocketAddr,
3112 referral: &'a ChildReferralResolutionInput<'a>,
3113 child_dnskey_rrset: &'a [ResourceRecord],
3114 child_dnskey_rrsig_rrset: &'a [ResourceRecord],
3115 initial_response: DnsMessage,
3116}
3117
3118fn resolve_secure_child_answer_records<T, V>(
3119 input: ChildSecureAnswerResolutionInput<'_, T, V>,
3120) -> Result<ResolutionAnswer, ResolverError>
3121where
3122 T: DnsTransport,
3123 V: DelegatedDnssecVerifier,
3124{
3125 let mut response = input.initial_response;
3126 let mut owner = input.referral.request_name.clone();
3127 let mut cname_records = Vec::new();
3128
3129 for _ in 0..=MAX_CNAME_CHAIN_LEN {
3130 let target_rrset = records_for(&response.answers, &owner, input.referral.qtype);
3131 let cname_rrset = if input.referral.qtype == RecordType::Cname {
3132 Vec::new()
3133 } else {
3134 records_for(&response.answers, &owner, RecordType::Cname)
3135 };
3136 if !target_rrset.is_empty() && !cname_rrset.is_empty() {
3137 return Err(ResolverError::DnssecFailed);
3138 }
3139
3140 if !target_rrset.is_empty() {
3141 validate_secure_child_rrset(
3142 input.verifier,
3143 ChildSecureRrsetValidationInput {
3144 referral: input.referral,
3145 child_dnskey_rrset: input.child_dnskey_rrset,
3146 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3147 owner: &owner,
3148 rrset: &target_rrset,
3149 response: &response,
3150 },
3151 )?;
3152 cname_records.extend(target_rrset);
3153 return Ok(ResolutionAnswer {
3154 name: input.referral.request_name.clone(),
3155 records: cname_records,
3156 secure: true,
3157 });
3158 }
3159
3160 if !cname_rrset.is_empty() {
3161 validate_secure_child_rrset(
3162 input.verifier,
3163 ChildSecureRrsetValidationInput {
3164 referral: input.referral,
3165 child_dnskey_rrset: input.child_dnskey_rrset,
3166 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3167 owner: &owner,
3168 rrset: &cname_rrset,
3169 response: &response,
3170 },
3171 )?;
3172 let next_owner = cname_target(&cname_rrset)?;
3173 if !dns_name_is_subdomain_or_equal(&next_owner, &input.referral.referral.owner) {
3174 return Err(ResolverError::DnssecFailed);
3175 }
3176 cname_records.extend(cname_rrset);
3177 owner = next_owner;
3178 continue;
3179 }
3180
3181 if owner != *input.referral.request_name && response.questions[0].name != owner {
3182 response = dns_query(input.transport, input.server, &owner, input.referral.qtype)?;
3183 continue;
3184 }
3185
3186 if response.header.flags.rcode() == DNS_RCODE_NXDOMAIN {
3187 return resolve_secure_child_name_error(
3188 input.verifier,
3189 ChildNameErrorResolutionInput {
3190 referral: input.referral,
3191 request_name: &owner,
3192 child_dnskey_rrset: input.child_dnskey_rrset,
3193 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3194 response: &response,
3195 prefix_records: &cname_records,
3196 },
3197 );
3198 }
3199
3200 return resolve_secure_child_no_data(
3201 input.verifier,
3202 ChildNoDataResolutionInput {
3203 referral: input.referral,
3204 request_name: &owner,
3205 qtype: input.referral.qtype,
3206 child_dnskey_rrset: input.child_dnskey_rrset,
3207 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3208 response: &response,
3209 prefix_records: &cname_records,
3210 },
3211 );
3212 }
3213
3214 Err(ResolverError::DnssecFailed)
3215}
3216
3217struct ChildSecureRrsetValidationInput<'a> {
3218 referral: &'a ChildReferralResolutionInput<'a>,
3219 child_dnskey_rrset: &'a [ResourceRecord],
3220 child_dnskey_rrsig_rrset: &'a [ResourceRecord],
3221 owner: &'a DnsName,
3222 rrset: &'a [ResourceRecord],
3223 response: &'a DnsMessage,
3224}
3225
3226fn validate_secure_child_rrset<V>(
3227 verifier: &V,
3228 input: ChildSecureRrsetValidationInput<'_>,
3229) -> Result<(), ResolverError>
3230where
3231 V: DelegatedDnssecVerifier,
3232{
3233 let rrsig_rrset = records_for(&input.response.answers, input.owner, RecordType::Rrsig);
3234 if rrsig_rrset.is_empty() {
3235 return Err(ResolverError::DnssecFailed);
3236 }
3237 let secure = verifier.validate_child_positive_rrset(DelegatedChildDnssecValidation {
3238 parent_dnskey_owner: &input.referral.parent_delegation.owner,
3239 parent_ds_rrset: input.referral.parent_ds_rrset,
3240 parent_dnskey_rrset: input.referral.parent_dnskey_rrset,
3241 parent_dnskey_rrsig_rrset: input.referral.parent_dnskey_rrsig_rrset,
3242 child_dnskey_owner: &input.referral.referral.owner,
3243 child_ds_rrset: &input.referral.referral.ds_rrset,
3244 child_ds_rrsig_rrset: &input.referral.referral.ds_rrsig_rrset,
3245 child_dnskey_rrset: input.child_dnskey_rrset,
3246 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3247 target_rrset: input.rrset,
3248 target_rrsig_rrset: &rrsig_rrset,
3249 })?;
3250 if secure {
3251 Ok(())
3252 } else {
3253 Err(ResolverError::DnssecFailed)
3254 }
3255}
3256
3257struct ChildNoDataResolutionInput<'a> {
3258 referral: &'a ChildReferralResolutionInput<'a>,
3259 request_name: &'a DnsName,
3260 qtype: RecordType,
3261 child_dnskey_rrset: &'a [ResourceRecord],
3262 child_dnskey_rrsig_rrset: &'a [ResourceRecord],
3263 response: &'a DnsMessage,
3264 prefix_records: &'a [ResourceRecord],
3265}
3266
3267struct ChildNameErrorResolutionInput<'a> {
3268 referral: &'a ChildReferralResolutionInput<'a>,
3269 request_name: &'a DnsName,
3270 child_dnskey_rrset: &'a [ResourceRecord],
3271 child_dnskey_rrsig_rrset: &'a [ResourceRecord],
3272 response: &'a DnsMessage,
3273 prefix_records: &'a [ResourceRecord],
3274}
3275
3276fn resolve_secure_child_no_data<V>(
3277 verifier: &V,
3278 input: ChildNoDataResolutionInput<'_>,
3279) -> Result<ResolutionAnswer, ResolverError>
3280where
3281 V: DelegatedDnssecVerifier,
3282{
3283 let proof_records = combined_response_records(input.response);
3284 let nsec_rrset = records_for(&proof_records, input.request_name, RecordType::Nsec);
3285 let nsec_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3286 let nsec3_rrset = records_of_type(&proof_records, RecordType::Nsec3);
3287 let nsec3_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3288 let secure = verifier.validate_child_no_data(DelegatedChildDnssecNoDataValidation {
3289 parent_dnskey_owner: &input.referral.parent_delegation.owner,
3290 parent_ds_rrset: input.referral.parent_ds_rrset,
3291 parent_dnskey_rrset: input.referral.parent_dnskey_rrset,
3292 parent_dnskey_rrsig_rrset: input.referral.parent_dnskey_rrsig_rrset,
3293 child_dnskey_owner: &input.referral.referral.owner,
3294 child_ds_rrset: &input.referral.referral.ds_rrset,
3295 child_ds_rrsig_rrset: &input.referral.referral.ds_rrsig_rrset,
3296 child_dnskey_rrset: input.child_dnskey_rrset,
3297 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3298 query_name: input.request_name,
3299 query_type: input.qtype,
3300 nsec_rrset: &nsec_rrset,
3301 nsec_rrsig_rrset: &nsec_rrsig_rrset,
3302 nsec3_rrset: &nsec3_rrset,
3303 nsec3_rrsig_rrset: &nsec3_rrsig_rrset,
3304 })?;
3305 if !secure {
3306 return Err(ResolverError::DnssecFailed);
3307 }
3308
3309 Ok(ResolutionAnswer {
3310 name: input.request_name.clone(),
3311 records: input.prefix_records.to_vec(),
3312 secure: true,
3313 })
3314}
3315
3316fn resolve_secure_child_name_error<V>(
3317 verifier: &V,
3318 input: ChildNameErrorResolutionInput<'_>,
3319) -> Result<ResolutionAnswer, ResolverError>
3320where
3321 V: DelegatedDnssecVerifier,
3322{
3323 if input.child_dnskey_rrset.is_empty() || input.child_dnskey_rrsig_rrset.is_empty() {
3324 return Err(ResolverError::DnssecFailed);
3325 }
3326 let proof_records = combined_response_records(input.response);
3327 let nsec_rrset = records_of_type(&proof_records, RecordType::Nsec);
3328 let nsec_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3329 let nsec3_rrset = records_of_type(&proof_records, RecordType::Nsec3);
3330 let nsec3_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3331 for closest_encloser in
3332 closest_encloser_candidates(input.request_name, &input.referral.referral.owner)?
3333 {
3334 let secure =
3335 verifier.validate_child_name_error(DelegatedChildDnssecNameErrorValidation {
3336 parent_dnskey_owner: &input.referral.parent_delegation.owner,
3337 parent_ds_rrset: input.referral.parent_ds_rrset,
3338 parent_dnskey_rrset: input.referral.parent_dnskey_rrset,
3339 parent_dnskey_rrsig_rrset: input.referral.parent_dnskey_rrsig_rrset,
3340 child_dnskey_owner: &input.referral.referral.owner,
3341 child_ds_rrset: &input.referral.referral.ds_rrset,
3342 child_ds_rrsig_rrset: &input.referral.referral.ds_rrsig_rrset,
3343 child_dnskey_rrset: input.child_dnskey_rrset,
3344 child_dnskey_rrsig_rrset: input.child_dnskey_rrsig_rrset,
3345 query_name: input.request_name,
3346 closest_encloser: &closest_encloser,
3347 nsec_rrset: &nsec_rrset,
3348 nsec_rrsig_rrset: &nsec_rrsig_rrset,
3349 nsec3_rrset: &nsec3_rrset,
3350 nsec3_rrsig_rrset: &nsec3_rrsig_rrset,
3351 })?;
3352 if secure {
3353 return Ok(ResolutionAnswer {
3354 name: input.request_name.clone(),
3355 records: input.prefix_records.to_vec(),
3356 secure: true,
3357 });
3358 }
3359 }
3360
3361 Err(ResolverError::DnssecFailed)
3362}
3363
3364struct SecureAnswerResolutionInput<'a, T, V> {
3365 transport: &'a T,
3366 verifier: &'a V,
3367 target: DnsQueryTarget<'a>,
3368 delegation: &'a HnsDelegation,
3369 request_name: &'a DnsName,
3370 qtype: RecordType,
3371 ds_rrset: &'a [ResourceRecord],
3372 dnskey_rrset: &'a [ResourceRecord],
3373 dnskey_rrsig_rrset: &'a [ResourceRecord],
3374 initial_response: DnsMessage,
3375}
3376
3377fn resolve_secure_answer_records<T, V>(
3378 input: SecureAnswerResolutionInput<'_, T, V>,
3379) -> Result<ResolutionAnswer, ResolverError>
3380where
3381 T: DnsTransport,
3382 V: DelegatedDnssecVerifier,
3383{
3384 let mut response = input.initial_response;
3385 let mut owner = input.request_name.clone();
3386 let mut cname_records = Vec::new();
3387
3388 for _ in 0..=MAX_CNAME_CHAIN_LEN {
3389 let target_rrset = records_for(&response.answers, &owner, input.qtype);
3390 let cname_rrset = if input.qtype == RecordType::Cname {
3391 Vec::new()
3392 } else {
3393 records_for(&response.answers, &owner, RecordType::Cname)
3394 };
3395 if !target_rrset.is_empty() && !cname_rrset.is_empty() {
3396 return Err(ResolverError::DnssecFailed);
3397 }
3398
3399 if !target_rrset.is_empty() {
3400 validate_secure_rrset(
3401 input.verifier,
3402 SecureRrsetValidationInput {
3403 delegation: input.delegation,
3404 ds_rrset: input.ds_rrset,
3405 dnskey_rrset: input.dnskey_rrset,
3406 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3407 owner: &owner,
3408 rrset: &target_rrset,
3409 response: &response,
3410 },
3411 )?;
3412 cname_records.extend(target_rrset);
3413 return Ok(ResolutionAnswer {
3414 name: input.request_name.clone(),
3415 records: cname_records,
3416 secure: true,
3417 });
3418 }
3419
3420 if !cname_rrset.is_empty() {
3421 validate_secure_rrset(
3422 input.verifier,
3423 SecureRrsetValidationInput {
3424 delegation: input.delegation,
3425 ds_rrset: input.ds_rrset,
3426 dnskey_rrset: input.dnskey_rrset,
3427 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3428 owner: &owner,
3429 rrset: &cname_rrset,
3430 response: &response,
3431 },
3432 )?;
3433 let next_owner = cname_target(&cname_rrset)?;
3434 if !dns_name_is_subdomain_or_equal(&next_owner, &input.delegation.owner) {
3435 return Err(ResolverError::DnssecFailed);
3436 }
3437 cname_records.extend(cname_rrset);
3438 owner = next_owner;
3439 continue;
3440 }
3441
3442 if owner != *input.request_name && response.questions[0].name != owner {
3443 response = dns_query_target(input.transport, input.target, &owner, input.qtype)?;
3444 continue;
3445 }
3446
3447 if response.header.flags.rcode() == DNS_RCODE_NXDOMAIN {
3448 return resolve_secure_name_error(
3449 input.verifier,
3450 NameErrorResolutionInput {
3451 delegation: input.delegation,
3452 request_name: &owner,
3453 ds_rrset: input.ds_rrset,
3454 dnskey_rrset: input.dnskey_rrset,
3455 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3456 response: &response,
3457 prefix_records: &cname_records,
3458 },
3459 );
3460 }
3461
3462 return resolve_secure_no_data(
3463 input.verifier,
3464 NoDataResolutionInput {
3465 delegation: input.delegation,
3466 request_name: &owner,
3467 qtype: input.qtype,
3468 ds_rrset: input.ds_rrset,
3469 dnskey_rrset: input.dnskey_rrset,
3470 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3471 response: &response,
3472 prefix_records: &cname_records,
3473 },
3474 );
3475 }
3476
3477 Err(ResolverError::DnssecFailed)
3478}
3479
3480struct SecureRrsetValidationInput<'a> {
3481 delegation: &'a HnsDelegation,
3482 ds_rrset: &'a [ResourceRecord],
3483 dnskey_rrset: &'a [ResourceRecord],
3484 dnskey_rrsig_rrset: &'a [ResourceRecord],
3485 owner: &'a DnsName,
3486 rrset: &'a [ResourceRecord],
3487 response: &'a DnsMessage,
3488}
3489
3490fn validate_secure_rrset<V>(
3491 verifier: &V,
3492 input: SecureRrsetValidationInput<'_>,
3493) -> Result<(), ResolverError>
3494where
3495 V: DelegatedDnssecVerifier,
3496{
3497 let rrsig_rrset = records_for(&input.response.answers, input.owner, RecordType::Rrsig);
3498 if rrsig_rrset.is_empty() {
3499 return Err(ResolverError::DnssecFailed);
3500 }
3501 let secure = verifier.validate_positive_rrset(DelegatedDnssecValidation {
3502 dnskey_owner: &input.delegation.owner,
3503 ds_rrset: input.ds_rrset,
3504 dnskey_rrset: input.dnskey_rrset,
3505 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3506 target_rrset: input.rrset,
3507 target_rrsig_rrset: &rrsig_rrset,
3508 })?;
3509 if secure {
3510 Ok(())
3511 } else {
3512 Err(ResolverError::DnssecFailed)
3513 }
3514}
3515
3516struct NoDataResolutionInput<'a> {
3517 delegation: &'a HnsDelegation,
3518 request_name: &'a DnsName,
3519 qtype: RecordType,
3520 ds_rrset: &'a [ResourceRecord],
3521 dnskey_rrset: &'a [ResourceRecord],
3522 dnskey_rrsig_rrset: &'a [ResourceRecord],
3523 response: &'a DnsMessage,
3524 prefix_records: &'a [ResourceRecord],
3525}
3526
3527struct NameErrorResolutionInput<'a> {
3528 delegation: &'a HnsDelegation,
3529 request_name: &'a DnsName,
3530 ds_rrset: &'a [ResourceRecord],
3531 dnskey_rrset: &'a [ResourceRecord],
3532 dnskey_rrsig_rrset: &'a [ResourceRecord],
3533 response: &'a DnsMessage,
3534 prefix_records: &'a [ResourceRecord],
3535}
3536
3537fn resolve_secure_no_data<V>(
3538 verifier: &V,
3539 input: NoDataResolutionInput<'_>,
3540) -> Result<ResolutionAnswer, ResolverError>
3541where
3542 V: DelegatedDnssecVerifier,
3543{
3544 if input.dnskey_rrset.is_empty() || input.dnskey_rrsig_rrset.is_empty() {
3545 return Err(ResolverError::DnssecFailed);
3546 }
3547 let proof_records = combined_response_records(input.response);
3548 let nsec_rrset = records_for(&proof_records, input.request_name, RecordType::Nsec);
3549 let nsec_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3550 let nsec3_rrset = records_of_type(&proof_records, RecordType::Nsec3);
3551 let nsec3_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3552 let secure = verifier.validate_no_data(DelegatedDnssecNoDataValidation {
3553 dnskey_owner: &input.delegation.owner,
3554 ds_rrset: input.ds_rrset,
3555 dnskey_rrset: input.dnskey_rrset,
3556 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3557 query_name: input.request_name,
3558 query_type: input.qtype,
3559 nsec_rrset: &nsec_rrset,
3560 nsec_rrsig_rrset: &nsec_rrsig_rrset,
3561 nsec3_rrset: &nsec3_rrset,
3562 nsec3_rrsig_rrset: &nsec3_rrsig_rrset,
3563 })?;
3564 if !secure {
3565 return Err(ResolverError::DnssecFailed);
3566 }
3567
3568 Ok(ResolutionAnswer {
3569 name: input.request_name.clone(),
3570 records: input.prefix_records.to_vec(),
3571 secure: true,
3572 })
3573}
3574
3575fn resolve_secure_name_error<V>(
3576 verifier: &V,
3577 input: NameErrorResolutionInput<'_>,
3578) -> Result<ResolutionAnswer, ResolverError>
3579where
3580 V: DelegatedDnssecVerifier,
3581{
3582 if input.dnskey_rrset.is_empty() || input.dnskey_rrsig_rrset.is_empty() {
3583 return Err(ResolverError::DnssecFailed);
3584 }
3585 let proof_records = combined_response_records(input.response);
3586 let nsec_rrset = records_of_type(&proof_records, RecordType::Nsec);
3587 let nsec_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3588 let nsec3_rrset = records_of_type(&proof_records, RecordType::Nsec3);
3589 let nsec3_rrsig_rrset = records_of_type(&proof_records, RecordType::Rrsig);
3590 for closest_encloser in
3591 closest_encloser_candidates(input.request_name, &input.delegation.owner)?
3592 {
3593 let secure = verifier.validate_name_error(DelegatedDnssecNameErrorValidation {
3594 dnskey_owner: &input.delegation.owner,
3595 ds_rrset: input.ds_rrset,
3596 dnskey_rrset: input.dnskey_rrset,
3597 dnskey_rrsig_rrset: input.dnskey_rrsig_rrset,
3598 query_name: input.request_name,
3599 closest_encloser: &closest_encloser,
3600 nsec_rrset: &nsec_rrset,
3601 nsec_rrsig_rrset: &nsec_rrsig_rrset,
3602 nsec3_rrset: &nsec3_rrset,
3603 nsec3_rrsig_rrset: &nsec3_rrsig_rrset,
3604 })?;
3605 if secure {
3606 return Ok(ResolutionAnswer {
3607 name: input.request_name.clone(),
3608 records: input.prefix_records.to_vec(),
3609 secure: true,
3610 });
3611 }
3612 }
3613
3614 Err(ResolverError::DnssecFailed)
3615}
3616
3617fn closest_encloser_candidates(
3618 query_name: &DnsName,
3619 zone_owner: &DnsName,
3620) -> Result<Vec<DnsName>, ResolverError> {
3621 let query_labels = query_name.labels();
3622 let zone_labels = zone_owner.labels();
3623 if query_labels.len() <= zone_labels.len() || !query_labels.ends_with(zone_labels) {
3624 return Ok(Vec::new());
3625 }
3626
3627 let mut candidates = Vec::new();
3628 for start in 1..=(query_labels.len() - zone_labels.len()) {
3629 let candidate = DnsName::from_ascii(&query_labels[start..].join("."))
3630 .map_err(|_| ResolverError::InvalidDnsResponse)?;
3631 candidates.push(candidate);
3632 }
3633 Ok(candidates)
3634}
3635
3636#[derive(Clone, Copy)]
3637enum DnsQueryTarget<'a> {
3638 Server(SocketAddr),
3639 ServerTcp(SocketAddr),
3640 Doh(&'a AuthoritativeDohEndpoint),
3641}
3642
3643fn validate_dns_server(policy: DnsEndpointPolicy, server: SocketAddr) -> Result<(), ResolverError> {
3644 if policy.allow_non_public_addresses || is_publicly_routable(server.ip()) {
3645 Ok(())
3646 } else {
3647 Err(ResolverError::NonPublicDnsEndpoint)
3648 }
3649}
3650
3651fn validate_doh_endpoint(
3652 policy: DnsEndpointPolicy,
3653 endpoint: &AuthoritativeDohEndpoint,
3654) -> Result<(), ResolverError> {
3655 validate_dns_server(
3656 policy,
3657 SocketAddr::new(endpoint.connect_addr, endpoint.port),
3658 )?;
3659 if policy.allow_unsafe_doh_ports || !is_browser_blocked_port(endpoint.port) {
3660 Ok(())
3661 } else {
3662 Err(ResolverError::UnsafeAuthoritativeDohPort(endpoint.port))
3663 }
3664}
3665
3666fn dns_query<T: DnsTransport>(
3667 transport: &T,
3668 server: SocketAddr,
3669 qname: &DnsName,
3670 qtype: RecordType,
3671) -> Result<DnsMessage, ResolverError> {
3672 dns_query_target(transport, DnsQueryTarget::Server(server), qname, qtype)
3673}
3674
3675fn dns_query_doh<T: DnsTransport>(
3676 transport: &T,
3677 endpoint: &AuthoritativeDohEndpoint,
3678 qname: &DnsName,
3679 qtype: RecordType,
3680) -> Result<DnsMessage, ResolverError> {
3681 dns_query_target(transport, DnsQueryTarget::Doh(endpoint), qname, qtype)
3682}
3683
3684fn dns_query_target<T: DnsTransport>(
3685 transport: &T,
3686 target: DnsQueryTarget<'_>,
3687 qname: &DnsName,
3688 qtype: RecordType,
3689) -> Result<DnsMessage, ResolverError> {
3690 let endpoint_policy = transport.endpoint_policy();
3691 match target {
3692 DnsQueryTarget::Server(server) | DnsQueryTarget::ServerTcp(server) => {
3693 validate_dns_server(endpoint_policy, server)?
3694 }
3695 DnsQueryTarget::Doh(endpoint) => validate_doh_endpoint(endpoint_policy, endpoint)?,
3696 }
3697 let id = next_dns_query_id();
3698 let query = build_dns_query(id, qname, qtype)?;
3699 if transport.is_recursive_relay()
3700 && matches!(
3701 target,
3702 DnsQueryTarget::Server(_) | DnsQueryTarget::ServerTcp(_)
3703 )
3704 {
3705 let server = match target {
3706 DnsQueryTarget::Server(server) | DnsQueryTarget::ServerTcp(server) => server,
3707 DnsQueryTarget::Doh(_) => return Err(ResolverError::UnsupportedBackend),
3708 };
3709 let response = transport.exchange_udp(server, &query)?;
3710 let response = parse_dns_response(id, qname, qtype, &response)?;
3711 if response.header.flags.truncated() {
3712 return Err(ResolverError::InvalidDnsResponse);
3713 }
3714 return Ok(response);
3715 }
3716 let server = match target {
3717 DnsQueryTarget::Server(server) => server,
3718 DnsQueryTarget::ServerTcp(server) => {
3719 return dns_query_tcp(transport, server, id, qname, qtype, &query);
3720 }
3721 DnsQueryTarget::Doh(_) => {
3722 return dns_query_https(transport, target, qname, qtype, &query);
3723 }
3724 };
3725 let udp_response = match transport.exchange_udp(server, &query) {
3726 Ok(response) => response,
3727 Err(error) if dns_query_should_retry_tcp(&error) => {
3728 return dns_query_tcp(transport, server, id, qname, qtype, &query)
3729 .map_err(|tcp_error| strongest_resolution_error(error, tcp_error));
3730 }
3731 Err(error) => return Err(error),
3732 };
3733 let response = match parse_dns_response(id, qname, qtype, &udp_response) {
3734 Ok(response) => response,
3735 Err(error) if dns_query_should_retry_tcp(&error) => {
3736 return dns_query_tcp(transport, server, id, qname, qtype, &query)
3737 .map_err(|tcp_error| strongest_resolution_error(error, tcp_error));
3738 }
3739 Err(error) => return Err(error),
3740 };
3741 if response.header.flags.truncated() {
3742 return dns_query_tcp(transport, server, id, qname, qtype, &query);
3743 }
3744
3745 Ok(response)
3746}
3747
3748fn dns_query_https<T: DnsTransport>(
3749 transport: &T,
3750 target: DnsQueryTarget<'_>,
3751 qname: &DnsName,
3752 qtype: RecordType,
3753 query: &[u8],
3754) -> Result<DnsMessage, ResolverError> {
3755 let DnsQueryTarget::Doh(endpoint) = target else {
3756 return Err(ResolverError::UnsupportedBackend);
3757 };
3758 let mut query = query.to_vec();
3759 if query.len() < 2 {
3760 return Err(ResolverError::InvalidDnsResponse);
3761 }
3762 query[0] = 0;
3763 query[1] = 0;
3764 let response = transport.exchange_doh(endpoint, &query)?;
3765 parse_dns_response(0, qname, qtype, &response)
3766}
3767
3768fn dns_query_should_retry_tcp(error: &ResolverError) -> bool {
3769 matches!(
3770 error,
3771 ResolverError::DnsTransport(_) | ResolverError::InvalidDnsResponse
3772 )
3773}
3774
3775fn dns_query_tcp<T: DnsTransport>(
3776 transport: &T,
3777 server: SocketAddr,
3778 id: u16,
3779 qname: &DnsName,
3780 qtype: RecordType,
3781 query: &[u8],
3782) -> Result<DnsMessage, ResolverError> {
3783 let tcp_response = transport.exchange_tcp(server, query)?;
3784 let response = parse_dns_response(id, qname, qtype, &tcp_response)?;
3785 if response.header.flags.truncated() {
3786 return Err(ResolverError::InvalidDnsResponse);
3787 }
3788
3789 Ok(response)
3790}
3791
3792fn next_dns_query_id() -> u16 {
3793 DNS_QUERY_ID.fetch_add(1, Ordering::Relaxed).wrapping_add(1)
3794}
3795
3796fn build_dns_query(id: u16, qname: &DnsName, qtype: RecordType) -> Result<Vec<u8>, ResolverError> {
3797 let message = DnsMessage {
3798 header: DnsHeader {
3799 id,
3800 flags: DnsFlags::new(0),
3801 question_count: 1,
3802 answer_count: 0,
3803 authority_count: 0,
3804 additional_count: 1,
3805 },
3806 questions: vec![DnsQuestion {
3807 name: qname.clone(),
3808 record_type: qtype,
3809 class: DNS_CLASS_IN,
3810 }],
3811 answers: Vec::new(),
3812 authorities: Vec::new(),
3813 additionals: vec![ResourceRecord {
3814 name: DnsName::root(),
3815 record_type: RecordType::Unknown(DNS_OPT_RECORD_TYPE),
3816 class: DEFAULT_DNS_UDP_PAYLOAD as u16,
3817 ttl: DNSSEC_DO_FLAG,
3818 rdata: Vec::new(),
3819 }],
3820 };
3821
3822 message
3823 .encode(&DnsEncodeConfig {
3824 max_message_len: DEFAULT_DNS_UDP_PAYLOAD,
3825 })
3826 .map_err(|_| ResolverError::InvalidDnsResponse)
3827}
3828
3829fn parse_dns_response(
3830 id: u16,
3831 qname: &DnsName,
3832 qtype: RecordType,
3833 response: &[u8],
3834) -> Result<DnsMessage, ResolverError> {
3835 let message = DnsMessage::parse(response).map_err(|_| ResolverError::InvalidDnsResponse)?;
3836 let rcode = message.header.flags.rcode();
3837 if message.header.id != id
3838 || !message.header.flags.is_response()
3839 || message.header.flags.opcode() != 0
3840 || message.questions.len() != 1
3841 || message.questions[0].name != *qname
3842 || message.questions[0].record_type != qtype
3843 || message.questions[0].class != DNS_CLASS_IN
3844 {
3845 return Err(ResolverError::InvalidDnsResponse);
3846 }
3847 if !matches!(rcode, DNS_RCODE_NOERROR | DNS_RCODE_NXDOMAIN) {
3848 return Err(ResolverError::DnsResponseCode(rcode));
3849 }
3850
3851 Ok(message)
3852}
3853
3854fn nameserver_addresses(delegation: &HnsDelegation) -> Vec<SocketAddr> {
3855 nameserver_ip_addresses(delegation)
3856 .into_iter()
3857 .map(|(_, address)| SocketAddr::new(address, 53))
3858 .fold(Vec::new(), |mut addresses, socket| {
3859 if !addresses.contains(&socket) {
3860 addresses.push(socket);
3861 }
3862 addresses
3863 })
3864}
3865
3866fn nameserver_ip_addresses(delegation: &HnsDelegation) -> Vec<(DnsName, IpAddr)> {
3867 let ns_names = delegation
3868 .records
3869 .iter()
3870 .filter(|record| record.name == delegation.owner && record.record_type == RecordType::Ns)
3871 .filter_map(record_name_rdata)
3872 .fold(Vec::<DnsName>::new(), |mut names, name| {
3873 if !names.contains(&name) {
3874 names.push(name);
3875 }
3876 names
3877 });
3878
3879 let mut addresses = Vec::new();
3880 for ns_name in ns_names {
3881 for record in delegation
3882 .records
3883 .iter()
3884 .filter(|record| record.name == ns_name)
3885 {
3886 let address = match record.record_type {
3887 RecordType::A if record.rdata.len() == 4 => Some(IpAddr::V4(Ipv4Addr::new(
3888 record.rdata[0],
3889 record.rdata[1],
3890 record.rdata[2],
3891 record.rdata[3],
3892 ))),
3893 RecordType::Aaaa if record.rdata.len() == 16 => {
3894 let mut bytes = [0u8; 16];
3895 bytes.copy_from_slice(&record.rdata);
3896 Some(IpAddr::V6(Ipv6Addr::from(bytes)))
3897 }
3898 _ => None,
3899 };
3900 let Some(address) = address else {
3901 continue;
3902 };
3903 let entry = (ns_name.clone(), address);
3904 if !addresses.contains(&entry) {
3905 addresses.push(entry);
3906 }
3907 }
3908 }
3909
3910 addresses
3911}
3912
3913fn child_referral(
3914 response: &DnsMessage,
3915 parent_owner: &DnsName,
3916 request_name: &DnsName,
3917) -> Option<ChildReferral> {
3918 let owner = response
3919 .authorities
3920 .iter()
3921 .filter(|record| record.record_type == RecordType::Ns)
3922 .map(|record| record.name.clone())
3923 .filter(|owner| {
3924 owner != parent_owner
3925 && dns_name_is_subdomain_or_equal(owner, parent_owner)
3926 && dns_name_is_subdomain_or_equal(request_name, owner)
3927 })
3928 .max_by_key(|owner| owner.labels().len())?;
3929 let ns_rrset = records_for(&response.authorities, &owner, RecordType::Ns);
3930 let ds_rrset = records_for(&response.authorities, &owner, RecordType::Ds);
3931 let ds_rrsig_rrset = records_for(&response.authorities, &owner, RecordType::Rrsig);
3932 if ns_rrset.is_empty() || ds_rrset.is_empty() || ds_rrsig_rrset.is_empty() {
3933 return None;
3934 }
3935
3936 Some(ChildReferral {
3937 owner,
3938 servers: referral_nameserver_addresses(&ns_rrset, &response.additionals),
3939 ds_rrset,
3940 ds_rrsig_rrset,
3941 })
3942}
3943
3944fn inline_child_answer_signer(
3945 delegation: &HnsDelegation,
3946 request_name: &DnsName,
3947 rrset: &[ResourceRecord],
3948 rrsig_rrset: &[ResourceRecord],
3949 record_type: RecordType,
3950) -> Option<DnsName> {
3951 let first = rrset.first()?;
3952 for record in rrsig_rrset.iter().filter(|record| {
3953 record.name == first.name
3954 && record.class == first.class
3955 && record.record_type == RecordType::Rrsig
3956 }) {
3957 let rrsig = RrsigRecord::from_record(record).ok()?;
3958 if rrsig.type_covered == record_type
3959 && rrsig.signer_name != delegation.owner
3960 && dns_name_is_subdomain_or_equal(&rrsig.signer_name, &delegation.owner)
3961 && dns_name_is_subdomain_or_equal(request_name, &rrsig.signer_name)
3962 {
3963 return Some(rrsig.signer_name);
3964 }
3965 }
3966
3967 None
3968}
3969
3970fn inline_child_denial_signer(
3971 delegation: &HnsDelegation,
3972 request_name: &DnsName,
3973 proof_records: &[ResourceRecord],
3974) -> Option<DnsName> {
3975 proof_records
3976 .iter()
3977 .filter(|record| record.record_type == RecordType::Rrsig)
3978 .filter_map(|record| {
3979 let rrsig = RrsigRecord::from_record(record).ok()?;
3980 if matches!(rrsig.type_covered, RecordType::Nsec | RecordType::Nsec3)
3981 && rrsig.signer_name != delegation.owner
3982 && dns_name_is_subdomain_or_equal(&rrsig.signer_name, &delegation.owner)
3983 && dns_name_is_subdomain_or_equal(request_name, &rrsig.signer_name)
3984 {
3985 Some(rrsig.signer_name)
3986 } else {
3987 None
3988 }
3989 })
3990 .max_by_key(|owner| owner.labels().len())
3991}
3992
3993fn referral_nameserver_addresses(
3994 ns_rrset: &[ResourceRecord],
3995 additionals: &[ResourceRecord],
3996) -> Vec<SocketAddr> {
3997 let ns_names = ns_rrset.iter().filter_map(record_name_rdata).fold(
3998 Vec::<DnsName>::new(),
3999 |mut names, name| {
4000 if !names.contains(&name) {
4001 names.push(name);
4002 }
4003 names
4004 },
4005 );
4006 let mut addresses = Vec::new();
4007 for ns_name in ns_names {
4008 for record in additionals.iter().filter(|record| record.name == ns_name) {
4009 let address = match record.record_type {
4010 RecordType::A if record.rdata.len() == 4 => Some(IpAddr::V4(Ipv4Addr::new(
4011 record.rdata[0],
4012 record.rdata[1],
4013 record.rdata[2],
4014 record.rdata[3],
4015 ))),
4016 RecordType::Aaaa if record.rdata.len() == 16 => {
4017 let mut bytes = [0u8; 16];
4018 bytes.copy_from_slice(&record.rdata);
4019 Some(IpAddr::V6(Ipv6Addr::from(bytes)))
4020 }
4021 _ => None,
4022 };
4023 let Some(address) = address else {
4024 continue;
4025 };
4026 let socket = SocketAddr::new(address, 53);
4027 if !addresses.contains(&socket) {
4028 addresses.push(socket);
4029 }
4030 }
4031 }
4032
4033 addresses
4034}
4035
4036fn record_name_rdata(record: &ResourceRecord) -> Option<DnsName> {
4037 let (name, end) = DnsName::parse_wire(&record.rdata, 0).ok()?;
4038 (end == record.rdata.len()).then_some(name)
4039}
4040
4041fn cname_target(cname_rrset: &[ResourceRecord]) -> Result<DnsName, ResolverError> {
4042 if cname_rrset.len() != 1 || cname_rrset[0].record_type != RecordType::Cname {
4043 return Err(ResolverError::DnssecFailed);
4044 }
4045 record_name_rdata(&cname_rrset[0]).ok_or(ResolverError::DnssecFailed)
4046}
4047
4048fn dns_name_is_subdomain_or_equal(name: &DnsName, parent: &DnsName) -> bool {
4049 name.labels().ends_with(parent.labels())
4050}
4051
4052fn records_for(
4053 records: &[ResourceRecord],
4054 owner: &DnsName,
4055 record_type: RecordType,
4056) -> Vec<ResourceRecord> {
4057 records
4058 .iter()
4059 .filter(|record| record.name == *owner && record.record_type == record_type)
4060 .cloned()
4061 .collect()
4062}
4063
4064fn records_of_type(records: &[ResourceRecord], record_type: RecordType) -> Vec<ResourceRecord> {
4065 records
4066 .iter()
4067 .filter(|record| record.record_type == record_type)
4068 .cloned()
4069 .collect()
4070}
4071
4072fn combined_response_records(response: &DnsMessage) -> Vec<ResourceRecord> {
4073 response
4074 .answers
4075 .iter()
4076 .chain(response.authorities.iter())
4077 .cloned()
4078 .collect()
4079}
4080
4081pub fn hns_root_label(input: &str) -> Result<String, ResolverError> {
4082 let trimmed = input
4083 .trim()
4084 .trim_start_matches("https://")
4085 .trim_start_matches("http://")
4086 .split(['/', '?', '#'])
4087 .next()
4088 .unwrap_or_default()
4089 .trim_end_matches('.');
4090 let name = DnsName::from_ascii(trimmed).map_err(|_| ResolverError::UnsupportedBackend)?;
4091 let labels = name.labels();
4092 let root = labels.last().ok_or(ResolverError::UnsupportedBackend)?;
4093
4094 NameHash::from_name(root)?;
4095 Ok(root.to_owned())
4096}
4097
4098pub fn classify_name(input: &str) -> NameClass {
4099 let trimmed = input.trim();
4100 if trimmed.is_empty() || trimmed.chars().any(char::is_whitespace) {
4101 return NameClass::Search;
4102 }
4103
4104 let host = trimmed
4105 .trim_start_matches("https://")
4106 .trim_start_matches("http://")
4107 .split(['/', '?', '#'])
4108 .next()
4109 .unwrap_or_default();
4110
4111 let host = host.trim_end_matches('.');
4112
4113 if host.is_empty() {
4114 NameClass::Search
4115 } else if host.parse::<IpAddr>().is_ok() || uses_icann_namespace(host) {
4116 NameClass::Icann
4117 } else if hns_root_label(host).is_ok() {
4118 NameClass::Hns
4119 } else {
4120 NameClass::Icann
4121 }
4122}
4123
4124fn uses_icann_namespace(host: &str) -> bool {
4125 let host = host.trim_end_matches('.');
4126 let Some(suffix) = host.rsplit('.').next() else {
4127 return false;
4128 };
4129 is_browser_special_use_host(host)
4130 || host.contains('.')
4131 && ICANN_TLDS
4132 .lines()
4133 .any(|candidate| suffix.eq_ignore_ascii_case(candidate))
4134}
4135
4136#[cfg(test)]
4137mod tests {
4138 use super::*;
4139 use std::sync::Arc;
4140 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
4141
4142 type DnsRequestLog = Arc<Mutex<Vec<(SocketAddr, String, u16, bool)>>>;
4143 type DnsValidationLog = Arc<Mutex<Vec<(usize, usize, usize, usize, usize)>>>;
4144 type DnsResponseMap = HashMap<(String, u16), DnsResponseFixture>;
4145 type ServerDnsResponseMap = HashMap<(SocketAddr, String, u16), DnsResponseFixture>;
4146
4147 struct CountingResolver {
4148 count: AtomicUsize,
4149 }
4150
4151 struct CountingNameNotFoundResolver {
4152 count: AtomicUsize,
4153 }
4154
4155 struct StaticProofProvider {
4156 proven: ProvenNameRecords,
4157 }
4158
4159 struct MapProofProvider {
4160 proven: HashMap<String, ProvenNameRecords>,
4161 }
4162
4163 struct StaticValueProvider {
4164 verified: VerifiedResourceValue,
4165 }
4166
4167 struct ScriptedResolver {
4168 responses: Vec<(ResolutionRequest, ResolutionAnswer)>,
4169 requests: Arc<Mutex<Vec<ResolutionRequest>>>,
4170 }
4171
4172 struct CapturingDelegatedResolver {
4173 delegations: Arc<Mutex<Vec<HnsDelegation>>>,
4174 }
4175
4176 struct ScriptedDnsTransport {
4177 responses: DnsResponseMap,
4178 server_responses: ServerDnsResponseMap,
4179 requests: DnsRequestLog,
4180 udp_behavior: ScriptedUdpBehavior,
4181 }
4182
4183 struct PolicyDnsTransport {
4184 policy: DnsEndpointPolicy,
4185 calls: AtomicUsize,
4186 }
4187
4188 struct FailingPinnedDohTransport {
4189 doh_calls: AtomicUsize,
4190 udp_calls: AtomicUsize,
4191 tcp_calls: AtomicUsize,
4192 }
4193
4194 struct InterceptedDnsTransport {
4195 interception_detected: AtomicBool,
4196 probe_calls: AtomicUsize,
4197 doh_calls: AtomicUsize,
4198 udp_calls: AtomicUsize,
4199 tcp_calls: AtomicUsize,
4200 }
4201
4202 struct TcpRepairDnsTransport {
4203 requests: DnsRequestLog,
4204 }
4205
4206 struct RecursiveRelayErrorTransport {
4207 udp_calls: AtomicUsize,
4208 tcp_calls: AtomicUsize,
4209 }
4210
4211 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4212 enum ScriptedUdpBehavior {
4213 #[default]
4214 Normal,
4215 Truncated,
4216 TransportError,
4217 InvalidResponse,
4218 }
4219
4220 struct StaticDnssecVerifier {
4221 positive_valid: bool,
4222 no_data_valid: bool,
4223 name_error_valid: bool,
4224 child_positive_valid: bool,
4225 child_no_data_valid: bool,
4226 child_name_error_valid: bool,
4227 validations: DnsValidationLog,
4228 no_data_validations: DnsValidationLog,
4229 name_error_validations: DnsValidationLog,
4230 child_validations: DnsValidationLog,
4231 child_no_data_validations: DnsValidationLog,
4232 child_name_error_validations: DnsValidationLog,
4233 }
4234
4235 fn accepting_dnssec_verifier() -> StaticDnssecVerifier {
4236 StaticDnssecVerifier {
4237 positive_valid: true,
4238 no_data_valid: false,
4239 name_error_valid: false,
4240 child_positive_valid: false,
4241 child_no_data_valid: false,
4242 child_name_error_valid: false,
4243 validations: Arc::new(Mutex::new(Vec::new())),
4244 no_data_validations: Arc::new(Mutex::new(Vec::new())),
4245 name_error_validations: Arc::new(Mutex::new(Vec::new())),
4246 child_validations: Arc::new(Mutex::new(Vec::new())),
4247 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
4248 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
4249 }
4250 }
4251
4252 #[derive(Clone, Debug, Default, Eq, PartialEq)]
4253 struct DnsResponseFixture {
4254 rcode: u8,
4255 answers: Vec<ResourceRecord>,
4256 authorities: Vec<ResourceRecord>,
4257 additionals: Vec<ResourceRecord>,
4258 }
4259
4260 impl Resolver for CountingResolver {
4261 fn resolve(&self, _request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
4262 self.count.fetch_add(1, Ordering::SeqCst);
4263 Ok(ResolutionAnswer {
4264 name: DnsName::root(),
4265 records: Vec::new(),
4266 secure: true,
4267 })
4268 }
4269 }
4270
4271 impl Resolver for CountingNameNotFoundResolver {
4272 fn resolve(&self, _request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
4273 self.count.fetch_add(1, Ordering::SeqCst);
4274 Err(ResolverError::NameNotFound)
4275 }
4276 }
4277
4278 impl HnsProofProvider for StaticProofProvider {
4279 fn prove_name(
4280 &self,
4281 _root_name: &str,
4282 _name_hash: NameHash,
4283 ) -> Result<ProvenNameRecords, ResolverError> {
4284 Ok(self.proven.clone())
4285 }
4286 }
4287
4288 impl HnsProofProvider for MapProofProvider {
4289 fn prove_name(
4290 &self,
4291 root_name: &str,
4292 name_hash: NameHash,
4293 ) -> Result<ProvenNameRecords, ResolverError> {
4294 let proven = self
4295 .proven
4296 .get(root_name)
4297 .cloned()
4298 .ok_or(ResolverError::ProofUnavailable)?;
4299 if proven.root_name != root_name || proven.name_hash != name_hash || !proven.secure {
4300 return Err(ResolverError::ProofNameMismatch);
4301 }
4302 Ok(proven)
4303 }
4304 }
4305
4306 impl HnsResourceValueProvider for StaticValueProvider {
4307 fn prove_resource_value(
4308 &self,
4309 _root_name: &str,
4310 _name_hash: NameHash,
4311 ) -> Result<VerifiedResourceValue, ResolverError> {
4312 Ok(self.verified.clone())
4313 }
4314 }
4315
4316 impl ScriptedResolver {
4317 fn new(
4318 responses: Vec<(ResolutionRequest, ResolutionAnswer)>,
4319 requests: Arc<Mutex<Vec<ResolutionRequest>>>,
4320 ) -> Self {
4321 Self {
4322 responses,
4323 requests,
4324 }
4325 }
4326 }
4327
4328 impl Resolver for ScriptedResolver {
4329 fn resolve(&self, request: &ResolutionRequest) -> Result<ResolutionAnswer, ResolverError> {
4330 self.requests
4331 .lock()
4332 .map_err(|_| ResolverError::CachePoisoned)?
4333 .push(request.clone());
4334 self.responses
4335 .iter()
4336 .find(|(candidate, _)| candidate == request)
4337 .map(|(_, answer)| answer.clone())
4338 .ok_or(ResolverError::ProofUnavailable)
4339 }
4340 }
4341
4342 impl DelegatedResolver for CapturingDelegatedResolver {
4343 fn resolve_delegated(
4344 &self,
4345 request: &ResolutionRequest,
4346 delegation: &HnsDelegation,
4347 ) -> Result<ResolutionAnswer, ResolverError> {
4348 self.delegations
4349 .lock()
4350 .map_err(|_| ResolverError::CachePoisoned)?
4351 .push(delegation.clone());
4352 Ok(ResolutionAnswer {
4353 name: DnsName::from_ascii(&request.qname).unwrap(),
4354 records: vec![record(
4355 DnsName::from_ascii(&request.qname).unwrap(),
4356 RecordType::A,
4357 vec![127, 0, 0, 1],
4358 )],
4359 secure: true,
4360 })
4361 }
4362 }
4363
4364 impl DnsTransport for ScriptedDnsTransport {
4365 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4366 DnsEndpointPolicy::permissive()
4367 }
4368
4369 fn exchange_udp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
4370 let query = DnsMessage::parse(query).unwrap();
4371 let question = query.questions[0].clone();
4372 assert_eq!(query.additionals.len(), 1);
4373 assert_eq!(
4374 query.additionals[0].record_type,
4375 RecordType::Unknown(DNS_OPT_RECORD_TYPE)
4376 );
4377 assert_eq!(query.additionals[0].ttl, DNSSEC_DO_FLAG);
4378 self.requests.lock().unwrap().push((
4379 server,
4380 question.name.to_string(),
4381 question.record_type.code(),
4382 false,
4383 ));
4384 match self.udp_behavior {
4385 ScriptedUdpBehavior::Normal => {}
4386 ScriptedUdpBehavior::Truncated => {
4387 return Ok(dns_response(&query, DnsResponseFixture::default(), true));
4388 }
4389 ScriptedUdpBehavior::TransportError => {
4390 return Err(ResolverError::DnsTransport("udp failed".to_owned()));
4391 }
4392 ScriptedUdpBehavior::InvalidResponse => return Ok(vec![0, 1, 2, 3]),
4393 }
4394 let fixture = self
4395 .server_responses
4396 .get(&(
4397 server,
4398 question.name.to_string(),
4399 question.record_type.code(),
4400 ))
4401 .or_else(|| {
4402 self.responses
4403 .get(&(question.name.to_string(), question.record_type.code()))
4404 })
4405 .cloned()
4406 .unwrap_or_default();
4407 Ok(dns_response(&query, fixture, false))
4408 }
4409
4410 fn exchange_tcp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
4411 let query = DnsMessage::parse(query).unwrap();
4412 let question = query.questions[0].clone();
4413 self.requests.lock().unwrap().push((
4414 server,
4415 question.name.to_string(),
4416 question.record_type.code(),
4417 true,
4418 ));
4419 let fixture = self
4420 .server_responses
4421 .get(&(
4422 server,
4423 question.name.to_string(),
4424 question.record_type.code(),
4425 ))
4426 .or_else(|| {
4427 self.responses
4428 .get(&(question.name.to_string(), question.record_type.code()))
4429 })
4430 .cloned()
4431 .unwrap_or_default();
4432 Ok(dns_response(&query, fixture, false))
4433 }
4434
4435 fn exchange_doh(
4436 &self,
4437 endpoint: &AuthoritativeDohEndpoint,
4438 query: &[u8],
4439 ) -> Result<Vec<u8>, ResolverError> {
4440 let query = DnsMessage::parse(query).unwrap();
4441 let question = query.questions[0].clone();
4442 let server = SocketAddr::new(endpoint.connect_addr, endpoint.port);
4443 self.requests.lock().unwrap().push((
4444 server,
4445 question.name.to_string(),
4446 question.record_type.code(),
4447 true,
4448 ));
4449 let fixture = self
4450 .server_responses
4451 .get(&(
4452 server,
4453 question.name.to_string(),
4454 question.record_type.code(),
4455 ))
4456 .or_else(|| {
4457 self.responses
4458 .get(&(question.name.to_string(), question.record_type.code()))
4459 })
4460 .cloned()
4461 .unwrap_or_default();
4462 Ok(dns_response(&query, fixture, false))
4463 }
4464 }
4465
4466 impl DnsTransport for PolicyDnsTransport {
4467 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4468 self.policy
4469 }
4470
4471 fn exchange_udp(
4472 &self,
4473 _server: SocketAddr,
4474 _query: &[u8],
4475 ) -> Result<Vec<u8>, ResolverError> {
4476 self.calls.fetch_add(1, Ordering::SeqCst);
4477 Err(ResolverError::UnsupportedBackend)
4478 }
4479
4480 fn exchange_tcp(
4481 &self,
4482 _server: SocketAddr,
4483 _query: &[u8],
4484 ) -> Result<Vec<u8>, ResolverError> {
4485 self.calls.fetch_add(1, Ordering::SeqCst);
4486 Err(ResolverError::UnsupportedBackend)
4487 }
4488
4489 fn exchange_doh(
4490 &self,
4491 _endpoint: &AuthoritativeDohEndpoint,
4492 _query: &[u8],
4493 ) -> Result<Vec<u8>, ResolverError> {
4494 self.calls.fetch_add(1, Ordering::SeqCst);
4495 Err(ResolverError::UnsupportedBackend)
4496 }
4497 }
4498
4499 impl DnsTransport for FailingPinnedDohTransport {
4500 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4501 DnsEndpointPolicy::permissive()
4502 }
4503
4504 fn exchange_udp(
4505 &self,
4506 _server: SocketAddr,
4507 query: &[u8],
4508 ) -> Result<Vec<u8>, ResolverError> {
4509 self.udp_calls.fetch_add(1, Ordering::SeqCst);
4510 let query = DnsMessage::parse(query).unwrap();
4511 let question = query.questions[0].clone();
4512 Ok(dns_response(
4513 &query,
4514 tcp_repair_fixture(&question, true),
4515 false,
4516 ))
4517 }
4518
4519 fn exchange_tcp(
4520 &self,
4521 _server: SocketAddr,
4522 _query: &[u8],
4523 ) -> Result<Vec<u8>, ResolverError> {
4524 self.tcp_calls.fetch_add(1, Ordering::SeqCst);
4525 Err(ResolverError::DnsTransport("unexpected TCP".to_owned()))
4526 }
4527
4528 fn exchange_doh(
4529 &self,
4530 _endpoint: &AuthoritativeDohEndpoint,
4531 _query: &[u8],
4532 ) -> Result<Vec<u8>, ResolverError> {
4533 self.doh_calls.fetch_add(1, Ordering::SeqCst);
4534 Err(ResolverError::DnsTransport(
4535 "HNS proof TLSA validation failed".to_owned(),
4536 ))
4537 }
4538 }
4539
4540 impl DnsTransport for InterceptedDnsTransport {
4541 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4542 DnsEndpointPolicy::permissive()
4543 }
4544
4545 fn exchange_udp(
4546 &self,
4547 _server: SocketAddr,
4548 query: &[u8],
4549 ) -> Result<Vec<u8>, ResolverError> {
4550 self.udp_calls.fetch_add(1, Ordering::SeqCst);
4551 let query = DnsMessage::parse(query).unwrap();
4552 let question = query.questions[0].clone();
4553 Ok(dns_response(
4554 &query,
4555 tcp_repair_fixture(&question, false),
4556 false,
4557 ))
4558 }
4559
4560 fn exchange_tcp(
4561 &self,
4562 _server: SocketAddr,
4563 _query: &[u8],
4564 ) -> Result<Vec<u8>, ResolverError> {
4565 self.tcp_calls.fetch_add(1, Ordering::SeqCst);
4566 Err(ResolverError::DnsTransport(
4567 "intercepted TCP must not be attempted".to_owned(),
4568 ))
4569 }
4570
4571 fn exchange_doh(
4572 &self,
4573 _endpoint: &AuthoritativeDohEndpoint,
4574 query: &[u8],
4575 ) -> Result<Vec<u8>, ResolverError> {
4576 self.doh_calls.fetch_add(1, Ordering::SeqCst);
4577 let query = DnsMessage::parse(query).unwrap();
4578 let question = query.questions[0].clone();
4579 Ok(dns_response(
4580 &query,
4581 tcp_repair_fixture(&question, true),
4582 false,
4583 ))
4584 }
4585
4586 fn probe_dns_interception(&self) -> DnsInterceptionStatus {
4587 self.probe_calls.fetch_add(1, Ordering::SeqCst);
4588 self.interception_detected.store(true, Ordering::SeqCst);
4589 DnsInterceptionStatus::Detected
4590 }
4591
4592 fn dns_interception_status(&self) -> DnsInterceptionStatus {
4593 if self.interception_detected.load(Ordering::SeqCst) {
4594 DnsInterceptionStatus::Detected
4595 } else {
4596 DnsInterceptionStatus::NotTested
4597 }
4598 }
4599 }
4600
4601 impl DnsTransport for TcpRepairDnsTransport {
4602 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4603 DnsEndpointPolicy::permissive()
4604 }
4605
4606 fn exchange_udp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
4607 let query = DnsMessage::parse(query).unwrap();
4608 let question = query.questions[0].clone();
4609 self.requests.lock().unwrap().push((
4610 server,
4611 question.name.to_string(),
4612 question.record_type.code(),
4613 false,
4614 ));
4615 Ok(dns_response(
4616 &query,
4617 tcp_repair_fixture(&question, false),
4618 false,
4619 ))
4620 }
4621
4622 fn exchange_tcp(&self, server: SocketAddr, query: &[u8]) -> Result<Vec<u8>, ResolverError> {
4623 let query = DnsMessage::parse(query).unwrap();
4624 let question = query.questions[0].clone();
4625 self.requests.lock().unwrap().push((
4626 server,
4627 question.name.to_string(),
4628 question.record_type.code(),
4629 true,
4630 ));
4631 Ok(dns_response(
4632 &query,
4633 tcp_repair_fixture(&question, true),
4634 false,
4635 ))
4636 }
4637 }
4638
4639 impl DnsTransport for RecursiveRelayErrorTransport {
4640 fn endpoint_policy(&self) -> DnsEndpointPolicy {
4641 DnsEndpointPolicy::permissive()
4642 }
4643
4644 fn exchange_udp(
4645 &self,
4646 _server: SocketAddr,
4647 _query: &[u8],
4648 ) -> Result<Vec<u8>, ResolverError> {
4649 self.udp_calls.fetch_add(1, Ordering::SeqCst);
4650 Err(ResolverError::DnsTransport("relay unavailable".to_owned()))
4651 }
4652
4653 fn exchange_tcp(
4654 &self,
4655 _server: SocketAddr,
4656 _query: &[u8],
4657 ) -> Result<Vec<u8>, ResolverError> {
4658 self.tcp_calls.fetch_add(1, Ordering::SeqCst);
4659 Err(ResolverError::DnsTransport(
4660 "recursive relay must not receive TCP retry".to_owned(),
4661 ))
4662 }
4663
4664 fn is_recursive_relay(&self) -> bool {
4665 true
4666 }
4667 }
4668
4669 #[test]
4670 fn composite_resolver_routes_hns_and_icann_requests() {
4671 let resolver = CompositeResolver::new(
4672 CountingResolver {
4673 count: AtomicUsize::new(0),
4674 },
4675 CountingResolver {
4676 count: AtomicUsize::new(0),
4677 },
4678 );
4679
4680 resolver
4681 .resolve(&ResolutionRequest {
4682 qname: "name".to_owned(),
4683 qtype: RecordType::A.code(),
4684 })
4685 .unwrap();
4686 resolver
4687 .resolve(&ResolutionRequest {
4688 qname: "example.com".to_owned(),
4689 qtype: RecordType::A.code(),
4690 })
4691 .unwrap();
4692 assert_eq!(
4693 resolver
4694 .resolve(&ResolutionRequest {
4695 qname: "bad name".to_owned(),
4696 qtype: RecordType::A.code(),
4697 })
4698 .unwrap_err(),
4699 ResolverError::UnsupportedBackend,
4700 );
4701
4702 let (hns, icann) = resolver.into_parts();
4703 assert_eq!(hns.count.load(Ordering::SeqCst), 1);
4704 assert_eq!(icann.count.load(Ordering::SeqCst), 1);
4705 }
4706
4707 #[test]
4708 fn recursive_relay_owns_retries_and_ignores_additional_nameserver_addresses() {
4709 let transport = RecursiveRelayErrorTransport {
4710 udp_calls: AtomicUsize::new(0),
4711 tcp_calls: AtomicUsize::new(0),
4712 };
4713 let resolver = AuthoritativeDnssecResolver::new(transport, accepting_dnssec_verifier())
4714 .without_authoritative_doh();
4715 let delegation = HnsDelegation {
4716 root_name: "welcome".to_owned(),
4717 owner: DnsName::from_ascii("welcome").unwrap(),
4718 records: vec![
4719 ns_record("welcome", "ns1.welcome"),
4720 ns_record("welcome", "ns2.welcome"),
4721 glue4_record("ns1.welcome", [203, 0, 113, 53]),
4722 glue4_record("ns2.welcome", [203, 0, 113, 54]),
4723 ],
4724 };
4725
4726 assert!(matches!(
4727 resolver.resolve_delegated(
4728 &ResolutionRequest {
4729 qname: "www.welcome".to_owned(),
4730 qtype: RecordType::A.code(),
4731 },
4732 &delegation,
4733 ),
4734 Err(ResolverError::DnsTransport(_))
4735 ));
4736 let (transport, _) = resolver.into_parts();
4737 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 1);
4738 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 0);
4739 }
4740
4741 impl DelegatedDnssecVerifier for StaticDnssecVerifier {
4742 fn validate_positive_rrset(
4743 &self,
4744 input: DelegatedDnssecValidation<'_>,
4745 ) -> Result<bool, ResolverError> {
4746 self.validations.lock().unwrap().push((
4747 input.ds_rrset.len(),
4748 input.dnskey_rrset.len(),
4749 input.dnskey_rrsig_rrset.len(),
4750 input.target_rrset.len(),
4751 input.target_rrsig_rrset.len(),
4752 ));
4753 Ok(self.positive_valid)
4754 }
4755
4756 fn validate_no_data(
4757 &self,
4758 input: DelegatedDnssecNoDataValidation<'_>,
4759 ) -> Result<bool, ResolverError> {
4760 self.no_data_validations.lock().unwrap().push((
4761 input.ds_rrset.len(),
4762 input.dnskey_rrset.len(),
4763 input.dnskey_rrsig_rrset.len(),
4764 input.nsec_rrset.len() + input.nsec3_rrset.len(),
4765 input.nsec_rrsig_rrset.len() + input.nsec3_rrsig_rrset.len(),
4766 ));
4767 Ok(self.no_data_valid)
4768 }
4769
4770 fn validate_name_error(
4771 &self,
4772 input: DelegatedDnssecNameErrorValidation<'_>,
4773 ) -> Result<bool, ResolverError> {
4774 self.name_error_validations.lock().unwrap().push((
4775 input.ds_rrset.len(),
4776 input.dnskey_rrset.len(),
4777 input.dnskey_rrsig_rrset.len(),
4778 input.nsec_rrset.len() + input.nsec3_rrset.len(),
4779 input.nsec_rrsig_rrset.len() + input.nsec3_rrsig_rrset.len(),
4780 ));
4781 Ok(self.name_error_valid)
4782 }
4783
4784 fn validate_child_positive_rrset(
4785 &self,
4786 input: DelegatedChildDnssecValidation<'_>,
4787 ) -> Result<bool, ResolverError> {
4788 self.child_validations.lock().unwrap().push((
4789 input.child_ds_rrset.len(),
4790 input.child_dnskey_rrset.len(),
4791 input.child_dnskey_rrsig_rrset.len(),
4792 input.target_rrset.len(),
4793 input.target_rrsig_rrset.len(),
4794 ));
4795 Ok(self.child_positive_valid)
4796 }
4797
4798 fn validate_child_no_data(
4799 &self,
4800 input: DelegatedChildDnssecNoDataValidation<'_>,
4801 ) -> Result<bool, ResolverError> {
4802 self.child_no_data_validations.lock().unwrap().push((
4803 input.child_ds_rrset.len(),
4804 input.child_dnskey_rrset.len(),
4805 input.child_dnskey_rrsig_rrset.len(),
4806 input.nsec_rrset.len() + input.nsec3_rrset.len(),
4807 input.nsec_rrsig_rrset.len() + input.nsec3_rrsig_rrset.len(),
4808 ));
4809 Ok(self.child_no_data_valid)
4810 }
4811
4812 fn validate_child_name_error(
4813 &self,
4814 input: DelegatedChildDnssecNameErrorValidation<'_>,
4815 ) -> Result<bool, ResolverError> {
4816 self.child_name_error_validations.lock().unwrap().push((
4817 input.child_ds_rrset.len(),
4818 input.child_dnskey_rrset.len(),
4819 input.child_dnskey_rrsig_rrset.len(),
4820 input.nsec_rrset.len() + input.nsec3_rrset.len(),
4821 input.nsec_rrsig_rrset.len() + input.nsec3_rrsig_rrset.len(),
4822 ));
4823 Ok(self.child_name_error_valid)
4824 }
4825 }
4826
4827 #[test]
4828 fn single_label_is_hns() {
4829 assert_eq!(classify_name("welcome"), NameClass::Hns);
4830 }
4831
4832 #[test]
4833 fn trailing_dot_single_label_is_hns() {
4834 assert_eq!(classify_name("welcome."), NameClass::Hns);
4835 }
4836
4837 #[test]
4838 fn service_prefixed_name_extracts_hns_root() {
4839 assert_eq!(hns_root_label("_443._tcp.welcome").unwrap(), "welcome");
4840 assert_eq!(hns_root_label("_443._tcp.welcome.2d").unwrap(), "2d");
4841 }
4842
4843 #[test]
4844 fn strongest_resolution_error_preserves_terminal_evidence_failures() {
4845 let mut current = Some(ResolverError::DnssecFailed);
4846 retain_strongest_resolution_error(
4847 &mut current,
4848 ResolverError::DnsTransport("later timeout".to_owned()),
4849 );
4850 assert_eq!(current, Some(ResolverError::DnssecFailed));
4851
4852 let mut current = Some(ResolverError::InvalidDnsResponse);
4853 retain_strongest_resolution_error(&mut current, ResolverError::Port53InterceptionDetected);
4854 assert_eq!(current, Some(ResolverError::InvalidDnsResponse));
4855
4856 let mut current = Some(ResolverError::ProofUnavailable);
4857 retain_strongest_resolution_error(
4858 &mut current,
4859 ResolverError::DnsTransport("later refusal".to_owned()),
4860 );
4861 assert_eq!(current, Some(ResolverError::ProofUnavailable));
4862 }
4863
4864 #[test]
4865 fn strongest_resolution_error_prefers_confirmed_interception_over_transport_failure() {
4866 let mut current = Some(ResolverError::DnsTransport("timeout".to_owned()));
4867 retain_strongest_resolution_error(&mut current, ResolverError::Port53InterceptionDetected);
4868 assert_eq!(current, Some(ResolverError::Port53InterceptionDetected));
4869
4870 retain_strongest_resolution_error(
4871 &mut current,
4872 ResolverError::DnsTransport("later refusal".to_owned()),
4873 );
4874 assert_eq!(current, Some(ResolverError::Port53InterceptionDetected));
4875 }
4876
4877 #[test]
4878 fn dotted_name_is_icann() {
4879 assert_eq!(classify_name("example.com"), NameClass::Icann);
4880 }
4881
4882 #[test]
4883 fn uncommon_and_internationalized_iana_tlds_are_icann() {
4884 assert_eq!(classify_name("collection.museum"), NameClass::Icann);
4885 assert_eq!(
4886 classify_name("example.xn--vermgensberater-ctb"),
4887 NameClass::Icann
4888 );
4889 assert_eq!(classify_name("museum"), NameClass::Hns);
4890 }
4891
4892 #[test]
4893 fn special_use_suffixes_and_ip_literals_never_route_to_hns() {
4894 for host in [
4895 "alt",
4896 "name.alt",
4897 "example",
4898 "www.example",
4899 "internal",
4900 "corp.internal",
4901 "name.invalid",
4902 "printer.local",
4903 "home.arpa",
4904 "localhost",
4905 "www.localhost",
4906 "service.onion",
4907 "name.test",
4908 "127.0.0.1",
4909 "::1",
4910 ] {
4911 assert_eq!(classify_name(host), NameClass::Icann, "{host}");
4912 }
4913 }
4914
4915 #[test]
4916 fn delegated_dns_policy_rejects_non_public_endpoints_before_transport() {
4917 let name = DnsName::from_ascii("host.name").unwrap();
4918 for address in [
4919 "127.0.0.1",
4920 "10.0.0.1",
4921 "169.254.169.254",
4922 "::1",
4923 "fc00::1",
4924 "fe80::1",
4925 "64:ff9b::a00:1",
4926 ] {
4927 let transport = PolicyDnsTransport {
4928 policy: DnsEndpointPolicy::strict(),
4929 calls: AtomicUsize::new(0),
4930 };
4931 let server = SocketAddr::new(address.parse().unwrap(), 53);
4932
4933 assert_eq!(
4934 dns_query(&transport, server, &name, RecordType::A).unwrap_err(),
4935 ResolverError::NonPublicDnsEndpoint,
4936 "{address}"
4937 );
4938 assert_eq!(transport.calls.load(Ordering::SeqCst), 0, "{address}");
4939 }
4940 }
4941
4942 #[test]
4943 fn authoritative_doh_policy_rejects_unsafe_port_before_transport() {
4944 let transport = PolicyDnsTransport {
4945 policy: DnsEndpointPolicy::strict(),
4946 calls: AtomicUsize::new(0),
4947 };
4948 let endpoint = AuthoritativeDohEndpoint {
4949 ns: DnsName::from_ascii("ns.name").unwrap(),
4950 host: "ns.name".to_owned(),
4951 connect_addr: "1.1.1.1".parse().unwrap(),
4952 port: 22,
4953 path_and_query: "/dns-query".to_owned(),
4954 tls_authentication: AuthoritativeDohTlsAuthentication::WebPki,
4955 };
4956
4957 assert_eq!(
4958 dns_query_doh(
4959 &transport,
4960 &endpoint,
4961 &DnsName::from_ascii("host.name").unwrap(),
4962 RecordType::A,
4963 )
4964 .unwrap_err(),
4965 ResolverError::UnsafeAuthoritativeDohPort(22),
4966 );
4967 assert_eq!(transport.calls.load(Ordering::SeqCst), 0);
4968 }
4969
4970 #[test]
4971 fn regtest_endpoint_policy_explicitly_allows_private_endpoints() {
4972 let transport = PolicyDnsTransport {
4973 policy: DnsEndpointPolicy::for_network(NetworkKind::Regtest),
4974 calls: AtomicUsize::new(0),
4975 };
4976 let error = dns_query(
4977 &transport,
4978 "127.0.0.1:53".parse().unwrap(),
4979 &DnsName::from_ascii("host.name").unwrap(),
4980 RecordType::A,
4981 )
4982 .unwrap_err();
4983
4984 assert_eq!(error, ResolverError::UnsupportedBackend);
4985 assert_eq!(transport.calls.load(Ordering::SeqCst), 1);
4986 assert_eq!(
4987 DnsEndpointPolicy::for_network(NetworkKind::Mainnet),
4988 DnsEndpointPolicy::strict()
4989 );
4990 assert_eq!(
4991 DnsEndpointPolicy::for_network(NetworkKind::Testnet),
4992 DnsEndpointPolicy::strict()
4993 );
4994 }
4995
4996 #[test]
4997 fn udp_transport_rejects_response_from_wrong_source_port() {
4998 let server = UdpSocket::bind("127.0.0.1:0").unwrap();
4999 let server_address = server.local_addr().unwrap();
5000 let responder = std::thread::spawn(move || {
5001 let mut query = [0u8; 16];
5002 let (_, client) = server.recv_from(&mut query).unwrap();
5003 let wrong_source = UdpSocket::bind("127.0.0.1:0").unwrap();
5004 wrong_source.send_to(b"spoofed", client).unwrap();
5005 });
5006 let transport = UdpTcpDnsTransport {
5007 timeout: Duration::from_secs(1),
5008 endpoint_policy: DnsEndpointPolicy::permissive(),
5009 ..UdpTcpDnsTransport::default()
5010 };
5011
5012 assert_eq!(
5013 transport
5014 .exchange_udp(server_address, b"query")
5015 .unwrap_err(),
5016 ResolverError::InvalidDnsResponse
5017 );
5018 responder.join().unwrap();
5019 }
5020
5021 #[test]
5022 fn dotted_hns_name_extracts_final_root_label() {
5023 assert_eq!(hns_root_label("welcome.2d").unwrap(), "2d");
5024 assert_eq!(classify_name("welcome.2d"), NameClass::Hns);
5025 }
5026
5027 #[test]
5028 fn whitespace_is_search() {
5029 assert_eq!(classify_name("two words"), NameClass::Search);
5030 }
5031
5032 #[test]
5033 fn cached_resolver_reuses_fresh_answer() {
5034 let resolver = CachedResolver::new(
5035 CountingResolver {
5036 count: AtomicUsize::new(0),
5037 },
5038 32,
5039 Duration::from_secs(60),
5040 );
5041 let request = ResolutionRequest {
5042 qname: "name".to_owned(),
5043 qtype: 1,
5044 };
5045
5046 resolver.resolve(&request).unwrap();
5047 resolver.resolve(&request).unwrap();
5048
5049 assert_eq!(resolver.inner.count.load(Ordering::SeqCst), 1);
5050 }
5051
5052 #[test]
5053 fn cached_resolver_reuses_name_not_found() {
5054 let resolver = CachedResolver::new(
5055 CountingNameNotFoundResolver {
5056 count: AtomicUsize::new(0),
5057 },
5058 32,
5059 Duration::from_secs(60),
5060 );
5061 let request = ResolutionRequest {
5062 qname: "missing".to_owned(),
5063 qtype: 1,
5064 };
5065
5066 assert_eq!(
5067 resolver.resolve(&request).unwrap_err(),
5068 ResolverError::NameNotFound
5069 );
5070 assert_eq!(
5071 resolver.resolve(&request).unwrap_err(),
5072 ResolverError::NameNotFound
5073 );
5074
5075 assert_eq!(resolver.inner.count.load(Ordering::SeqCst), 1);
5076 }
5077
5078 #[test]
5079 fn proof_backed_resolver_filters_verified_records() {
5080 let root_name = "welcome".to_owned();
5081 let request_name = DnsName::from_ascii("welcome").unwrap();
5082 let resolver = ProofBackedResolver::new(StaticProofProvider {
5083 proven: ProvenNameRecords {
5084 root_name: root_name.clone(),
5085 name_hash: NameHash::from_name(&root_name).unwrap(),
5086 records: vec![
5087 record(request_name.clone(), RecordType::A, vec![127, 0, 0, 1]),
5088 record(request_name.clone(), RecordType::Aaaa, vec![0; 16]),
5089 record(
5090 DnsName::from_ascii("other").unwrap(),
5091 RecordType::A,
5092 vec![1, 1, 1, 1],
5093 ),
5094 ],
5095 secure: true,
5096 exists: true,
5097 },
5098 });
5099
5100 let answer = resolver
5101 .resolve(&ResolutionRequest {
5102 qname: "welcome".to_owned(),
5103 qtype: RecordType::A.code(),
5104 })
5105 .unwrap();
5106
5107 assert_eq!(answer.name, request_name);
5108 assert!(answer.secure);
5109 assert_eq!(
5110 answer.records,
5111 vec![record(answer.name, RecordType::A, vec![127, 0, 0, 1])]
5112 );
5113 }
5114
5115 #[test]
5116 fn proof_backed_resolver_rejects_mismatched_proof_name() {
5117 let resolver = ProofBackedResolver::new(StaticProofProvider {
5118 proven: ProvenNameRecords {
5119 root_name: "other".to_owned(),
5120 name_hash: NameHash::from_name("other").unwrap(),
5121 records: Vec::new(),
5122 secure: true,
5123 exists: true,
5124 },
5125 });
5126
5127 assert_eq!(
5128 resolver
5129 .resolve(&ResolutionRequest {
5130 qname: "welcome".to_owned(),
5131 qtype: RecordType::A.code(),
5132 })
5133 .unwrap_err(),
5134 ResolverError::ProofNameMismatch,
5135 );
5136 }
5137
5138 #[test]
5139 fn proof_backed_resolver_reports_verified_non_inclusion() {
5140 let root_name = "missing".to_owned();
5141 let name_hash = NameHash::from_name(&root_name).unwrap();
5142 let resolver = ProofBackedResolver::new(StaticProofProvider {
5143 proven: ProvenNameRecords {
5144 root_name: root_name.clone(),
5145 name_hash,
5146 records: Vec::new(),
5147 secure: true,
5148 exists: false,
5149 },
5150 });
5151
5152 assert_eq!(
5153 resolver
5154 .resolve(&ResolutionRequest {
5155 qname: root_name,
5156 qtype: RecordType::A.code(),
5157 })
5158 .unwrap_err(),
5159 ResolverError::NameNotFound,
5160 );
5161 }
5162
5163 #[test]
5164 fn proven_records_decode_hsd_resource_value() {
5165 let root_name = "welcome".to_owned();
5166 let name_hash = NameHash::from_name(&root_name).unwrap();
5167 let mut value = vec![0, 1];
5168 encode_name(&mut value, "ns1.welcome");
5169
5170 let proven =
5171 ProvenNameRecords::from_resource_value(root_name.clone(), name_hash, &value).unwrap();
5172
5173 assert_eq!(proven.root_name, root_name);
5174 assert_eq!(proven.name_hash, name_hash);
5175 assert!(proven.secure);
5176 assert!(proven.exists);
5177 assert_eq!(proven.records.len(), 1);
5178 assert_eq!(
5179 proven.records[0].name,
5180 DnsName::from_ascii("welcome").unwrap()
5181 );
5182 assert_eq!(proven.records[0].record_type, RecordType::Ns);
5183 assert_eq!(
5184 proven.records[0].ttl,
5185 hns_core::resource::DEFAULT_HANDSHAKE_RESOURCE_TTL
5186 );
5187 assert_eq!(proven.records[0].rdata, name_bytes("ns1.welcome"));
5188 }
5189
5190 #[test]
5191 fn proven_records_reject_invalid_resource_value() {
5192 assert_eq!(
5193 ProvenNameRecords::from_resource_value(
5194 "welcome".to_owned(),
5195 NameHash::from_name("welcome").unwrap(),
5196 &[1],
5197 )
5198 .unwrap_err(),
5199 ResolverError::InvalidResource(ResourceError::UnsupportedVersion),
5200 );
5201 }
5202
5203 #[test]
5204 fn resource_value_provider_decodes_verified_inclusion_for_resolver() {
5205 let root_name = "welcome".to_owned();
5206 let name_hash = NameHash::from_name(&root_name).unwrap();
5207 let mut value = vec![0, 1];
5208 encode_name(&mut value, "ns1.welcome");
5209 let resolver =
5210 ProofBackedResolver::new(ResourceValueProofProvider::new(StaticValueProvider {
5211 verified: VerifiedResourceValue::inclusion(root_name.clone(), name_hash, value),
5212 }));
5213
5214 let answer = resolver
5215 .resolve(&ResolutionRequest {
5216 qname: root_name,
5217 qtype: RecordType::Ns.code(),
5218 })
5219 .unwrap();
5220
5221 assert!(answer.secure);
5222 assert_eq!(answer.records.len(), 1);
5223 assert_eq!(answer.records[0].record_type, RecordType::Ns);
5224 assert_eq!(answer.records[0].rdata, name_bytes("ns1.welcome"));
5225 }
5226
5227 #[test]
5228 fn delegating_resolver_answers_root_ns_from_hns_proof() {
5229 let root_name = "welcome".to_owned();
5230 let request_name = DnsName::from_ascii("welcome").unwrap();
5231 let resolver = DelegatingResolver::new(
5232 StaticProofProvider {
5233 proven: ProvenNameRecords {
5234 root_name: root_name.clone(),
5235 name_hash: NameHash::from_name(&root_name).unwrap(),
5236 records: vec![ns_record("welcome", "ns1.welcome")],
5237 secure: true,
5238 exists: true,
5239 },
5240 },
5241 FailClosedResolver,
5242 );
5243
5244 let answer = resolver
5245 .resolve(&ResolutionRequest {
5246 qname: root_name,
5247 qtype: RecordType::Ns.code(),
5248 })
5249 .unwrap();
5250
5251 assert_eq!(answer.name, request_name);
5252 assert!(answer.secure);
5253 assert_eq!(answer.records, vec![ns_record("welcome", "ns1.welcome")]);
5254 }
5255
5256 #[test]
5257 fn delegating_resolver_delegates_apex_address_with_ds() {
5258 let root_name = "welcome".to_owned();
5259 let requests = Arc::new(Mutex::new(Vec::new()));
5260 let resolver = DelegatingResolver::new(
5261 StaticProofProvider {
5262 proven: ProvenNameRecords {
5263 root_name: root_name.clone(),
5264 name_hash: NameHash::from_name(&root_name).unwrap(),
5265 records: vec![ns_record("welcome", "ns1.welcome"), ds_record("welcome")],
5266 secure: true,
5267 exists: true,
5268 },
5269 },
5270 ScriptedResolver::new(
5271 vec![resolver_response(
5272 "welcome",
5273 RecordType::A.code(),
5274 true,
5275 vec![record(
5276 DnsName::from_ascii("welcome").unwrap(),
5277 RecordType::A,
5278 vec![127, 0, 0, 1],
5279 )],
5280 )],
5281 Arc::clone(&requests),
5282 ),
5283 );
5284
5285 let answer = resolver
5286 .resolve(&ResolutionRequest {
5287 qname: root_name,
5288 qtype: RecordType::A.code(),
5289 })
5290 .unwrap();
5291
5292 assert!(answer.secure);
5293 assert_eq!(answer.records.len(), 1);
5294 assert_eq!(answer.records[0].record_type, RecordType::A);
5295 assert_eq!(
5296 *requests.lock().unwrap(),
5297 vec![ResolutionRequest {
5298 qname: "welcome".to_owned(),
5299 qtype: RecordType::A.code(),
5300 }],
5301 );
5302 }
5303
5304 #[test]
5305 fn delegating_resolver_does_not_synthesize_from_hns_dane_capsule_experiment() {
5306 let root_name = "welcome".to_owned();
5307 let resolver = DelegatingResolver::new(
5308 StaticProofProvider {
5309 proven: ProvenNameRecords {
5310 root_name: root_name.clone(),
5311 name_hash: NameHash::from_name(&root_name).unwrap(),
5312 records: vec![txt_record(
5313 "welcome",
5314 "hnsb=1;host=@;a=203.0.113.10;alpn=h2,h3;tlsa=3,1,1,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5315 )],
5316 secure: true,
5317 exists: true,
5318 },
5319 },
5320 FailClosedResolver,
5321 );
5322
5323 let answer = resolver
5324 .resolve(&ResolutionRequest {
5325 qname: root_name,
5326 qtype: RecordType::A.code(),
5327 })
5328 .unwrap();
5329
5330 assert!(answer.secure);
5331 assert!(answer.records.is_empty());
5332 }
5333
5334 #[test]
5335 fn authoritative_doh_endpoint_bootstraps_from_hns_proven_txt_without_port_53() {
5336 let delegation = HnsDelegation {
5337 root_name: "welcome".to_owned(),
5338 owner: DnsName::from_ascii("welcome").unwrap(),
5339 records: vec![
5340 ns_record("welcome", "ns1.welcome"),
5341 glue4_record("ns1.welcome", [203, 0, 113, 53]),
5342 txt_record(
5343 "welcome",
5344 "hnsdns=1;ns=ns1;transport=doh;doh=https://doh.example:8443/dns-query{?dns}",
5345 ),
5346 ],
5347 };
5348 let requests = Arc::new(Mutex::new(Vec::new()));
5349 let transport = ScriptedDnsTransport {
5350 responses: HashMap::new(),
5351 server_responses: HashMap::new(),
5352 requests: Arc::clone(&requests),
5353 udp_behavior: ScriptedUdpBehavior::Normal,
5354 };
5355
5356 assert_eq!(
5357 authoritative_doh_endpoints(&transport, &accepting_dnssec_verifier(), &delegation)
5358 .unwrap(),
5359 vec![AuthoritativeDohEndpoint {
5360 ns: DnsName::from_ascii("ns1.welcome").unwrap(),
5361 host: "doh.example".to_owned(),
5362 connect_addr: IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)),
5363 port: 8443,
5364 path_and_query: "/dns-query".to_owned(),
5365 tls_authentication: AuthoritativeDohTlsAuthentication::WebPki,
5366 }]
5367 );
5368 assert!(requests.lock().unwrap().is_empty());
5369 }
5370
5371 #[test]
5372 fn authoritative_doh_endpoint_uses_hns_proof_tlsa_pins() {
5373 let first = "11".repeat(32);
5374 let second = "AA".repeat(32);
5375 let declaration = format!(
5376 "hnsdns=1;ns=ns1.denuoweb.;transport=doh;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,{first};tlsa=3,1,1,{second}"
5377 );
5378 assert!(declaration.len() <= HNSDNS_MAX_TEXT_BYTES);
5379 let delegation = HnsDelegation {
5380 root_name: "denuoweb".to_owned(),
5381 owner: DnsName::from_ascii("denuoweb").unwrap(),
5382 records: vec![
5383 ns_record("denuoweb", "ns1.denuoweb"),
5384 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5385 txt_record("denuoweb", &declaration),
5386 ],
5387 };
5388 let requests = Arc::new(Mutex::new(Vec::new()));
5389 let transport = ScriptedDnsTransport {
5390 responses: HashMap::new(),
5391 server_responses: HashMap::new(),
5392 requests: Arc::clone(&requests),
5393 udp_behavior: ScriptedUdpBehavior::Normal,
5394 };
5395
5396 let endpoints =
5397 authoritative_doh_endpoints(&transport, &accepting_dnssec_verifier(), &delegation)
5398 .unwrap();
5399 assert_eq!(endpoints.len(), 1);
5400 assert_eq!(endpoints[0].host, "denuoweb");
5401 assert_eq!(endpoints[0].port, 8443);
5402 assert_eq!(
5403 endpoints[0].tls_authentication,
5404 AuthoritativeDohTlsAuthentication::HnsProofTlsa(vec![
5405 TlsaRecord {
5406 usage: TlsaUsage::DaneEe,
5407 selector: TlsaSelector::SubjectPublicKeyInfo,
5408 matching: TlsaMatching::Sha256,
5409 association_data: vec![0x11; 32],
5410 },
5411 TlsaRecord {
5412 usage: TlsaUsage::DaneEe,
5413 selector: TlsaSelector::SubjectPublicKeyInfo,
5414 matching: TlsaMatching::Sha256,
5415 association_data: vec![0xaa; 32],
5416 },
5417 ])
5418 );
5419 assert!(requests.lock().unwrap().is_empty());
5420 }
5421
5422 #[test]
5423 fn pinned_authoritative_doh_failure_falls_back_to_port_53() {
5424 let pin = "36".repeat(32);
5425 let delegation = HnsDelegation {
5426 root_name: "denuoweb".to_owned(),
5427 owner: DnsName::from_ascii("denuoweb").unwrap(),
5428 records: vec![
5429 ns_record("denuoweb", "ns1.denuoweb"),
5430 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5431 ds_record("denuoweb"),
5432 txt_record(
5433 "denuoweb",
5434 &format!(
5435 "hnsdns=1;ns=ns1.denuoweb.;transport=doh;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,{pin}"
5436 ),
5437 ),
5438 ],
5439 };
5440 let resolver = AuthoritativeDnssecResolver::new(
5441 FailingPinnedDohTransport {
5442 doh_calls: AtomicUsize::new(0),
5443 udp_calls: AtomicUsize::new(0),
5444 tcp_calls: AtomicUsize::new(0),
5445 },
5446 accepting_dnssec_verifier(),
5447 )
5448 .with_authoritative_doh_preferred();
5449
5450 let answer = resolver
5451 .resolve_delegated(
5452 &ResolutionRequest {
5453 qname: "denuoweb".to_owned(),
5454 qtype: RecordType::A.code(),
5455 },
5456 &delegation,
5457 )
5458 .unwrap();
5459 assert!(answer.secure);
5460 assert_eq!(
5461 answer.records,
5462 vec![record(
5463 DnsName::from_ascii("denuoweb").unwrap(),
5464 RecordType::A,
5465 vec![1, 1, 1, 1],
5466 )]
5467 );
5468
5469 let (transport, _) = resolver.into_parts();
5470 assert_eq!(transport.doh_calls.load(Ordering::SeqCst), 1);
5471 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 2);
5472 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 0);
5473 }
5474
5475 #[test]
5476 fn direct_authority_precedes_available_pinned_doh_by_default() {
5477 let pin = "36".repeat(32);
5478 let delegation = HnsDelegation {
5479 root_name: "denuoweb".to_owned(),
5480 owner: DnsName::from_ascii("denuoweb").unwrap(),
5481 records: vec![
5482 ns_record("denuoweb", "ns1.denuoweb"),
5483 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5484 ds_record("denuoweb"),
5485 txt_record(
5486 "denuoweb",
5487 &format!(
5488 "hnsdns=1;ns=ns1.denuoweb.;transport=doh;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,{pin}"
5489 ),
5490 ),
5491 ],
5492 };
5493 let resolver = AuthoritativeDnssecResolver::new(
5494 FailingPinnedDohTransport {
5495 doh_calls: AtomicUsize::new(0),
5496 udp_calls: AtomicUsize::new(0),
5497 tcp_calls: AtomicUsize::new(0),
5498 },
5499 accepting_dnssec_verifier(),
5500 );
5501
5502 let answer = resolver
5503 .resolve_delegated(
5504 &ResolutionRequest {
5505 qname: "denuoweb".to_owned(),
5506 qtype: RecordType::A.code(),
5507 },
5508 &delegation,
5509 )
5510 .unwrap();
5511 assert!(answer.secure);
5512
5513 let (transport, _) = resolver.into_parts();
5514 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 2);
5515 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 0);
5516 assert_eq!(transport.doh_calls.load(Ordering::SeqCst), 0);
5517 }
5518
5519 #[test]
5520 fn later_authoritative_doh_transport_failure_cannot_mask_direct_dnssec_failure() {
5521 let pin = "36".repeat(32);
5522 let delegation = HnsDelegation {
5523 root_name: "denuoweb".to_owned(),
5524 owner: DnsName::from_ascii("denuoweb").unwrap(),
5525 records: vec![
5526 ns_record("denuoweb", "ns1.denuoweb"),
5527 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5528 ds_record("denuoweb"),
5529 txt_record(
5530 "denuoweb",
5531 &format!(
5532 "hnsdns=1;ns=ns1.denuoweb.;transport=doh;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,{pin}"
5533 ),
5534 ),
5535 ],
5536 };
5537 let mut verifier = accepting_dnssec_verifier();
5538 verifier.positive_valid = false;
5539 let resolver = AuthoritativeDnssecResolver::new(
5540 FailingPinnedDohTransport {
5541 doh_calls: AtomicUsize::new(0),
5542 udp_calls: AtomicUsize::new(0),
5543 tcp_calls: AtomicUsize::new(0),
5544 },
5545 verifier,
5546 );
5547
5548 assert_eq!(
5549 resolver
5550 .resolve_delegated(
5551 &ResolutionRequest {
5552 qname: "denuoweb".to_owned(),
5553 qtype: RecordType::A.code(),
5554 },
5555 &delegation,
5556 )
5557 .unwrap_err(),
5558 ResolverError::DnssecFailed,
5559 );
5560
5561 let (transport, _) = resolver.into_parts();
5562 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 2);
5563 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 1);
5564 assert_eq!(transport.doh_calls.load(Ordering::SeqCst), 1);
5565 }
5566
5567 #[test]
5568 fn confirmed_port53_interception_pivots_to_pinned_doh_and_stays_off_direct() {
5569 let pin = "36".repeat(32);
5570 let delegation = HnsDelegation {
5571 root_name: "denuoweb".to_owned(),
5572 owner: DnsName::from_ascii("denuoweb").unwrap(),
5573 records: vec![
5574 ns_record("denuoweb", "ns1.denuoweb"),
5575 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5576 ds_record("denuoweb"),
5577 txt_record(
5578 "denuoweb",
5579 &format!(
5580 "hnsdns=1;ns=ns1.denuoweb.;transport=doh;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,{pin}"
5581 ),
5582 ),
5583 ],
5584 };
5585 let resolver = AuthoritativeDnssecResolver::new(
5586 InterceptedDnsTransport {
5587 interception_detected: AtomicBool::new(false),
5588 probe_calls: AtomicUsize::new(0),
5589 doh_calls: AtomicUsize::new(0),
5590 udp_calls: AtomicUsize::new(0),
5591 tcp_calls: AtomicUsize::new(0),
5592 },
5593 accepting_dnssec_verifier(),
5594 );
5595 let request = ResolutionRequest {
5596 qname: "denuoweb".to_owned(),
5597 qtype: RecordType::A.code(),
5598 };
5599
5600 for _ in 0..2 {
5601 let answer = resolver.resolve_delegated(&request, &delegation).unwrap();
5602 assert!(answer.secure);
5603 assert_eq!(
5604 answer.records,
5605 vec![record(
5606 DnsName::from_ascii("denuoweb").unwrap(),
5607 RecordType::A,
5608 vec![1, 1, 1, 1],
5609 )]
5610 );
5611 }
5612
5613 let (transport, _) = resolver.into_parts();
5614 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 2);
5615 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 0);
5616 assert_eq!(transport.probe_calls.load(Ordering::SeqCst), 1);
5617 assert_eq!(transport.doh_calls.load(Ordering::SeqCst), 4);
5618 }
5619
5620 #[test]
5621 fn malformed_pinned_authoritative_doh_falls_back_to_port_53() {
5622 let delegation = HnsDelegation {
5623 root_name: "denuoweb".to_owned(),
5624 owner: DnsName::from_ascii("denuoweb").unwrap(),
5625 records: vec![
5626 ns_record("denuoweb", "ns1.denuoweb"),
5627 glue4_record("ns1.denuoweb", [35, 212, 156, 128]),
5628 ds_record("denuoweb"),
5629 txt_record(
5630 "denuoweb",
5631 "hnsdns=1;ns=ns1.denuoweb.;doh=https://denuoweb:8443/dns-query;tlsa=3,1,1,invalid",
5632 ),
5633 ],
5634 };
5635 let resolver = AuthoritativeDnssecResolver::new(
5636 FailingPinnedDohTransport {
5637 doh_calls: AtomicUsize::new(0),
5638 udp_calls: AtomicUsize::new(0),
5639 tcp_calls: AtomicUsize::new(0),
5640 },
5641 accepting_dnssec_verifier(),
5642 )
5643 .with_authoritative_doh_preferred();
5644
5645 let answer = resolver
5646 .resolve_delegated(
5647 &ResolutionRequest {
5648 qname: "denuoweb".to_owned(),
5649 qtype: RecordType::A.code(),
5650 },
5651 &delegation,
5652 )
5653 .unwrap();
5654 assert!(answer.secure);
5655 assert_eq!(
5656 answer.records,
5657 vec![record(
5658 DnsName::from_ascii("denuoweb").unwrap(),
5659 RecordType::A,
5660 vec![1, 1, 1, 1],
5661 )]
5662 );
5663
5664 let (transport, _) = resolver.into_parts();
5665 assert_eq!(transport.doh_calls.load(Ordering::SeqCst), 0);
5666 assert_eq!(transport.udp_calls.load(Ordering::SeqCst), 2);
5667 assert_eq!(transport.tcp_calls.load(Ordering::SeqCst), 0);
5668 }
5669
5670 #[test]
5671 fn authoritative_doh_endpoint_rejects_invalid_or_excess_proof_tlsa_pins() {
5672 let valid = "11".repeat(32);
5673 let invalid_declarations = [
5674 "hnsdns=1;ns=ns1;doh=https://welcome/dns-query;tlsa=3,1,1,abcd".to_owned(),
5675 format!("hnsdns=1;ns=ns1;doh=https://welcome/dns-query;tlsa=2,1,1,{valid}"),
5676 format!("hnsdns=1;ns=ns1;doh=https://welcome/dns-query;tlsa=3,0,1,{valid}"),
5677 format!("hnsdns=1;ns=ns1;doh=https://welcome/dns-query;tlsa=3,1,2,{valid}"),
5678 format!(
5679 "hnsdns=1;ns=ns1;tlsa=3,1,1,{valid};tlsa=3,1,1,{};tlsa=3,1,1,{}",
5680 "22".repeat(32),
5681 "33".repeat(32),
5682 ),
5683 ];
5684
5685 for declaration in invalid_declarations {
5686 assert!(declaration.len() <= HNSDNS_MAX_TEXT_BYTES, "{declaration}");
5687 assert_eq!(
5688 parse_hnsdns_declaration(&declaration, &DnsName::from_ascii("welcome").unwrap(),)
5689 .unwrap_err(),
5690 ResolverError::InvalidAuthoritativeDoh,
5691 "{declaration}",
5692 );
5693 }
5694 }
5695
5696 #[test]
5697 fn authoritative_doh_cache_key_changes_when_proof_pin_changes() {
5698 let delegation = |pin: &str| HnsDelegation {
5699 root_name: "welcome".to_owned(),
5700 owner: DnsName::from_ascii("welcome").unwrap(),
5701 records: vec![
5702 ns_record("welcome", "ns1.welcome"),
5703 glue4_record("ns1.welcome", [203, 0, 113, 53]),
5704 txt_record(
5705 "welcome",
5706 &format!("hnsdns=1;ns=ns1;doh=https://welcome/dns-query;tlsa=3,1,1,{pin}"),
5707 ),
5708 ],
5709 };
5710
5711 assert_ne!(
5712 authoritative_doh_cache_key(&delegation(&"11".repeat(32))),
5713 authoritative_doh_cache_key(&delegation(&"22".repeat(32))),
5714 );
5715 }
5716
5717 #[test]
5718 fn authoritative_doh_endpoint_is_discovered_from_rfc9461_svcb() {
5719 let delegation = HnsDelegation {
5720 root_name: "welcome".to_owned(),
5721 owner: DnsName::from_ascii("welcome").unwrap(),
5722 records: vec![
5723 ns_record("welcome", "ns1.welcome"),
5724 glue4_record("ns1.welcome", [203, 0, 113, 53]),
5725 ds_record("welcome"),
5726 ],
5727 };
5728 let requests = Arc::new(Mutex::new(Vec::new()));
5729 let transport = ScriptedDnsTransport {
5730 responses: dns_responses(vec![
5731 (
5732 "_dns.ns1.welcome",
5733 RecordType::Svcb,
5734 vec![
5735 svcb_doh_record("_dns.ns1.welcome", "doh.example", "/dns-query{?dns}"),
5736 rrsig_record("_dns.ns1.welcome"),
5737 ],
5738 ),
5739 (
5740 "welcome",
5741 RecordType::Dnskey,
5742 vec![
5743 record(
5744 DnsName::from_ascii("welcome").unwrap(),
5745 RecordType::Dnskey,
5746 vec![1, 2, 3, 4],
5747 ),
5748 rrsig_record("welcome"),
5749 ],
5750 ),
5751 ]),
5752 server_responses: HashMap::new(),
5753 requests: Arc::clone(&requests),
5754 udp_behavior: ScriptedUdpBehavior::Normal,
5755 };
5756
5757 assert_eq!(
5758 authoritative_doh_endpoints(&transport, &accepting_dnssec_verifier(), &delegation)
5759 .unwrap(),
5760 vec![AuthoritativeDohEndpoint {
5761 ns: DnsName::from_ascii("ns1.welcome").unwrap(),
5762 host: "doh.example".to_owned(),
5763 connect_addr: IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)),
5764 port: 443,
5765 path_and_query: "/dns-query".to_owned(),
5766 tls_authentication: AuthoritativeDohTlsAuthentication::WebPki,
5767 }]
5768 );
5769 assert_eq!(
5770 *requests.lock().unwrap(),
5771 vec![
5772 (
5773 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 53),
5774 "_dns.ns1.welcome".to_owned(),
5775 RecordType::Svcb.code(),
5776 false,
5777 ),
5778 (
5779 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 53),
5780 "welcome".to_owned(),
5781 RecordType::Dnskey.code(),
5782 false,
5783 ),
5784 ]
5785 );
5786 }
5787
5788 #[test]
5789 fn authoritative_dnssec_resolver_prefers_discovered_authoritative_doh_when_enabled() {
5790 let delegation = HnsDelegation {
5791 root_name: "welcome".to_owned(),
5792 owner: DnsName::from_ascii("welcome").unwrap(),
5793 records: vec![
5794 ns_record("welcome", "ns1.welcome"),
5795 glue4_record("ns1.welcome", [203, 0, 113, 53]),
5796 ds_record("welcome"),
5797 ],
5798 };
5799 let requests = Arc::new(Mutex::new(Vec::new()));
5800 let resolver = AuthoritativeDnssecResolver::new(
5801 ScriptedDnsTransport {
5802 responses: dns_responses(vec![
5803 (
5804 "_dns.ns1.welcome",
5805 RecordType::Svcb,
5806 vec![
5807 svcb_doh_record("_dns.ns1.welcome", "doh.example", "/dns-query{?dns}"),
5808 rrsig_record("_dns.ns1.welcome"),
5809 ],
5810 ),
5811 (
5812 "welcome",
5813 RecordType::A,
5814 vec![
5815 record(
5816 DnsName::from_ascii("welcome").unwrap(),
5817 RecordType::A,
5818 vec![203, 0, 113, 20],
5819 ),
5820 rrsig_record("welcome"),
5821 ],
5822 ),
5823 (
5824 "welcome",
5825 RecordType::Dnskey,
5826 vec![
5827 record(
5828 DnsName::from_ascii("welcome").unwrap(),
5829 RecordType::Dnskey,
5830 vec![1, 2, 3, 4],
5831 ),
5832 rrsig_record("welcome"),
5833 ],
5834 ),
5835 ]),
5836 server_responses: HashMap::new(),
5837 requests: Arc::clone(&requests),
5838 udp_behavior: ScriptedUdpBehavior::Normal,
5839 },
5840 StaticDnssecVerifier {
5841 positive_valid: true,
5842 no_data_valid: false,
5843 name_error_valid: false,
5844 child_positive_valid: false,
5845 child_no_data_valid: false,
5846 child_name_error_valid: false,
5847 validations: Arc::new(Mutex::new(Vec::new())),
5848 no_data_validations: Arc::new(Mutex::new(Vec::new())),
5849 name_error_validations: Arc::new(Mutex::new(Vec::new())),
5850 child_validations: Arc::new(Mutex::new(Vec::new())),
5851 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
5852 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
5853 },
5854 )
5855 .with_authoritative_doh_preferred();
5856
5857 let answer = resolver
5858 .resolve_delegated(
5859 &ResolutionRequest {
5860 qname: "welcome".to_owned(),
5861 qtype: RecordType::A.code(),
5862 },
5863 &delegation,
5864 )
5865 .unwrap();
5866 let second_answer = resolver
5867 .resolve_delegated(
5868 &ResolutionRequest {
5869 qname: "welcome".to_owned(),
5870 qtype: RecordType::A.code(),
5871 },
5872 &delegation,
5873 )
5874 .unwrap();
5875
5876 assert!(answer.secure);
5877 assert!(second_answer.secure);
5878 assert_eq!(
5879 *requests.lock().unwrap(),
5880 vec![
5881 (
5882 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 53),
5883 "_dns.ns1.welcome".to_owned(),
5884 RecordType::Svcb.code(),
5885 false,
5886 ),
5887 (
5888 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 53),
5889 "welcome".to_owned(),
5890 RecordType::Dnskey.code(),
5891 false,
5892 ),
5893 (
5894 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 443),
5895 "welcome".to_owned(),
5896 RecordType::A.code(),
5897 true,
5898 ),
5899 (
5900 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 443),
5901 "welcome".to_owned(),
5902 RecordType::Dnskey.code(),
5903 true,
5904 ),
5905 (
5906 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 443),
5907 "welcome".to_owned(),
5908 RecordType::A.code(),
5909 true,
5910 ),
5911 (
5912 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 443),
5913 "welcome".to_owned(),
5914 RecordType::Dnskey.code(),
5915 true,
5916 ),
5917 ]
5918 );
5919 }
5920
5921 #[test]
5922 fn authoritative_dnssec_resolver_retries_tcp_when_udp_dnssec_fails() {
5923 let requests = Arc::new(Mutex::new(Vec::new()));
5924 let server = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 53)), 53);
5925 let resolver = AuthoritativeDnssecResolver::new(
5926 TcpRepairDnsTransport {
5927 requests: Arc::clone(&requests),
5928 },
5929 StaticDnssecVerifier {
5930 positive_valid: true,
5931 no_data_valid: false,
5932 name_error_valid: false,
5933 child_positive_valid: false,
5934 child_no_data_valid: false,
5935 child_name_error_valid: false,
5936 validations: Arc::new(Mutex::new(Vec::new())),
5937 no_data_validations: Arc::new(Mutex::new(Vec::new())),
5938 name_error_validations: Arc::new(Mutex::new(Vec::new())),
5939 child_validations: Arc::new(Mutex::new(Vec::new())),
5940 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
5941 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
5942 },
5943 );
5944
5945 let answer = resolver
5946 .resolve_delegated(
5947 &ResolutionRequest {
5948 qname: "welcome".to_owned(),
5949 qtype: RecordType::A.code(),
5950 },
5951 &delegation_with_records(vec![
5952 ns_record("welcome", "ns1.welcome"),
5953 glue4_record("ns1.welcome", [203, 0, 113, 53]),
5954 ds_record("welcome"),
5955 ]),
5956 )
5957 .unwrap();
5958
5959 assert!(answer.secure);
5960 assert_eq!(
5961 answer.records,
5962 vec![record(
5963 DnsName::from_ascii("welcome").unwrap(),
5964 RecordType::A,
5965 vec![1, 1, 1, 1],
5966 )]
5967 );
5968 assert_eq!(
5969 *requests.lock().unwrap(),
5970 vec![
5971 (server, "welcome".to_owned(), RecordType::A.code(), false),
5972 (
5973 server,
5974 "welcome".to_owned(),
5975 RecordType::Dnskey.code(),
5976 false
5977 ),
5978 (server, "welcome".to_owned(), RecordType::A.code(), true),
5979 (
5980 server,
5981 "welcome".to_owned(),
5982 RecordType::Dnskey.code(),
5983 true
5984 ),
5985 ]
5986 );
5987 }
5988
5989 #[test]
5990 fn delegating_resolver_fails_closed_when_ds_child_is_insecure() {
5991 let root_name = "welcome".to_owned();
5992 let resolver = DelegatingResolver::new(
5993 StaticProofProvider {
5994 proven: ProvenNameRecords {
5995 root_name: root_name.clone(),
5996 name_hash: NameHash::from_name(&root_name).unwrap(),
5997 records: vec![ns_record("welcome", "ns1.welcome"), ds_record("welcome")],
5998 secure: true,
5999 exists: true,
6000 },
6001 },
6002 ScriptedResolver::new(
6003 vec![resolver_response(
6004 "welcome",
6005 RecordType::A.code(),
6006 false,
6007 Vec::new(),
6008 )],
6009 Arc::new(Mutex::new(Vec::new())),
6010 ),
6011 );
6012
6013 assert_eq!(
6014 resolver
6015 .resolve(&ResolutionRequest {
6016 qname: root_name,
6017 qtype: RecordType::A.code(),
6018 })
6019 .unwrap_err(),
6020 ResolverError::DnssecFailed,
6021 );
6022 }
6023
6024 #[test]
6025 fn delegating_resolver_marks_unsigned_delegation_insecure() {
6026 let root_name = "welcome".to_owned();
6027 let resolver = DelegatingResolver::new(
6028 StaticProofProvider {
6029 proven: ProvenNameRecords {
6030 root_name: root_name.clone(),
6031 name_hash: NameHash::from_name(&root_name).unwrap(),
6032 records: vec![ns_record("welcome", "ns1.welcome")],
6033 secure: true,
6034 exists: true,
6035 },
6036 },
6037 ScriptedResolver::new(
6038 vec![resolver_response(
6039 "welcome",
6040 RecordType::A.code(),
6041 true,
6042 vec![record(
6043 DnsName::from_ascii("welcome").unwrap(),
6044 RecordType::A,
6045 vec![127, 0, 0, 1],
6046 )],
6047 )],
6048 Arc::new(Mutex::new(Vec::new())),
6049 ),
6050 );
6051
6052 let answer = resolver
6053 .resolve(&ResolutionRequest {
6054 qname: root_name,
6055 qtype: RecordType::A.code(),
6056 })
6057 .unwrap();
6058
6059 assert!(!answer.secure);
6060 assert_eq!(answer.records.len(), 1);
6061 }
6062
6063 #[test]
6064 fn delegated_name_error_requires_a_ds_secured_child() {
6065 let resolver_for = |secure_child: bool| {
6066 let mut records = vec![ns_record("welcome", "ns1.welcome")];
6067 if secure_child {
6068 records.push(ds_record("welcome"));
6069 }
6070 DelegatingResolver::new(
6071 StaticProofProvider {
6072 proven: ProvenNameRecords {
6073 root_name: "welcome".to_owned(),
6074 name_hash: NameHash::from_name("welcome").unwrap(),
6075 records,
6076 secure: true,
6077 exists: true,
6078 },
6079 },
6080 CountingNameNotFoundResolver {
6081 count: AtomicUsize::new(0),
6082 },
6083 )
6084 };
6085 let request = ResolutionRequest {
6086 qname: "welcome".to_owned(),
6087 qtype: RecordType::A.code(),
6088 };
6089
6090 assert_eq!(
6091 resolver_for(true).resolve(&request).unwrap_err(),
6092 ResolverError::NameNotFound,
6093 );
6094 assert_eq!(
6095 resolver_for(false).resolve(&request).unwrap_err(),
6096 ResolverError::DnssecFailed,
6097 );
6098 }
6099
6100 #[test]
6101 fn delegating_resolver_passes_hns_delegation_context() {
6102 let root_name = "welcome".to_owned();
6103 let delegations = Arc::new(Mutex::new(Vec::new()));
6104 let resolver = DelegatingResolver::new(
6105 StaticProofProvider {
6106 proven: ProvenNameRecords {
6107 root_name: root_name.clone(),
6108 name_hash: NameHash::from_name(&root_name).unwrap(),
6109 records: vec![
6110 ns_record("welcome", "ns1.welcome"),
6111 record(
6112 DnsName::from_ascii("ns1.welcome").unwrap(),
6113 RecordType::A,
6114 vec![127, 0, 0, 1],
6115 ),
6116 ds_record("welcome"),
6117 ],
6118 secure: true,
6119 exists: true,
6120 },
6121 },
6122 CapturingDelegatedResolver {
6123 delegations: Arc::clone(&delegations),
6124 },
6125 );
6126
6127 let answer = resolver
6128 .resolve(&ResolutionRequest {
6129 qname: root_name,
6130 qtype: RecordType::A.code(),
6131 })
6132 .unwrap();
6133
6134 assert!(answer.secure);
6135 let captured = delegations.lock().unwrap();
6136 assert_eq!(captured.len(), 1);
6137 assert_eq!(captured[0].root_name, "welcome");
6138 assert_eq!(captured[0].owner, DnsName::from_ascii("welcome").unwrap());
6139 assert_eq!(captured[0].records.len(), 3);
6140 }
6141
6142 #[test]
6143 fn delegating_resolver_hydrates_out_of_zone_hns_nameserver_address() {
6144 let root_name = "welcome".to_owned();
6145 let ns_root_name = "hshub".to_owned();
6146 let ns_name = DnsName::from_ascii("ns1.hshub").unwrap();
6147 let delegations = Arc::new(Mutex::new(Vec::new()));
6148 let mut proven = HashMap::new();
6149 proven.insert(
6150 root_name.clone(),
6151 ProvenNameRecords {
6152 root_name: root_name.clone(),
6153 name_hash: NameHash::from_name(&root_name).unwrap(),
6154 records: vec![ns_record("welcome", "ns1.hshub"), ds_record("welcome")],
6155 secure: true,
6156 exists: true,
6157 },
6158 );
6159 proven.insert(
6160 ns_root_name.clone(),
6161 ProvenNameRecords {
6162 root_name: ns_root_name.clone(),
6163 name_hash: NameHash::from_name(&ns_root_name).unwrap(),
6164 records: vec![
6165 ns_record("hshub", "ns1.hshub"),
6166 record(ns_name.clone(), RecordType::A, vec![127, 0, 0, 9]),
6167 ],
6168 secure: true,
6169 exists: true,
6170 },
6171 );
6172 let resolver = DelegatingResolver::new(
6173 MapProofProvider { proven },
6174 CapturingDelegatedResolver {
6175 delegations: Arc::clone(&delegations),
6176 },
6177 );
6178
6179 let answer = resolver
6180 .resolve(&ResolutionRequest {
6181 qname: root_name,
6182 qtype: RecordType::A.code(),
6183 })
6184 .unwrap();
6185
6186 assert!(answer.secure);
6187 let captured = delegations.lock().unwrap();
6188 assert_eq!(captured.len(), 1);
6189 assert!(
6190 captured[0]
6191 .records
6192 .contains(&record(ns_name, RecordType::A, vec![127, 0, 0, 9],))
6193 );
6194 }
6195
6196 #[test]
6197 fn authoritative_dnssec_resolver_validates_positive_rrset() {
6198 let server = SocketAddr::from(([127, 0, 0, 1], 53));
6199 let validations = Arc::new(Mutex::new(Vec::new()));
6200 let requests = Arc::new(Mutex::new(Vec::new()));
6201 let resolver = AuthoritativeDnssecResolver::new(
6202 ScriptedDnsTransport {
6203 responses: dns_responses(vec![
6204 (
6205 "welcome",
6206 RecordType::A,
6207 vec![
6208 record(
6209 DnsName::from_ascii("welcome").unwrap(),
6210 RecordType::A,
6211 vec![127, 0, 0, 1],
6212 ),
6213 rrsig_record("welcome"),
6214 ],
6215 ),
6216 (
6217 "welcome",
6218 RecordType::Dnskey,
6219 vec![
6220 record(
6221 DnsName::from_ascii("welcome").unwrap(),
6222 RecordType::Dnskey,
6223 vec![1, 2, 3, 4],
6224 ),
6225 rrsig_record("welcome"),
6226 ],
6227 ),
6228 ]),
6229 server_responses: HashMap::new(),
6230 requests: Arc::clone(&requests),
6231 udp_behavior: ScriptedUdpBehavior::Normal,
6232 },
6233 StaticDnssecVerifier {
6234 positive_valid: true,
6235 no_data_valid: false,
6236 name_error_valid: false,
6237 child_positive_valid: false,
6238 child_no_data_valid: false,
6239 child_name_error_valid: false,
6240 validations: Arc::clone(&validations),
6241 no_data_validations: Arc::new(Mutex::new(Vec::new())),
6242 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6243 child_validations: Arc::new(Mutex::new(Vec::new())),
6244 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6245 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6246 },
6247 );
6248
6249 let answer = resolver
6250 .resolve_delegated(
6251 &ResolutionRequest {
6252 qname: "welcome".to_owned(),
6253 qtype: RecordType::A.code(),
6254 },
6255 &delegation_with_records(vec![
6256 ns_record("welcome", "ns1.welcome"),
6257 record(
6258 DnsName::from_ascii("ns1.welcome").unwrap(),
6259 RecordType::A,
6260 vec![127, 0, 0, 1],
6261 ),
6262 ds_record("welcome"),
6263 ]),
6264 )
6265 .unwrap();
6266
6267 assert!(answer.secure);
6268 assert_eq!(answer.records.len(), 1);
6269 assert_eq!(answer.records[0].rdata, vec![127, 0, 0, 1]);
6270 assert_eq!(
6271 *requests.lock().unwrap(),
6272 vec![
6273 (server, "welcome".to_owned(), RecordType::A.code(), false),
6274 (
6275 server,
6276 "welcome".to_owned(),
6277 RecordType::Dnskey.code(),
6278 false
6279 ),
6280 ],
6281 );
6282 assert_eq!(*validations.lock().unwrap(), vec![(1, 1, 1, 1, 1)]);
6283 }
6284
6285 #[test]
6286 fn authoritative_dnssec_resolver_validates_inline_child_signed_answer() {
6287 let server = SocketAddr::from(([127, 0, 0, 1], 53));
6288 let child_validations = Arc::new(Mutex::new(Vec::new()));
6289 let requests = Arc::new(Mutex::new(Vec::new()));
6290 let resolver = AuthoritativeDnssecResolver::new(
6291 ScriptedDnsTransport {
6292 responses: dns_responses(vec![
6293 (
6294 "blog.welcome",
6295 RecordType::A,
6296 vec![
6297 record(
6298 DnsName::from_ascii("blog.welcome").unwrap(),
6299 RecordType::A,
6300 vec![127, 0, 0, 1],
6301 ),
6302 rrsig_record_for_signer("blog.welcome", RecordType::A, "blog.welcome"),
6303 ],
6304 ),
6305 (
6306 "welcome",
6307 RecordType::Dnskey,
6308 vec![
6309 record(
6310 DnsName::from_ascii("welcome").unwrap(),
6311 RecordType::Dnskey,
6312 vec![1, 2, 3, 4],
6313 ),
6314 rrsig_record_for_signer("welcome", RecordType::Dnskey, "welcome"),
6315 ],
6316 ),
6317 (
6318 "blog.welcome",
6319 RecordType::Ds,
6320 vec![
6321 ds_record("blog.welcome"),
6322 rrsig_record_for_signer("blog.welcome", RecordType::Ds, "welcome"),
6323 ],
6324 ),
6325 (
6326 "blog.welcome",
6327 RecordType::Dnskey,
6328 vec![
6329 record(
6330 DnsName::from_ascii("blog.welcome").unwrap(),
6331 RecordType::Dnskey,
6332 vec![5, 6, 7, 8],
6333 ),
6334 rrsig_record_for_signer(
6335 "blog.welcome",
6336 RecordType::Dnskey,
6337 "blog.welcome",
6338 ),
6339 ],
6340 ),
6341 ]),
6342 server_responses: HashMap::new(),
6343 requests: Arc::clone(&requests),
6344 udp_behavior: ScriptedUdpBehavior::Normal,
6345 },
6346 StaticDnssecVerifier {
6347 positive_valid: false,
6348 no_data_valid: false,
6349 name_error_valid: false,
6350 child_positive_valid: true,
6351 child_no_data_valid: false,
6352 child_name_error_valid: false,
6353 validations: Arc::new(Mutex::new(Vec::new())),
6354 no_data_validations: Arc::new(Mutex::new(Vec::new())),
6355 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6356 child_validations: Arc::clone(&child_validations),
6357 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6358 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6359 },
6360 );
6361
6362 let answer = resolver
6363 .resolve_delegated(
6364 &ResolutionRequest {
6365 qname: "blog.welcome".to_owned(),
6366 qtype: RecordType::A.code(),
6367 },
6368 &delegation_with_records(vec![
6369 ns_record("welcome", "ns1.welcome"),
6370 record(
6371 DnsName::from_ascii("ns1.welcome").unwrap(),
6372 RecordType::A,
6373 vec![127, 0, 0, 1],
6374 ),
6375 ds_record("welcome"),
6376 ]),
6377 )
6378 .unwrap();
6379
6380 assert!(answer.secure);
6381 assert_eq!(answer.records.len(), 1);
6382 assert_eq!(
6383 *requests.lock().unwrap(),
6384 vec![
6385 (
6386 server,
6387 "blog.welcome".to_owned(),
6388 RecordType::A.code(),
6389 false
6390 ),
6391 (
6392 server,
6393 "welcome".to_owned(),
6394 RecordType::Dnskey.code(),
6395 false
6396 ),
6397 (
6398 server,
6399 "blog.welcome".to_owned(),
6400 RecordType::Ds.code(),
6401 false
6402 ),
6403 (
6404 server,
6405 "blog.welcome".to_owned(),
6406 RecordType::Dnskey.code(),
6407 false
6408 ),
6409 ],
6410 );
6411 assert_eq!(
6412 *child_validations.lock().unwrap(),
6413 vec![(1usize, 1usize, 1usize, 1usize, 1usize)]
6414 );
6415 }
6416
6417 #[test]
6418 fn authoritative_dnssec_resolver_validates_inline_child_nsec_no_data() {
6419 let server = SocketAddr::from(([127, 0, 0, 1], 53));
6420 let child_no_data_validations = Arc::new(Mutex::new(Vec::new()));
6421 let requests = Arc::new(Mutex::new(Vec::new()));
6422 let mut responses = dns_responses(vec![
6423 (
6424 "welcome",
6425 RecordType::Dnskey,
6426 vec![
6427 record(
6428 DnsName::from_ascii("welcome").unwrap(),
6429 RecordType::Dnskey,
6430 vec![1, 2, 3, 4],
6431 ),
6432 rrsig_record_for_signer("welcome", RecordType::Dnskey, "welcome"),
6433 ],
6434 ),
6435 (
6436 "blog.welcome",
6437 RecordType::Ds,
6438 vec![
6439 ds_record("blog.welcome"),
6440 rrsig_record_for_signer("blog.welcome", RecordType::Ds, "welcome"),
6441 ],
6442 ),
6443 (
6444 "blog.welcome",
6445 RecordType::Dnskey,
6446 vec![
6447 record(
6448 DnsName::from_ascii("blog.welcome").unwrap(),
6449 RecordType::Dnskey,
6450 vec![5, 6, 7, 8],
6451 ),
6452 rrsig_record_for_signer("blog.welcome", RecordType::Dnskey, "blog.welcome"),
6453 ],
6454 ),
6455 ]);
6456 responses.insert(
6457 ("blog.welcome".to_owned(), RecordType::Https.code()),
6458 DnsResponseFixture {
6459 rcode: DNS_RCODE_NOERROR,
6460 answers: Vec::new(),
6461 authorities: vec![
6462 nsec_record("blog.welcome"),
6463 rrsig_record_for_signer("blog.welcome", RecordType::Nsec, "blog.welcome"),
6464 ],
6465 additionals: Vec::new(),
6466 },
6467 );
6468 let resolver = AuthoritativeDnssecResolver::new(
6469 ScriptedDnsTransport {
6470 responses,
6471 server_responses: HashMap::new(),
6472 requests: Arc::clone(&requests),
6473 udp_behavior: ScriptedUdpBehavior::Normal,
6474 },
6475 StaticDnssecVerifier {
6476 positive_valid: false,
6477 no_data_valid: false,
6478 name_error_valid: false,
6479 child_positive_valid: false,
6480 child_no_data_valid: true,
6481 child_name_error_valid: false,
6482 validations: Arc::new(Mutex::new(Vec::new())),
6483 no_data_validations: Arc::new(Mutex::new(Vec::new())),
6484 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6485 child_validations: Arc::new(Mutex::new(Vec::new())),
6486 child_no_data_validations: Arc::clone(&child_no_data_validations),
6487 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6488 },
6489 );
6490
6491 let answer = resolver
6492 .resolve_delegated(
6493 &ResolutionRequest {
6494 qname: "blog.welcome".to_owned(),
6495 qtype: RecordType::Https.code(),
6496 },
6497 &delegation_with_records(vec![
6498 ns_record("welcome", "ns1.welcome"),
6499 record(
6500 DnsName::from_ascii("ns1.welcome").unwrap(),
6501 RecordType::A,
6502 vec![127, 0, 0, 1],
6503 ),
6504 ds_record("welcome"),
6505 ]),
6506 )
6507 .unwrap();
6508
6509 assert!(answer.secure);
6510 assert!(answer.records.is_empty());
6511 assert_eq!(
6512 *requests.lock().unwrap(),
6513 vec![
6514 (
6515 server,
6516 "blog.welcome".to_owned(),
6517 RecordType::Https.code(),
6518 false
6519 ),
6520 (
6521 server,
6522 "welcome".to_owned(),
6523 RecordType::Dnskey.code(),
6524 false
6525 ),
6526 (
6527 server,
6528 "blog.welcome".to_owned(),
6529 RecordType::Ds.code(),
6530 false
6531 ),
6532 (
6533 server,
6534 "blog.welcome".to_owned(),
6535 RecordType::Dnskey.code(),
6536 false
6537 ),
6538 ],
6539 );
6540 assert_eq!(
6541 *child_no_data_validations.lock().unwrap(),
6542 vec![(1usize, 1usize, 1usize, 1usize, 2usize)]
6543 );
6544 }
6545
6546 #[test]
6547 fn authoritative_dnssec_resolver_accepts_secure_nsec_no_data() {
6548 let validations = Arc::new(Mutex::new(Vec::new()));
6549 let no_data_validations = Arc::new(Mutex::new(Vec::new()));
6550 let resolver = AuthoritativeDnssecResolver::new(
6551 ScriptedDnsTransport {
6552 responses: dns_responses(vec![
6553 (
6554 "welcome",
6555 RecordType::Aaaa,
6556 vec![nsec_record("welcome"), rrsig_record("welcome")],
6557 ),
6558 (
6559 "welcome",
6560 RecordType::Dnskey,
6561 vec![
6562 record(
6563 DnsName::from_ascii("welcome").unwrap(),
6564 RecordType::Dnskey,
6565 vec![1, 2, 3, 4],
6566 ),
6567 rrsig_record("welcome"),
6568 ],
6569 ),
6570 ]),
6571 server_responses: HashMap::new(),
6572 requests: Arc::new(Mutex::new(Vec::new())),
6573 udp_behavior: ScriptedUdpBehavior::Normal,
6574 },
6575 StaticDnssecVerifier {
6576 positive_valid: false,
6577 no_data_valid: true,
6578 name_error_valid: false,
6579 child_positive_valid: false,
6580 child_no_data_valid: false,
6581 child_name_error_valid: false,
6582 validations: Arc::clone(&validations),
6583 no_data_validations: Arc::clone(&no_data_validations),
6584 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6585 child_validations: Arc::new(Mutex::new(Vec::new())),
6586 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6587 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6588 },
6589 );
6590
6591 let answer = resolver
6592 .resolve_delegated(
6593 &ResolutionRequest {
6594 qname: "welcome".to_owned(),
6595 qtype: RecordType::Aaaa.code(),
6596 },
6597 &delegation_with_records(vec![
6598 ns_record("welcome", "ns1.welcome"),
6599 record(
6600 DnsName::from_ascii("ns1.welcome").unwrap(),
6601 RecordType::A,
6602 vec![127, 0, 0, 1],
6603 ),
6604 ds_record("welcome"),
6605 ]),
6606 )
6607 .unwrap();
6608
6609 assert!(answer.secure);
6610 assert!(answer.records.is_empty());
6611 assert!(validations.lock().unwrap().is_empty());
6612 assert_eq!(*no_data_validations.lock().unwrap(), vec![(1, 1, 1, 1, 2)]);
6613 }
6614
6615 #[test]
6616 fn authoritative_dnssec_resolver_accepts_secure_nsec_name_error() {
6617 let validations = Arc::new(Mutex::new(Vec::new()));
6618 let no_data_validations = Arc::new(Mutex::new(Vec::new()));
6619 let name_error_validations = Arc::new(Mutex::new(Vec::new()));
6620 let mut responses = dns_responses(vec![(
6621 "welcome",
6622 RecordType::Dnskey,
6623 vec![
6624 record(
6625 DnsName::from_ascii("welcome").unwrap(),
6626 RecordType::Dnskey,
6627 vec![1, 2, 3, 4],
6628 ),
6629 rrsig_record("welcome"),
6630 ],
6631 )]);
6632 responses.insert(
6633 ("missing.welcome".to_owned(), RecordType::A.code()),
6634 DnsResponseFixture {
6635 rcode: DNS_RCODE_NXDOMAIN,
6636 answers: Vec::new(),
6637 authorities: vec![
6638 nsec_record("alpha.welcome"),
6639 nsec_record("z.welcome"),
6640 rrsig_record("welcome"),
6641 ],
6642 additionals: Vec::new(),
6643 },
6644 );
6645 let resolver = AuthoritativeDnssecResolver::new(
6646 ScriptedDnsTransport {
6647 responses,
6648 server_responses: HashMap::new(),
6649 requests: Arc::new(Mutex::new(Vec::new())),
6650 udp_behavior: ScriptedUdpBehavior::Normal,
6651 },
6652 StaticDnssecVerifier {
6653 positive_valid: false,
6654 no_data_valid: false,
6655 name_error_valid: true,
6656 child_positive_valid: false,
6657 child_no_data_valid: false,
6658 child_name_error_valid: false,
6659 validations: Arc::clone(&validations),
6660 no_data_validations: Arc::clone(&no_data_validations),
6661 name_error_validations: Arc::clone(&name_error_validations),
6662 child_validations: Arc::new(Mutex::new(Vec::new())),
6663 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6664 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6665 },
6666 );
6667
6668 let answer = resolver
6669 .resolve_delegated(
6670 &ResolutionRequest {
6671 qname: "missing.welcome".to_owned(),
6672 qtype: RecordType::A.code(),
6673 },
6674 &delegation_with_records(vec![
6675 ns_record("welcome", "ns1.welcome"),
6676 record(
6677 DnsName::from_ascii("ns1.welcome").unwrap(),
6678 RecordType::A,
6679 vec![127, 0, 0, 1],
6680 ),
6681 ds_record("welcome"),
6682 ]),
6683 )
6684 .unwrap();
6685
6686 assert!(answer.secure);
6687 assert!(answer.records.is_empty());
6688 assert!(validations.lock().unwrap().is_empty());
6689 assert!(no_data_validations.lock().unwrap().is_empty());
6690 assert_eq!(
6691 *name_error_validations.lock().unwrap(),
6692 vec![(1, 1, 1, 2, 2)]
6693 );
6694 }
6695
6696 #[test]
6697 fn authoritative_dnssec_resolver_follows_secure_cname_chain() {
6698 let validations = Arc::new(Mutex::new(Vec::new()));
6699 let resolver = AuthoritativeDnssecResolver::new(
6700 ScriptedDnsTransport {
6701 responses: dns_responses(vec![
6702 (
6703 "welcome",
6704 RecordType::A,
6705 vec![
6706 cname_record("welcome", "edge.welcome"),
6707 rrsig_record("welcome"),
6708 record(
6709 DnsName::from_ascii("edge.welcome").unwrap(),
6710 RecordType::A,
6711 vec![127, 0, 0, 1],
6712 ),
6713 rrsig_record("edge.welcome"),
6714 ],
6715 ),
6716 (
6717 "welcome",
6718 RecordType::Dnskey,
6719 vec![
6720 record(
6721 DnsName::from_ascii("welcome").unwrap(),
6722 RecordType::Dnskey,
6723 vec![1, 2, 3, 4],
6724 ),
6725 rrsig_record("welcome"),
6726 ],
6727 ),
6728 ]),
6729 server_responses: HashMap::new(),
6730 requests: Arc::new(Mutex::new(Vec::new())),
6731 udp_behavior: ScriptedUdpBehavior::Normal,
6732 },
6733 StaticDnssecVerifier {
6734 positive_valid: true,
6735 no_data_valid: false,
6736 name_error_valid: false,
6737 child_positive_valid: false,
6738 child_no_data_valid: false,
6739 child_name_error_valid: false,
6740 validations: Arc::clone(&validations),
6741 no_data_validations: Arc::new(Mutex::new(Vec::new())),
6742 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6743 child_validations: Arc::new(Mutex::new(Vec::new())),
6744 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6745 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6746 },
6747 );
6748
6749 let answer = resolver
6750 .resolve_delegated(
6751 &ResolutionRequest {
6752 qname: "welcome".to_owned(),
6753 qtype: RecordType::A.code(),
6754 },
6755 &delegation_with_records(vec![
6756 ns_record("welcome", "ns1.welcome"),
6757 record(
6758 DnsName::from_ascii("ns1.welcome").unwrap(),
6759 RecordType::A,
6760 vec![127, 0, 0, 1],
6761 ),
6762 ds_record("welcome"),
6763 ]),
6764 )
6765 .unwrap();
6766
6767 assert!(answer.secure);
6768 assert_eq!(answer.name, DnsName::from_ascii("welcome").unwrap());
6769 assert_eq!(answer.records.len(), 2);
6770 assert_eq!(answer.records[0].record_type, RecordType::Cname);
6771 assert_eq!(
6772 answer.records[1].name,
6773 DnsName::from_ascii("edge.welcome").unwrap()
6774 );
6775 assert_eq!(answer.records[1].record_type, RecordType::A);
6776 assert_eq!(
6777 *validations.lock().unwrap(),
6778 vec![(1, 1, 1, 1, 1), (1, 1, 1, 1, 1)]
6779 );
6780 }
6781
6782 #[test]
6783 fn authoritative_dnssec_resolver_follows_secure_child_referral() {
6784 let parent_server = SocketAddr::from(([127, 0, 0, 1], 53));
6785 let child_server = SocketAddr::from(([127, 0, 0, 2], 53));
6786 let requests = Arc::new(Mutex::new(Vec::new()));
6787 let child_validations = Arc::new(Mutex::new(Vec::new()));
6788 let mut responses = dns_responses(vec![(
6789 "welcome",
6790 RecordType::Dnskey,
6791 vec![
6792 record(
6793 DnsName::from_ascii("welcome").unwrap(),
6794 RecordType::Dnskey,
6795 vec![1, 2, 3, 4],
6796 ),
6797 rrsig_record("welcome"),
6798 ],
6799 )]);
6800 responses.insert(
6801 ("www.sub.welcome".to_owned(), RecordType::A.code()),
6802 DnsResponseFixture {
6803 rcode: DNS_RCODE_NOERROR,
6804 answers: Vec::new(),
6805 authorities: vec![
6806 ns_record("sub.welcome", "ns1.sub.welcome"),
6807 ds_record("sub.welcome"),
6808 rrsig_record("sub.welcome"),
6809 ],
6810 additionals: vec![record(
6811 DnsName::from_ascii("ns1.sub.welcome").unwrap(),
6812 RecordType::A,
6813 vec![127, 0, 0, 2],
6814 )],
6815 },
6816 );
6817 let mut server_responses = HashMap::new();
6818 server_responses.insert(
6819 (
6820 child_server,
6821 "sub.welcome".to_owned(),
6822 RecordType::Dnskey.code(),
6823 ),
6824 DnsResponseFixture {
6825 rcode: DNS_RCODE_NOERROR,
6826 answers: vec![
6827 record(
6828 DnsName::from_ascii("sub.welcome").unwrap(),
6829 RecordType::Dnskey,
6830 vec![1, 2, 3, 4],
6831 ),
6832 rrsig_record("sub.welcome"),
6833 ],
6834 authorities: Vec::new(),
6835 additionals: Vec::new(),
6836 },
6837 );
6838 server_responses.insert(
6839 (
6840 child_server,
6841 "www.sub.welcome".to_owned(),
6842 RecordType::A.code(),
6843 ),
6844 DnsResponseFixture {
6845 rcode: DNS_RCODE_NOERROR,
6846 answers: vec![
6847 record(
6848 DnsName::from_ascii("www.sub.welcome").unwrap(),
6849 RecordType::A,
6850 vec![127, 0, 0, 3],
6851 ),
6852 rrsig_record("www.sub.welcome"),
6853 ],
6854 authorities: Vec::new(),
6855 additionals: Vec::new(),
6856 },
6857 );
6858 let resolver = AuthoritativeDnssecResolver::new(
6859 ScriptedDnsTransport {
6860 responses,
6861 server_responses,
6862 requests: Arc::clone(&requests),
6863 udp_behavior: ScriptedUdpBehavior::Normal,
6864 },
6865 StaticDnssecVerifier {
6866 positive_valid: false,
6867 no_data_valid: false,
6868 name_error_valid: false,
6869 child_positive_valid: true,
6870 child_no_data_valid: false,
6871 child_name_error_valid: false,
6872 validations: Arc::new(Mutex::new(Vec::new())),
6873 no_data_validations: Arc::new(Mutex::new(Vec::new())),
6874 name_error_validations: Arc::new(Mutex::new(Vec::new())),
6875 child_validations: Arc::clone(&child_validations),
6876 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
6877 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
6878 },
6879 );
6880
6881 let answer = resolver
6882 .resolve_delegated(
6883 &ResolutionRequest {
6884 qname: "www.sub.welcome".to_owned(),
6885 qtype: RecordType::A.code(),
6886 },
6887 &delegation_with_records(vec![
6888 ns_record("welcome", "ns1.welcome"),
6889 record(
6890 DnsName::from_ascii("ns1.welcome").unwrap(),
6891 RecordType::A,
6892 vec![127, 0, 0, 1],
6893 ),
6894 ds_record("welcome"),
6895 ]),
6896 )
6897 .unwrap();
6898
6899 assert!(answer.secure);
6900 assert_eq!(answer.records.len(), 1);
6901 assert_eq!(answer.records[0].rdata, vec![127, 0, 0, 3]);
6902 assert_eq!(
6903 *requests.lock().unwrap(),
6904 vec![
6905 (
6906 parent_server,
6907 "www.sub.welcome".to_owned(),
6908 RecordType::A.code(),
6909 false,
6910 ),
6911 (
6912 parent_server,
6913 "welcome".to_owned(),
6914 RecordType::Dnskey.code(),
6915 false,
6916 ),
6917 (
6918 child_server,
6919 "sub.welcome".to_owned(),
6920 RecordType::Dnskey.code(),
6921 false,
6922 ),
6923 (
6924 child_server,
6925 "www.sub.welcome".to_owned(),
6926 RecordType::A.code(),
6927 false,
6928 ),
6929 ],
6930 );
6931 assert_eq!(*child_validations.lock().unwrap(), vec![(1, 1, 1, 1, 1)]);
6932 }
6933
6934 #[test]
6935 fn authoritative_dnssec_resolver_follows_secure_child_cname_chain() {
6936 let parent_server = SocketAddr::from(([127, 0, 0, 1], 53));
6937 let child_server = SocketAddr::from(([127, 0, 0, 2], 53));
6938 let requests = Arc::new(Mutex::new(Vec::new()));
6939 let child_validations = Arc::new(Mutex::new(Vec::new()));
6940 let mut responses = dns_responses(vec![(
6941 "welcome",
6942 RecordType::Dnskey,
6943 vec![
6944 record(
6945 DnsName::from_ascii("welcome").unwrap(),
6946 RecordType::Dnskey,
6947 vec![1, 2, 3, 4],
6948 ),
6949 rrsig_record("welcome"),
6950 ],
6951 )]);
6952 responses.insert(
6953 ("www.sub.welcome".to_owned(), RecordType::A.code()),
6954 DnsResponseFixture {
6955 rcode: DNS_RCODE_NOERROR,
6956 answers: Vec::new(),
6957 authorities: vec![
6958 ns_record("sub.welcome", "ns1.sub.welcome"),
6959 ds_record("sub.welcome"),
6960 rrsig_record("sub.welcome"),
6961 ],
6962 additionals: vec![record(
6963 DnsName::from_ascii("ns1.sub.welcome").unwrap(),
6964 RecordType::A,
6965 vec![127, 0, 0, 2],
6966 )],
6967 },
6968 );
6969 let mut server_responses = HashMap::new();
6970 server_responses.insert(
6971 (
6972 child_server,
6973 "sub.welcome".to_owned(),
6974 RecordType::Dnskey.code(),
6975 ),
6976 DnsResponseFixture {
6977 rcode: DNS_RCODE_NOERROR,
6978 answers: vec![
6979 record(
6980 DnsName::from_ascii("sub.welcome").unwrap(),
6981 RecordType::Dnskey,
6982 vec![1, 2, 3, 4],
6983 ),
6984 rrsig_record("sub.welcome"),
6985 ],
6986 authorities: Vec::new(),
6987 additionals: Vec::new(),
6988 },
6989 );
6990 server_responses.insert(
6991 (
6992 child_server,
6993 "www.sub.welcome".to_owned(),
6994 RecordType::A.code(),
6995 ),
6996 DnsResponseFixture {
6997 rcode: DNS_RCODE_NOERROR,
6998 answers: vec![
6999 cname_record("www.sub.welcome", "edge.sub.welcome"),
7000 rrsig_record("www.sub.welcome"),
7001 record(
7002 DnsName::from_ascii("edge.sub.welcome").unwrap(),
7003 RecordType::A,
7004 vec![127, 0, 0, 4],
7005 ),
7006 rrsig_record("edge.sub.welcome"),
7007 ],
7008 authorities: Vec::new(),
7009 additionals: Vec::new(),
7010 },
7011 );
7012 let resolver = AuthoritativeDnssecResolver::new(
7013 ScriptedDnsTransport {
7014 responses,
7015 server_responses,
7016 requests: Arc::clone(&requests),
7017 udp_behavior: ScriptedUdpBehavior::Normal,
7018 },
7019 StaticDnssecVerifier {
7020 positive_valid: false,
7021 no_data_valid: false,
7022 name_error_valid: false,
7023 child_positive_valid: true,
7024 child_no_data_valid: false,
7025 child_name_error_valid: false,
7026 validations: Arc::new(Mutex::new(Vec::new())),
7027 no_data_validations: Arc::new(Mutex::new(Vec::new())),
7028 name_error_validations: Arc::new(Mutex::new(Vec::new())),
7029 child_validations: Arc::clone(&child_validations),
7030 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
7031 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
7032 },
7033 );
7034
7035 let answer = resolver
7036 .resolve_delegated(
7037 &ResolutionRequest {
7038 qname: "www.sub.welcome".to_owned(),
7039 qtype: RecordType::A.code(),
7040 },
7041 &delegation_with_records(vec![
7042 ns_record("welcome", "ns1.welcome"),
7043 record(
7044 DnsName::from_ascii("ns1.welcome").unwrap(),
7045 RecordType::A,
7046 vec![127, 0, 0, 1],
7047 ),
7048 ds_record("welcome"),
7049 ]),
7050 )
7051 .unwrap();
7052
7053 assert!(answer.secure);
7054 assert_eq!(answer.records.len(), 2);
7055 assert_eq!(answer.records[0].record_type, RecordType::Cname);
7056 assert_eq!(answer.records[1].rdata, vec![127, 0, 0, 4]);
7057 assert_eq!(
7058 *requests.lock().unwrap(),
7059 vec![
7060 (
7061 parent_server,
7062 "www.sub.welcome".to_owned(),
7063 RecordType::A.code(),
7064 false,
7065 ),
7066 (
7067 parent_server,
7068 "welcome".to_owned(),
7069 RecordType::Dnskey.code(),
7070 false,
7071 ),
7072 (
7073 child_server,
7074 "sub.welcome".to_owned(),
7075 RecordType::Dnskey.code(),
7076 false,
7077 ),
7078 (
7079 child_server,
7080 "www.sub.welcome".to_owned(),
7081 RecordType::A.code(),
7082 false,
7083 ),
7084 ],
7085 );
7086 assert_eq!(
7087 *child_validations.lock().unwrap(),
7088 vec![(1, 1, 1, 1, 1), (1, 1, 1, 1, 1)]
7089 );
7090 }
7091
7092 #[test]
7093 fn authoritative_dnssec_resolver_accepts_secure_child_nsec_no_data() {
7094 let parent_server = SocketAddr::from(([127, 0, 0, 1], 53));
7095 let child_server = SocketAddr::from(([127, 0, 0, 2], 53));
7096 let requests = Arc::new(Mutex::new(Vec::new()));
7097 let child_no_data_validations = Arc::new(Mutex::new(Vec::new()));
7098 let mut responses = dns_responses(vec![(
7099 "welcome",
7100 RecordType::Dnskey,
7101 vec![
7102 record(
7103 DnsName::from_ascii("welcome").unwrap(),
7104 RecordType::Dnskey,
7105 vec![1, 2, 3, 4],
7106 ),
7107 rrsig_record("welcome"),
7108 ],
7109 )]);
7110 responses.insert(
7111 ("missing.sub.welcome".to_owned(), RecordType::A.code()),
7112 DnsResponseFixture {
7113 rcode: DNS_RCODE_NOERROR,
7114 answers: Vec::new(),
7115 authorities: vec![
7116 ns_record("sub.welcome", "ns1.sub.welcome"),
7117 ds_record("sub.welcome"),
7118 rrsig_record("sub.welcome"),
7119 ],
7120 additionals: vec![record(
7121 DnsName::from_ascii("ns1.sub.welcome").unwrap(),
7122 RecordType::A,
7123 vec![127, 0, 0, 2],
7124 )],
7125 },
7126 );
7127 let mut server_responses = HashMap::new();
7128 server_responses.insert(
7129 (
7130 child_server,
7131 "sub.welcome".to_owned(),
7132 RecordType::Dnskey.code(),
7133 ),
7134 DnsResponseFixture {
7135 rcode: DNS_RCODE_NOERROR,
7136 answers: vec![
7137 record(
7138 DnsName::from_ascii("sub.welcome").unwrap(),
7139 RecordType::Dnskey,
7140 vec![1, 2, 3, 4],
7141 ),
7142 rrsig_record("sub.welcome"),
7143 ],
7144 authorities: Vec::new(),
7145 additionals: Vec::new(),
7146 },
7147 );
7148 server_responses.insert(
7149 (
7150 child_server,
7151 "missing.sub.welcome".to_owned(),
7152 RecordType::A.code(),
7153 ),
7154 DnsResponseFixture {
7155 rcode: DNS_RCODE_NOERROR,
7156 answers: Vec::new(),
7157 authorities: vec![
7158 nsec_record("missing.sub.welcome"),
7159 rrsig_record("missing.sub.welcome"),
7160 ],
7161 additionals: Vec::new(),
7162 },
7163 );
7164 let resolver = AuthoritativeDnssecResolver::new(
7165 ScriptedDnsTransport {
7166 responses,
7167 server_responses,
7168 requests: Arc::clone(&requests),
7169 udp_behavior: ScriptedUdpBehavior::Normal,
7170 },
7171 StaticDnssecVerifier {
7172 positive_valid: false,
7173 no_data_valid: false,
7174 name_error_valid: false,
7175 child_positive_valid: false,
7176 child_no_data_valid: true,
7177 child_name_error_valid: false,
7178 validations: Arc::new(Mutex::new(Vec::new())),
7179 no_data_validations: Arc::new(Mutex::new(Vec::new())),
7180 name_error_validations: Arc::new(Mutex::new(Vec::new())),
7181 child_validations: Arc::new(Mutex::new(Vec::new())),
7182 child_no_data_validations: Arc::clone(&child_no_data_validations),
7183 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
7184 },
7185 );
7186
7187 let answer = resolver
7188 .resolve_delegated(
7189 &ResolutionRequest {
7190 qname: "missing.sub.welcome".to_owned(),
7191 qtype: RecordType::A.code(),
7192 },
7193 &delegation_with_records(vec![
7194 ns_record("welcome", "ns1.welcome"),
7195 record(
7196 DnsName::from_ascii("ns1.welcome").unwrap(),
7197 RecordType::A,
7198 vec![127, 0, 0, 1],
7199 ),
7200 ds_record("welcome"),
7201 ]),
7202 )
7203 .unwrap();
7204
7205 assert!(answer.secure);
7206 assert!(answer.records.is_empty());
7207 assert_eq!(
7208 *requests.lock().unwrap(),
7209 vec![
7210 (
7211 parent_server,
7212 "missing.sub.welcome".to_owned(),
7213 RecordType::A.code(),
7214 false,
7215 ),
7216 (
7217 parent_server,
7218 "welcome".to_owned(),
7219 RecordType::Dnskey.code(),
7220 false,
7221 ),
7222 (
7223 child_server,
7224 "sub.welcome".to_owned(),
7225 RecordType::Dnskey.code(),
7226 false,
7227 ),
7228 (
7229 child_server,
7230 "missing.sub.welcome".to_owned(),
7231 RecordType::A.code(),
7232 false,
7233 ),
7234 ],
7235 );
7236 assert_eq!(
7237 *child_no_data_validations.lock().unwrap(),
7238 vec![(1, 1, 1, 1, 2)]
7239 );
7240 }
7241
7242 #[test]
7243 fn authoritative_dnssec_resolver_fails_closed_when_verifier_rejects() {
7244 let resolver = AuthoritativeDnssecResolver::new(
7245 ScriptedDnsTransport {
7246 responses: dns_responses(vec![
7247 (
7248 "welcome",
7249 RecordType::A,
7250 vec![
7251 record(
7252 DnsName::from_ascii("welcome").unwrap(),
7253 RecordType::A,
7254 vec![127, 0, 0, 1],
7255 ),
7256 rrsig_record("welcome"),
7257 ],
7258 ),
7259 (
7260 "welcome",
7261 RecordType::Dnskey,
7262 vec![
7263 record(
7264 DnsName::from_ascii("welcome").unwrap(),
7265 RecordType::Dnskey,
7266 vec![1, 2, 3, 4],
7267 ),
7268 rrsig_record("welcome"),
7269 ],
7270 ),
7271 ]),
7272 server_responses: HashMap::new(),
7273 requests: Arc::new(Mutex::new(Vec::new())),
7274 udp_behavior: ScriptedUdpBehavior::Normal,
7275 },
7276 StaticDnssecVerifier {
7277 positive_valid: false,
7278 no_data_valid: false,
7279 name_error_valid: false,
7280 child_positive_valid: false,
7281 child_no_data_valid: false,
7282 child_name_error_valid: false,
7283 validations: Arc::new(Mutex::new(Vec::new())),
7284 no_data_validations: Arc::new(Mutex::new(Vec::new())),
7285 name_error_validations: Arc::new(Mutex::new(Vec::new())),
7286 child_validations: Arc::new(Mutex::new(Vec::new())),
7287 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
7288 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
7289 },
7290 );
7291
7292 assert_eq!(
7293 resolver
7294 .resolve_delegated(
7295 &ResolutionRequest {
7296 qname: "welcome".to_owned(),
7297 qtype: RecordType::A.code(),
7298 },
7299 &delegation_with_records(vec![
7300 ns_record("welcome", "ns1.welcome"),
7301 record(
7302 DnsName::from_ascii("ns1.welcome").unwrap(),
7303 RecordType::A,
7304 vec![127, 0, 0, 1],
7305 ),
7306 ds_record("welcome"),
7307 ]),
7308 )
7309 .unwrap_err(),
7310 ResolverError::DnssecFailed,
7311 );
7312 }
7313
7314 fn authoritative_dnssec_retry_resolver(
7315 udp_behavior: ScriptedUdpBehavior,
7316 requests: DnsRequestLog,
7317 ) -> AuthoritativeDnssecResolver<ScriptedDnsTransport, StaticDnssecVerifier> {
7318 AuthoritativeDnssecResolver::new(
7319 ScriptedDnsTransport {
7320 responses: dns_responses(vec![
7321 (
7322 "welcome",
7323 RecordType::A,
7324 vec![
7325 record(
7326 DnsName::from_ascii("welcome").unwrap(),
7327 RecordType::A,
7328 vec![127, 0, 0, 1],
7329 ),
7330 rrsig_record("welcome"),
7331 ],
7332 ),
7333 (
7334 "welcome",
7335 RecordType::Dnskey,
7336 vec![
7337 record(
7338 DnsName::from_ascii("welcome").unwrap(),
7339 RecordType::Dnskey,
7340 vec![1, 2, 3, 4],
7341 ),
7342 rrsig_record("welcome"),
7343 ],
7344 ),
7345 ]),
7346 server_responses: HashMap::new(),
7347 requests,
7348 udp_behavior,
7349 },
7350 StaticDnssecVerifier {
7351 positive_valid: true,
7352 no_data_valid: false,
7353 name_error_valid: false,
7354 child_positive_valid: false,
7355 child_no_data_valid: false,
7356 child_name_error_valid: false,
7357 validations: Arc::new(Mutex::new(Vec::new())),
7358 no_data_validations: Arc::new(Mutex::new(Vec::new())),
7359 name_error_validations: Arc::new(Mutex::new(Vec::new())),
7360 child_validations: Arc::new(Mutex::new(Vec::new())),
7361 child_no_data_validations: Arc::new(Mutex::new(Vec::new())),
7362 child_name_error_validations: Arc::new(Mutex::new(Vec::new())),
7363 },
7364 )
7365 }
7366
7367 fn resolve_welcome_a(
7368 resolver: &AuthoritativeDnssecResolver<ScriptedDnsTransport, StaticDnssecVerifier>,
7369 ) -> Result<ResolutionAnswer, ResolverError> {
7370 resolver.resolve_delegated(
7371 &ResolutionRequest {
7372 qname: "welcome".to_owned(),
7373 qtype: RecordType::A.code(),
7374 },
7375 &delegation_with_records(vec![
7376 ns_record("welcome", "ns1.welcome"),
7377 record(
7378 DnsName::from_ascii("ns1.welcome").unwrap(),
7379 RecordType::A,
7380 vec![127, 0, 0, 1],
7381 ),
7382 ds_record("welcome"),
7383 ]),
7384 )
7385 }
7386
7387 fn assert_welcome_a_retried_over_tcp(requests: &DnsRequestLog) {
7388 let requests = requests.lock().unwrap();
7389 assert!(requests.iter().any(|(_, qname, qtype, tcp)| {
7390 qname == "welcome" && *qtype == RecordType::A.code() && !*tcp
7391 }));
7392 assert!(requests.iter().any(|(_, qname, qtype, tcp)| {
7393 qname == "welcome" && *qtype == RecordType::A.code() && *tcp
7394 }));
7395 }
7396
7397 #[test]
7398 fn authoritative_dnssec_resolver_retries_truncated_udp_over_tcp() {
7399 let requests = Arc::new(Mutex::new(Vec::new()));
7400 let resolver = authoritative_dnssec_retry_resolver(
7401 ScriptedUdpBehavior::Truncated,
7402 Arc::clone(&requests),
7403 );
7404 let answer = resolve_welcome_a(&resolver).unwrap();
7405
7406 assert!(answer.secure);
7407 assert_welcome_a_retried_over_tcp(&requests);
7408 }
7409
7410 #[test]
7411 fn authoritative_dnssec_resolver_retries_udp_transport_error_over_tcp() {
7412 let requests = Arc::new(Mutex::new(Vec::new()));
7413 let resolver = authoritative_dnssec_retry_resolver(
7414 ScriptedUdpBehavior::TransportError,
7415 Arc::clone(&requests),
7416 );
7417 let answer = resolve_welcome_a(&resolver).unwrap();
7418
7419 assert!(answer.secure);
7420 assert_welcome_a_retried_over_tcp(&requests);
7421 }
7422
7423 #[test]
7424 fn authoritative_dnssec_resolver_retries_invalid_udp_response_over_tcp() {
7425 let requests = Arc::new(Mutex::new(Vec::new()));
7426 let resolver = authoritative_dnssec_retry_resolver(
7427 ScriptedUdpBehavior::InvalidResponse,
7428 Arc::clone(&requests),
7429 );
7430 let answer = resolve_welcome_a(&resolver).unwrap();
7431
7432 assert!(answer.secure);
7433 assert_welcome_a_retried_over_tcp(&requests);
7434 }
7435
7436 #[test]
7437 fn dns_response_parser_returns_response_code_for_servfail() {
7438 let qname = DnsName::from_ascii("welcome").unwrap();
7439 let id = 0x1234;
7440 let query =
7441 DnsMessage::parse(&build_dns_query(id, &qname, RecordType::A).unwrap()).unwrap();
7442 let response = dns_response(
7443 &query,
7444 DnsResponseFixture {
7445 rcode: 2,
7446 answers: Vec::new(),
7447 authorities: Vec::new(),
7448 additionals: Vec::new(),
7449 },
7450 false,
7451 );
7452
7453 assert_eq!(
7454 parse_dns_response(id, &qname, RecordType::A, &response).unwrap_err(),
7455 ResolverError::DnsResponseCode(2),
7456 );
7457 }
7458
7459 #[test]
7460 fn resolver_all_record_query_keeps_synth_address_records() {
7461 let root_name = "welcome".to_owned();
7462 let name_hash = NameHash::from_name(&root_name).unwrap();
7463 let value = vec![0, 4, 127, 0, 0, 1];
7464 let resolver =
7465 ProofBackedResolver::new(ResourceValueProofProvider::new(StaticValueProvider {
7466 verified: VerifiedResourceValue::inclusion(root_name.clone(), name_hash, value),
7467 }));
7468
7469 let answer = resolver
7470 .resolve(&ResolutionRequest {
7471 qname: root_name,
7472 qtype: u16::MAX,
7473 })
7474 .unwrap();
7475
7476 assert_eq!(answer.records.len(), 2);
7477 assert!(
7478 answer
7479 .records
7480 .iter()
7481 .any(|record| record.record_type == RecordType::A && record.rdata == [127, 0, 0, 1])
7482 );
7483 }
7484
7485 #[test]
7486 fn resource_value_provider_allows_verified_non_inclusion() {
7487 let root_name = "welcome".to_owned();
7488 let name_hash = NameHash::from_name(&root_name).unwrap();
7489 let provider = ResourceValueProofProvider::new(StaticValueProvider {
7490 verified: VerifiedResourceValue::non_inclusion(root_name.clone(), name_hash),
7491 });
7492
7493 let proven = provider.prove_name(&root_name, name_hash).unwrap();
7494
7495 assert!(proven.secure);
7496 assert!(!proven.exists);
7497 assert!(proven.records.is_empty());
7498 }
7499
7500 #[test]
7501 fn resource_value_provider_rejects_mismatched_verified_value() {
7502 let provider = ResourceValueProofProvider::new(StaticValueProvider {
7503 verified: VerifiedResourceValue::non_inclusion(
7504 "other".to_owned(),
7505 NameHash::from_name("other").unwrap(),
7506 ),
7507 });
7508
7509 assert_eq!(
7510 provider
7511 .prove_name("welcome", NameHash::from_name("welcome").unwrap())
7512 .unwrap_err(),
7513 ResolverError::ProofNameMismatch,
7514 );
7515 }
7516
7517 #[test]
7518 fn memory_resource_value_provider_serves_inserted_value() {
7519 let root_name = "welcome".to_owned();
7520 let name_hash = NameHash::from_name(&root_name).unwrap();
7521 let mut value = vec![0, 1];
7522 encode_name(&mut value, "ns1.welcome");
7523 let values = MemoryResourceValueProvider::new();
7524 values
7525 .insert(VerifiedResourceValue::inclusion(
7526 root_name.clone(),
7527 name_hash,
7528 value,
7529 ))
7530 .unwrap();
7531 let resolver = ProofBackedResolver::new(ResourceValueProofProvider::new(values));
7532
7533 let answer = resolver
7534 .resolve(&ResolutionRequest {
7535 qname: root_name,
7536 qtype: RecordType::Ns.code(),
7537 })
7538 .unwrap();
7539
7540 assert_eq!(answer.records.len(), 1);
7541 assert_eq!(answer.records[0].rdata, name_bytes("ns1.welcome"));
7542 }
7543
7544 #[test]
7545 fn memory_resource_value_provider_rejects_missing_value() {
7546 let values = MemoryResourceValueProvider::new();
7547
7548 assert_eq!(
7549 values
7550 .prove_resource_value("welcome", NameHash::from_name("welcome").unwrap())
7551 .unwrap_err(),
7552 ResolverError::ProofUnavailable,
7553 );
7554 assert!(values.is_empty().unwrap());
7555 }
7556
7557 #[test]
7558 fn memory_resource_value_provider_rejects_mismatched_hash() {
7559 let values = MemoryResourceValueProvider::new();
7560
7561 assert_eq!(
7562 values
7563 .insert(VerifiedResourceValue::non_inclusion(
7564 "welcome".to_owned(),
7565 NameHash::from_name("other").unwrap(),
7566 ))
7567 .unwrap_err(),
7568 ResolverError::ProofNameMismatch,
7569 );
7570 }
7571
7572 #[test]
7573 fn sqlite_resource_value_provider_persists_inserted_value() {
7574 let path = temp_db_path("resource-value");
7575 let root_name = "welcome".to_owned();
7576 let name_hash = NameHash::from_name(&root_name).unwrap();
7577 let mut value = vec![0, 1];
7578 encode_name(&mut value, "ns1.welcome");
7579
7580 {
7581 let values = SqliteResourceValueProvider::open(&path).unwrap();
7582 values
7583 .insert(VerifiedResourceValue::inclusion(
7584 root_name.clone(),
7585 name_hash,
7586 value.clone(),
7587 ))
7588 .unwrap();
7589 assert_eq!(values.len().unwrap(), 1);
7590 values.flush().unwrap();
7591 }
7592
7593 {
7594 let values = SqliteResourceValueProvider::open(&path).unwrap();
7595 let verified = values.prove_resource_value(&root_name, name_hash).unwrap();
7596 assert_eq!(verified.value, Some(value.clone()));
7597
7598 let resolver = ProofBackedResolver::new(ResourceValueProofProvider::new(values));
7599 let answer = resolver
7600 .resolve(&ResolutionRequest {
7601 qname: root_name,
7602 qtype: RecordType::Ns.code(),
7603 })
7604 .unwrap();
7605
7606 assert_eq!(answer.records.len(), 1);
7607 assert_eq!(answer.records[0].rdata, name_bytes("ns1.welcome"));
7608 }
7609
7610 cleanup_db_path(&path);
7611 }
7612
7613 #[test]
7614 fn sqlite_resource_value_provider_persists_non_inclusion() {
7615 let path = temp_db_path("resource-non-inclusion");
7616 let root_name = "welcome".to_owned();
7617 let name_hash = NameHash::from_name(&root_name).unwrap();
7618
7619 {
7620 let values = SqliteResourceValueProvider::open(&path).unwrap();
7621 values
7622 .insert(VerifiedResourceValue::non_inclusion(
7623 root_name.clone(),
7624 name_hash,
7625 ))
7626 .unwrap();
7627 values.flush().unwrap();
7628 }
7629
7630 {
7631 let values = SqliteResourceValueProvider::open(&path).unwrap();
7632 let verified = values.prove_resource_value(&root_name, name_hash).unwrap();
7633 assert_eq!(verified.value, None);
7634 assert!(verified.secure);
7635 }
7636
7637 cleanup_db_path(&path);
7638 }
7639
7640 #[test]
7641 fn sqlite_resource_value_provider_reports_bytes_and_evicts_oldest_values() {
7642 let values = SqliteResourceValueProvider::in_memory().unwrap();
7643 let alpha_hash = NameHash::from_name("alpha").unwrap();
7644 let beta_hash = NameHash::from_name("beta").unwrap();
7645
7646 values
7647 .insert(VerifiedResourceValue::inclusion(
7648 "alpha".to_owned(),
7649 alpha_hash,
7650 vec![1, 2, 3, 4, 5, 6],
7651 ))
7652 .unwrap();
7653 values
7654 .insert(VerifiedResourceValue::inclusion(
7655 "beta".to_owned(),
7656 beta_hash,
7657 vec![7, 8],
7658 ))
7659 .unwrap();
7660
7661 assert_eq!(
7662 values.stats().unwrap(),
7663 ResourceValueCacheStats {
7664 entries: 2,
7665 value_bytes: 8,
7666 },
7667 );
7668 assert_eq!(values.enforce_value_byte_limit(2).unwrap(), 1);
7669
7670 assert_eq!(
7671 values.stats().unwrap(),
7672 ResourceValueCacheStats {
7673 entries: 1,
7674 value_bytes: 2,
7675 },
7676 );
7677 assert_eq!(
7678 values
7679 .prove_resource_value("alpha", alpha_hash)
7680 .unwrap_err(),
7681 ResolverError::ProofUnavailable,
7682 );
7683 assert_eq!(
7684 values
7685 .prove_resource_value("beta", beta_hash)
7686 .unwrap()
7687 .value,
7688 Some(vec![7, 8]),
7689 );
7690
7691 values.clear().unwrap();
7692 assert_eq!(
7693 values.stats().unwrap(),
7694 ResourceValueCacheStats {
7695 entries: 0,
7696 value_bytes: 0,
7697 },
7698 );
7699 }
7700
7701 #[test]
7702 fn sqlite_resource_value_provider_persists_and_prunes_anchors() {
7703 let values = SqliteResourceValueProvider::in_memory().unwrap();
7704 let alpha_hash = NameHash::from_name("alpha").unwrap();
7705 let beta_hash = NameHash::from_name("beta").unwrap();
7706 let gamma_hash = NameHash::from_name("gamma").unwrap();
7707 let valid_anchor = ResourceValueAnchor {
7708 tree_root: Hash::new([1; 32]),
7709 height: Height(3),
7710 };
7711 let invalid_anchor = ResourceValueAnchor {
7712 tree_root: Hash::new([2; 32]),
7713 height: Height(3),
7714 };
7715
7716 values
7717 .insert(
7718 VerifiedResourceValue::inclusion("alpha".to_owned(), alpha_hash, vec![1])
7719 .with_anchor(valid_anchor.tree_root, valid_anchor.height),
7720 )
7721 .unwrap();
7722 values
7723 .insert(
7724 VerifiedResourceValue::inclusion("beta".to_owned(), beta_hash, vec![2])
7725 .with_anchor(invalid_anchor.tree_root, invalid_anchor.height),
7726 )
7727 .unwrap();
7728 values
7729 .insert(VerifiedResourceValue::inclusion(
7730 "gamma".to_owned(),
7731 gamma_hash,
7732 vec![3],
7733 ))
7734 .unwrap();
7735
7736 assert_eq!(values.anchored_heights().unwrap(), vec![Height(3)]);
7737 assert_eq!(
7738 values.prune_invalid_anchors(&[valid_anchor], true).unwrap(),
7739 2
7740 );
7741 assert_eq!(
7742 values
7743 .prove_resource_value("alpha", alpha_hash)
7744 .unwrap()
7745 .anchor,
7746 Some(valid_anchor),
7747 );
7748 assert_eq!(
7749 values.prove_resource_value("beta", beta_hash).unwrap_err(),
7750 ResolverError::ProofUnavailable,
7751 );
7752 assert_eq!(
7753 values
7754 .prove_resource_value("gamma", gamma_hash)
7755 .unwrap_err(),
7756 ResolverError::ProofUnavailable,
7757 );
7758 }
7759
7760 #[test]
7761 fn sqlite_resource_value_provider_migrates_previous_anchor_columns() {
7762 let connection = Connection::open_in_memory().unwrap();
7763 connection
7764 .execute_batch(
7765 "
7766 CREATE TABLE verified_resource_values (
7767 root_name TEXT NOT NULL,
7768 name_hash BLOB NOT NULL,
7769 value BLOB,
7770 secure INTEGER NOT NULL,
7771 updated_at_unix INTEGER NOT NULL,
7772 PRIMARY KEY(root_name, name_hash)
7773 );
7774 ",
7775 )
7776 .unwrap();
7777 let values = SqliteResourceValueProvider::from_connection(connection).unwrap();
7778 let root_name = "alpha".to_owned();
7779 let name_hash = NameHash::from_name(&root_name).unwrap();
7780 let anchor = ResourceValueAnchor {
7781 tree_root: Hash::new([3; 32]),
7782 height: Height(11),
7783 };
7784
7785 values
7786 .insert(
7787 VerifiedResourceValue::inclusion(root_name.clone(), name_hash, vec![1, 2])
7788 .with_anchor(anchor.tree_root, anchor.height),
7789 )
7790 .unwrap();
7791
7792 let stored = values.prove_resource_value(&root_name, name_hash).unwrap();
7793 assert_eq!(stored.anchor, Some(anchor));
7794 }
7795
7796 fn record(name: DnsName, record_type: RecordType, rdata: Vec<u8>) -> ResourceRecord {
7797 ResourceRecord {
7798 name,
7799 record_type,
7800 class: 1,
7801 ttl: 300,
7802 rdata,
7803 }
7804 }
7805
7806 fn ns_record(owner: &str, target: &str) -> ResourceRecord {
7807 record(
7808 DnsName::from_ascii(owner).unwrap(),
7809 RecordType::Ns,
7810 name_bytes(target),
7811 )
7812 }
7813
7814 fn ds_record(owner: &str) -> ResourceRecord {
7815 record(
7816 DnsName::from_ascii(owner).unwrap(),
7817 RecordType::Ds,
7818 vec![0, 1, 8, 2, 0xaa],
7819 )
7820 }
7821
7822 fn glue4_record(owner: &str, address: [u8; 4]) -> ResourceRecord {
7823 record(
7824 DnsName::from_ascii(owner).unwrap(),
7825 RecordType::A,
7826 address.to_vec(),
7827 )
7828 }
7829
7830 fn txt_record(owner: &str, text: &str) -> ResourceRecord {
7831 assert!(text.len() <= u8::MAX as usize);
7832 let mut rdata = Vec::new();
7833 rdata.push(text.len() as u8);
7834 rdata.extend(text.as_bytes());
7835 record(DnsName::from_ascii(owner).unwrap(), RecordType::Txt, rdata)
7836 }
7837
7838 fn svcb_doh_record(owner: &str, target: &str, dohpath: &str) -> ResourceRecord {
7839 let mut rdata = Vec::new();
7840 rdata.extend(1u16.to_be_bytes());
7841 encode_name(&mut rdata, target);
7842 rdata.extend(SVCB_PARAM_ALPN.to_be_bytes());
7843 rdata.extend(3u16.to_be_bytes());
7844 rdata.extend([2, b'h', b'2']);
7845 rdata.extend(SVCB_PARAM_DOHPATH.to_be_bytes());
7846 rdata.extend((dohpath.len() as u16).to_be_bytes());
7847 rdata.extend(dohpath.as_bytes());
7848 record(DnsName::from_ascii(owner).unwrap(), RecordType::Svcb, rdata)
7849 }
7850
7851 fn rrsig_record(owner: &str) -> ResourceRecord {
7852 record(
7853 DnsName::from_ascii(owner).unwrap(),
7854 RecordType::Rrsig,
7855 vec![0, 1, 8, 1],
7856 )
7857 }
7858
7859 fn rrsig_record_for_signer(
7860 owner: &str,
7861 type_covered: RecordType,
7862 signer: &str,
7863 ) -> ResourceRecord {
7864 let mut rdata = Vec::new();
7865 rdata.extend(type_covered.code().to_be_bytes());
7866 rdata.push(8);
7867 rdata.push(DnsName::from_ascii(owner).unwrap().labels().len() as u8);
7868 rdata.extend(300u32.to_be_bytes());
7869 rdata.extend(2_000_000_000u32.to_be_bytes());
7870 rdata.extend(1u32.to_be_bytes());
7871 rdata.extend(0x1234u16.to_be_bytes());
7872 DnsName::from_ascii(signer)
7873 .unwrap()
7874 .encode_wire(&mut rdata)
7875 .unwrap();
7876 rdata.push(0xaa);
7877 record(
7878 DnsName::from_ascii(owner).unwrap(),
7879 RecordType::Rrsig,
7880 rdata,
7881 )
7882 }
7883
7884 fn cname_record(owner: &str, target: &str) -> ResourceRecord {
7885 record(
7886 DnsName::from_ascii(owner).unwrap(),
7887 RecordType::Cname,
7888 name_bytes(target),
7889 )
7890 }
7891
7892 fn nsec_record(owner: &str) -> ResourceRecord {
7893 record(
7894 DnsName::from_ascii(owner).unwrap(),
7895 RecordType::Nsec,
7896 name_bytes(owner),
7897 )
7898 }
7899
7900 fn delegation_with_records(records: Vec<ResourceRecord>) -> HnsDelegation {
7901 HnsDelegation {
7902 root_name: "welcome".to_owned(),
7903 owner: DnsName::from_ascii("welcome").unwrap(),
7904 records,
7905 }
7906 }
7907
7908 fn dns_responses(responses: Vec<(&str, RecordType, Vec<ResourceRecord>)>) -> DnsResponseMap {
7909 responses
7910 .into_iter()
7911 .map(|(name, record_type, records)| {
7912 (
7913 (name.to_owned(), record_type.code()),
7914 DnsResponseFixture {
7915 rcode: DNS_RCODE_NOERROR,
7916 answers: records,
7917 authorities: Vec::new(),
7918 additionals: Vec::new(),
7919 },
7920 )
7921 })
7922 .collect()
7923 }
7924
7925 fn tcp_repair_fixture(question: &DnsQuestion, valid_dnskey: bool) -> DnsResponseFixture {
7926 let records = match question.record_type {
7927 RecordType::A => vec![
7928 record(question.name.clone(), RecordType::A, vec![1, 1, 1, 1]),
7929 rrsig_record(&question.name.to_string()),
7930 ],
7931 RecordType::Dnskey if valid_dnskey => vec![
7932 record(question.name.clone(), RecordType::Dnskey, vec![1, 2, 3, 4]),
7933 rrsig_record(&question.name.to_string()),
7934 ],
7935 _ => Vec::new(),
7936 };
7937 DnsResponseFixture {
7938 rcode: DNS_RCODE_NOERROR,
7939 answers: records,
7940 authorities: Vec::new(),
7941 additionals: Vec::new(),
7942 }
7943 }
7944
7945 fn dns_response(query: &DnsMessage, fixture: DnsResponseFixture, truncated: bool) -> Vec<u8> {
7946 let flags = (if truncated { 0x8600 } else { 0x8400 }) | fixture.rcode as u16;
7947 DnsMessage {
7948 header: DnsHeader {
7949 id: query.header.id,
7950 flags: DnsFlags::new(flags),
7951 question_count: 1,
7952 answer_count: fixture.answers.len() as u16,
7953 authority_count: fixture.authorities.len() as u16,
7954 additional_count: fixture.additionals.len() as u16,
7955 },
7956 questions: query.questions.clone(),
7957 answers: fixture.answers,
7958 authorities: fixture.authorities,
7959 additionals: fixture.additionals,
7960 }
7961 .encode(&DnsEncodeConfig {
7962 max_message_len: DEFAULT_DNS_TCP_MAX_MESSAGE_LEN,
7963 })
7964 .unwrap()
7965 }
7966
7967 fn resolver_response(
7968 qname: &str,
7969 qtype: u16,
7970 secure: bool,
7971 records: Vec<ResourceRecord>,
7972 ) -> (ResolutionRequest, ResolutionAnswer) {
7973 (
7974 ResolutionRequest {
7975 qname: qname.to_owned(),
7976 qtype,
7977 },
7978 ResolutionAnswer {
7979 name: DnsName::from_ascii(qname).unwrap(),
7980 records,
7981 secure,
7982 },
7983 )
7984 }
7985
7986 fn encode_name(out: &mut Vec<u8>, name: &str) {
7987 DnsName::from_ascii(name).unwrap().encode_wire(out).unwrap();
7988 }
7989
7990 fn name_bytes(name: &str) -> Vec<u8> {
7991 let mut out = Vec::new();
7992 encode_name(&mut out, name);
7993 out
7994 }
7995
7996 fn temp_db_path(label: &str) -> std::path::PathBuf {
7997 let now = std::time::SystemTime::now()
7998 .duration_since(std::time::UNIX_EPOCH)
7999 .unwrap()
8000 .as_nanos();
8001 std::env::temp_dir().join(format!(
8002 "hns-resolver-{label}-{}-{now}.sqlite",
8003 std::process::id()
8004 ))
8005 }
8006
8007 fn cleanup_db_path(path: &std::path::Path) {
8008 let _ = std::fs::remove_file(path);
8009 let _ = std::fs::remove_file(path.with_extension("sqlite-wal"));
8010 let _ = std::fs::remove_file(path.with_extension("sqlite-shm"));
8011 }
8012}