mirror of
https://github.com/coredns/coredns.git
synced 2026-10-20 17:25:43 -04:00
plugin/rewrite: Limit rewrite cname recursion (#8570)
This PR limit rewrite cname recursion with the existing DNS server loop counter. The issu was that rewrite cname can recurse indefinitely through internal lookups, causing crash at the end Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
@@ -314,3 +314,73 @@ func TestNewCNAMERuleNormalization(t *testing.T) {
|
||||
t.Errorf("expected toTarget to be normalized to 'vpce-123.amazonaws.com.', got %q", cnameRule.paramToTarget)
|
||||
}
|
||||
}
|
||||
|
||||
type cnameLoopBackend struct{}
|
||||
|
||||
func (cnameLoopBackend) Name() string { return "cname-loop" }
|
||||
|
||||
func (cnameLoopBackend) ServeDNS(_ context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Authoritative = true
|
||||
|
||||
switch r.Question[0].Name {
|
||||
case "victim.poc.internal.", "target.poc.internal.":
|
||||
m.Answer = []dns.RR{
|
||||
test.CNAME(r.Question[0].Name + " 500 IN CNAME loop.poc.internal."),
|
||||
test.A("loop.poc.internal. 500 IN A 192.0.2.1"),
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
type reentrantCNAMEUpstream struct {
|
||||
top plugin.Handler
|
||||
calls int
|
||||
maxCalls int
|
||||
exceeded bool
|
||||
}
|
||||
|
||||
func (u *reentrantCNAMEUpstream) Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error) {
|
||||
u.calls++
|
||||
if u.calls > u.maxCalls {
|
||||
u.exceeded = true
|
||||
return nil, errors.New("test recursion limit exceeded")
|
||||
}
|
||||
|
||||
req := state.NewWithQuestion(name, typ)
|
||||
rec := dnstest.NewRecorder(state.W)
|
||||
_, err := u.top.ServeDNS(ctx, rec, req.Req)
|
||||
return rec.Msg, err
|
||||
}
|
||||
|
||||
func TestCNAMETargetRewriteLoop(t *testing.T) {
|
||||
rule, err := newCNAMERule(Stop, ExactMatch, "loop.poc.internal.", "target.poc.internal.")
|
||||
if err != nil {
|
||||
t.Fatalf("newCNAMERule failed: %v", err)
|
||||
}
|
||||
|
||||
rw := &Rewrite{
|
||||
Next: cnameLoopBackend{},
|
||||
Rules: []Rule{rule},
|
||||
}
|
||||
const maxExpectedLookups = 9
|
||||
upstream := &reentrantCNAMEUpstream{top: rw, maxCalls: maxExpectedLookups + 1}
|
||||
rule.(*cnameTargetRule).Upstream = upstream
|
||||
|
||||
req := new(dns.Msg)
|
||||
req.SetQuestion("victim.poc.internal.", dns.TypeA)
|
||||
rec := dnstest.NewRecorder(&test.ResponseWriter{})
|
||||
if _, err := rw.ServeDNS(context.Background(), rec, req); err != nil {
|
||||
t.Fatalf("ServeDNS returned error: %v", err)
|
||||
}
|
||||
|
||||
if upstream.exceeded {
|
||||
t.Fatalf("rewrite cname recursion exceeded %d internal lookups", upstream.maxCalls)
|
||||
}
|
||||
if upstream.calls > maxExpectedLookups {
|
||||
t.Fatalf("rewrite cname recursion was not bounded: got %d internal lookups", upstream.calls)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user