diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index 27161860d03..9dda61deeab 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -15,7 +15,7 @@ - + diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 20b88a86cd2..4f45b1be300 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -56,11 +56,11 @@ #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); diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index de69a4c0b62..fd4ba9db162 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -7876,6 +7876,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. diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index 51c2c0a1d54..2d8f19139f2 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; ISC_LIST(isc_quota_t) http_quotas; isc_mutex_t http_quotas_lock; diff --git a/lib/ns/include/ns/stats.h b/lib/ns/include/ns/stats.h index 2de556423be..c235384f48f 100644 --- a/lib/ns/include/ns/stats.h +++ b/lib/ns/include/ns/stats.h @@ -107,7 +107,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 5c80a7c52e6..1cc7864a85d 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -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); diff --git a/lib/ns/update.c b/lib/ns/update.c index b15bfc4f86c..715a4a18666 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -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));