reth_dns_discovery/
resolver.rs1use dashmap::DashMap;
4pub use hickory_resolver::{net::NetError, TokioResolver};
5use hickory_resolver::{proto::rr::RData, ConnectionProvider};
6use std::future::Future;
7use tracing::trace;
8
9pub trait Resolver: Send + Sync + Unpin + 'static {
11 fn lookup_txt(&self, query: &str) -> impl Future<Output = Option<String>> + Send;
13}
14
15impl<P: ConnectionProvider> Resolver for hickory_resolver::Resolver<P> {
16 async fn lookup_txt(&self, query: &str) -> Option<String> {
17 let fqn = if query.ends_with('.') { query.to_string() } else { format!("{query}.") };
20 match self.txt_lookup(fqn).await {
21 Err(err) => {
22 trace!(target: "disc::dns", %err, ?query, "dns lookup failed");
23 None
24 }
25 Ok(lookup) => {
26 let txt = lookup.answers().iter().find_map(|r| match &r.data {
27 RData::TXT(txt) => Some(txt),
28 _ => None,
29 })?;
30 let entry = txt.txt_data.first()?;
31 String::from_utf8(entry.to_vec()).ok()
32 }
33 }
34 }
35}
36
37#[derive(Clone, Debug)]
52pub struct DnsResolver(TokioResolver);
53
54impl DnsResolver {
57 pub const fn new(resolver: TokioResolver) -> Self {
59 Self(resolver)
60 }
61
62 pub fn from_system_conf() -> Result<Self, NetError> {
66 TokioResolver::builder_tokio()?.build().map(Self::new)
67 }
68}
69
70impl Resolver for DnsResolver {
71 async fn lookup_txt(&self, query: &str) -> Option<String> {
72 Resolver::lookup_txt(&self.0, query).await
73 }
74}
75
76#[derive(Debug, Default)]
78pub struct MapResolver(DashMap<String, String>);
79
80impl MapResolver {
83 pub fn insert(&self, k: String, v: String) -> Option<String> {
85 self.0.insert(k, v)
86 }
87
88 pub fn get(&self, k: &str) -> Option<String> {
90 self.0.get(k).map(|entry| entry.value().clone())
91 }
92
93 pub fn remove(&self, k: &str) -> Option<String> {
96 self.0.remove(k).map(|(_, v)| v)
97 }
98}
99
100impl Resolver for MapResolver {
101 async fn lookup_txt(&self, query: &str) -> Option<String> {
102 self.get(query)
103 }
104}
105
106#[cfg(test)]
108pub(crate) struct TimeoutResolver(pub(crate) std::time::Duration);
109
110#[cfg(test)]
111impl Resolver for TimeoutResolver {
112 async fn lookup_txt(&self, _query: &str) -> Option<String> {
113 tokio::time::sleep(self.0).await;
114 None
115 }
116}