mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 22:45:39 +00:00
Merge branch '1447-incremental-rpz-update' into 'master'
incrementally clean up old RPZ records during updates Closes #1447 See merge request isc-projects/bind9!3318
This commit is contained in:
5
CHANGES
5
CHANGES
@@ -1,3 +1,8 @@
|
|||||||
|
5371. [bug] Improve incremental updates of the RPZ summary
|
||||||
|
database to reduce delays that could occur when
|
||||||
|
a policy zone update included a large number of
|
||||||
|
record deletions. [GL #1447]
|
||||||
|
|
||||||
5370. [bug] Deactivation of a netmgr handle associated with a
|
5370. [bug] Deactivation of a netmgr handle associated with a
|
||||||
socket could be skipped in some circumstances.
|
socket could be skipped in some circumstances.
|
||||||
Fixed by deactivating the netmgr handle before
|
Fixed by deactivating the netmgr handle before
|
||||||
|
@@ -55,7 +55,12 @@
|
|||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
None.
|
When an RPZ policy zone was updated via zone transfer
|
||||||
|
and a large number of records were deleted, <command>named</command>
|
||||||
|
could become nonresponsive for a short period while deleted
|
||||||
|
names were removed from the RPZ summary database. This database
|
||||||
|
cleanup is now done incrementally over a longer period of time,
|
||||||
|
reducing such delays. [GL #1447]
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
192
lib/dns/rpz.c
192
lib/dns/rpz.c
@@ -1781,32 +1781,85 @@ cleanup:
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
finish_update(dns_rpz_zone_t *rpz) {
|
finish_update(dns_rpz_zone_t *rpz) {
|
||||||
isc_result_t result;
|
LOCK(&rpz->rpzs->maint_lock);
|
||||||
isc_ht_t *tmpht = NULL;
|
rpz->updaterunning = false;
|
||||||
isc_ht_iter_t *iter = NULL;
|
|
||||||
dns_fixedname_t fname;
|
|
||||||
char dname[DNS_NAME_FORMATSIZE];
|
|
||||||
dns_name_t *name;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate over old ht with existing nodes deleted to delete
|
* If there's an update pending, schedule it.
|
||||||
* deleted nodes from RPZ
|
|
||||||
*/
|
*/
|
||||||
result = isc_ht_iter_create(rpz->nodes, &iter);
|
if (rpz->updatepending == true) {
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (rpz->min_update_interval > 0) {
|
||||||
char domain[DNS_NAME_FORMATSIZE];
|
uint64_t defer = rpz->min_update_interval;
|
||||||
|
char dname[DNS_NAME_FORMATSIZE];
|
||||||
|
isc_interval_t interval;
|
||||||
|
|
||||||
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
dns_name_format(&rpz->origin, dname,
|
||||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
DNS_NAME_FORMATSIZE);
|
||||||
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||||
"rpz: %s: failed to create HT iterator - %s",
|
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||||
domain, isc_result_totext(result));
|
"rpz: %s: new zone version came "
|
||||||
goto cleanup;
|
"too soon, deferring update for "
|
||||||
|
"%" PRIu64 " seconds",
|
||||||
|
dname, defer);
|
||||||
|
isc_interval_set(&interval, (unsigned int)defer, 0);
|
||||||
|
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
|
||||||
|
NULL, &interval, true);
|
||||||
|
} else {
|
||||||
|
isc_event_t *event = NULL;
|
||||||
|
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||||
|
ISC_EVENT_INIT(&rpz->updateevent,
|
||||||
|
sizeof(rpz->updateevent), 0, NULL,
|
||||||
|
DNS_EVENT_RPZUPDATED,
|
||||||
|
dns_rpz_update_taskaction, rpz, rpz,
|
||||||
|
NULL, NULL);
|
||||||
|
event = &rpz->updateevent;
|
||||||
|
isc_task_send(rpz->rpzs->updater, &event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNLOCK(&rpz->rpzs->maint_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cleanup_quantum(isc_task_t *task, isc_event_t *event) {
|
||||||
|
isc_result_t result = ISC_R_SUCCESS;
|
||||||
|
char domain[DNS_NAME_FORMATSIZE];
|
||||||
|
dns_rpz_zone_t *rpz = NULL;
|
||||||
|
isc_ht_iter_t *iter = NULL;
|
||||||
|
dns_fixedname_t fname;
|
||||||
|
dns_name_t *name = NULL;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
UNUSED(task);
|
||||||
|
|
||||||
|
REQUIRE(event != NULL);
|
||||||
|
REQUIRE(event->ev_sender != NULL);
|
||||||
|
|
||||||
|
rpz = (dns_rpz_zone_t *)event->ev_sender;
|
||||||
|
iter = (isc_ht_iter_t *)event->ev_arg;
|
||||||
|
isc_event_free(&event);
|
||||||
|
|
||||||
|
if (iter == NULL) {
|
||||||
|
/*
|
||||||
|
* Iterate over old ht with existing nodes deleted to
|
||||||
|
* delete deleted nodes from RPZ
|
||||||
|
*/
|
||||||
|
result = isc_ht_iter_create(rpz->nodes, &iter);
|
||||||
|
if (result != ISC_R_SUCCESS) {
|
||||||
|
dns_name_format(&rpz->origin, domain,
|
||||||
|
DNS_NAME_FORMATSIZE);
|
||||||
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||||
|
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
|
||||||
|
"rpz: %s: failed to create HT "
|
||||||
|
"iterator - %s",
|
||||||
|
domain, isc_result_totext(result));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
name = dns_fixedname_initname(&fname);
|
name = dns_fixedname_initname(&fname);
|
||||||
|
|
||||||
for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
|
for (result = isc_ht_iter_first(iter);
|
||||||
|
result == ISC_R_SUCCESS && count++ < DNS_RPZ_QUANTUM;
|
||||||
result = isc_ht_iter_delcurrent_next(iter))
|
result = isc_ht_iter_delcurrent_next(iter))
|
||||||
{
|
{
|
||||||
isc_region_t region;
|
isc_region_t region;
|
||||||
@@ -1820,58 +1873,62 @@ finish_update(dns_rpz_zone_t *rpz) {
|
|||||||
dns_rpz_delete(rpz->rpzs, rpz->num, name);
|
dns_rpz_delete(rpz->rpzs, rpz->num, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpht = rpz->nodes;
|
if (result == ISC_R_SUCCESS) {
|
||||||
rpz->nodes = rpz->newnodes;
|
isc_event_t *nevent = NULL;
|
||||||
rpz->newnodes = tmpht;
|
|
||||||
|
|
||||||
LOCK(&rpz->rpzs->maint_lock);
|
/*
|
||||||
rpz->updaterunning = false;
|
* We finished a quantum; trigger the next one and return.
|
||||||
/*
|
*/
|
||||||
* If there's an update pending schedule it
|
|
||||||
*/
|
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||||
if (rpz->updatepending == true) {
|
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||||
if (rpz->min_update_interval > 0) {
|
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
|
||||||
uint64_t defer = rpz->min_update_interval;
|
iter, rpz, NULL, NULL);
|
||||||
isc_interval_t interval;
|
nevent = &rpz->updateevent;
|
||||||
dns_name_format(&rpz->origin, dname,
|
isc_task_send(rpz->rpzs->updater, &nevent);
|
||||||
DNS_NAME_FORMATSIZE);
|
return;
|
||||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
} else if (result == ISC_R_NOMORE) {
|
||||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
isc_ht_t *tmpht = NULL;
|
||||||
"rpz: %s: new zone version came "
|
|
||||||
"too soon, deferring update for "
|
/*
|
||||||
"%" PRIu64 " seconds",
|
* Done with cleanup of deleted nodes; finalize
|
||||||
dname, defer);
|
* the update.
|
||||||
isc_interval_set(&interval, (unsigned int)defer, 0);
|
*/
|
||||||
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
|
tmpht = rpz->nodes;
|
||||||
NULL, &interval, true);
|
rpz->nodes = rpz->newnodes;
|
||||||
} else {
|
rpz->newnodes = tmpht;
|
||||||
isc_event_t *event;
|
|
||||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
finish_update(rpz);
|
||||||
ISC_EVENT_INIT(&rpz->updateevent,
|
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
|
||||||
sizeof(rpz->updateevent), 0, NULL,
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
||||||
DNS_EVENT_RPZUPDATED,
|
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
||||||
dns_rpz_update_taskaction, rpz, rpz,
|
"rpz: %s: reload done", domain);
|
||||||
NULL, NULL);
|
|
||||||
event = &rpz->updateevent;
|
|
||||||
isc_task_send(rpz->rpzs->updater, &event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UNLOCK(&rpz->rpzs->maint_lock);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're here, we're finished or something went wrong.
|
||||||
|
*/
|
||||||
cleanup:
|
cleanup:
|
||||||
if (iter != NULL) {
|
if (iter != NULL) {
|
||||||
isc_ht_iter_destroy(&iter);
|
isc_ht_iter_destroy(&iter);
|
||||||
}
|
}
|
||||||
|
if (rpz->newnodes != NULL) {
|
||||||
|
isc_ht_destroy(&rpz->newnodes);
|
||||||
|
}
|
||||||
|
dns_db_closeversion(rpz->updb, &rpz->updbversion, false);
|
||||||
|
dns_db_detach(&rpz->updb);
|
||||||
|
rpz_detach(&rpz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_quantum(isc_task_t *task, isc_event_t *event) {
|
update_quantum(isc_task_t *task, isc_event_t *event) {
|
||||||
isc_result_t result = ISC_R_SUCCESS;
|
isc_result_t result = ISC_R_SUCCESS;
|
||||||
dns_dbnode_t *node = NULL;
|
dns_dbnode_t *node = NULL;
|
||||||
dns_rpz_zone_t *rpz;
|
dns_rpz_zone_t *rpz = NULL;
|
||||||
char domain[DNS_NAME_FORMATSIZE];
|
char domain[DNS_NAME_FORMATSIZE];
|
||||||
dns_fixedname_t fixname;
|
dns_fixedname_t fixname;
|
||||||
dns_name_t *name;
|
dns_name_t *name = NULL;
|
||||||
|
isc_event_t *nevent = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
UNUSED(task);
|
UNUSED(task);
|
||||||
@@ -1975,13 +2032,13 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result == ISC_R_SUCCESS) {
|
if (result == ISC_R_SUCCESS) {
|
||||||
isc_event_t *nevent;
|
|
||||||
/*
|
/*
|
||||||
* Pause the iterator so that the DB is not locked
|
* Pause the iterator so that the DB is not locked.
|
||||||
*/
|
*/
|
||||||
dns_dbiterator_pause(rpz->updbit);
|
dns_dbiterator_pause(rpz->updbit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We finished a quantum; trigger the next one and return
|
* We finished a quantum; trigger the next one and return.
|
||||||
*/
|
*/
|
||||||
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||||
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||||
@@ -1992,17 +2049,22 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
|
|||||||
return;
|
return;
|
||||||
} else if (result == ISC_R_NOMORE) {
|
} else if (result == ISC_R_NOMORE) {
|
||||||
/*
|
/*
|
||||||
* All done.
|
* Done with the new database; now we just need to
|
||||||
|
* clean up the old.
|
||||||
*/
|
*/
|
||||||
finish_update(rpz);
|
dns_dbiterator_destroy(&rpz->updbit);
|
||||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
|
||||||
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
|
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
|
||||||
"rpz: %s: reload done", domain);
|
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
|
||||||
|
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
|
||||||
|
NULL, rpz, NULL, NULL);
|
||||||
|
nevent = &rpz->updateevent;
|
||||||
|
isc_task_send(rpz->rpzs->updater, &nevent);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're here, we've either finished or something went wrong,
|
* If we're here, something went wrong, so clean up.
|
||||||
* so clean up.
|
|
||||||
*/
|
*/
|
||||||
if (rpz->updbit != NULL) {
|
if (rpz->updbit != NULL) {
|
||||||
dns_dbiterator_destroy(&rpz->updbit);
|
dns_dbiterator_destroy(&rpz->updbit);
|
||||||
|
Reference in New Issue
Block a user