From cde7dfea4c1267a2b526114f4ea80fe9db1fc557 Mon Sep 17 00:00:00 2001 From: Brian Wellington Date: Tue, 22 Jan 2002 22:05:59 +0000 Subject: [PATCH] 1190. [func] Add the "rndc freeze" and"rndc unfreeze" commands. [RT #2394] Basically, "freeze" disables dynamic updates to a zone, syncs the journal file into the master file, and removes the journal. This allows manual edits of a dynamic zone file without stopping the server, since the zone is temporarily considered non-dynamic. "unfreeze" re-enables dynamic updates to a zone. So, instead of the old: rndc stop edit master file remove journal restart server you can now do: rndc freeze zone edit master file rndc reload zone rndc unfreeze zone which doesn't require stopping the server. About everyone here at the secure dynamic update workshop wanted this. It will be documented soon. --- CHANGES | 3 ++ bin/named/control.c | 6 ++- bin/named/include/named/control.h | 4 +- bin/named/include/named/server.h | 8 +++- bin/named/server.c | 62 ++++++++++++++++++++++++++++++- bin/named/update.c | 4 +- lib/dns/include/dns/zone.h | 8 +++- lib/dns/zone.c | 21 +++++++++-- 8 files changed, 107 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 6797b52f24..b9688519d5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +1190. [func] Add the "rndc freeze" and"rndc unfreeze" commands. + [RT #2394] + 1189. [bug] On some systems, malloc(0) returns NULL, which could cause the caller to report an out of memory error. [RT #2398] diff --git a/bin/named/control.c b/bin/named/control.c index b32005891b..2725a1cabc 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.c,v 1.10 2001/12/01 00:34:22 marka Exp $ */ +/* $Id: control.c,v 1.11 2002/01/22 22:05:46 bwelling Exp $ */ #include @@ -117,6 +117,10 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { result = ns_server_flushname(ns_g_server, command); } else if (command_compare(command, NS_COMMAND_STATUS)) { result = ns_server_status(ns_g_server, text); + } else if (command_compare(command, NS_COMMAND_FREEZE)) { + result = ns_server_freeze(ns_g_server, ISC_TRUE, command); + } else if (command_compare(command, NS_COMMAND_UNFREEZE)) { + result = ns_server_freeze(ns_g_server, ISC_FALSE, command); } else { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 9ff44a064b..15678e5b19 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.h,v 1.8 2001/11/27 04:06:10 marka Exp $ */ +/* $Id: control.h,v 1.9 2002/01/22 22:05:51 bwelling Exp $ */ #ifndef NAMED_CONTROL_H #define NAMED_CONTROL_H 1 @@ -45,6 +45,8 @@ #define NS_COMMAND_FLUSH "flush" #define NS_COMMAND_FLUSHNAME "flushname" #define NS_COMMAND_STATUS "status" +#define NS_COMMAND_FREEZE "freeze" +#define NS_COMMAND_UNFREEZE "unfreeze" isc_result_t ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp); diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 7a1dd83c46..e5d0f475b3 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.63 2001/11/27 04:06:11 marka Exp $ */ +/* $Id: server.h,v 1.64 2002/01/22 22:05:52 bwelling Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -185,4 +185,10 @@ ns_server_flushname(ns_server_t *server, char *args); isc_result_t ns_server_status(ns_server_t *server, isc_buffer_t *text); +/* + * Enable or disable updates for a zone. + */ +isc_result_t +ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args); + #endif /* NAMED_SERVER_H */ diff --git a/bin/named/server.c b/bin/named/server.c index 487efa3f08..20111acfa7 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.367 2002/01/04 02:32:04 gson Exp $ */ +/* $Id: server.c,v 1.368 2002/01/22 22:05:48 bwelling Exp $ */ #include @@ -2841,3 +2841,63 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) { isc_buffer_add(text, n); return (ISC_R_SUCCESS); } + +/* + * Act on a "freeze" or "unfreeze" command from the command channel. + */ +isc_result_t +ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { + isc_result_t result; + dns_zone_t *zone = NULL; + dns_zonetype_t type; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; + dns_view_t *view; + char *journal; + const char *vname, *sep; + + result = zone_from_args(server, args, &zone); + if (result != ISC_R_SUCCESS) + return (result); + if (zone == NULL) + return (ISC_R_UNEXPECTEDEND); + type = dns_zone_gettype(zone); + if (type != dns_zone_master) { + dns_zone_detach(&zone); + return (ISC_R_NOTFOUND); + } + + if (freeze) { + result = dns_zone_flush(zone); + if (result == ISC_R_SUCCESS) { + journal = dns_zone_getjournal(zone); + if (journal != NULL) + (void)isc_file_remove(journal); + } + } + if (result == ISC_R_SUCCESS) + dns_zone_setupdatedisabled(zone, freeze); + + view = dns_zone_getview(zone); + if (strcmp(view->name, "_bind") == 0 || + strcmp(view->name, "_default") == 0) + { + vname = ""; + sep = ""; + } else { + vname = view->name; + sep = " "; + } + dns_rdataclass_format(dns_zone_getclass(zone), classstr, + sizeof(classstr)); + dns_name_format(dns_zone_getorigin(zone), + zonename, sizeof(zonename)); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "%s zone '%s/%s'%s%s: %s", + freeze ? "freezing" : "unfreezing", + zonename, classstr, sep, vname, + isc_result_totext(result)); + dns_zone_detach(&zone); + return (result); +} diff --git a/bin/named/update.c b/bin/named/update.c index 0263d351ea..2d1d0ffff4 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.95 2002/01/22 21:45:07 gson Exp $ */ +/* $Id: update.c,v 1.96 2002/01/22 22:05:49 bwelling Exp $ */ #include @@ -2163,6 +2163,8 @@ update_action(isc_task_t *task, isc_event_t *event) { * Check Requestor's Permissions. It seems a bit silly to do this * only after prerequisite testing, but that is what RFC2136 says. */ + if (dns_zone_getupdatedisabled(zone)) + FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled"); if (ssutable == NULL) { char msg[DNS_RDATACLASS_FORMATSIZE + DNS_NAME_FORMATSIZE + sizeof("update '/'")]; diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 98f3a2d58c..6cb8f96c83 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.110 2002/01/22 21:52:32 gson Exp $ */ +/* $Id: zone.h,v 1.111 2002/01/22 22:05:56 bwelling Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -758,6 +758,12 @@ dns_zone_clearxfracl(dns_zone_t *zone); * 'zone' to be a valid zone. */ +isc_boolean_t +dns_zone_getupdatedisabled(dns_zone_t *zone); + +void +dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state); + void dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity); /* diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 96b7ab0c6d..b1f716e55e 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.359 2002/01/21 11:00:20 bwelling Exp $ */ +/* $Id: zone.c,v 1.360 2002/01/22 22:05:53 bwelling Exp $ */ #include @@ -185,6 +185,7 @@ struct dns_zone { dns_acl_t *notify_acl; dns_acl_t *query_acl; dns_acl_t *xfr_acl; + isc_boolean_t update_disabled; dns_severity_t check_names; ISC_LIST(dns_notify_t) notifies; dns_request_t *request; @@ -537,6 +538,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->notify_acl = NULL; zone->query_acl = NULL; zone->xfr_acl = NULL; + zone->update_disabled = ISC_FALSE; zone->check_names = dns_severity_ignore; zone->request = NULL; zone->lctx = NULL; @@ -908,8 +910,8 @@ zone_isdynamic(dns_zone_t *zone) { return (ISC_TF(zone->type == dns_zone_slave || zone->type == dns_zone_stub || - zone->ssutable != NULL || - (zone->update_acl != NULL && + (!zone->update_disabled && zone->ssutable != NULL) || + (!zone->update_disabled && zone->update_acl != NULL && ! (zone->update_acl->length == 1 && zone->update_acl->elements[0].negative == ISC_TRUE && @@ -4469,6 +4471,19 @@ dns_zone_clearxfracl(dns_zone_t *zone) { UNLOCK_ZONE(zone); } +isc_boolean_t +dns_zone_getupdatedisabled(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return (zone->update_disabled); + +} + +void +dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state) { + REQUIRE(DNS_ZONE_VALID(zone)); + zone->update_disabled = state; +} + void dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity) {