]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
allow IXFR-to-AXFR fallback on DNS_R_TOOMANYRECORDS
authorJINMEI Tatuya <jtatuya@infoblox.com>
Fri, 16 Aug 2024 07:53:38 +0000 (16:53 +0900)
committerNicki Křížek <nicki@isc.org>
Tue, 10 Sep 2024 12:02:38 +0000 (14:02 +0200)
This change allows fallback from an IXFR failure to AXFR when the
reason is DNS_R_TOOMANYRECORDS. This is because this error condition
could be temporary only in an intermediate version of IXFR
transactions and it's possible that the latest version of the zone
doesn't have that condition. In such a case, the secondary would never
be able to update the zone (even if it could) without this fallback.

This fallback behavior is particularly useful with the recently
introduced max-records-per-type and max-types-per-name options:
the primary may not have these limitations and may temporarily
introduce "too many" records, breaking IXFR. If the primary side
subsequently deletes these records, this fallback will help recover
the zone transfer failure automatically; without it, the secondary
side would first need to increase the limit, which requires more
operational overhead and has its own adverse effect.

This change also fixes a minor glitch that DNS_R_TOOMANYRECORDS wasn't
logged in xfrin_fail.

bin/tests/system/ixfr/tests.sh
lib/dns/xfrin.c

index 2b9e085cd5fd7041d5feb3936e622d94d11b4ac1..97014200f23aca8e07f0370c8e4663e956b20735 100644 (file)
@@ -65,6 +65,7 @@ zone "nil" {
        type secondary;
        file "myftp.db";
        primaries { 10.53.0.2; };
+       max-records-per-type 5; # use a small value for fallback test
 };
 EOF
 
@@ -144,6 +145,44 @@ $DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'fallback AXFR' >/dev/null || ret=1
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+n=$((n + 1))
+echo_i "testing AXFR fallback after IXFR failure (too many records) ($n)"
+ret=0
+
+# Provide an IXFR response that would cause a "too many records" condition
+
+sendcmd <<EOF
+/SOA/
+nil.           300     SOA     ns.nil. root.nil. 4 300 300 604800 300
+/IXFR/
+nil.           300     SOA     ns.nil. root.nil. 4 300 300 604800 300
+nil.           300     SOA     ns.nil. root.nil. 3 300 300 604800 300
+nil.           300     SOA     ns.nil. root.nil. 4 300 300 604800 300
+nil.           300     TXT     "text 1"
+nil.           300     TXT     "text 2"
+nil.           300     TXT     "text 3"
+nil.           300     TXT     "text 4"
+nil.           300     TXT     "text 5"
+nil.           300     TXT     "text 6: causing too many records"
+nil.           300     SOA     ns.nil. root.nil. 4 300 300 604800 300
+/AXFR/
+nil.           300     SOA     ns.nil. root.nil. 3 300 300 604800 300
+nil.           300     NS      ns.nil.
+nil.           300     TXT     "fallback AXFR on too many records"
+/AXFR/
+nil.           300     SOA     ns.nil. root.nil. 3 300 300 604800 300
+EOF
+
+sleep 1
+
+$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i
+
+sleep 2
+
+$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'AXFR on too many records' >/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
 n=$((n + 1))
 echo_i "testing AXFR fallback after IXFR failure (bad SOA owner) ($n)"
 ret=0
index 99da559b89569af61370f61d70a870f7a371b6f9..3d5a175202717232d17aec7f777941fdbbc863d0 100644 (file)
@@ -1125,8 +1125,7 @@ xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg) {
        if (atomic_compare_exchange_strong(&xfr->shuttingdown, &(bool){ false },
                                           true))
        {
-               if (result != DNS_R_UPTODATE && result != DNS_R_TOOMANYRECORDS)
-               {
+               if (result != DNS_R_UPTODATE) {
                        xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg,
                                  isc_result_totext(result));
                        if (atomic_load(&xfr->is_ixfr) &&