dns_resolver/
lib.rs

1#![warn(clippy::pedantic)]
2// Sometimes a redundant else is clearer
3#![allow(clippy::redundant_else)]
4// False positives for `bytes::Bytes`
5#![allow(clippy::mutable_key_type)]
6// I think explicit lifetimes make it easier to read in some cases
7#![allow(clippy::needless_lifetimes)]
8#![allow(clippy::elidable_lifetime_names)]
9// Don't care enough to fix
10#![allow(clippy::match_same_arms)]
11#![allow(clippy::must_use_candidate)]
12#![allow(clippy::module_name_repetitions)]
13#![allow(clippy::return_self_not_must_use)]
14#![allow(clippy::similar_names)]
15#![allow(clippy::struct_excessive_bools)]
16#![allow(clippy::too_many_lines)]
17#![allow(clippy::wildcard_imports)]
18
19pub mod cache;
20pub mod context;
21pub mod forwarding;
22pub mod local;
23pub mod metrics;
24pub mod recursive;
25pub mod util;
26
27use std::net::SocketAddr;
28use tracing::Instrument;
29
30use dns_types::protocol::types::Question;
31use dns_types::zones::types::Zones;
32
33use self::cache::SharedCache;
34use self::context::Context;
35use self::forwarding::{resolve_forwarding, ForwardingContextInner};
36use self::local::resolve_local;
37use self::metrics::Metrics;
38use self::recursive::{resolve_recursive, RecursiveContextInner};
39use self::util::types::{ProtocolMode, ResolutionError, ResolvedRecord};
40
41/// Maximum recursion depth.  Recursion is used to resolve CNAMEs, so
42/// a chain of CNAMEs longer than this cannot be resolved.
43///
44/// This is to protect against a maliciously-configured upstream
45/// nameserver which returns an infinite stream of CNAME records when
46/// trying to resolve some other record type.
47pub const RECURSION_LIMIT: usize = 32;
48
49/// Resolve a question using the standard DNS algorithms.
50pub async fn resolve(
51    is_recursive: bool,
52    protocol_mode: ProtocolMode,
53    upstream_dns_port: u16,
54    forward_address: Option<SocketAddr>,
55    zones: &Zones,
56    cache: &SharedCache,
57    question: &Question,
58) -> (Metrics, Result<ResolvedRecord, ResolutionError>) {
59    match (is_recursive, forward_address) {
60        (true, Some(address)) => {
61            let mut context = Context::new(
62                ForwardingContextInner {
63                    forward_address: address,
64                },
65                zones,
66                cache,
67                RECURSION_LIMIT,
68            );
69            let result = resolve_forwarding(&mut context, question)
70                .instrument(tracing::error_span!("resolve_forwarding", %address, %question))
71                .await;
72            (context.done(), result)
73        }
74        (true, None) => {
75            let mut context = Context::new(
76                RecursiveContextInner {
77                    protocol_mode,
78                    upstream_dns_port,
79                },
80                zones,
81                cache,
82                RECURSION_LIMIT,
83            );
84            let result = resolve_recursive(&mut context, question)
85                .instrument(tracing::error_span!("resolve_recursive", %question))
86                .await;
87            (context.done(), result)
88        }
89        (false, _) => {
90            let mut context = Context::new((), zones, cache, RECURSION_LIMIT);
91            let result = resolve_local(&mut context, question).map(ResolvedRecord::from);
92            (context.done(), result)
93        }
94    }
95}