]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Apply XFR-out quota after ACL is checked
authorAram Sargsyan <aram@isc.org>
Tue, 31 Mar 2026 13:00:00 +0000 (13:00 +0000)
committerMichał Kępień <michal@isc.org>
Thu, 7 May 2026 11:32:15 +0000 (13:32 +0200)
Unauthorized clients can consume XFR-out quota and block authorized
XFR clients. Apply the quota after ACL is checked.

lib/ns/xfrout.c

index 98c7374b4fceee4808fd8f7a05e20f2a95ab6b7b..1865f6b1f450a647d637dde55975b7d8e1b81e02 100644 (file)
@@ -738,6 +738,7 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
        bool is_poll = false;
        bool is_dlz = false;
        bool is_ixfr = false;
+       bool is_quota_applied = false;
        bool useviewacl = false;
        uint32_t begin_serial = 0, current_serial;
 
@@ -754,16 +755,6 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
 
        ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
                      ISC_LOG_DEBUG(6), "%s request", mnemonic);
-       /*
-        * Apply quota.
-        */
-       result = isc_quota_acquire(&client->manager->sctx->xfroutquota);
-       if (result != ISC_R_SUCCESS) {
-               isc_log_write(DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
-                             ISC_LOG_WARNING, "%s request denied: %s",
-                             mnemonic, isc_result_totext(result));
-               goto max_quota;
-       }
 
        /*
         * Interpret the question section.
@@ -922,6 +913,19 @@ got_soa:
                FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");
        }
 
+       /*
+        * Apply quota after ACL is checked, so that unauthorized clients
+        * can not starve the authorized clients.
+        */
+       result = isc_quota_acquire(&client->manager->sctx->xfroutquota);
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
+                             ISC_LOG_WARNING, "%s request denied: %s",
+                             mnemonic, isc_result_totext(result));
+               goto cleanup;
+       }
+       is_quota_applied = true;
+
        /*
         * Look up the requesting server in the peer table.
         */
@@ -1060,7 +1064,7 @@ have_stream:
        CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf));
        /*
         * Create the xfrout context object.  This transfers the ownership
-        * of "stream", "db", "ver", and "quota" to the xfrout context object.
+        * of "stream", "db" and "ver" to the xfrout context object.
         */
 
        if (is_dlz) {
@@ -1179,10 +1183,13 @@ cleanup:
        }
 
        if (xfr != NULL) {
+               /* The quota will be released in xfrout_ctx_destroy(). */
+               INSIST(is_quota_applied);
                xfrout_fail(xfr, result, "setting up zone transfer");
        } else if (result != ISC_R_SUCCESS) {
-               isc_quota_release(&client->manager->sctx->xfroutquota);
-       max_quota:
+               if (is_quota_applied) {
+                       isc_quota_release(&client->manager->sctx->xfroutquota);
+               }
                ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
                              NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3),
                              "zone transfer setup failed");