]> 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 11:21:36 +0000 (12:21 +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.

(cherry picked from commit 7c47254a140c3e9cf383cda73c7b6a55c4782826)

bin/named/bind9.xsl
bin/named/bind9.xsl.h
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 c145915a1979c493d7e16de3da737715e1e58cbf..309e5d4bb759cc5864cdb77541ca50d30b628a0c 100644 (file)
@@ -2,7 +2,9 @@
 
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
   <xsl:output method="html" indent="yes" version="4.0"/>
-  <xsl:template match="statistics[@version=&quot;3.11&quot;]">
+  <!-- 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.11.1&quot;]">
     <html>
       <head>
         <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
index 3d3e200eda0f0a4ba29b7a61eb4ceba318c2eef4..fabb5fa879146b534ed28bfa83248f07d7ae4441 100644 (file)
@@ -8,7 +8,11 @@ static char xslmsg[] =
        "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" "
        "xmlns=\"http://www.w3.org/1999/xhtml\" version=\"1.0\">\n"
        " <xsl:output method=\"html\" indent=\"yes\" version=\"4.0\"/>\n"
-       " <xsl:template match=\"statistics[@version=&quot;3.11&quot;]\">\n"
+       " <!-- the version number **below** must match version in "
+       "bin/named/statschannel.c -->\n"
+       " <!-- don't forget to update \"/xml/v<STATS_XML_VERSION_MAJOR>\" in "
+       "the HTTP endpoints listed below -->\n"
+       " <xsl:template match=\"statistics[@version=&quot;3.11.1&quot;]\">\n"
        " <html>\n"
        " <head>\n"
        " <script type=\"text/javascript\" "
index e6a3f5aba656795a8601aaaf1ec8f456ad6d1206..ff3deab06c6eed442ef73bd92990119c2874dc11 100644 (file)
@@ -344,6 +344,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);
 
@@ -2018,7 +2019,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
                                              "href=\"/bind9.xsl\""));
        TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
        TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
-                                        ISC_XMLCHAR "3.11"));
+                                        ISC_XMLCHAR "3.11.1"));
 
        /* Set common fields for statistics dump */
        dumparg.type = isc_statsformat_xml;
@@ -2878,7 +2879,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
        /*
         * These statistics are included no matter which URL we use.
         */
-       obj = json_object_new_string("1.5");
+       obj = json_object_new_string("1.5.1");
        CHECKMEM(obj);
        json_object_object_add(bindstats, "json-stats-version", obj);
 
index 727e9084823a32a019c881a33816a6511c52a032..2603d602518d0a3341cf97250c3dc3024aa90336 100644 (file)
@@ -6837,6 +6837,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 the update quota.
+
 ``RateDropped``
     This indicates the number of responses dropped due to rate limits.
 
index 8edfcd3c8b1b8e8ddc35fc4c76ea42d36344f535..6ace9f3e3058f8677350bc01a7d818382dc775d5 100644 (file)
@@ -86,6 +86,7 @@ struct ns_server {
        isc_quota_t recursionquota;
        isc_quota_t tcpquota;
        isc_quota_t xfroutquota;
+       isc_quota_t updquota;
 
        /*% Test options and other configurables */
        uint32_t options;
index ee480959a5c7358b602511f2988510cd934d9f63..b9564aaf444f6c7debe7aef592edd64df7920830 100644 (file)
@@ -108,7 +108,9 @@ enum {
 
        ns_statscounter_reclimitdropped = 66,
 
-       ns_statscounter_max = 67,
+       ns_statscounter_updatequota = 67,
+
+       ns_statscounter_max = 68,
 };
 
 void
index f5dad49f882ebb844c3805823eb0a1c22e6f870a..63bea5dca4b980fb426cbc3cc1c4235a33179ef6 100644 (file)
@@ -54,6 +54,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);
 
        CHECKFATAL(dns_tkeyctx_create(mctx, &sctx->tkeyctx));
 
@@ -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 bbfb1974bcf17afbae8eacd1c339e5bb6646f249..9fc21a462d392e52b408e17c7750d05b1a6c0ba4 100644 (file)
@@ -1550,6 +1550,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->mctx, client, DNS_EVENT_UPDATE, update_action, NULL,
                sizeof(*event));
@@ -1688,12 +1701,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);
        }
@@ -3518,6 +3538,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);
 }
@@ -3534,6 +3555,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) {
        INSIST(client->nupdates > 0);
        client->nupdates--;
        respond(client, DNS_R_SERVFAIL);
+
+       isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota });
        isc_event_free(&event);
        isc_nmhandle_detach(&client->updatehandle);
 }
@@ -3571,6 +3594,8 @@ forward_done(isc_task_t *task, isc_event_t *event) {
        client->nupdates--;
        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);
@@ -3606,6 +3631,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->mctx, client, DNS_EVENT_UPDATE, forward_action, NULL,
                sizeof(*event));