From 9e11a8e7ba63b90a5d8cab597e2161dd7c3e63c0 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Mon, 16 Mar 2026 02:28:31 +0000 Subject: [PATCH] Return NOERROR for A queries on valid .fips names instead of NXDOMAIN The DNS responder returned NXDOMAIN for non-AAAA queries (e.g. A record) on valid .fips names. This caused resolvers like nslookup and tinyproxy to give up without attempting AAAA, since NXDOMAIN means "name does not exist." Return NOERROR with an empty answer section instead, which tells the client the name exists but has no records of that type. Fixes jmcorgan/fips#9. --- src/upper/dns.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/upper/dns.rs b/src/upper/dns.rs index 98e6514..1063ff8 100644 --- a/src/upper/dns.rs +++ b/src/upper/dns.rs @@ -126,7 +126,15 @@ pub fn handle_dns_packet( return Some((bytes, Some(identity))); } - // Query we can't answer: NXDOMAIN + // Non-AAAA query (e.g. A) for a resolvable .fips name: return NOERROR + // with empty answers. NXDOMAIN would tell the client the name doesn't + // exist, causing resolvers like nslookup to give up without trying AAAA. + if !is_aaaa && resolve_fips_query_with_hosts(&qname, hosts).is_some() { + let bytes = response.build_bytes_vec_compressed().ok()?; + return Some((bytes, None)); + } + + // Unresolvable name: NXDOMAIN *response.rcode_mut() = RCODE::NameError; let bytes = response.build_bytes_vec_compressed().ok()?; Some((bytes, None)) @@ -392,8 +400,11 @@ mod tests { let (response_bytes, identity_opt) = result.unwrap(); assert!(identity_opt.is_none(), "A query should not resolve .fips"); + // Valid .fips name but unsupported record type: NOERROR with empty + // answers (not NXDOMAIN, which would stop resolvers from trying AAAA) let response = Packet::parse(&response_bytes).unwrap(); - assert_eq!(response.rcode(), RCODE::NameError); + assert_eq!(response.rcode(), RCODE::NoError); + assert!(response.answers.is_empty()); } #[tokio::test]