diff --git a/src/upstream/doh_client.rs b/src/upstream/doh_client.rs index 7fd2834..903e10f 100644 --- a/src/upstream/doh_client.rs +++ b/src/upstream/doh_client.rs @@ -37,7 +37,8 @@ impl DohClient { /// Create a new DoH client with the given upstream resolvers. pub fn new(resolvers: Vec) -> Self { let http = Client::builder() - .timeout(std::time::Duration::from_secs(10)) + .connect_timeout(std::time::Duration::from_secs(3)) + .timeout(std::time::Duration::from_secs(5)) .build() .expect("failed to build HTTP client"); Self { http, resolvers } @@ -45,7 +46,8 @@ impl DohClient { /// Forward a DNS wire-format query using the given strategy. /// - /// For round-robin, `index` is used to select the resolver. + /// Both strategies retry with the next resolver on failure. + /// For round-robin, `index` picks the starting resolver. /// For failover, resolvers are tried in order starting from `index`. pub async fn forward( &self, @@ -54,24 +56,14 @@ impl DohClient { index: usize, ) -> Result, UpstreamError> { match strategy { - Strategy::RoundRobin => self.forward_to(query_bytes, index).await, - Strategy::Failover => self.forward_failover(query_bytes, index).await, + Strategy::RoundRobin => self.forward_with_retry(query_bytes, index).await, + Strategy::Failover => self.forward_with_retry(query_bytes, index).await, } } - /// Forward to a specific resolver by index (wraps around). - async fn forward_to( - &self, - query_bytes: &[u8], - resolver_index: usize, - ) -> Result, UpstreamError> { - let resolver = &self.resolvers[resolver_index % self.resolvers.len()]; - self.send_to(query_bytes, resolver).await - } - - /// Try resolvers in order starting from `start_index`, returning the - /// first successful response. - async fn forward_failover( + /// Try resolvers starting from `start_index`, retrying with the next + /// on failure. This provides resilience for both strategies. + async fn forward_with_retry( &self, query_bytes: &[u8], start_index: usize, @@ -85,13 +77,13 @@ impl DohClient { match self.send_to(query_bytes, resolver).await { Ok(bytes) => return Ok(bytes), Err(e) => { - warn!(resolver = %resolver.name, error = %e, "failover: resolver failed, trying next"); + warn!(resolver = %resolver.name, error = %e, "resolver failed, trying next"); last_err = Some(e); } } } - Err(last_err.expect("failover: no resolvers configured")) + Err(last_err.expect("no resolvers configured")) } /// Send a query to a single resolver.