Skip to content
Snippets Groups Projects
Commit 1f98f8dc authored by Daniel Salzman's avatar Daniel Salzman
Browse files

nameserver: decrease maximum CNAME/DNAME chain length from 20 to 5

The reason for this change is to reduce possible amplification attacks and
other negative effects of long processing loops.

Also most resolvers don't accept multiple jumps without requerying, so this
change should be harmless.
parent 06a319ca
No related branches found
No related tags found
1 merge request!1243nameserver: allow applying one DNAME repeatedly (e.g. DNAME loop)
Pipeline #77632 passed
/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -21,7 +21,7 @@
#include "knot/nameserver/process_query.h"
/*! \brief Don't follow CNAME/DNAME chain beyond this depth. */
#define CNAME_CHAIN_MAX 20
#define CNAME_CHAIN_MAX 5
/*!
* \brief Answer query from an IN class zone.
......
......@@ -70,7 +70,11 @@ d.dname-tree CNAME cname-wildcard
e.dname-tree CNAME e.dname
f.dname-tree DNAME f.f.dname-tree
dname-loop DNAME loop.dname-loop
dname-outloop DNAME loop.dname-outloop
loop.dname-inloop A 1.2.3.4
loop.dname-inloop DNAME dname-inloop
dname-out DNAME outside.zone.
dname-dangl DNAME dangling
dname.below.sub DNAME dname-tree
......
......@@ -54,7 +54,7 @@ resp.check_count(3, rtype="CNAME")
resp = knot.dig("chain.follow", "AAAA", udp=False)
resp.check(rcode="NOERROR")
resp.check_count(20, rtype="CNAME")
resp.check_count(5, rtype="CNAME")
resp.check_count(0, rtype="AAAA")
# query for RRSIG
......
......@@ -131,7 +131,7 @@ resp.cmp(bind)
# Long CNAME loop (Bind truncates the loop at 17 records)
resp = knot.dig("ab.flags", "A", udp=True)
resp.check(rcode="NOERROR")
compare(resp.count(rtype="CNAME", section="answer"), 19, "Count of CNAME records in loop.")
compare(resp.count(rtype="CNAME", section="answer"), 5, "Count of CNAME records in loop.")
''' CNAME in MX EXCHANGE. '''
......@@ -212,15 +212,32 @@ resp.check_record(name="dname.flags.", rtype="DNAME", ttl=3600, rdata="
resp.check_record(name="x.f.dname.flags.", rtype="CNAME", ttl=3600, rdata="x.f.dname-tree.flags.")
resp.check_record(name="f.dname-tree.flags.", rtype="DNAME", ttl=3600, rdata="f.f.dname-tree.flags.")
resp.check_record(name="x.f.dname-tree.flags.", rtype="CNAME", ttl=3600, rdata="x.f.f.dname-tree.flags.")
resp.check_counts(22, 0, 0)
# resp.cmp(bind) BIND responds partially unrolled CNAME loop
resp.check_counts(7, 0, 0)
# resp.cmp(bind) BIND responds deeply unrolled CNAME loop
# Infinite DNAME loop
resp = knot.dig("end.dname-loop.flags", "A", udp=False)
resp = knot.dig("end.dname-outloop.flags", "A", udp=True)
resp.check(rcode="NOERROR")
resp.check_record(name="dname-loop.flags.", rtype="DNAME", ttl=3600, rdata="loop.dname-loop.flags.")
compare(resp.count(rtype="CNAME", section="answer"), 20, "Count of synthesized CNAME records in loop.")
resp.check_record(name="end.loop.loop.loop.dname-loop.flags.", rtype="CNAME", ttl=3600, rdata="end.loop.loop.loop.loop.dname-loop.flags.")
resp.check_record(name="dname-outloop.flags.", rtype="DNAME", ttl=3600, rdata="loop.dname-outloop.flags.")
compare(resp.count(rtype="CNAME", section="answer"), 5, "Count of synthesized CNAME records in loop.")
resp.check_record(name="end.loop.loop.loop.loop.dname-outloop.flags.", rtype="CNAME", ttl=3600,
rdata="end.loop.loop.loop.loop.loop.dname-outloop.flags.")
resp.check_counts(6, 0, 0)
# Recursive DNAME loop - full
resp = knot.dig("loop.loop.loop.loop.loop.loop.dname-inloop.flags", "A", udp=True)
resp.check(rcode="NOERROR")
resp.check_record(name="loop.dname-inloop.flags.", rtype="DNAME", ttl=3600, rdata="dname-inloop.flags.")
compare(resp.count(rtype="CNAME", section="answer"), 5, "Count of synthesized CNAME records in loop.")
resp.check_record(name="loop.dname-inloop.flags.", rtype="A", ttl=3600, rdata="1.2.3.4")
resp.check_counts(7, 0, 0)
# Recursive DNAME loop - incomplete
resp = knot.dig("loop.loop.loop.loop.loop.loop.loop.dname-inloop.flags", "A", udp=True)
resp.check(rcode="NOERROR")
resp.check_record(name="loop.dname-inloop.flags.", rtype="DNAME", ttl=3600, rdata="dname-inloop.flags.")
compare(resp.count(rtype="CNAME", section="answer"), 5, "Count of synthesized CNAME records in loop.")
resp.check_counts(6, 0, 0)
''' Wildcard answers. '''
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment