diff --git a/rust/connlib/tunnel/src/io.rs b/rust/connlib/tunnel/src/io.rs index 6657162ce..8febe9e7b 100644 --- a/rust/connlib/tunnel/src/io.rs +++ b/rust/connlib/tunnel/src/io.rs @@ -47,6 +47,7 @@ pub struct Io { gso_queue: GsoQueue, nameservers: NameserverSet, + reval_nameserver_interval: tokio::time::Interval, udp_dns_server: l4_udp_dns_server::Server, tcp_dns_server: l4_tcp_dns_server::Server, @@ -92,6 +93,7 @@ pub enum Input { } const DNS_QUERY_TIMEOUT: Duration = Duration::from_secs(5); +const RE_EVALUATE_NAMESERVER_INTERVAL: Duration = Duration::from_secs(60); impl Io { /// Creates a new I/O abstraction @@ -105,18 +107,16 @@ impl Io { let mut sockets = Sockets::default(); sockets.rebind(udp_socket_factory.clone()); // Bind sockets on startup. - let mut nameservers = NameserverSet::new( - nameservers, - tcp_socket_factory.clone(), - udp_socket_factory.clone(), - ); - nameservers.evaluate(); - Self { outbound_packet_buffer: VecDeque::default(), timeout: None, sockets, - nameservers, + nameservers: NameserverSet::new( + nameservers, + tcp_socket_factory.clone(), + udp_socket_factory.clone(), + ), + reval_nameserver_interval: tokio::time::interval(RE_EVALUATE_NAMESERVER_INTERVAL), tcp_socket_factory, udp_socket_factory, dns_queries: FuturesTupleSet::new(DNS_QUERY_TIMEOUT, 1000), @@ -171,7 +171,13 @@ impl Io { >, > { ready!(self.flush(cx)?); - ready!(self.nameservers.poll(cx)); + + if self.reval_nameserver_interval.poll_tick(cx).is_ready() { + self.nameservers.evaluate(); + } + + // We purposely don't want to block the event loop here because we can do plenty of other work while this is running. + let _ = self.nameservers.poll(cx); if let Poll::Ready(network) = self.sockets.poll_recv_from(cx) { return Poll::Ready(Ok(Input::Network( diff --git a/rust/connlib/tunnel/src/io/nameserver_set.rs b/rust/connlib/tunnel/src/io/nameserver_set.rs index 2551b7999..578869a35 100644 --- a/rust/connlib/tunnel/src/io/nameserver_set.rs +++ b/rust/connlib/tunnel/src/io/nameserver_set.rs @@ -51,7 +51,12 @@ impl NameserverSet { } pub fn evaluate(&mut self) { - self.nameserver_by_rtt.clear(); + if self.inner.is_empty() { + return; + } + + tracing::info!(ips = ?self.inner, "Evaluating fastest nameserver"); + let start = Instant::now(); for nameserver in self.inner.iter().copied() { diff --git a/website/src/components/Changelog/Gateway.tsx b/website/src/components/Changelog/Gateway.tsx index 26763aa6e..098373370 100644 --- a/website/src/components/Changelog/Gateway.tsx +++ b/website/src/components/Changelog/Gateway.tsx @@ -27,6 +27,10 @@ export default function Gateway() { Fixes an issue where ICMP unreachable errors for large packets would not be sent. + + Fixes an issue where service discovery for DNS resources would fail + in case the Gateway's started up with no network connectivity. +