]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
nameserver: decrease maximum CNAME/DNAME chain length from 20 to 5
authorDaniel Salzman <daniel.salzman@nic.cz>
Thu, 4 Mar 2021 18:03:42 +0000 (19:03 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 5 Mar 2021 07:50:06 +0000 (08:50 +0100)
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.

src/knot/nameserver/internet.h
tests-extra/data/flags.zone
tests-extra/tests/basic/cname-follow/test.py
tests-extra/tests/basic/query/test.py

index 420256746c784308e7393da59bc1962a5265b542..ea6d93a45838710dc39674440577ec0f12682e7a 100644 (file)
@@ -1,4 +1,4 @@
-/*  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.
index 0014ccf88bc935c21872362e6d25b9e5e269f961..a243803189b414cedd469fc03fc5e3c5ead82a43 100644 (file)
@@ -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
index 04c6b0ad3f6004eddd0e377c24a91e12f94d0533..68f7a927c7f08bbd88e9af7fe586c02280834aa9 100644 (file)
@@ -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
index 92fa8c191ab7f6e6742a825a9478e425c571da5d..04a6bb91be9fe69685a922bfa0dfa6899c8992df 100644 (file)
@@ -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. '''