From: Daniel Salzman Date: Thu, 4 Mar 2021 18:03:42 +0000 (+0100) Subject: nameserver: decrease maximum CNAME/DNAME chain length from 20 to 5 X-Git-Tag: v3.1.0~212^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f98f8dc18dc86a4e2dec3f2f8f2aab5086958f9;p=thirdparty%2Fknot-dns.git 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. --- diff --git a/src/knot/nameserver/internet.h b/src/knot/nameserver/internet.h index 420256746c..ea6d93a458 100644 --- a/src/knot/nameserver/internet.h +++ b/src/knot/nameserver/internet.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. +/* Copyright (C) 2021 CZ.NIC, z.s.p.o. 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. diff --git a/tests-extra/data/flags.zone b/tests-extra/data/flags.zone index 0014ccf88b..a243803189 100644 --- a/tests-extra/data/flags.zone +++ b/tests-extra/data/flags.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 diff --git a/tests-extra/tests/basic/cname-follow/test.py b/tests-extra/tests/basic/cname-follow/test.py index 04c6b0ad3f..68f7a927c7 100644 --- a/tests-extra/tests/basic/cname-follow/test.py +++ b/tests-extra/tests/basic/cname-follow/test.py @@ -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 diff --git a/tests-extra/tests/basic/query/test.py b/tests-extra/tests/basic/query/test.py index 92fa8c191a..04a6bb91be 100644 --- a/tests-extra/tests/basic/query/test.py +++ b/tests-extra/tests/basic/query/test.py @@ -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. '''