From 030650a905f4a2983de2b9df501432c9791244dc Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Wed, 21 Jan 2026 08:48:32 +0100 Subject: [PATCH] [client] Fix RFC 4592 wildcard matching for existing domain names (#5145) Per RFC 4592 section 2.2.1, wildcards should only match when the queried name does not exist in the zone. Previously, if host.example.com had an A record and *.example.com had an AAAA record, querying AAAA for host.example.com would incorrectly return the wildcard AAAA instead of NODATA. Now the resolver checks if the domain exists (with any record type) before falling back to wildcard matching, returning proper NODATA responses for existing names without the requested record type. --- client/internal/dns/local/local.go | 8 ++++++-- client/internal/dns/local/local_test.go | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/internal/dns/local/local.go b/client/internal/dns/local/local.go index ae27b3b56..cbdc64997 100644 --- a/client/internal/dns/local/local.go +++ b/client/internal/dns/local/local.go @@ -201,9 +201,13 @@ func (d *Resolver) lookupRecords(logger *log.Entry, question dns.Question) looku records, found := d.records[question] usingWildcard := false wildQuestion := transformToWildcard(question) + // RFC 4592 section 2.2.1: wildcard only matches if the name does NOT exist in the zone. + // If the domain exists with any record type, return NODATA instead of wildcard match. if !found && supportsWildcard(question.Qtype) { - records, found = d.records[wildQuestion] - usingWildcard = found + if _, domainExists := d.domains[domain.Domain(question.Name)]; !domainExists { + records, found = d.records[wildQuestion] + usingWildcard = found + } } if !found { diff --git a/client/internal/dns/local/local_test.go b/client/internal/dns/local/local_test.go index dc295cd17..73f70035f 100644 --- a/client/internal/dns/local/local_test.go +++ b/client/internal/dns/local/local_test.go @@ -2506,8 +2506,10 @@ func TestLocalResolver_MixedRecordTypes(t *testing.T) { resolver.ServeDNS(&test.MockResponseWriter{WriteMsgFunc: func(m *dns.Msg) error { respAAAA = m; return nil }}, msgAAAA) require.NotNil(t, respAAAA) - // host.example.com exists (has A), so AAAA query returns NODATA, not wildcard + // RFC 4592 section 2.2.1: wildcard should NOT match when the name EXISTS in zone. + // host.example.com exists (has A record), so AAAA query returns NODATA, not wildcard. assert.Equal(t, dns.RcodeSuccess, respAAAA.Rcode, "Should return NODATA for existing host without AAAA") + assert.Len(t, respAAAA.Answer, 0, "RFC 4592: wildcard should not match when name exists") // AAAA query for other host should return wildcard AAAA msgAAAAOther := new(dns.Msg).SetQuestion("other.example.com.", dns.TypeAAAA)