From 18036bb3f435eaa20d60093738c61e5da42a6cfe Mon Sep 17 00:00:00 2001 From: Evan Hunt <each@isc.org> Date: Thu, 1 Sep 2022 16:05:04 -0700 Subject: [PATCH] add an update quota 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 | 4 +++- bin/named/bind9.xsl.h | 6 +++++- bin/named/statschannel.c | 5 +++-- doc/arm/reference.rst | 5 +++++ lib/ns/include/ns/server.h | 1 + lib/ns/include/ns/stats.h | 4 +++- lib/ns/server.c | 2 ++ lib/ns/update.c | 37 ++++++++++++++++++++++++++++++++++++- 8 files changed, 58 insertions(+), 6 deletions(-) diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index 5078115..194625b 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -12,7 +12,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="3.11"]"> + <!-- 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="3.11.1"]"> <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h index e30f7f5..b182742 100644 --- a/bin/named/bind9.xsl.h +++ b/bin/named/bind9.xsl.h @@ -20,7 +20,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="3.11"]\">\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="3.11.1"]\">\n" " <html>\n" " <head>\n" " <script type=\"text/javascript\" " diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 832ce93..7361ead 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -335,6 +335,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); @@ -2007,7 +2008,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; @@ -2876,7 +2877,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); diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 2d05aec..25c20d7 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -6705,6 +6705,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. diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index 6a1f345..0abb579 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -84,6 +84,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; diff --git a/lib/ns/include/ns/stats.h b/lib/ns/include/ns/stats.h index 3c08799..95b15d0 100644 --- a/lib/ns/include/ns/stats.h +++ b/lib/ns/include/ns/stats.h @@ -106,7 +106,9 @@ enum { ns_statscounter_reclimitdropped = 66, - ns_statscounter_max = 67, + ns_statscounter_updatequota = 67, + + ns_statscounter_max = 68, }; void diff --git a/lib/ns/server.c b/lib/ns/server.c index a970a28..540bc2e 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -52,6 +52,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)); @@ -131,6 +132,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); diff --git a/lib/ns/update.c b/lib/ns/update.c index 546b70a..1871438 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -1544,6 +1544,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)); @@ -1676,12 +1689,18 @@ 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); + } else { + respond(client, result); + } + if (zone != NULL) { dns_zone_detach(&zone); } @@ -3489,6 +3508,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); } @@ -3505,6 +3525,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); } @@ -3542,6 +3564,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->updatehandle); } @@ -3576,6 +3600,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)); -- 2.39.2