diff --git a/CHANGES b/CHANGES index 2175018277..68da4cf442 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +3084. [func] A new command "rndc sync" dumps pending changes in + a dynamic zone to disk; "rndc sync -clean" also + removes the journal file after syncing. Also, + "rndc freeze" no longer removes journal files. + [RT #22473] + 3083. [bug] NOTIFY messages were not being sent when generating a NSEC3 chain incrementally. [RT #23702] diff --git a/bin/named/control.c b/bin/named/control.c index ff084fc7d5..96f76ac9bc 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.c,v 1.41 2010/12/03 22:05:19 each Exp $ */ +/* $Id: control.c,v 1.42 2011/03/21 07:22:11 each Exp $ */ /*! \file */ @@ -183,6 +183,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { command_compare(command, NS_COMMAND_THAW)) { result = ns_server_freeze(ns_g_server, ISC_FALSE, command, text); + } else if (command_compare(command, NS_COMMAND_SYNC)) { + result = ns_server_sync(ns_g_server, command, text); } else if (command_compare(command, NS_COMMAND_RECURSING)) { result = ns_server_dumprecursing(ns_g_server); } else if (command_compare(command, NS_COMMAND_TIMERPOKE)) { diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 24e59093b4..b3c0949c23 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: control.h,v 1.31 2010/08/16 22:21:06 marka Exp $ */ +/* $Id: control.h,v 1.32 2011/03/21 07:22:11 each Exp $ */ #ifndef NAMED_CONTROL_H #define NAMED_CONTROL_H 1 @@ -62,6 +62,7 @@ #define NS_COMMAND_LOADKEYS "loadkeys" #define NS_COMMAND_ADDZONE "addzone" #define NS_COMMAND_DELZONE "delzone" +#define NS_COMMAND_SYNC "sync" 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 25aa641ad3..bdc18b5b87 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.110 2010/08/16 23:46:52 tbox Exp $ */ +/* $Id: server.h,v 1.111 2011/03/21 07:22:11 each Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -294,6 +294,12 @@ isc_result_t ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, isc_buffer_t *text); +/*% + * Dump zone updates to disk, optionally removing the journal file + */ +isc_result_t +ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text); + /*% * Update a zone's DNSKEY set from the key repository. If * the command that triggered the call to this function was "sign", diff --git a/bin/named/server.c b/bin/named/server.c index 6172adce7f..d6042dfa35 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.608 2011/03/11 06:11:21 marka Exp $ */ +/* $Id: server.c,v 1.609 2011/03/21 07:22:11 each Exp $ */ /*! \file */ @@ -6981,6 +6981,106 @@ ns_server_rekey(ns_server_t *server, char *args) { return (result); } +/* + * Act on a "sync" command from the command channel. +*/ +static isc_result_t +synczone(dns_zone_t *zone, void *uap) { + isc_boolean_t cleanup = *(isc_boolean_t *)uap; + isc_result_t result; + char *journal; + + result = dns_zone_flush(zone); + if (result != ISC_R_SUCCESS) + cleanup = ISC_FALSE; + if (cleanup) { + journal = dns_zone_getjournal(zone); + if (journal != NULL) + (void)isc_file_remove(journal); + } + return (result); +} + +isc_result_t +ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) { + isc_result_t result, tresult; + dns_view_t *view; + dns_zone_t *zone = NULL; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; + const char *vname, *sep, *msg = NULL; + isc_boolean_t cleanup = ISC_FALSE; + char arg[8]; + int n; + + /* Did the user specify -clean? */ + n = sscanf(args, "%*s %7s", arg); + if (n > 0 && strcmp(arg, "-clean") == 0) { + cleanup = ISC_TRUE; + + /* shift so that zone_from_args() won't be confused */ + (void) next_token(&args, " \t"); + } + + result = zone_from_args(server, args, &zone, NULL); + if (result != ISC_R_SUCCESS) + return (result); + + if (zone == NULL) { + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + tresult = ISC_R_SUCCESS; + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + result = dns_zt_apply(view->zonetable, ISC_FALSE, + synczone, &cleanup); + if (result != ISC_R_SUCCESS && + tresult == ISC_R_SUCCESS) + tresult = result; + } + isc_task_endexclusive(server->task); + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_SERVER, ISC_LOG_INFO, + "dumping all zones%s: %s", + cleanup ? ", removing journal files" : "", + isc_result_totext(result)); + return (tresult); + } + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = synczone(zone, &cleanup); + isc_task_endexclusive(server->task); + + if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) + isc_buffer_putmem(text, (const unsigned char *)msg, + strlen(msg) + 1); + + view = dns_zone_getview(zone); + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 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, + "dumping zone '%s/%s'%s%s%s: %s", + zonename, classstr, sep, vname, + cleanup ? ", removing journal file" : "", + isc_result_totext(result)); + dns_zone_detach(&zone); + return (result); +} + /* * Act on a "freeze" or "thaw" command from the command channel. */ @@ -6994,7 +7094,6 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, char classstr[DNS_RDATACLASS_FORMATSIZE]; char zonename[DNS_NAME_FORMATSIZE]; dns_view_t *view; - char *journal; const char *vname, *sep; isc_boolean_t frozen; const char *msg = NULL; @@ -7028,6 +7127,11 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, return (DNS_R_NOTMASTER); } + if (freeze && !dns_zone_isdynamic(zone)) { + dns_zone_detach(&zone); + return (DNS_R_NOTDYNAMIC); + } + result = isc_task_beginexclusive(server->task); RUNTIME_CHECK(result == ISC_R_SUCCESS); frozen = dns_zone_getupdatedisabled(zone); @@ -7044,11 +7148,6 @@ ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args, msg = "Flushing the zone updates to " "disk failed."; } - 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); } else { diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 83449c8870..3c65f5398c 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -1235,15 +1235,12 @@ zone "eng.example.com" { Suspend updates to a dynamic zone. If no zone is - specified, - then all zones are suspended. This allows manual - edits to be made to a zone normally updated by dynamic - update. It - also causes changes in the journal file to be synced - into the master - and the journal file to be removed. All dynamic - update attempts will - be refused while the zone is frozen. + specified, then all zones are suspended. This allows + manual edits to be made to a zone normally updated by + dynamic update. It also causes changes in the + journal file to be synced into the master file. + All dynamic update attempts will be refused while + the zone is frozen. @@ -1255,15 +1252,28 @@ zone "eng.example.com" { view - Enable updates to a frozen dynamic zone. If no zone - is - specified, then all frozen zones are enabled. This - causes - the server to reload the zone from disk, and - re-enables dynamic updates - after the load has completed. After a zone is thawed, - dynamic updates - will no longer be refused. + Enable updates to a frozen dynamic zone. If no + zone is specified, then all frozen zones are + enabled. This causes the server to reload the zone + from disk, and re-enables dynamic updates after the + load has completed. After a zone is thawed, + dynamic updates will no longer be refused. + + + + + + sync + -clean + zone + class + view + + + Sync changes in the journal file for a dynamic zone + to the master file. If the "-clean" option is + specified, the journal file is also removed. If + no zone is specified, then all zones are synced. diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h index 9195f20e10..18c49ba8a0 100644 --- a/lib/dns/include/dns/result.h +++ b/lib/dns/include/dns/result.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.h,v 1.122 2011/01/11 23:47:13 tbox Exp $ */ +/* $Id: result.h,v 1.123 2011/03/21 07:22:14 each Exp $ */ #ifndef DNS_RESULT_H #define DNS_RESULT_H 1 @@ -151,8 +151,9 @@ #define DNS_R_NOTMASTER (ISC_RESULTCLASS_DNS + 105) #define DNS_R_BROKENCHAIN (ISC_RESULTCLASS_DNS + 106) #define DNS_R_EXPIRED (ISC_RESULTCLASS_DNS + 107) +#define DNS_R_NOTDYNAMIC (ISC_RESULTCLASS_DNS + 108) -#define DNS_R_NRESULTS 108 /*%< Number of results */ +#define DNS_R_NRESULTS 109 /*%< Number of results */ /* * DNS wire format rcodes. diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index d3709ac423..35ca8efaa9 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.184 2011/03/01 23:48:07 tbox Exp $ */ +/* $Id: zone.h,v 1.185 2011/03/21 07:22:14 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -1853,6 +1853,21 @@ dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db); * Load the origin names for a writeable DLZ database. */ +isc_boolean_t +dns_zone_isdynamic(dns_zone_t *zone); +/*% + * Return true iff the zone is "dynamic", in the sense that the zone's + * master file (if any) is written by the server, rather than being + * updated manually and read by the server. + * + * This is true for slave zones, stub zones, key zones, and zones that + * allow dynamic updates either by having an update policy ("ssutable") + * or an "allow-update" ACL with a value other than exactly "{ none; }". + * + * Requires: + * \li 'zone' to be valid. + */ + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/result.c b/lib/dns/result.c index 547ac14c35..e0b9cee5b8 100644 --- a/lib/dns/result.c +++ b/lib/dns/result.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: result.c,v 1.132 2011/01/11 23:47:13 tbox Exp $ */ +/* $Id: result.c,v 1.133 2011/03/21 07:22:13 each Exp $ */ /*! \file */ @@ -161,6 +161,7 @@ static const char *text[DNS_R_NRESULTS] = { "not master", /*%< 105 DNS_R_NOTMASTER */ "broken trust chain", /*%< 106 DNS_R_BROKENCHAIN */ "expired", /*%< 106 DNS_R_EXPIRED */ + "not dynamic", /*%< 107 DNS_R_NOTDYNAMIC */ }; static const char *rcode_text[DNS_R_NRCODERESULTS] = { diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 2f9d1dce5f..db40131a3a 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -813,6 +813,7 @@ dns_zone_getxfrsource6 dns_zone_getzeronosoattl dns_zone_iattach dns_zone_idetach +dns_zone_isdynamic dns_zone_isforced dns_zone_load dns_zone_loadandthaw diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 6aeec1b747..eb59179770 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.598 2011/03/21 01:02:39 marka Exp $ */ +/* $Id: zone.c,v 1.599 2011/03/21 07:22:13 each Exp $ */ /*! \file */ @@ -1367,8 +1367,8 @@ dns_zone_getjournal(dns_zone_t *zone) { * allow dynamic updates either by having an update policy ("ssutable") * or an "allow-update" ACL with a value other than exactly "{ none; }". */ -static isc_boolean_t -zone_isdynamic(dns_zone_t *zone) { +isc_boolean_t +dns_zone_isdynamic(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); return (ISC_TF(zone->type == dns_zone_slave || @@ -1381,7 +1381,6 @@ zone_isdynamic(dns_zone_t *zone) { !dns_acl_isnone(zone->update_acl)))); } - static isc_result_t zone_load(dns_zone_t *zone, unsigned int flags) { isc_result_t result; @@ -1418,7 +1417,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) { goto cleanup; } - if (zone->db != NULL && zone_isdynamic(zone)) { + if (zone->db != NULL && dns_zone_isdynamic(zone)) { /* * This is a slave, stub, or dynamically updated * zone being reloaded. Do nothing - the database @@ -2602,7 +2601,7 @@ check_nsec3param(dns_zone_t *zone, dns_db_t *db) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; isc_boolean_t dynamic = (zone->type == dns_zone_master) ? - zone_isdynamic(zone) : ISC_FALSE; + dns_zone_isdynamic(zone) : ISC_FALSE; dns_rdataset_init(&rdataset); result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node); diff --git a/lib/dns/zt.c b/lib/dns/zt.c index ed7f28a4a9..8b4b1abf4e 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zt.c,v 1.47 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: zt.c,v 1.48 2011/03/21 07:22:14 each Exp $ */ /*! \file */ @@ -299,6 +299,8 @@ freezezones(dns_zone_t *zone, void *uap) { if (dns_zone_gettype(zone) != dns_zone_master) return (ISC_R_SUCCESS); + if (!dns_zone_isdynamic(zone)) + return (ISC_R_SUCCESS); frozen = dns_zone_getupdatedisabled(zone); if (freeze) {