From 8c3395e74b890313d1f704fbb16b674ea05eb1a5 Mon Sep 17 00:00:00 2001 From: Razvan Dimescu Date: Fri, 3 Apr 2026 00:02:12 +0300 Subject: [PATCH] fix: check forwarding rules before recursive resolution Conditional forwarding (Tailscale .ts.net, VPC private zones) was only checked in the forward mode branch. In recursive mode, queries for forwarding-rule domains went to root servers instead of the configured upstream, returning NXDOMAIN for private domains. Move the forwarding rule check before the recursive/forward branch so it takes priority regardless of mode. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/ctx.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ctx.rs b/src/ctx.rs index 4e80b16..7529bc1 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -162,6 +162,29 @@ pub async fn handle_query( resp.header.authed_data = true; } (resp, QueryPath::Cached, cached_dnssec) + } else if let Some(fwd_addr) = + crate::system_dns::match_forwarding_rule(&qname, &ctx.forwarding_rules) + { + // Conditional forwarding takes priority over recursive mode + // (e.g. Tailscale .ts.net, VPC private zones) + let upstream = Upstream::Udp(fwd_addr); + match forward_query(&query, &upstream, ctx.timeout).await { + Ok(resp) => { + ctx.cache.write().unwrap().insert(&qname, qtype, &resp); + (resp, QueryPath::Forwarded, DnssecStatus::Indeterminate) + } + Err(e) => { + error!( + "{} | {:?} {} | FORWARD ERROR | {}", + src_addr, qtype, qname, e + ); + ( + DnsPacket::response_from(&query, ResultCode::SERVFAIL), + QueryPath::UpstreamError, + DnssecStatus::Indeterminate, + ) + } + } } else if ctx.upstream_mode == UpstreamMode::Recursive { let key = (qname.clone(), qtype); let (resp, path, err) = resolve_coalesced(&ctx.inflight, key, &query, || {