]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add an update quota
authorEvan Hunt <each@isc.org>
Thu, 1 Sep 2022 23:05:04 +0000 (16:05 -0700)
committerMichał Kępień <michal@isc.org>
Thu, 12 Jan 2023 10:52:48 +0000 (11:52 +0100)
limit the number of simultaneous DNS UPDATE events that can be
processed by adding a quota for update and update forwarding.
this quota currently, arbitrarily, defaults to 100.

also add a statistics counter to record when the update quota
has been exceeded.

bin/named/bind9.xsl
bin/named/statschannel.c
doc/arm/reference.rst
lib/ns/include/ns/server.h
lib/ns/include/ns/stats.h
lib/ns/server.c
lib/ns/update.c

index 27161860d037cf76a37c692c8071a18bf28c1d5d..9dda61deeab039b968e23c242dda935ef24b3885 100644 (file)
@@ -15,7 +15,7 @@
   <xsl:output method="html" indent="yes" version="4.0"/>
   <!-- the version number **below** must match version in bin/named/statschannel.c -->
   <!-- don't forget to update "/xml/v<STATS_XML_VERSION_MAJOR>" in the HTTP endpoints listed below -->
-  <xsl:template match="statistics[@version=&quot;3.12&quot;]">
+  <xsl:template match="statistics[@version=&quot;3.13&quot;]">
     <html>
       <head>
         <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
index 20b88a86cd2a1f419a0aa9625ee197251d799904..4f45b1be300a9c37821f382dabbbe4ac0951f0c8 100644 (file)
 #include "xsl_p.h"
 
 #define STATS_XML_VERSION_MAJOR "3"
-#define STATS_XML_VERSION_MINOR "12"
+#define STATS_XML_VERSION_MINOR "13"
 #define STATS_XML_VERSION      STATS_XML_VERSION_MAJOR "." STATS_XML_VERSION_MINOR
 
 #define STATS_JSON_VERSION_MAJOR "1"
-#define STATS_JSON_VERSION_MINOR "6"
+#define STATS_JSON_VERSION_MINOR "7"
 #define STATS_JSON_VERSION      STATS_JSON_VERSION_MAJOR "." STATS_JSON_VERSION_MINOR
 
 #define CHECK(m)                               \
@@ -352,6 +352,7 @@ init_desc(void) {
        SET_NSSTATDESC(reclimitdropped,
                       "queries dropped due to recursive client limit",
                       "RecLimitDropped");
+       SET_NSSTATDESC(updatequota, "Update quota exceeded", "UpdateQuota");
 
        INSIST(i == ns_statscounter_max);
 
index c229f15a613f0330bc6c8f6f3ac9e1cc0f4ef609..a106b5e10df867c4afc4f0470354f9d409f41995 100644 (file)
@@ -7838,6 +7838,11 @@ Name Server Statistics Counters
 ``UpdateBadPrereq``
     This indicates the number of dynamic updates rejected due to a prerequisite failure.
 
+``UpdateQuota``
+    This indicates the number of times a dynamic update or update
+    forwarding request was rejected because the number of pending
+    requests exceeded :any:`update-quota`.
+
 ``RateDropped``
     This indicates the number of responses dropped due to rate limits.
 
index 51c2c0a1d540118310936ada000b8f85cab3a79e..2d8f19139f29f301fda3ed98a713df7f24c980b6 100644 (file)
@@ -84,6 +84,7 @@ struct ns_server {
        isc_quota_t recursionquota;
        isc_quota_t tcpquota;
        isc_quota_t xfroutquota;
+       isc_quota_t updquota;
        ISC_LIST(isc_quota_t) http_quotas;
        isc_mutex_t http_quotas_lock;
 
index 2de556423beab2c0e3e1b523d45778a4b44b71fd..c235384f48f945fef53fa104cd432fb4296093d2 100644 (file)
@@ -107,7 +107,9 @@ enum {
 
        ns_statscounter_reclimitdropped = 66,
 
-       ns_statscounter_max = 67,
+       ns_statscounter_updatequota = 67,
+
+       ns_statscounter_max = 68,
 };
 
 void
index 5c80a7c52e6b54ece50d895468fd2dfc1968f797..1cc7864a85d658a91c66e58584a148460bba414f 100644 (file)
@@ -61,6 +61,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
        isc_quota_init(&sctx->xfroutquota, 10);
        isc_quota_init(&sctx->tcpquota, 10);
        isc_quota_init(&sctx->recursionquota, 100);
+       isc_quota_init(&sctx->updquota, 100);
        ISC_LIST_INIT(sctx->http_quotas);
        isc_mutex_init(&sctx->http_quotas_lock);
 
@@ -133,6 +134,7 @@ ns_server_detach(ns_server_t **sctxp) {
                        isc_mem_put(sctx->mctx, altsecret, sizeof(*altsecret));
                }
 
+               isc_quota_destroy(&sctx->updquota);
                isc_quota_destroy(&sctx->recursionquota);
                isc_quota_destroy(&sctx->tcpquota);
                isc_quota_destroy(&sctx->xfroutquota);
index b15bfc4f86c3ce21fb42fba4fd6ff52903b7dfa0..715a4a18666f379280cd72b966794a4542a2e47b 100644 (file)
@@ -1644,6 +1644,19 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) {
        update_event_t *event = NULL;
        isc_task_t *zonetask = NULL;
 
+       result = isc_quota_attach(&client->manager->sctx->updquota,
+                                 &(isc_quota_t *){ NULL });
+       if (result != ISC_R_SUCCESS) {
+               update_log(client, zone, LOGLEVEL_PROTOCOL,
+                          "update failed: too many DNS UPDATEs queued (%s)",
+                          isc_result_totext(result));
+               ns_stats_increment(client->manager->sctx->nsstats,
+                                  ns_statscounter_updatequota);
+               ns_client_drop(client, result);
+               isc_nmhandle_detach(&client->reqhandle);
+               return (DNS_R_DROP);
+       }
+
        event = (update_event_t *)isc_event_allocate(
                client->manager->mctx, client, DNS_EVENT_UPDATE, update_action,
                NULL, sizeof(*event));
@@ -1780,12 +1793,19 @@ failure:
                       dns_zone_gettype(zone) == dns_zone_mirror);
                inc_stats(client, zone, ns_statscounter_updaterej);
        }
+
        /*
         * We failed without having sent an update event to the zone.
         * We are still in the client task context, so we can
         * simply give an error response without switching tasks.
         */
-       respond(client, result);
+       if (result == DNS_R_DROP) {
+               ns_client_drop(client, result);
+               isc_nmhandle_detach(&client->reqhandle);
+       } else {
+               respond(client, result);
+       }
+
        if (zone != NULL) {
                dns_zone_detach(&zone);
        }
@@ -3582,6 +3602,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
 
        respond(client, uev->result);
 
+       isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
        isc_event_free(&event);
        isc_nmhandle_detach(&client->updatehandle);
 }
@@ -3596,6 +3617,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) {
        UNUSED(task);
 
        respond(client, DNS_R_SERVFAIL);
+
+       isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
        isc_event_free(&event);
        isc_nmhandle_detach(&client->updatehandle);
 }
@@ -3631,6 +3654,8 @@ forward_done(isc_task_t *task, isc_event_t *event) {
 
        ns_client_sendraw(client, uev->answer);
        dns_message_detach(&uev->answer);
+
+       isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
        isc_event_free(&event);
        isc_nmhandle_detach(&client->reqhandle);
        isc_nmhandle_detach(&client->updatehandle);
@@ -3666,6 +3691,17 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) {
        update_event_t *event = NULL;
        isc_task_t *zonetask = NULL;
 
+       result = isc_quota_attach(&client->manager->sctx->updquota,
+                                 &(isc_quota_t *){ NULL });
+       if (result != ISC_R_SUCCESS) {
+               update_log(client, zone, LOGLEVEL_PROTOCOL,
+                          "update failed: too many DNS UPDATEs queued (%s)",
+                          isc_result_totext(result));
+               ns_stats_increment(client->manager->sctx->nsstats,
+                                  ns_statscounter_updatequota);
+               return (DNS_R_DROP);
+       }
+
        event = (update_event_t *)isc_event_allocate(
                client->manager->mctx, client, DNS_EVENT_UPDATE, forward_action,
                NULL, sizeof(*event));