Skip to content

Commit 81f24ed

Browse files
update for latest changes
1 parent f804dbd commit 81f24ed

File tree

7 files changed

+130
-85
lines changed

7 files changed

+130
-85
lines changed

iroh-dns-server/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ mod tests {
270270
let node_id = secret_key.public();
271271
let relay_url: Url = "https://relay.example.".parse()?;
272272
let node_info = NodeInfo::new(node_id, Some(relay_url.clone()), Default::default());
273-
node_info.to_pkarr_signed_packet(&secret_key, 30)
273+
let packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;
274+
Ok(packet)
274275
}
275276
}

iroh-net-report/src/reportgen.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ async fn relay_lookup_ipv4_staggered(
11811181
.map(|ip| ip.to_canonical())
11821182
.map(|addr| SocketAddr::new(addr, port))
11831183
.ok_or(anyhow!("No suitable relay addr found")),
1184-
Err(err) => Err(err.context("No suitable relay addr found")),
1184+
Err(err) => Err(anyhow::Error::from(err).context("No suitable relay addr found")),
11851185
}
11861186
}
11871187
Some(url::Host::Ipv4(addr)) => Ok(SocketAddr::new(addr.into(), port)),
@@ -1211,7 +1211,7 @@ async fn relay_lookup_ipv6_staggered(
12111211
.map(|ip| ip.to_canonical())
12121212
.map(|addr| SocketAddr::new(addr, port))
12131213
.ok_or(anyhow!("No suitable relay addr found")),
1214-
Err(err) => Err(err.context("No suitable relay addr found")),
1214+
Err(err) => Err(anyhow::Error::from(err).context("No suitable relay addr found")),
12151215
}
12161216
}
12171217
Some(url::Host::Ipv4(_addr)) => Err(anyhow!("No suitable relay addr found")),

iroh-relay/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ tracing-test = "0.2.5"
129129
cfg_aliases = { version = "0.2" }
130130

131131
[features]
132-
default = ["metrics"]
132+
default = ["metrics", "server", "test-utils"]
133133
server = [
134134
"dep:anyhow",
135135
"dep:clap",

iroh-relay/src/client.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ use std::{
1010
};
1111

1212
use conn::Conn;
13-
#[cfg(not(wasm_browser))]
14-
use connect_relay::DnsError;
1513
use iroh_base::{RelayUrl, SecretKey};
1614
use n0_future::{
1715
split::{split, SplitSink, SplitStream},
@@ -24,7 +22,7 @@ use url::Url;
2422

2523
pub use self::conn::{ConnSendError, ReceivedMessage, SendMessage};
2624
#[cfg(not(wasm_browser))]
27-
use crate::dns::DnsResolver;
25+
use crate::dns::{DnsResolver, Error as DnsError};
2826
use crate::{
2927
http::{Protocol, RELAY_PATH},
3028
KeyCache,

iroh-relay/src/client/connect_relay.rs

-21
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
1414
// Based on tailscale/derp/derphttp/derphttp_client.go
1515

16-
use std::{future::Future, net::IpAddr};
17-
1816
use bytes::Bytes;
1917
use data_encoding::BASE64URL;
2018
use http_body_util::Empty;
@@ -316,23 +314,6 @@ fn url_port(url: &Url) -> Option<u16> {
316314
}
317315
}
318316

319-
#[derive(Debug, thiserror::Error)]
320-
pub enum DnsError {
321-
#[error(transparent)]
322-
Timeout(#[from] tokio::time::error::Elapsed),
323-
#[error("No response")]
324-
NoResponse,
325-
#[error("Resolve failed ipv4: {ipv4}, ipv6 {ipv6}")]
326-
ResolveBoth {
327-
ipv4: Box<DnsError>,
328-
ipv6: Box<DnsError>,
329-
},
330-
#[error("missing host")]
331-
MissingHost,
332-
#[error(transparent)]
333-
Resolve(#[from] hickory_resolver::ResolveError),
334-
}
335-
336317
#[cfg(test)]
337318
mod tests {
338319
use std::str::FromStr;
@@ -345,8 +326,6 @@ mod tests {
345326
#[test]
346327
#[traced_test]
347328
fn test_host_header_value() -> TestResult {
348-
let _guard = iroh_test::logging::setup();
349-
350329
let cases = [
351330
(
352331
"https://euw1-1.relay.iroh.network.",

iroh-relay/src/dns.rs

+76-34
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! DNS resolver
22
33
use std::{
4-
fmt::{self, Write},
4+
fmt,
55
future::Future,
66
net::{IpAddr, Ipv6Addr, SocketAddr},
77
};
@@ -16,11 +16,33 @@ use url::Url;
1616

1717
pub mod node_info;
1818

19+
use node_info::Error as NodeError;
20+
1921
/// The n0 testing DNS node origin, for production.
2022
pub const N0_DNS_NODE_ORIGIN_PROD: &str = "dns.iroh.link";
2123
/// The n0 testing DNS node origin, for testing.
2224
pub const N0_DNS_NODE_ORIGIN_STAGING: &str = "staging-dns.iroh.link";
2325

26+
/// Potential errors related to dns.
27+
#[allow(missing_docs)]
28+
#[derive(Debug, thiserror::Error)]
29+
pub enum Error {
30+
#[error(transparent)]
31+
Timeout(#[from] tokio::time::error::Elapsed),
32+
#[error("No response")]
33+
NoResponse,
34+
#[error("Resolve failed ipv4: {ipv4}, ipv6 {ipv6}")]
35+
ResolveBoth { ipv4: Box<Error>, ipv6: Box<Error> },
36+
#[error("missing host")]
37+
MissingHost,
38+
#[error(transparent)]
39+
Resolve(#[from] hickory_resolver::ResolveError),
40+
#[error("invalid DNS response: not a query for _iroh.z32encodedpubkey")]
41+
InvalidResponse,
42+
#[error("no calls succeeded: [{}]", errors.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(""))]
43+
Staggered { errors: Vec<Error> },
44+
}
45+
2446
/// The DNS resolver used throughout `iroh`.
2547
#[derive(Debug, Clone)]
2648
pub struct DnsResolver(TokioResolver);
@@ -74,7 +96,11 @@ impl DnsResolver {
7496
}
7597

7698
/// Lookup a TXT record.
77-
pub async fn lookup_txt(&self, host: impl ToString, timeout: Duration) -> Result<TxtLookup> {
99+
pub async fn lookup_txt(
100+
&self,
101+
host: impl ToString,
102+
timeout: Duration,
103+
) -> Result<TxtLookup, Error> {
78104
let host = host.to_string();
79105
let res = time::timeout(timeout, self.0.txt_lookup(host)).await??;
80106
Ok(TxtLookup(res))
@@ -85,7 +111,7 @@ impl DnsResolver {
85111
&self,
86112
host: impl ToString,
87113
timeout: Duration,
88-
) -> Result<impl Iterator<Item = IpAddr>> {
114+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
89115
let host = host.to_string();
90116
let addrs = time::timeout(timeout, self.0.ipv4_lookup(host)).await??;
91117
Ok(addrs.into_iter().map(|ip| IpAddr::V4(ip.0)))
@@ -96,7 +122,7 @@ impl DnsResolver {
96122
&self,
97123
host: impl ToString,
98124
timeout: Duration,
99-
) -> Result<impl Iterator<Item = IpAddr>> {
125+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
100126
let host = host.to_string();
101127
let addrs = time::timeout(timeout, self.0.ipv6_lookup(host)).await??;
102128
Ok(addrs.into_iter().map(|ip| IpAddr::V6(ip.0)))
@@ -111,7 +137,7 @@ impl DnsResolver {
111137
&self,
112138
host: impl ToString,
113139
timeout: Duration,
114-
) -> Result<impl Iterator<Item = IpAddr>> {
140+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
115141
let host = host.to_string();
116142
let res = tokio::join!(
117143
self.lookup_ipv4(host.clone(), timeout),
@@ -122,9 +148,10 @@ impl DnsResolver {
122148
(Ok(ipv4), Ok(ipv6)) => Ok(LookupIter::Both(ipv4.chain(ipv6))),
123149
(Ok(ipv4), Err(_)) => Ok(LookupIter::Ipv4(ipv4)),
124150
(Err(_), Ok(ipv6)) => Ok(LookupIter::Ipv6(ipv6)),
125-
(Err(ipv4_err), Err(ipv6_err)) => {
126-
bail!("Ipv4: {:?}, Ipv6: {:?}", ipv4_err, ipv6_err)
127-
}
151+
(Err(ipv4_err), Err(ipv6_err)) => Err(Error::ResolveBoth {
152+
ipv4: Box::new(ipv4_err),
153+
ipv6: Box::new(ipv6_err),
154+
}),
128155
}
129156
}
130157

@@ -134,8 +161,8 @@ impl DnsResolver {
134161
url: &Url,
135162
prefer_ipv6: bool,
136163
timeout: Duration,
137-
) -> Result<IpAddr> {
138-
let host = url.host().context("Invalid URL")?;
164+
) -> Result<IpAddr, Error> {
165+
let host = url.host().ok_or(Error::MissingHost)?;
139166
match host {
140167
url::Host::Domain(domain) => {
141168
// Need to do a DNS lookup
@@ -145,13 +172,20 @@ impl DnsResolver {
145172
);
146173
let (v4, v6) = match lookup {
147174
(Err(ipv4_err), Err(ipv6_err)) => {
148-
bail!("Ipv4: {ipv4_err:?}, Ipv6: {ipv6_err:?}");
175+
return Err(Error::ResolveBoth {
176+
ipv4: Box::new(ipv4_err),
177+
ipv6: Box::new(ipv6_err),
178+
});
149179
}
150180
(Err(_), Ok(mut v6)) => (None, v6.next()),
151181
(Ok(mut v4), Err(_)) => (v4.next(), None),
152182
(Ok(mut v4), Ok(mut v6)) => (v4.next(), v6.next()),
153183
};
154-
if prefer_ipv6 { v6.or(v4) } else { v4.or(v6) }.context("No response")
184+
if prefer_ipv6 {
185+
v6.or(v4).ok_or(Error::NoResponse)
186+
} else {
187+
v4.or(v6).ok_or(Error::NoResponse)
188+
}
155189
}
156190
url::Host::Ipv4(ip) => Ok(IpAddr::V4(ip)),
157191
url::Host::Ipv6(ip) => Ok(IpAddr::V6(ip)),
@@ -169,10 +203,12 @@ impl DnsResolver {
169203
host: impl ToString,
170204
timeout: Duration,
171205
delays_ms: &[u64],
172-
) -> Result<impl Iterator<Item = IpAddr>> {
206+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
173207
let host = host.to_string();
174208
let f = || self.lookup_ipv4(host.clone(), timeout);
175-
stagger_call(f, delays_ms).await
209+
stagger_call(f, delays_ms)
210+
.await
211+
.map_err(|errors| Error::Staggered { errors })
176212
}
177213

178214
/// Perform an ipv6 lookup with a timeout in a staggered fashion.
@@ -186,10 +222,12 @@ impl DnsResolver {
186222
host: impl ToString,
187223
timeout: Duration,
188224
delays_ms: &[u64],
189-
) -> Result<impl Iterator<Item = IpAddr>> {
225+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
190226
let host = host.to_string();
191227
let f = || self.lookup_ipv6(host.clone(), timeout);
192-
stagger_call(f, delays_ms).await
228+
stagger_call(f, delays_ms)
229+
.await
230+
.map_err(|errors| Error::Staggered { errors })
193231
}
194232

195233
/// Race an ipv4 and ipv6 lookup with a timeout in a staggered fashion.
@@ -204,25 +242,31 @@ impl DnsResolver {
204242
host: impl ToString,
205243
timeout: Duration,
206244
delays_ms: &[u64],
207-
) -> Result<impl Iterator<Item = IpAddr>> {
245+
) -> Result<impl Iterator<Item = IpAddr>, Error> {
208246
let host = host.to_string();
209247
let f = || self.lookup_ipv4_ipv6(host.clone(), timeout);
210-
stagger_call(f, delays_ms).await
248+
stagger_call(f, delays_ms)
249+
.await
250+
.map_err(|errors| Error::Staggered { errors })
211251
}
212252

213253
/// Looks up node info by [`NodeId`] and origin domain name.
214254
///
215255
/// To lookup nodes that published their node info to the DNS servers run by n0,
216256
/// pass [`N0_DNS_NODE_ORIGIN_PROD`] as `origin`.
217-
pub async fn lookup_node_by_id(&self, node_id: &NodeId, origin: &str) -> Result<NodeAddr> {
257+
pub async fn lookup_node_by_id(
258+
&self,
259+
node_id: &NodeId,
260+
origin: &str,
261+
) -> Result<NodeAddr, NodeError> {
218262
let attrs =
219263
node_info::TxtAttrs::<node_info::IrohAttr>::lookup_by_id(self, node_id, origin).await?;
220264
let info: node_info::NodeInfo = attrs.into();
221265
Ok(info.into())
222266
}
223267

224268
/// Looks up node info by DNS name.
225-
pub async fn lookup_node_by_domain_name(&self, name: &str) -> Result<NodeAddr> {
269+
pub async fn lookup_node_by_domain_name(&self, name: &str) -> Result<NodeAddr, NodeError> {
226270
let attrs = node_info::TxtAttrs::<node_info::IrohAttr>::lookup_by_name(self, name).await?;
227271
let info: node_info::NodeInfo = attrs.into();
228272
Ok(info.into())
@@ -238,9 +282,11 @@ impl DnsResolver {
238282
&self,
239283
name: &str,
240284
delays_ms: &[u64],
241-
) -> Result<NodeAddr> {
285+
) -> Result<NodeAddr, NodeError> {
242286
let f = || self.lookup_node_by_domain_name(name);
243-
stagger_call(f, delays_ms).await
287+
stagger_call(f, delays_ms)
288+
.await
289+
.map_err(|errors| NodeError::Staggered { errors })
244290
}
245291

246292
/// Looks up node info by [`NodeId`] and origin domain name.
@@ -254,9 +300,11 @@ impl DnsResolver {
254300
node_id: &NodeId,
255301
origin: &str,
256302
delays_ms: &[u64],
257-
) -> Result<NodeAddr> {
303+
) -> Result<NodeAddr, NodeError> {
258304
let f = || self.lookup_node_by_id(node_id, origin);
259-
stagger_call(f, delays_ms).await
305+
stagger_call(f, delays_ms)
306+
.await
307+
.map_err(|errors| NodeError::Staggered { errors })
260308
}
261309
}
262310

@@ -346,10 +394,10 @@ impl<A: Iterator<Item = IpAddr>, B: Iterator<Item = IpAddr>> Iterator for Lookup
346394
///
347395
/// The first call is performed immediately. The first call to succeed generates an Ok result
348396
/// ignoring any previous error. If all calls fail, an error summarizing all errors is returned.
349-
async fn stagger_call<T, F: Fn() -> Fut, Fut: Future<Output = Result<T>>>(
397+
async fn stagger_call<T, E, F: Fn() -> Fut, Fut: Future<Output = Result<T, E>>>(
350398
f: F,
351399
delays_ms: &[u64],
352-
) -> Result<T> {
400+
) -> Result<T, Vec<E>> {
353401
let mut calls = n0_future::FuturesUnorderedBounded::new(delays_ms.len() + 1);
354402
// NOTE: we add the 0 delay here to have a uniform set of futures. This is more performant than
355403
// using alternatives that allow futures of different types.
@@ -371,13 +419,7 @@ async fn stagger_call<T, F: Fn() -> Fut, Fut: Future<Output = Result<T>>>(
371419
}
372420
}
373421

374-
bail!(
375-
"no calls succeed: [ {}]",
376-
errors.into_iter().fold(String::new(), |mut summary, e| {
377-
write!(summary, "{e} ").expect("infallible");
378-
summary
379-
})
380-
)
422+
Err(errors)
381423
}
382424

383425
#[cfg(test)]
@@ -397,7 +439,7 @@ pub(crate) mod tests {
397439
let r_pos = DONE_CALL.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
398440
async move {
399441
tracing::info!(r_pos, "call");
400-
CALL_RESULTS[r_pos].map_err(|e| anyhow::anyhow!("{e}"))
442+
CALL_RESULTS[r_pos].map_err(|_| Error::InvalidResponse)
401443
}
402444
};
403445

0 commit comments

Comments
 (0)