Skip to content

Commit f6c6c09

Browse files
add timouts
1 parent d6fa8b3 commit f6c6c09

1 file changed

Lines changed: 45 additions & 24 deletions

File tree

iroh-relay/src/dns/resolver.rs

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::{
77
};
88

99
use n0_error::e;
10+
use n0_future::time::{self, Duration};
1011
use rustls::ClientConfig;
1112
use simple_dns::TYPE;
1213
use tracing::{debug, trace};
@@ -17,6 +18,11 @@ use super::{
1718
query, system_config, transport,
1819
};
1920

21+
/// Per-nameserver timeout. Ensures we move on to the next nameserver
22+
/// if one is unresponsive, rather than consuming the entire query budget.
23+
/// Matches hickory-resolver's default of 5 seconds.
24+
const NAMESERVER_TIMEOUT: Duration = Duration::from_secs(5);
25+
2026
#[derive(Debug)]
2127
pub(super) struct SimpleDnsResolver {
2228
nameservers: Vec<(SocketAddr, DnsProtocol)>,
@@ -81,32 +87,47 @@ impl SimpleDnsResolver {
8187
let mut last_err = None;
8288
for (addr, proto) in &self.nameservers {
8389
trace!(%addr, ?proto, "sending DNS query");
84-
let result = match proto {
85-
DnsProtocol::Udp => {
86-
let resp = transport::udp_query(*addr, query_bytes).await?;
87-
// Check for truncation, fallback to TCP
88-
if query::is_truncated(&resp) {
89-
debug!(%addr, "UDP response truncated, retrying over TCP");
90-
transport::tcp_query(*addr, query_bytes).await
91-
} else {
92-
Ok(resp)
90+
let result = time::timeout(NAMESERVER_TIMEOUT, async {
91+
match proto {
92+
DnsProtocol::Udp => {
93+
let resp = transport::udp_query(*addr, query_bytes).await?;
94+
// Check for truncation, fallback to TCP
95+
if query::is_truncated(&resp) {
96+
debug!(%addr, "UDP response truncated, retrying over TCP");
97+
transport::tcp_query(*addr, query_bytes).await
98+
} else {
99+
Ok(resp)
100+
}
101+
}
102+
DnsProtocol::Tcp => transport::tcp_query(*addr, query_bytes).await,
103+
DnsProtocol::Tls => {
104+
let tls_config = self.tls_config.as_ref().ok_or_else(|| {
105+
e!(DnsError::Transport {
106+
source: std::io::Error::new(
107+
std::io::ErrorKind::InvalidInput,
108+
"TLS config required for DNS-over-TLS",
109+
),
110+
})
111+
})?;
112+
transport::tls_query(*addr, query_bytes, tls_config).await
113+
}
114+
DnsProtocol::Https => {
115+
let client = self.get_or_init_https_client().await?;
116+
transport::https_query(*addr, query_bytes, &client).await
93117
}
94118
}
95-
DnsProtocol::Tcp => transport::tcp_query(*addr, query_bytes).await,
96-
DnsProtocol::Tls => {
97-
let tls_config = self.tls_config.as_ref().ok_or_else(|| {
98-
e!(DnsError::Transport {
99-
source: std::io::Error::new(
100-
std::io::ErrorKind::InvalidInput,
101-
"TLS config required for DNS-over-TLS",
102-
),
103-
})
104-
})?;
105-
transport::tls_query(*addr, query_bytes, tls_config).await
106-
}
107-
DnsProtocol::Https => {
108-
let client = self.get_or_init_https_client().await?;
109-
transport::https_query(*addr, query_bytes, &client).await
119+
})
120+
.await;
121+
let result = match result {
122+
Ok(inner) => inner,
123+
Err(_elapsed) => {
124+
trace!(%addr, ?proto, "DNS query timed out");
125+
Err(e!(DnsError::Transport {
126+
source: std::io::Error::new(
127+
std::io::ErrorKind::TimedOut,
128+
"nameserver query timed out",
129+
),
130+
}))
110131
}
111132
};
112133
match result {

0 commit comments

Comments
 (0)