Skip to main content

hns_browser_resolver/
lib.rs

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);
56// Generated from https://data.iana.org/TLD/tlds-alpha-by-domain.txt, version 2026062302.
57const ICANN_TLDS: &str = include_str!("icann_tlds.txt");
58
59/// Returns the generated IANA root-zone snapshot used by browser namespace
60/// classification. The trailing newline, when present, is not significant.
61pub 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/// Atomic dual-root decision and any selected root's retained raw DNS
86/// material. A completed `Neither` decision has no selected answer but still
87/// crosses this boundary so consumers retain its exact request-local evidence
88/// and fingerprint. Consumers use the complete selected plan for connection
89/// state; the answer exists only for diagnostics and compatibility.
90#[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    /// Builds one complete dual-root browser decision when the resolver owns
172    /// that adapter. Legacy record-oriented resolvers return `None`.
173    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    /// A recursive relay ignores the proof-derived authoritative socket. Its
333    /// transport owns retry diversity, so authoritative UDP-to-TCP and
334    /// per-nameserver retries must not duplicate the same recursive question.
335    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    /// Disables authoritative DoH discovery for transports that deliberately
1047    /// implement only a later resolver stage, such as the experimental P2P
1048    /// recursive relay. The proof-backed primary resolver remains responsible
1049    /// for trying authoritative DoH before such a stage is constructed.
1050    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        // Only these typed availability failures may reach a separately
1231        // consented recursive fallback. Keep every authenticated-data,
1232        // response-validity, proof, and policy failure stronger so a later
1233        // transport failure cannot erase it.
1234        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}