Skip to content

Commit 446b96e

Browse files
committed
cleanups and docs
1 parent 71cee9e commit 446b96e

File tree

3 files changed

+122
-129
lines changed

3 files changed

+122
-129
lines changed

iroh-relay/src/dns.rs

Lines changed: 120 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,62 @@ pub const N0_DNS_NODE_ORIGIN_PROD: &str = "dns.iroh.link";
2727
/// The n0 testing DNS node origin, for testing.
2828
pub const N0_DNS_NODE_ORIGIN_STAGING: &str = "staging-dns.iroh.link";
2929

30-
/// The default DNS resolver used throughout `iroh`.
30+
/// Trait for DNS resolvers used in iroh.
31+
pub trait Resolver: fmt::Debug + Send + Sync + 'static {
32+
/// Looks up an IPv4 address.
33+
fn lookup_ipv4(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>>>;
34+
35+
/// Looks up an IPv6 address.
36+
fn lookup_ipv6(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>>>;
37+
38+
/// Looks up TXT records.
39+
fn lookup_txt(&self, host: String) -> BoxFuture<Result<BoxIter<TxtRecord>>>;
40+
41+
/// Clears the internal cache.
42+
fn clear_cache(&self);
43+
}
44+
45+
/// Boxed iterator alias.
46+
pub type BoxIter<T> = Box<dyn Iterator<Item = T> + Send + 'static>;
47+
48+
/// DNS resolver for use in iroh.
49+
///
50+
/// This internally contains a [`dyn Resolver`]. See the public methods for how to construct
51+
/// a [`DnsResolver`] with sensible defaults or with a custom resolver.
3152
#[derive(Debug, Clone)]
32-
struct HickoryResolver(TokioResolver);
53+
pub struct DnsResolver(Arc<dyn Resolver>);
3354

34-
impl HickoryResolver {
35-
/// Create a new DNS resolver with sensible cross-platform defaults.
55+
impl std::ops::Deref for DnsResolver {
56+
type Target = dyn Resolver;
57+
fn deref(&self) -> &Self::Target {
58+
&*self.0
59+
}
60+
}
61+
62+
impl Default for DnsResolver {
63+
fn default() -> Self {
64+
Self::new_with_system_defaults()
65+
}
66+
}
67+
68+
impl DnsResolver {
69+
/// Creates a new [`DnsResolver`] from a struct that implements [`Resolver`].
70+
///
71+
/// [`Resolver`] is implemented for [`hickory_resolver::TokioResolver`], so you can construct
72+
/// a [`TokioResolver`] and pass that to this function.
73+
///
74+
/// To use a different DNS resolver, you need to implement [`Resolver`] for your custom resolver
75+
/// and then pass to this function.
76+
pub fn new(resolver: impl Resolver) -> Self {
77+
Self(Arc::new(resolver))
78+
}
79+
80+
/// Creates a new DNS resolver with sensible cross-platform defaults.
3681
///
3782
/// We first try to read the system's resolver from `/etc/resolv.conf`.
3883
/// This does not work at least on some Androids, therefore we fallback
39-
/// to the default `ResolverConfig` which uses eg. to google's `8.8.8.8` or `8.8.4.4`.
40-
fn new() -> Self {
84+
/// to the default `ResolverConfig` which uses Google's `8.8.8.8` or `8.8.4.4`.
85+
pub fn new_with_system_defaults() -> Self {
4186
let (system_config, mut options) =
4287
hickory_resolver::system_conf::read_system_conf().unwrap_or_default();
4388

@@ -62,11 +107,11 @@ impl HickoryResolver {
62107
let mut builder =
63108
TokioResolver::builder_with_config(config, TokioConnectionProvider::default());
64109
*builder.options_mut() = options;
65-
HickoryResolver(builder.build())
110+
Self::new(builder.build())
66111
}
67112

68-
/// Create a new DNS resolver configured with a single UDP DNS nameserver.
69-
fn with_nameserver(nameserver: SocketAddr) -> Self {
113+
/// Creates a new DNS resolver configured with a single UDP DNS nameserver.
114+
pub fn with_nameserver(nameserver: SocketAddr) -> Self {
70115
let mut config = hickory_resolver::config::ResolverConfig::new();
71116
let nameserver_config = hickory_resolver::config::NameServerConfig::new(
72117
nameserver,
@@ -76,108 +121,10 @@ impl HickoryResolver {
76121

77122
let builder =
78123
TokioResolver::builder_with_config(config, TokioConnectionProvider::default());
79-
HickoryResolver(builder.build())
124+
Self::new(builder.build())
80125
}
81-
}
82126

83-
impl Default for HickoryResolver {
84-
fn default() -> Self {
85-
Self::new()
86-
}
87-
}
88-
89-
/// Trait for DNS resolvers used in iroh.
90-
pub trait Resolver: std::fmt::Debug + Send + Sync + 'static {
91-
/// Lookup an IPv4 address.
92-
fn lookup_ipv4(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>>>;
93-
/// Lookup an IPv6 address.
94-
fn lookup_ipv6(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>>>;
95-
/// Lookup TXT records.
96-
fn lookup_txt(&self, host: String) -> BoxFuture<Result<BoxIter<TxtRecord>>>;
97-
/// Clear the internal cache.
98-
fn clear_cache(&self);
99-
}
100-
101-
/// Boxed iterator alias.
102-
pub type BoxIter<T> = Box<dyn Iterator<Item = T> + Send + 'static>;
103-
104-
impl Resolver for HickoryResolver {
105-
fn lookup_ipv4(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>>> {
106-
let this = self.0.clone();
107-
Box::pin(async move {
108-
let addrs = this.ipv4_lookup(host).await?;
109-
let iter: BoxIter<Ipv4Addr> = Box::new(addrs.into_iter().map(Ipv4Addr::from));
110-
Ok(iter)
111-
})
112-
}
113-
114-
fn lookup_ipv6(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>>> {
115-
let this = self.0.clone();
116-
Box::pin(async move {
117-
let addrs = this.ipv6_lookup(host).await?;
118-
let iter: BoxIter<Ipv6Addr> = Box::new(addrs.into_iter().map(Ipv6Addr::from));
119-
Ok(iter)
120-
})
121-
}
122-
123-
fn lookup_txt(&self, host: String) -> BoxFuture<Result<BoxIter<TxtRecord>>> {
124-
let this = self.0.clone();
125-
Box::pin(async move {
126-
let lookup = this.txt_lookup(host).await?;
127-
let iter: BoxIter<TxtRecord> = Box::new(
128-
lookup
129-
.into_iter()
130-
.map(|txt| TxtRecord::from_iter(txt.iter().cloned())),
131-
);
132-
Ok(iter)
133-
})
134-
}
135-
136-
fn clear_cache(&self) {
137-
self.0.clear_cache();
138-
}
139-
}
140-
141-
impl From<TokioResolver> for HickoryResolver {
142-
fn from(resolver: TokioResolver) -> Self {
143-
HickoryResolver(resolver)
144-
}
145-
}
146-
147-
///
148-
#[derive(Debug, Clone)]
149-
pub struct DnsResolver(Arc<dyn Resolver>);
150-
151-
impl std::ops::Deref for DnsResolver {
152-
type Target = dyn Resolver;
153-
fn deref(&self) -> &Self::Target {
154-
&*self.0
155-
}
156-
}
157-
158-
impl Default for DnsResolver {
159-
fn default() -> Self {
160-
Self::new_with_system_defaults()
161-
}
162-
}
163-
164-
impl DnsResolver {
165-
///
166-
pub fn new(resolver: impl Resolver) -> Self {
167-
Self(Arc::new(resolver))
168-
}
169-
170-
///
171-
pub fn new_with_system_defaults() -> Self {
172-
Self::new(HickoryResolver::new())
173-
}
174-
175-
///
176-
pub fn with_nameserver(nameserver: SocketAddr) -> Self {
177-
Self::new(HickoryResolver::with_nameserver(nameserver))
178-
}
179-
180-
/// Lookup a TXT record.
127+
/// Performs a TXT lookup with a timeout.
181128
pub async fn lookup_txt(
182129
&self,
183130
host: impl ToString,
@@ -187,7 +134,7 @@ impl DnsResolver {
187134
Ok(res)
188135
}
189136

190-
/// Perform an ipv4 lookup with a timeout.
137+
/// Performs an IPv4 lookup with a timeout.
191138
pub async fn lookup_ipv4(
192139
&self,
193140
host: impl ToString,
@@ -197,7 +144,7 @@ impl DnsResolver {
197144
Ok(addrs.map(|ip| IpAddr::V4(ip)))
198145
}
199146

200-
/// Perform an ipv6 lookup with a timeout.
147+
/// Performs an IPv6 lookup with a timeout.
201148
pub async fn lookup_ipv6(
202149
&self,
203150
host: impl ToString,
@@ -207,7 +154,7 @@ impl DnsResolver {
207154
Ok(addrs.map(|ip| IpAddr::V6(ip)))
208155
}
209156

210-
/// Resolve IPv4 and IPv6 in parallel with a timeout.
157+
/// Resolves IPv4 and IPv6 in parallel with a timeout.
211158
///
212159
/// `LookupIpStrategy::Ipv4AndIpv6` will wait for ipv6 resolution timeout, even if it is
213160
/// not usable on the stack, so we manually query both lookups concurrently and time them out
@@ -233,7 +180,7 @@ impl DnsResolver {
233180
}
234181
}
235182

236-
/// Resolve a hostname from a URL to an IP address.
183+
/// Resolves a hostname from a URL to an IP address.
237184
pub async fn resolve_host(
238185
&self,
239186
url: &Url,
@@ -263,7 +210,7 @@ impl DnsResolver {
263210
}
264211
}
265212

266-
/// Perform an ipv4 lookup with a timeout in a staggered fashion.
213+
/// Performs an IPv4 lookup with a timeout in a staggered fashion.
267214
///
268215
/// From the moment this function is called, each lookup is scheduled after the delays in
269216
/// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
@@ -280,7 +227,7 @@ impl DnsResolver {
280227
stagger_call(f, delays_ms).await
281228
}
282229

283-
/// Perform an ipv6 lookup with a timeout in a staggered fashion.
230+
/// Performs an IPv6 lookup with a timeout in a staggered fashion.
284231
///
285232
/// From the moment this function is called, each lookup is scheduled after the delays in
286233
/// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
@@ -297,7 +244,7 @@ impl DnsResolver {
297244
stagger_call(f, delays_ms).await
298245
}
299246

300-
/// Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.
247+
/// Races an IPv4 and IPv6 lookup with a timeout in a staggered fashion.
301248
///
302249
/// From the moment this function is called, each lookup is scheduled after the delays in
303250
/// `delays_ms` with the first call being done immediately. `[200ms, 300ms]` results in calls
@@ -367,24 +314,66 @@ impl DnsResolver {
367314
}
368315
}
369316

317+
/// Implementation of [`Resolver`] for [`hickory_resolver::TokioResolver`].
318+
impl Resolver for TokioResolver {
319+
fn lookup_ipv4(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>>> {
320+
let this = self.clone();
321+
Box::pin(async move {
322+
let addrs = this.ipv4_lookup(host).await?;
323+
let iter: BoxIter<Ipv4Addr> = Box::new(addrs.into_iter().map(Ipv4Addr::from));
324+
Ok(iter)
325+
})
326+
}
327+
328+
fn lookup_ipv6(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>>> {
329+
let this = self.clone();
330+
Box::pin(async move {
331+
let addrs = this.ipv6_lookup(host).await?;
332+
let iter: BoxIter<Ipv6Addr> = Box::new(addrs.into_iter().map(Ipv6Addr::from));
333+
Ok(iter)
334+
})
335+
}
336+
337+
fn lookup_txt(&self, host: String) -> BoxFuture<Result<BoxIter<TxtRecord>>> {
338+
let this = self.clone();
339+
Box::pin(async move {
340+
let lookup = this.txt_lookup(host).await?;
341+
let iter: BoxIter<TxtRecord> = Box::new(
342+
lookup
343+
.into_iter()
344+
.map(|txt| TxtRecord::from_iter(txt.iter().cloned())),
345+
);
346+
Ok(iter)
347+
})
348+
}
349+
350+
fn clear_cache(&self) {
351+
self.clear_cache();
352+
}
353+
}
354+
370355
/// Record data for a TXT record.
356+
///
357+
/// This contains a list of character strings, as defined in [RFC 1035 Section 3.3.14].
358+
///
359+
/// [`TxtRecord`] implements [`fmt::Display`], so you can call [`ToString::to_string`] to
360+
/// convert the record data into a string. This will parse each character string with
361+
/// [`String::from_utf8_lossy`] and then concatenate all strings without a seperator.
362+
///
363+
/// If you want to process each character string individually, use [`Self::iter`].
364+
///
365+
/// [RFC 1035 Section 3.3.14]: https://datatracker.ietf.org/doc/html/rfc1035#section-3.3.14
371366
#[derive(Debug, Clone)]
372-
pub struct TxtRecord(Vec<Box<[u8]>>);
367+
pub struct TxtRecord(Box<[Box<[u8]>]>);
373368

374369
impl TxtRecord {
375-
///
370+
/// Returns an iterator over the character strings contained in this TXT record.
376371
pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
377372
self.0.iter().map(|x| x.as_ref())
378373
}
379-
380-
///
381-
pub fn to_strings(&self) -> impl Iterator<Item = String> + '_ {
382-
self.iter()
383-
.map(|cstr| String::from_utf8_lossy(&cstr).to_string())
384-
}
385374
}
386375

387-
impl std::fmt::Display for TxtRecord {
376+
impl fmt::Display for TxtRecord {
388377
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389378
for s in self.iter() {
390379
write!(f, "{}", &String::from_utf8_lossy(s))?
@@ -399,6 +388,12 @@ impl FromIterator<Box<[u8]>> for TxtRecord {
399388
}
400389
}
401390

391+
impl From<Vec<Box<[u8]>>> for TxtRecord {
392+
fn from(value: Vec<Box<[u8]>>) -> Self {
393+
Self(value.into_boxed_slice())
394+
}
395+
}
396+
402397
/// Deprecated IPv6 site-local anycast addresses still configured by windows.
403398
///
404399
/// Windows still configures these site-local addresses as soon even as an IPv6 loopback

iroh/src/dns.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
//! See the [`node_info`](crate::node_info) module documentation for details on how
88
//! iroh node records are structured.
99
10-
pub use iroh_relay::dns::{
11-
DnsResolver, Resolver, N0_DNS_NODE_ORIGIN_PROD, N0_DNS_NODE_ORIGIN_STAGING,
12-
};
10+
pub use iroh_relay::dns::*;
1311

1412
#[cfg(test)]
1513
pub(crate) mod tests {

iroh/src/endpoint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ impl Connection {
19911991
/// [`Connecting::handshake_data()`] succeeds. See that method's documentations for
19921992
/// details on the returned value.
19931993
///
1994-
/// [`Connection::handshake_data()`]: crate::Connecting::handshake_data
1994+
/// [`Connection::handshake_data()`]: crate::endpoint::Connecting::handshake_data
19951995
#[inline]
19961996
pub fn handshake_data(&self) -> Option<Box<dyn Any>> {
19971997
self.inner.handshake_data()

0 commit comments

Comments
 (0)