]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement the 'request-ixfr-max-diffs' configuration option
authorAram Sargsyan <aram@isc.org>
Fri, 7 Jun 2024 14:47:55 +0000 (14:47 +0000)
committerArаm Sаrgsyаn <aram@isc.org>
Thu, 22 Aug 2024 13:42:27 +0000 (13:42 +0000)
This limits the maximum number of received incremental zone
transfer differences for a secondary server. Upon reaching the
confgiured limit, the secondary aborts IXFR and initiates a full
zone transfer (AXFR).

16 files changed:
bin/named/config.c
bin/named/server.c
bin/named/zoneconf.c
bin/tests/system/checkconf/bad-master-request-ixfr-max-diffs.conf [new file with mode: 0644]
bin/tests/system/checkconf/good-server-christmas-tree.conf.in
doc/misc/mirror.zoneopt
doc/misc/options
doc/misc/secondary.zoneopt
lib/dns/include/dns/peer.h
lib/dns/include/dns/xfrin.h
lib/dns/include/dns/zone.h
lib/dns/peer.c
lib/dns/xfrin.c
lib/dns/zone.c
lib/isccfg/check.c
lib/isccfg/namedconf.c

index 59f8902156e72f9b988e39e9712a67a7db67643f..8d962d78149a45719a943fc16820f6dc34fb1724 100644 (file)
@@ -190,6 +190,7 @@ options {\n\
        recursion true;\n\
        request-expire true;\n\
        request-ixfr true;\n\
+       request-ixfr-max-diffs 0;\n\
        require-server-cookie no;\n\
        root-key-sentinel yes;\n\
        servfail-ttl 1;\n\
index 57d1f9abf66bd5853f2d8a4a7f658827c7d0a6a9..2156394dc486559663fff4a5249a3fa33249b990 100644 (file)
@@ -1469,6 +1469,13 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
                CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
        }
 
+       obj = NULL;
+       (void)cfg_map_get(cpeer, "request-ixfr-max-diffs", &obj);
+       if (obj != NULL) {
+               CHECK(dns_peer_setrequestixfrmaxdiffs(peer,
+                                                     cfg_obj_asuint32(obj)));
+       }
+
        obj = NULL;
        (void)cfg_map_get(cpeer, "request-nsid", &obj);
        if (obj != NULL) {
index a78adae58a70cf12a8bc789a93434b6f2147b7a1..8129b01b176d537b6964e746bc6a7c7634f5422d 100644 (file)
@@ -1418,6 +1418,11 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
                INSIST(result == ISC_R_SUCCESS);
                dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj));
 
+               obj = NULL;
+               result = named_config_get(maps, "request-ixfr-max-diffs", &obj);
+               INSIST(result == ISC_R_SUCCESS);
+               dns_zone_setrequestixfrmaxdiffs(zone, cfg_obj_asuint32(obj));
+
                obj = NULL;
                checknames(ztype, maps, &obj);
                INSIST(obj != NULL);
diff --git a/bin/tests/system/checkconf/bad-master-request-ixfr-max-diffs.conf b/bin/tests/system/checkconf/bad-master-request-ixfr-max-diffs.conf
new file mode 100644 (file)
index 0000000..2fa30b6
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * request-ixfr clause is not allowed in zone of type primary.
+ */
+
+zone dummy {
+       type primary;
+       request-ixfr-max-diffs 100;
+       file "xxxx";
+};
index f619913bee2f5c363468813f007985c4ded026aa..2eceee6baf6e6da6b583a1ef7f69145fb8b70eee 100644 (file)
@@ -29,6 +29,7 @@ server 0.0.0.0 {
        query-source 0.0.0.0;
        request-expire no;
        request-ixfr no;
+       request-ixfr-max-diffs 0;
        request-nsid no;
        require-cookie no;
        send-cookie no;
@@ -52,6 +53,7 @@ server :: {
        query-source-v6 ::;
        request-expire no;
        request-ixfr no;
+       request-ixfr-max-diffs 0;
        request-nsid no;
        require-cookie no;
        send-cookie no;
index e7cb0b9ccbf40682585b289d1b9723b0d58a5591..72e90083bb89fddf197eb53fc42c347627ed5b1c 100644 (file)
@@ -34,6 +34,7 @@ zone <string> [ <class> ] {
        primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
        request-expire <boolean>;
        request-ixfr <boolean>;
+       request-ixfr-max-diffs <integer>;
        transfer-source ( <ipv4_address> | * );
        transfer-source-v6 ( <ipv6_address> | * );
        try-tcp-refresh <boolean>;
index dabaad9b68e0728c610aaa4d4d97e29129a06f9b..2390a98a2ed7c8fecd03d9f752a2278472b0416b 100644 (file)
@@ -257,6 +257,7 @@ options {
        recursive-clients <integer>;
        request-expire <boolean>;
        request-ixfr <boolean>;
+       request-ixfr-max-diffs <integer>;
        request-nsid <boolean>;
        require-server-cookie <boolean>;
        resolver-query-timeout <integer>;
@@ -346,6 +347,7 @@ server <netprefix> {
        query-source-v6 [ address ] ( <ipv6_address> | * );
        request-expire <boolean>;
        request-ixfr <boolean>;
+       request-ixfr-max-diffs <integer>;
        request-nsid <boolean>;
        require-cookie <boolean>;
        send-cookie <boolean>;
@@ -539,6 +541,7 @@ view <string> [ <class> ] {
        recursion <boolean>;
        request-expire <boolean>;
        request-ixfr <boolean>;
+       request-ixfr-max-diffs <integer>;
        request-nsid <boolean>;
        require-server-cookie <boolean>;
        resolver-query-timeout <integer>;
@@ -564,6 +567,7 @@ view <string> [ <class> ] {
                query-source-v6 [ address ] ( <ipv6_address> | * );
                request-expire <boolean>;
                request-ixfr <boolean>;
+               request-ixfr-max-diffs <integer>;
                request-nsid <boolean>;
                require-cookie <boolean>;
                send-cookie <boolean>;
index 610d32f26273c58bc1ae413b9ff15f65837d6182..3a28af9d84f4d9f267aad6477c0a4ad2a70bca69 100644 (file)
@@ -51,6 +51,7 @@ zone <string> [ <class> ] {
        primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
        request-expire <boolean>;
        request-ixfr <boolean>;
+       request-ixfr-max-diffs <integer>;
        sig-signing-nodes <integer>;
        sig-signing-signatures <integer>;
        sig-signing-type <integer>;
index d32d0076a8b3b84ae10bfc7341d0186dc5ab068b..d429d667d02d5de4e039e342c5a316252a1c84fc 100644 (file)
@@ -100,6 +100,12 @@ dns_peer_setrequestixfr(dns_peer_t *peer, bool newval);
 isc_result_t
 dns_peer_getrequestixfr(dns_peer_t *peer, bool *retval);
 
+isc_result_t
+dns_peer_setrequestixfrmaxdiffs(dns_peer_t *peer, uint32_t newval);
+
+isc_result_t
+dns_peer_getrequestixfrmaxdiffs(dns_peer_t *peer, uint32_t *retval);
+
 isc_result_t
 dns_peer_setprovideixfr(dns_peer_t *peer, bool newval);
 
index d44b44014377f5ddfb3a740e2bc4ff3a00d0982e..a024ce9ca3fe8e7e927383f9a344a31c8af7f255 100644 (file)
@@ -53,7 +53,7 @@ ISC_LANG_BEGINDECLS
 
 isc_result_t
 dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
-                const isc_sockaddr_t *primaryaddr,
+                uint32_t ixfr_maxdiffs, const isc_sockaddr_t *primaryaddr,
                 const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
                 dns_transport_type_t soa_transport_type,
                 dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
index 422448a1a726c4bb63794aacefda2b5f5427eff2..57b55addb8b746a7c94290ebd6a3a5ebead06f28 100644 (file)
@@ -2442,6 +2442,25 @@ dns_zone_setrequestixfr(dns_zone_t *zone, bool flag);
  * \li 'zone' to be valid.
  */
 
+bool
+dns_zone_getrequestixfrmaxdiffs(dns_zone_t *zone);
+/*%
+ * Returns the value of the request-ixfr-max-diffs option in the zone.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
+void
+dns_zone_setrequestixfrmaxdiffs(dns_zone_t *zone, uint32_t maxmsgs);
+/*%
+ * Sets the request-ixfr-max-diffs option for the zone. 0 means unlimited. The
+ * default value is determined by the setting of this option in the view.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
 uint32_t
 dns_zone_getixfrratio(dns_zone_t *zone);
 /*%
index c2f1d14dfae415adb7605c74d3e32df9c5930fa3..41bd2426fa0ae22a9df27bb9c324448a05f1269f 100644 (file)
@@ -14,6 +14,7 @@
 /*! \file */
 
 #include <inttypes.h>
+#include <limits.h>
 #include <stdbool.h>
 
 #include <isc/mem.h>
@@ -50,6 +51,7 @@ struct dns_peer {
        bool bogus;
        dns_transfer_format_t transfer_format;
        uint32_t transfers;
+       uint32_t request_ixfr_maxdiffs;
        bool support_ixfr;
        bool provide_ixfr;
        bool request_ixfr;
@@ -78,22 +80,29 @@ struct dns_peer {
 /*%
  * Bit positions in the dns_peer_t structure flags field
  */
-#define BOGUS_BIT                 0
-#define SERVER_TRANSFER_FORMAT_BIT 1
-#define TRANSFERS_BIT             2
-#define PROVIDE_IXFR_BIT          3
-#define REQUEST_IXFR_BIT          4
-#define SUPPORT_EDNS_BIT          5
-#define SERVER_UDPSIZE_BIT        6
-#define SERVER_MAXUDP_BIT         7
-#define REQUEST_NSID_BIT          8
-#define SEND_COOKIE_BIT                   9
-#define REQUEST_EXPIRE_BIT        10
-#define EDNS_VERSION_BIT          11
-#define FORCE_TCP_BIT             12
-#define SERVER_PADDING_BIT        13
-#define REQUEST_TCP_KEEPALIVE_BIT  14
-#define REQUIRE_COOKIE_BIT        15
+enum {
+       BOGUS_BIT = 0,
+       SERVER_TRANSFER_FORMAT_BIT,
+       TRANSFERS_BIT,
+       PROVIDE_IXFR_BIT,
+       REQUEST_IXFR_BIT,
+       REQUEST_IXFRMAXDIFFS_BIT,
+       SUPPORT_EDNS_BIT,
+       SERVER_UDPSIZE_BIT,
+       SERVER_MAXUDP_BIT,
+       REQUEST_NSID_BIT,
+       SEND_COOKIE_BIT,
+       REQUEST_EXPIRE_BIT,
+       EDNS_VERSION_BIT,
+       FORCE_TCP_BIT,
+       SERVER_PADDING_BIT,
+       REQUEST_TCP_KEEPALIVE_BIT,
+       REQUIRE_COOKIE_BIT,
+       DNS_PEER_FLAGS_COUNT
+};
+
+STATIC_ASSERT(DNS_PEER_FLAGS_COUNT <= CHAR_BIT * sizeof(uint32_t),
+             "dns_peer_t structure flags fields are too many for uint32_t");
 
 static void
 peerlist_delete(dns_peerlist_t **list);
@@ -372,6 +381,8 @@ ACCESS_OPTION(maxudp, SERVER_MAXUDP_BIT, uint16_t, maxudp)
 ACCESS_OPTION(provideixfr, PROVIDE_IXFR_BIT, bool, provide_ixfr)
 ACCESS_OPTION(requestexpire, REQUEST_EXPIRE_BIT, bool, request_expire)
 ACCESS_OPTION(requestixfr, REQUEST_IXFR_BIT, bool, request_ixfr)
+ACCESS_OPTION(requestixfrmaxdiffs, REQUEST_IXFRMAXDIFFS_BIT, uint32_t,
+             request_ixfr_maxdiffs)
 ACCESS_OPTION(requestnsid, REQUEST_NSID_BIT, bool, request_nsid)
 ACCESS_OPTION(requirecookie, REQUIRE_COOKIE_BIT, bool, require_cookie)
 ACCESS_OPTION(sendcookie, SEND_COOKIE_BIT, bool, send_cookie)
index 1327fa130a11e3c572cce4ef2a89f47c241714b2..99da559b89569af61370f61d70a870f7a371b6f9 100644 (file)
@@ -178,6 +178,8 @@ struct dns_xfrin {
        dns_rdatacallbacks_t axfr;
 
        struct {
+               uint32_t diffs;
+               uint32_t maxdiffs;
                uint32_t request_serial;
                uint32_t current_serial;
                dns_journal_t *journal;
@@ -212,7 +214,8 @@ typedef struct xfrin_work {
 static void
 xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
             dns_name_t *zonename, dns_rdataclass_t rdclass,
-            dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
+            dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
+            const isc_sockaddr_t *primaryaddr,
             const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
             dns_transport_type_t soa_transport_type,
             dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
@@ -459,6 +462,7 @@ ixfr_putdata(dns_xfrin_t *xfr, dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
        dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, &tuple);
        dns_diff_append(&xfr->diff, &tuple);
 
+       xfr->ixfr.diffs++;
 failure:
        return (result);
 }
@@ -863,7 +867,7 @@ failure:
 
 isc_result_t
 dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
-                const isc_sockaddr_t *primaryaddr,
+                uint32_t ixfr_maxdiffs, const isc_sockaddr_t *primaryaddr,
                 const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
                 dns_transport_type_t soa_transport_type,
                 dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
@@ -889,7 +893,7 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
        }
 
        xfrin_create(mctx, zone, db, loop, zonename, dns_zone_getclass(zone),
-                    xfrtype, primaryaddr, sourceaddr, tsigkey,
+                    xfrtype, ixfr_maxdiffs, primaryaddr, sourceaddr, tsigkey,
                     soa_transport_type, transport, tlsctx_cache, &xfr);
 
        if (db != NULL) {
@@ -1096,6 +1100,8 @@ xfrin_reset(dns_xfrin_t *xfr) {
 
        dns_diff_clear(&xfr->diff);
 
+       xfr->ixfr.diffs = 0;
+
        if (xfr->ixfr.journal != NULL) {
                dns_journal_destroy(&xfr->ixfr.journal);
        }
@@ -1145,7 +1151,8 @@ xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg) {
 static void
 xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
             dns_name_t *zonename, dns_rdataclass_t rdclass,
-            dns_rdatatype_t reqtype, const isc_sockaddr_t *primaryaddr,
+            dns_rdatatype_t reqtype, uint32_t ixfr_maxdiffs,
+            const isc_sockaddr_t *primaryaddr,
             const isc_sockaddr_t *sourceaddr, dns_tsigkey_t *tsigkey,
             dns_transport_type_t soa_transport_type,
             dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
@@ -1157,6 +1164,7 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_loop_t *loop,
                .shutdown_result = ISC_R_UNSET,
                .rdclass = rdclass,
                .reqtype = reqtype,
+               .ixfr.maxdiffs = ixfr_maxdiffs,
                .maxrecords = dns_zone_getmaxrecords(zone),
                .primaryaddr = *primaryaddr,
                .sourceaddr = *sourceaddr,
@@ -1902,6 +1910,19 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
                                dns_rdata_t rdata = DNS_RDATA_INIT;
                                dns_rdataset_current(rds, &rdata);
                                CHECK(xfr_rr(xfr, name, rds->ttl, &rdata));
+
+                               /*
+                                * Did we hit the maximum ixfr diffs limit?
+                                */
+                               if (xfr->reqtype == dns_rdatatype_ixfr &&
+                                   xfr->ixfr.maxdiffs != 0 &&
+                                   xfr->ixfr.diffs >= xfr->ixfr.maxdiffs)
+                               {
+                                       xfrin_log(xfr, ISC_LOG_DEBUG(3),
+                                                 "too many diffs, "
+                                                 "retrying with AXFR");
+                                       goto try_axfr;
+                               }
                        }
                }
        }
index 9d7af1f5c63933fefe7c26c2091ea087a211f6c9..056caffec248f510daf00493c61fc22d5e60d4b2 100644 (file)
@@ -465,6 +465,7 @@ struct dns_zone {
         * whether ixfr is requested
         */
        bool requestixfr;
+       uint32_t requestixfr_maxdiffs;
        uint32_t ixfr_ratio;
 
        /*%
@@ -18260,6 +18261,7 @@ got_transfer_quota(void *arg) {
        char primary[ISC_SOCKADDR_FORMATSIZE];
        char source[ISC_SOCKADDR_FORMATSIZE];
        dns_rdatatype_t xfrtype;
+       uint32_t ixfr_maxdiffs = 0;
        isc_netaddr_t primaryip;
        isc_sockaddr_t primaryaddr;
        isc_sockaddr_t sourceaddr;
@@ -18326,12 +18328,20 @@ got_transfer_quota(void *arg) {
                UNLOCK_ZONE(zone);
        } else {
                bool use_ixfr = true;
+
                if (peer != NULL) {
                        result = dns_peer_getrequestixfr(peer, &use_ixfr);
                }
                if (peer == NULL || result != ISC_R_SUCCESS) {
                        use_ixfr = zone->requestixfr;
                }
+               if (peer != NULL) {
+                       result = dns_peer_getrequestixfrmaxdiffs(
+                               peer, &ixfr_maxdiffs);
+               }
+               if (peer == NULL || result != ISC_R_SUCCESS) {
+                       ixfr_maxdiffs = zone->requestixfr_maxdiffs;
+               }
                if (!use_ixfr) {
                        dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
                                      ISC_LOG_DEBUG(1),
@@ -18415,10 +18425,10 @@ got_transfer_quota(void *arg) {
 
        zmgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache);
 
-       result = dns_xfrin_create(zone, xfrtype, &primaryaddr, &sourceaddr,
-                                 zone->tsigkey, soa_transport_type,
-                                 zone->transport, zmgr_tlsctx_cache,
-                                 zone->mctx, zone_xfrdone, &zone->xfr);
+       result = dns_xfrin_create(
+               zone, xfrtype, ixfr_maxdiffs, &primaryaddr, &sourceaddr,
+               zone->tsigkey, soa_transport_type, zone->transport,
+               zmgr_tlsctx_cache, zone->mctx, zone_xfrdone, &zone->xfr);
 
        isc_tlsctx_cache_detach(&zmgr_tlsctx_cache);
 
@@ -23139,6 +23149,18 @@ dns_zone_getrequestixfr(dns_zone_t *zone) {
        return (zone->requestixfr);
 }
 
+void
+dns_zone_setrequestixfrmaxdiffs(dns_zone_t *zone, uint32_t maxdiffs) {
+       REQUIRE(DNS_ZONE_VALID(zone));
+       zone->requestixfr_maxdiffs = maxdiffs;
+}
+
+bool
+dns_zone_getrequestixfrmaxdiffs(dns_zone_t *zone) {
+       REQUIRE(DNS_ZONE_VALID(zone));
+       return (zone->requestixfr_maxdiffs);
+}
+
 void
 dns_zone_setixfrratio(dns_zone_t *zone, uint32_t ratio) {
        REQUIRE(DNS_ZONE_VALID(zone));
index 87c85921db10290b491c6b9c315522fa60971320..df5551b7356ffe259232e12617ea0be6271ed304 100644 (file)
@@ -4344,6 +4344,13 @@ static struct {
        { "tcp-only", dns_peer_setforcetcp },
 };
 
+static struct {
+       const char *name;
+       isc_result_t (*set)(dns_peer_t *peer, uint32_t newval);
+} uint32s[] = {
+       { "request-ixfr-max-diffs", dns_peer_setrequestixfrmaxdiffs },
+};
+
 static isc_result_t
 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
              isc_symtab_t *symtab, isc_mem_t *mctx) {
@@ -4502,6 +4509,22 @@ check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
                                }
                        }
                }
+               for (i = 0; i < ARRAY_SIZE(uint32s); i++) {
+                       const cfg_obj_t *opt = NULL;
+                       cfg_map_get(v1, uint32s[i].name, &opt);
+                       if (opt != NULL) {
+                               tresult = (uint32s[i].set)(
+                                       peer, cfg_obj_asuint32(opt));
+                               if (tresult != ISC_R_SUCCESS) {
+                                       cfg_obj_log(opt, ISC_LOG_ERROR,
+                                                   "setting server option "
+                                                   "'%s' failed: %s",
+                                                   uint32s[i].name,
+                                                   isc_result_totext(tresult));
+                                       result = ISC_R_FAILURE;
+                               }
+                       }
+               }
                dns_peer_detach(&peer);
        }
        return (result);
index 83a8a997bbfeffa53a0a7f3509a59db533d2daf7..947432e00baae15a393401f11716ce584f2ddff2 100644 (file)
@@ -2484,6 +2484,8 @@ static cfg_clausedef_t zone_clauses[] = {
          CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
        { "request-ixfr", &cfg_type_boolean,
          CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
+       { "request-ixfr-max-diffs", &cfg_type_uint32,
+         CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
        { "serial-update-method", &cfg_type_updatemethod, CFG_ZONE_PRIMARY },
        { "sig-signing-nodes", &cfg_type_uint32,
          CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
@@ -2721,6 +2723,7 @@ static cfg_clausedef_t server_clauses[] = {
        { "query-source-v6", &cfg_type_querysource6, 0 },
        { "request-expire", &cfg_type_boolean, 0 },
        { "request-ixfr", &cfg_type_boolean, 0 },
+       { "request-ixfr-max-diffs", &cfg_type_uint32, 0 },
        { "request-nsid", &cfg_type_boolean, 0 },
        { "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
        { "require-cookie", &cfg_type_boolean, 0 },