Skip to content

Commit 4d08e83

Browse files
committed
feat(iroh-dns): Improve error messages
1 parent 5817271 commit 4d08e83

2 files changed

Lines changed: 75 additions & 10 deletions

File tree

iroh-dns/src/dns.rs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub type BoxIter<T> = Box<dyn Iterator<Item = T> + Send + 'static>;
8080

8181
/// Potential errors related to DNS operations.
8282
#[allow(missing_docs)]
83-
#[stack_error(derive, add_meta, from_sources, std_sources)]
83+
#[stack_error(derive, add_meta, std_sources)]
8484
#[non_exhaustive]
8585
pub enum DnsError {
8686
#[error("Request timed out")]
@@ -94,27 +94,62 @@ pub enum DnsError {
9494
},
9595
#[error("Missing host")]
9696
MissingHost {},
97+
98+
/// DEPRECATED since v1.1.0. Replaced by [`Self::Resolve2`].
99+
// TODO: This triggers warnings in n0_error expansions. Fix in n0_error.
100+
// #[deprecated(
101+
// since = "1.1.0",
102+
// note = "No longer constructed, replaced by DnsError::Resolve2"
103+
// )]
97104
#[error("Failed to resolve")]
98-
Resolve { source: AnyError },
105+
Resolve {
106+
// We keep the `from` here, because pre-1.1.0 the `stack_error` macro call on `DnsError` included
107+
// `from_sources`, which expanded to `impl From<AnyError> for `DnsError`. The manual `from` impl
108+
// here on the deprecated variant exists only to maintain backwards compatibility.
109+
#[error(source, from)]
110+
source: AnyError,
111+
},
112+
#[error("Failed to retrieve {kind} record for {host}")]
113+
Resolve2 {
114+
#[error(source)]
115+
source: AnyError,
116+
host: String,
117+
kind: QueryKind,
118+
},
99119
#[error("Invalid DNS response: not a query for _iroh.z32encodedpubkey")]
100120
InvalidResponse {},
101121
}
102122

123+
/// DNS query kind, for error reporting.
124+
#[derive(Debug, derive_more::Display)]
125+
pub enum QueryKind {
126+
/// A record (IPv4)
127+
#[display("A")]
128+
A,
129+
/// AAAA record (IPv6)
130+
#[display("AAAA")]
131+
AAAA,
132+
/// TXT record
133+
#[display("TXT")]
134+
TXT,
135+
}
136+
103137
/// Potential errors related to DNS endpoint address lookups.
104138
#[cfg(not(wasm_browser))]
105139
#[allow(missing_docs)]
106140
#[stack_error(derive, add_meta, from_sources)]
107141
#[non_exhaustive]
108142
pub enum LookupError {
109-
#[error("Malformed txt from lookup")]
143+
#[error("Received malformed TXT record")]
110144
ParseError { source: ParseError },
111-
#[error("Failed to resolve TXT record")]
145+
#[error(transparent)]
112146
LookupFailed { source: DnsError },
113147
}
114148

115149
/// Error returned when a staggered call fails.
116150
#[stack_error(derive, add_meta)]
117-
#[error("no calls succeeded: [{}]", errors.iter().map(|e| e.to_string()).collect::<Vec<_>>().join(""))]
151+
#[error("{}", errors.first().map(|err| format!("{err:#}")).unwrap_or("all resolves failed".to_string()))]
152+
// #[error("no calls succeeded:\n{}", errors.iter().map(|(delay, e)| format!("[{delay:?}] {e:#}")).collect::<Vec<_>>().join("\n"))]
118153
pub struct StaggeredError<E: n0_error::StackError + 'static> {
119154
errors: Vec<E>,
120155
}
@@ -795,7 +830,17 @@ impl Resolver for HickoryResolver {
795830
fn lookup_ipv4(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv4Addr>, DnsError>> {
796831
let resolver = self.resolver.clone();
797832
Box::pin(async move {
798-
let lookup = resolver.ipv4_lookup(host).await.anyerr()?;
833+
let lookup = resolver
834+
.ipv4_lookup(host.clone())
835+
.await
836+
.anyerr()
837+
.map_err(|source| {
838+
e!(DnsError::Resolve2 {
839+
source,
840+
host,
841+
kind: QueryKind::A
842+
})
843+
})?;
799844
let iter: BoxIter<Ipv4Addr> =
800845
Box::new(lookup.answers().to_vec().into_iter().filter_map(|record| {
801846
match &record.data {
@@ -810,7 +855,17 @@ impl Resolver for HickoryResolver {
810855
fn lookup_ipv6(&self, host: String) -> BoxFuture<Result<BoxIter<Ipv6Addr>, DnsError>> {
811856
let resolver = self.resolver.clone();
812857
Box::pin(async move {
813-
let lookup = resolver.ipv6_lookup(host).await.anyerr()?;
858+
let lookup = resolver
859+
.ipv6_lookup(host.clone())
860+
.await
861+
.anyerr()
862+
.map_err(|source| {
863+
e!(DnsError::Resolve2 {
864+
source,
865+
host,
866+
kind: QueryKind::AAAA
867+
})
868+
})?;
814869
let iter: BoxIter<Ipv6Addr> =
815870
Box::new(lookup.answers().to_vec().into_iter().filter_map(|record| {
816871
match &record.data {
@@ -825,7 +880,17 @@ impl Resolver for HickoryResolver {
825880
fn lookup_txt(&self, host: String) -> BoxFuture<Result<BoxIter<TxtRecordData>, DnsError>> {
826881
let resolver = self.resolver.clone();
827882
Box::pin(async move {
828-
let lookup = resolver.txt_lookup(host).await.anyerr()?;
883+
let lookup = resolver
884+
.txt_lookup(host.clone())
885+
.await
886+
.anyerr()
887+
.map_err(|source| {
888+
e!(DnsError::Resolve2 {
889+
source,
890+
host,
891+
kind: QueryKind::TXT
892+
})
893+
})?;
829894
let iter: BoxIter<TxtRecordData> =
830895
Box::new(lookup.answers().to_vec().into_iter().filter_map(|record| {
831896
match &record.data {

iroh/src/endpoint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,9 +906,9 @@ pub struct Endpoint {
906906
pub enum ConnectWithOptsError {
907907
#[error("Connecting to ourself is not supported")]
908908
SelfConnect,
909-
#[error("No addressing information available")]
909+
#[error("Failed to resolve remote address")]
910910
NoAddress { source: AddressLookupFailed },
911-
#[error("Unable to connect to remote")]
911+
#[error("Failed to connect to remote")]
912912
Noq {
913913
#[error(std_err)]
914914
source: QuicConnectError,

0 commit comments

Comments
 (0)