From dea2f90f24904966a85d22644601306ac0ae14c4 Mon Sep 17 00:00:00 2001 From: Baltasar Blanco Date: Tue, 8 Sep 2026 16:21:54 -0300 Subject: [PATCH] plugin/file: return SERVFAIL on self-referential CNAME loops (#8475) A CNAME whose target is its own owner name is chased by externalLookup until the depth cap, appending the same record on every pass. The reply was NOERROR with the CNAME repeated ten times. Self-referential DNAME already returns SERVFAIL, as do wildcard CNAME loops. Return SERVFAIL here too. The check runs on the CNAME chase path only, so normal responses are unaffected. Fixes #6421 Signed-off-by: baltasarblanco --- plugin/file/lookup.go | 5 +++++ test/file_loop_test.go | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/plugin/file/lookup.go b/plugin/file/lookup.go index 806bc5787..c76a7aa99 100644 --- a/plugin/file/lookup.go +++ b/plugin/file/lookup.go @@ -385,6 +385,11 @@ func (z *Zone) externalLookup(ctx context.Context, state request.Request, tr *tr Redo: cname := elem.Type(dns.TypeCNAME) if len(cname) > 0 { + // A CNAME that points to its own owner name can only loop. + if dns.CanonicalName(cname[0].Header().Name) == dns.CanonicalName(cname[0].(*dns.CNAME).Target) { + return nil, nil, nil, ServerFailure + } + rrs = append(rrs, cname...) if do { diff --git a/test/file_loop_test.go b/test/file_loop_test.go index efccf4f2d..0727b8fb1 100644 --- a/test/file_loop_test.go +++ b/test/file_loop_test.go @@ -14,7 +14,10 @@ a.example.com. 500 IN CNAME b.example.com. alias.example.com. 500 IN DNAME alias.example.com. redirect.example.com. 500 IN DNAME target.example.com. www.target.example.com. 500 IN A 192.0.2.1 -*.foo.example.com. 500 IN CNAME bar.foo.example.com.` +*.foo.example.com. 500 IN CNAME bar.foo.example.com. +self.example.com. 500 IN CNAME self.example.com. +c.example.com. 500 IN CNAME d.example.com. +d.example.com. 500 IN CNAME d.example.com.` func TestFileLoop(t *testing.T) { name, rm, err := test.TempFile(".", loopDB) @@ -43,6 +46,8 @@ func TestFileLoop(t *testing.T) { }{ {"wildcard CNAME", "something.foo.example.com.", dns.RcodeServerFailure, false, nil}, {"self-referential DNAME", "www.alias.example.com.", dns.RcodeServerFailure, true, nil}, + {"self-referential CNAME", "self.example.com.", dns.RcodeServerFailure, true, nil}, + {"CNAME chain into self-referential CNAME", "c.example.com.", dns.RcodeServerFailure, true, nil}, {"non-looping DNAME", "www.redirect.example.com.", dns.RcodeSuccess, true, []uint16{dns.TypeDNAME, dns.TypeCNAME, dns.TypeA}}, } for _, tc := range tests {