]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] store "addzone" zone config in a NZD database
authorEvan Hunt <each@isc.org>
Thu, 21 Jul 2016 18:13:03 +0000 (11:13 -0700)
committerEvan Hunt <each@isc.org>
Thu, 21 Jul 2016 18:13:37 +0000 (11:13 -0700)
4421. [func] When built with LMDB (Lightning Memory-mapped
Database), named will now use a database to store
the configuration for zones added by "rndc addzone"
instead of using a flat NZF file. This improves
performance of "rndc delzone" and "rndc modzone"
significantly. Existing NZF files will
automatically by converted to NZD databases.
To view the contents of an NZD or to roll back to
NZF format, use "named-nzd2nzf". To disable
                        this feature, use "configure --without-lmdb".
                        [RT #39837]

37 files changed:
CHANGES
bin/Makefile.in
bin/named/include/named/server.h
bin/named/server.c
bin/tests/system/addzone/clean.sh
bin/tests/system/addzone/tests.sh
bin/tests/system/autosign/clean.sh
bin/tests/system/autosign/tests.sh
bin/tests/system/conf.sh.in
bin/tests/system/delzone/clean.sh [new file with mode: 0644]
bin/tests/system/delzone/ns1/inlineslave.db [new file with mode: 0644]
bin/tests/system/delzone/ns1/named.conf [new file with mode: 0644]
bin/tests/system/delzone/ns2/added.db [new file with mode: 0644]
bin/tests/system/delzone/ns2/named.args [new file with mode: 0644]
bin/tests/system/delzone/ns2/named.conf [new file with mode: 0644]
bin/tests/system/delzone/ns2/normal.db [new file with mode: 0644]
bin/tests/system/delzone/setup.sh [new file with mode: 0644]
bin/tests/system/delzone/tests.sh [new file with mode: 0755]
bin/tests/system/inline/clean.sh
bin/tests/system/nzd2nzf/clean.sh [new file with mode: 0644]
bin/tests/system/nzd2nzf/ns1/added.db [new file with mode: 0644]
bin/tests/system/nzd2nzf/ns1/named.conf [new file with mode: 0644]
bin/tests/system/nzd2nzf/prereq.sh [new file with mode: 0644]
bin/tests/system/nzd2nzf/setup.sh [new file with mode: 0644]
bin/tests/system/nzd2nzf/tests.sh [new file with mode: 0644]
bin/tools/.gitignore
bin/tools/Makefile.in
bin/tools/named-nzd2nzf.8 [new file with mode: 0644]
bin/tools/named-nzd2nzf.c [new file with mode: 0644]
bin/tools/named-nzd2nzf.docbook [new file with mode: 0644]
bin/tools/named-nzd2nzf.html [new file with mode: 0644]
config.h.in
configure
configure.in
doc/arm/notes.xml
lib/dns/include/dns/view.h
lib/dns/view.c

diff --git a/CHANGES b/CHANGES
index 401c08601bbd488c3d9f118057b73700679d7cfc..782a4150e3197fad8079192b51532e2fd1c47604 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,15 @@
+4421.  [func]          When built with LMDB (Lightning Memory-mapped
+                       Database), named will now use a database to store
+                       the configuration for zones added by "rndc addzone"
+                       instead of using a flat NZF file. This improves
+                       performance of "rndc delzone" and "rndc modzone"
+                       significantly. Existing NZF files will
+                       automatically by converted to NZD databases.
+                       To view the contents of an NZD or to roll back to
+                       NZF format, use "named-nzd2nzf". To disable
+                        this feature, use "configure --without-lmdb".
+                        [RT #39837]
+
 4420.  [func]          nslookup now looks for AAAA as well as A by default.
                        [RT #40420]
 
index 4d8eaa119dc341a7bb2f8532fc8d78cc084b594f..f3cbed3f78cba57fcb2807fc01299506ad0300e3 100644 (file)
@@ -11,7 +11,7 @@ VPATH =               @srcdir@
 top_srcdir =   @top_srcdir@
 
 SUBDIRS =      named rndc dig delv dnssec tools tests nsupdate \
-               check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@
+               check confgen @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@
 TARGETS =
 
 @BIND9_MAKE_RULES@
index da32df70c4aa55934456025adf288055ab2aea12..2ecd888578e2aafe00642f00e0cdec4a1c792d2a 100644 (file)
@@ -27,6 +27,7 @@
 #define NS_EVENTCLASS          ISC_EVENTCLASS(0x4E43)
 #define NS_EVENT_RELOAD                (NS_EVENTCLASS + 0)
 #define NS_EVENT_CLIENTCONTROL (NS_EVENTCLASS + 1)
+#define NS_EVENT_DELZONE       (NS_EVENTCLASS + 2)
 
 /*%
  * Name server state.  Better here than in lots of separate global variables.
index e9e639a8e5be8aa10a853f7df799c31f24069d09..3d6f367a469ae6a2a5d31dfee9ca5c8c419165a5 100644 (file)
@@ -64,6 +64,7 @@
 #include <dns/dyndb.h>
 #include <dns/events.h>
 #include <dns/forward.h>
+#include <dns/fixedname.h>
 #include <dns/journal.h>
 #include <dns/keytable.h>
 #include <dns/keyvalues.h>
 #include <named/client.h>
 #include <named/config.h>
 #include <named/control.h>
+#ifdef HAVE_GEOIP
 #include <named/geoip.h>
+#endif /* HAVE_GEOIP */
 #include <named/interfacemgr.h>
 #include <named/log.h>
 #include <named/logconf.h>
 #include <named/ns_smf_globals.h>
 #include <stdlib.h>
 #endif
-#ifdef HAVE_GEOIP
-#include <named/geoip.h>
-#endif /* HAVE_GEOIP */
+
+#ifdef HAVE_LMDB
+#include <lmdb.h>
+#define count_newzones count_newzones_db
+#define configure_newzones configure_newzones_db
+#define dumpzone dumpzone_db
+#else  /* HAVE_LMDB */
+#define count_newzones count_newzones_file
+#define configure_newzones configure_newzones_file
+#define dumpzone dumpzone_file
+#endif /* HAVE_LMDB */
 
 #ifndef PATH_MAX
 #define PATH_MAX 1024
@@ -253,10 +264,16 @@ typedef struct ns_cfgctx {
        cfg_parser_t *                  add_parser;
        cfg_obj_t *                     config;
        cfg_obj_t *                     vconfig;
-       cfg_obj_t *                     nzconfig;
+       cfg_obj_t *                     nzf_config;
        cfg_aclconfctx_t *              actx;
 } ns_cfgctx_t;
 
+/*%
+ * A function to write out added-zone configuration to the new_zone_file
+ * specified in 'view'. Maybe called by delete_zoneconf().
+ */
+typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
+
 /*%
  * Holds state information for the initial zone loading process.
  * Uses the isc_refcount structure to count the number of views
@@ -429,6 +446,10 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
               isc_boolean_t added, isc_boolean_t old_rpz_ok,
               isc_boolean_t modify);
 
+static isc_result_t
+configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
+                  isc_mem_t *mctx, cfg_aclconfctx_t *actx);
+
 static isc_result_t
 add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
 
@@ -450,8 +471,25 @@ putuint8(isc_buffer_t **b, isc_uint8_t val);
 static inline isc_result_t
 putnull(isc_buffer_t **b);
 
+static int
+count_zones(const cfg_obj_t *conf);
+
+#ifdef HAVE_LMDB
+static isc_result_t
+migrate_nzf(dns_view_t *view);
+
+static isc_result_t
+nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
+
+static isc_result_t
+nzd_close(MDB_txn **txnp, isc_boolean_t commit);
+
+static isc_result_t
+nzd_count(dns_view_t *view, int *countp);
+#else
 static isc_result_t
-add_comment(FILE *fp, const char *viewname);
+nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
+#endif
 
 /*%
  * Configure a single view ACL at '*aclp'.  Get its configuration from
@@ -2177,7 +2215,7 @@ catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
        dns_name_format(dns_catz_entry_getname(ev->entry), cname,
-       DNS_NAME_FORMATSIZE);
+                       DNS_NAME_FORMATSIZE);
        result = dns_zt_find(ev->view->zonetable,
                             dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
        if (result != ISC_R_SUCCESS) {
@@ -3095,7 +3133,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
        isc_boolean_t zero_no_soattl;
        dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
        unsigned int query_timeout, ndisp;
-       ns_cfgctx_t *nzctx;
        isc_boolean_t old_rpz_ok = ISC_FALSE;
        isc_dscp_t dscp4 = -1, dscp6 = -1;
        dns_dyndbctx_t *dctx = NULL;
@@ -3255,26 +3292,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
         * from the newzone file for zones that were added during previous
         * runs.
         */
-       nzctx = view->new_zone_config;
-       if (nzctx != NULL && nzctx->nzconfig != NULL) {
-               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
-                             NS_LOGMODULE_SERVER, ISC_LOG_INFO,
-                             "loading additional zones for view '%s'",
-                             view->name);
-
-               zonelist = NULL;
-               cfg_map_get(nzctx->nzconfig, "zone", &zonelist);
-
-               for (element = cfg_list_first(zonelist);
-                    element != NULL;
-                    element = cfg_list_next(element))
-               {
-                       const cfg_obj_t *zconfig = cfg_listelt_value(element);
-                       CHECK(configure_zone(config, zconfig, vconfig,
-                                            mctx, view, NULL, actx,
-                                            ISC_TRUE, ISC_FALSE, ISC_FALSE));
-               }
-       }
+       CHECK(configure_newzones(view, config, vconfig, mctx, actx));
 
        /*
         * Create Dynamically Loadable Zone driver.
@@ -6197,9 +6215,91 @@ configure_session_key(const cfg_obj_t **maps, ns_server_t *server,
        return (result);
 }
 
+#ifndef HAVE_LMDB
+static isc_result_t
+count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
+       isc_result_t result;
+
+       /*
+        * In the case of NZF files, we also parse the configuration in
+        * the file at this stage.
+        *
+        * This may be called in multiple views, so we reset
+        * the parser each time.
+        */
+       cfg_parser_reset(ns_g_addparser);
+       result = cfg_parse_file(ns_g_addparser, view->new_zone_file,
+                               &cfg_type_addzoneconf, &nzcfg->nzf_config);
+       if (result == ISC_R_SUCCESS) {
+               int num_zones;
+
+               num_zones = count_zones(nzcfg->nzf_config);
+               isc_log_write(ns_g_lctx,
+                             NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_INFO,
+                             "NZF file '%s' contains %d zones",
+                             view->new_zone_file, num_zones);
+               if (num_zonesp != NULL)
+                       *num_zonesp = num_zones;
+       } else if (result == ISC_R_FILENOTFOUND) {
+               /* The new zone file may not exist. That is OK. */
+               result = ISC_R_SUCCESS;
+               if (num_zonesp != NULL)
+                       *num_zonesp = 0;
+       } else {
+               isc_log_write(ns_g_lctx,
+                             NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_ERROR,
+                             "Error parsing NZF file '%s': %s",
+                             view->new_zone_file,
+                             isc_result_totext(result));
+       }
+
+       return (result);
+}
+
+#else /* HAVE_LMDB */
+
+static isc_result_t
+count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
+       isc_result_t result;
+       int n;
+
+       UNUSED(nzcfg);
+
+       REQUIRE(num_zonesp != NULL);
+
+       CHECK(migrate_nzf(view));
+
+       isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO, "loading NZD zone count from '%s' "
+                     "for view '%s'",
+                     view->new_zone_db, view->name);
+
+       CHECK(nzd_count(view, &n));
+
+       *num_zonesp = n;
+
+       isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO,
+                     "NZD database '%s' contains %d zones",
+                     view->new_zone_db, n);
+
+ cleanup:
+       if (result != ISC_R_SUCCESS)
+               *num_zonesp = 0;
+
+       return (ISC_R_SUCCESS);
+}
+
+#endif /* HAVE_LMDB */
+
 static isc_result_t
 setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
-              cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx)
+              cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
+              int *num_zones)
 {
        isc_result_t result = ISC_R_SUCCESS;
        isc_boolean_t allow = ISC_FALSE;
@@ -6241,6 +6341,8 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
 
        if (!allow) {
                dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
+               if (num_zones != NULL)
+                       *num_zones = 0;
                return (ISC_R_SUCCESS);
        }
 
@@ -6252,7 +6354,12 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
 
        memset(nzcfg, 0, sizeof(*nzcfg));
 
-       dns_view_setnewzones(view, allow, nzcfg, newzone_cfgctx_destroy);
+       result = dns_view_setnewzones(view, allow, nzcfg,
+                                     newzone_cfgctx_destroy);
+       if (result != ISC_R_SUCCESS) {
+               isc_mem_free(view->mctx, nzcfg);
+               return (result);
+       }
 
        cfg_obj_attach(config, &nzcfg->config);
        if (vconfig != NULL)
@@ -6268,18 +6375,249 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
        isc_mem_attach(view->mctx, &nzcfg->mctx);
        cfg_aclconfctx_attach(actx, &nzcfg->actx);
 
-       /*
-        * This may be called in multiple views, so we reset
-        * the parser each time.
-        */
+       result = count_newzones(view, nzcfg, num_zones);
+       return (result);
+}
+
+#ifndef HAVE_LMDB
+
+static isc_result_t
+configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
+                  isc_mem_t *mctx, cfg_aclconfctx_t *actx)
+{
+       isc_result_t result;
+       ns_cfgctx_t *nzctx;
+       const cfg_obj_t *zonelist;
+       const cfg_listelt_t *element;
+
+       nzctx = view->new_zone_config;
+       if (nzctx == NULL || nzctx->nzf_config == NULL)
+               return (ISC_R_SUCCESS);
+
+       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                     NS_LOGMODULE_SERVER, ISC_LOG_INFO,
+                     "loading additional zones for view '%s'",
+                     view->name);
+
+       zonelist = NULL;
+       cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
+
+       for (element = cfg_list_first(zonelist);
+            element != NULL;
+            element = cfg_list_next(element))
+       {
+               const cfg_obj_t *zconfig = cfg_listelt_value(element);
+               CHECK(configure_zone(config, zconfig, vconfig,
+                                    mctx, view, NULL, actx,
+                                    ISC_TRUE, ISC_FALSE, ISC_FALSE));
+       }
+
+       result = ISC_R_SUCCESS;
+
+ cleanup:
+       return (result);
+}
+
+#else /* HAVE_LMDB */
+
+static isc_result_t
+data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data,
+          isc_buffer_t **text, cfg_obj_t **zoneconfig)
+{
+       isc_result_t result;
+       const char *zone_name;
+       size_t zone_name_len;
+       const char *zone_config;
+       size_t zone_config_len;
+       cfg_obj_t *zoneconf = NULL;
+
+       REQUIRE(view != NULL);
+       REQUIRE(key != NULL);
+       REQUIRE(data != NULL);
+       REQUIRE(text != NULL);
+       REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
+
+       if (*text == NULL) {
+               result = isc_buffer_allocate(view->mctx, text, 256);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup;
+       } else {
+               isc_buffer_clear(*text);
+       }
+
+       zone_name = (const char *) key->mv_data;
+       zone_name_len = key->mv_size;
+       INSIST(zone_name != NULL && zone_name_len > 0);
+
+       zone_config = (const char *) data->mv_data;
+       zone_config_len = data->mv_size;
+       INSIST(zone_config != NULL && zone_config_len > 0);
+
+       /* zone zonename { config; }; */
+       result = isc_buffer_reserve(text, 5 + zone_name_len + 1 +
+                                   zone_config_len + 2);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       putstr(text, "zone ");
+       putmem(text, (const void *) zone_name, zone_name_len);
+       putstr(text, " ");
+       putmem(text, (const void *) zone_config, zone_config_len);
+       putstr(text, ";\n");
+
        cfg_parser_reset(ns_g_addparser);
-       result = cfg_parse_file(ns_g_addparser, view->new_zone_file,
-                               &cfg_type_addzoneconf, &nzcfg->nzconfig);
-       if (result == ISC_R_FILENOTFOUND)
+       result = cfg_parse_buffer2(ns_g_addparser, *text, zone_name,
+                                  &cfg_type_addzoneconf, &zoneconf);
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                             NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
+                             "parsing config for zone '%.*s' in "
+                             "NZD database '%s' failed",
+                             (int) zone_name_len, zone_name,
+                             view->new_zone_db);
+               goto cleanup;
+       }
+
+       *zoneconfig = zoneconf;
+       zoneconf = NULL;
+       result = ISC_R_SUCCESS;
+
+ cleanup:
+       if (zoneconf != NULL)
+               cfg_obj_destroy(ns_g_addparser, &zoneconf);
+
+       return (result);
+}
+
+static isc_result_t
+configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
+                  isc_mem_t *mctx, cfg_aclconfctx_t *actx)
+{
+       isc_result_t result = ISC_R_SUCCESS;
+       int status;
+       isc_buffer_t *text = NULL;
+       cfg_obj_t *zoneconf = NULL;
+       MDB_cursor *cursor = NULL;
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+       MDB_val key, data;
+
+       if (view->new_zone_config == NULL)
+               return (ISC_R_SUCCESS);
+
+       result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
+       if (result != ISC_R_SUCCESS) {
                result = ISC_R_SUCCESS;
+               goto cleanup;
+       }
+
+       isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO, "loading NZD configs from '%s' "
+                     "for view '%s'",
+                     view->new_zone_db, view->name);
+
+       status = mdb_cursor_open(txn, dbi, &cursor);
+       if (status != 0) {
+               result = ISC_R_FAILURE;
+               goto cleanup;
+       }
+
+       while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == 0) {
+               const cfg_obj_t *zlist = NULL;
+               const cfg_obj_t *zoneobj = NULL;
+
+               result = data_to_cfg(view, &key, &data, &text, &zoneconf);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup;
+
+               CHECK(cfg_map_get(zoneconf, "zone", &zlist));
+               if (!cfg_obj_islist(zlist))
+                       CHECK(ISC_R_FAILURE);
+
+               zoneobj = cfg_listelt_value(cfg_list_first(zlist));
+               CHECK(configure_zone(config, zoneobj, vconfig,
+                                    mctx, view, NULL, actx,
+                                    ISC_TRUE, ISC_FALSE, ISC_FALSE));
+
+               cfg_obj_destroy(ns_g_addparser, &zoneconf);
+       }
+
+       result = ISC_R_SUCCESS;
+
+ cleanup:
+       if (cursor != NULL)
+               mdb_cursor_close(cursor);
+       (void) nzd_close(&txn, ISC_FALSE);
+       if (zoneconf != NULL)
+               cfg_obj_destroy(ns_g_addparser, &zoneconf);
+       if (text != NULL)
+               isc_buffer_free(&text);
+
+       return (result);
+}
+
+static isc_result_t
+get_newzone_config(dns_view_t *view, const char *zonename,
+                  cfg_obj_t **zoneconfig)
+{
+       isc_result_t result;
+       int status;
+       cfg_obj_t *zoneconf = NULL;
+       isc_buffer_t *text = NULL;
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+       MDB_val key, data;
+       char zname[DNS_NAME_FORMATSIZE];
+       dns_fixedname_t fname;
+       dns_name_t *name;
+       isc_buffer_t b;
+
+       INSIST(zoneconfig != NULL && *zoneconfig == NULL);
+
+       CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
+
+       isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO, "loading NZD config from '%s' "
+                     "for zone '%s'",
+                     view->new_zone_db, zonename);
+
+       /* Normalize zone name */
+       isc_buffer_constinit(&b, zonename, strlen(zonename));
+       isc_buffer_add(&b, strlen(zonename));
+       dns_fixedname_init(&fname);
+       name = dns_fixedname_name(&fname);
+       CHECK(dns_name_fromtext(name, &b, dns_rootname,
+                               DNS_NAME_DOWNCASE, NULL));
+       dns_name_format(name, zname, sizeof(zname));
+
+       key.mv_data = zname;
+       key.mv_size = strlen(zname);
+
+       status = mdb_get(txn, dbi, &key, &data);
+       if (status != 0)
+               CHECK(ISC_R_FAILURE);
+
+       CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
+
+       *zoneconfig = zoneconf;
+       zoneconf = NULL;
+       result = ISC_R_SUCCESS;
+
+ cleanup:
+       (void) nzd_close(&txn, ISC_FALSE);
+
+       if (zoneconf != NULL)
+               cfg_obj_destroy(ns_g_addparser, &zoneconf);
+       if (text != NULL)
+               isc_buffer_free(&text);
+
        return (result);
 }
 
+#endif /* HAVE_LMDB */
+
 static int
 count_zones(const cfg_obj_t *conf) {
        const cfg_obj_t *zonelist = NULL;
@@ -6410,7 +6748,6 @@ load_configuration(const char *filename, ns_server_t *server,
        isc_uint32_t transfer_message_size;
        ns_cache_t *nsc;
        ns_cachelist_t cachelist, tmpcachelist;
-       ns_cfgctx_t *nzctx;
        unsigned int maxsocks;
        isc_uint32_t softquota = 0;
 
@@ -6966,6 +7303,8 @@ load_configuration(const char *filename, ns_server_t *server,
        {
                cfg_obj_t *vconfig = cfg_listelt_value(element);
                const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
+               int nzf_num_zones;
+
                view = NULL;
 
                CHECK(create_view(vconfig, &viewlist, &view));
@@ -6974,10 +7313,8 @@ load_configuration(const char *filename, ns_server_t *server,
                num_zones += count_zones(voptions);
 
                CHECK(setup_newzones(view, config, vconfig, conf_parser,
-                                    ns_g_aclconfctx));
-               nzctx = view->new_zone_config;
-               if (nzctx != NULL && nzctx->nzconfig != NULL)
-                       num_zones += count_zones(nzctx->nzconfig);
+                                    ns_g_aclconfctx, &nzf_num_zones));
+               num_zones += nzf_num_zones;
 
                dns_view_detach(&view);
        }
@@ -6987,17 +7324,16 @@ load_configuration(const char *filename, ns_server_t *server,
         * view here.
         */
        if (views == NULL) {
+               int nzf_num_zones;
+
                CHECK(create_view(NULL, &viewlist, &view));
                INSIST(view != NULL);
 
                num_zones = count_zones(config);
 
                CHECK(setup_newzones(view, config, NULL, conf_parser,
-                                    ns_g_aclconfctx));
-
-               nzctx = view->new_zone_config;
-               if (nzctx != NULL && nzctx->nzconfig != NULL)
-                       num_zones += count_zones(nzctx->nzconfig);
+                                    ns_g_aclconfctx, &nzf_num_zones));
+               num_zones += nzf_num_zones;
 
                dns_view_detach(&view);
        }
@@ -10171,6 +10507,8 @@ ns_smf_add_message(isc_buffer_t **text) {
 }
 #endif /* HAVE_LIBSCF */
 
+#ifndef HAVE_LMDB
+
 /*
  * Emit a comment at the top of the nzf file containing the viewname
  * Expects the fp to already be open for writing
@@ -10188,164 +10526,420 @@ add_comment(FILE *fp, const char *viewname) {
        return (result);
 }
 
-#if 0
-/*
- * XXXMPA When we move to using a database instead of a flat file
- * we will use nzf_remove.  Remember that we need to use a cannonical
- * form of the zone name when we do.
- */
+static void
+dumpzone(void *arg, const char *buf, int len) {
+       FILE *fp = arg;
+
+       (void) isc_stdio_write(buf, len, 1, fp, NULL);
+}
+
 static isc_result_t
-nzf_remove(const char *nzfile, const char *viewname, const char *zonename) {
+nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
        isc_result_t result;
-       FILE *ifp = NULL, *ofp = NULL;
-       size_t znamelen = 0;
-       char tmp[1024], buf[1024];
-       isc_boolean_t inheader = ISC_TRUE;
-
-       znamelen = strlen(zonename);
-
-       /* Rewrite zone list */
-       result = isc_stdio_open(nzfile, "r", &ifp);
-       if (ifp != NULL && result == ISC_R_SUCCESS) {
-               char *found = NULL, *p = NULL;
-               size_t n;
-
-               /* Create a temporary file */
-               CHECK(isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp)));
-               CHECK(isc_file_openunique(tmp, &ofp));
-               CHECK(add_comment(ofp, viewname));
-
-               /* Look for the entry for that zone */
-               while (fgets(buf, 1024, ifp)) {
-                       /* Skip initial comment, if any */
-                       if (inheader && *buf == '#')
-                               continue;
-                       if (*buf != '#')
-                               inheader = ISC_FALSE;
+       off_t offset;
+       FILE *fp = NULL;
 
-                       /*
-                        * Any other lines not starting with zone, copy
-                        * them out and continue.
-                        */
-                       if (strncasecmp(buf, "zone", 4) != 0) {
-                               fputs(buf, ofp);
-                               continue;
-                       }
-                       p = buf+4;
+       LOCK(&view->new_zone_lock);
 
-                       /* This is a zone; find its name. */
-                       while (*p &&
-                              ((*p == '"') || isspace((unsigned char)*p)))
-                               p++;
+       CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
+       CHECK(isc_stdio_seek(fp, 0, SEEK_END));
 
-                       /*
-                        * If it's not the zone we're looking for, copy
-                        * it out and continue
-                        */
-                       if (strncasecmp(p, zonename, znamelen) != 0) {
-                               fputs(buf, ofp);
-                               continue;
-                       }
+       CHECK(isc_stdio_tell(fp, &offset));
+       if (offset == 0)
+               CHECK(add_comment(fp, view->name));
 
-                       /*
-                        * But if it is the zone we want, skip over it
-                        * so it will be omitted from the new file
-                        */
-                       p += znamelen;
-                       if (isspace((unsigned char)*p) ||
-                           *p == '"' || *p == '{') {
-                               /* This must be the entry */
-                               found = p;
-                               break;
-                       }
+       CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
+       cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
+       CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
 
-                       /* Copy the buffer out and continue */
-                       fputs(buf, ofp);
-               }
+ cleanup:
+       isc_stdio_flush(fp);
+       isc_stdio_close(fp);
+       UNLOCK(&view->new_zone_lock);
+       return (result);
+}
 
-               /* Skip over an option block (matching # of braces) */
-               if (found) {
-                       int openbrace = 0, closebrace = 0;
-                       for (;;) {
-                               while (*p) {
-                                       if (*p == '{') openbrace++;
-                                       if (*p == '}') closebrace++;
-                                       p++;
-                               }
-                               if (openbrace && (openbrace == closebrace))
-                                       break;
-                               if (!fgets(buf, 1024, ifp))
-                                       break;
-                               p = buf;
-                       }
+static isc_result_t
+nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
+       FILE *fp = NULL;
+       char tmp[1024];
+       isc_result_t result;
 
-                       /* Just spool the remainder of the file out */
-                       result = isc_stdio_read(buf, 1, 1024, ifp, &n);
-                       while (n > 0U) {
-                               if (result == ISC_R_EOF)
-                                       result = ISC_R_SUCCESS;
-                               CHECK(result);
-                               isc_stdio_write(buf, 1, n, ofp, NULL);
-                               result = isc_stdio_read(buf, 1, 1024, ifp, &n);
-                       }
+       result = isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp));
+       if (result == ISC_R_SUCCESS)
+               result = isc_file_openunique(tmp, &fp);
+       if (result != ISC_R_SUCCESS)
+               return (result);
 
-                       /*
-                        * Close files before overwriting the nzfile
-                        * with the temporary file as it's necessary on
-                        * some platforms (win32).
-                        */
-                       (void) isc_stdio_close(ifp);
-                       ifp = NULL;
-                       (void) isc_stdio_close(ofp);
-                       ofp = NULL;
+       CHECK(add_comment(fp, view->name));     /* force a comment */
 
-                       /* Move temporary into place */
-                       CHECK(isc_file_rename(tmp, nzfile));
-               } else {
-                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
-                                     NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
-                                     "deleted zone %s was missing from "
-                                     "new zone file", zonename);
+       cfg_printx(config, CFG_PRINTER_ONELINE, dumpzone, fp);
+
+       CHECK(isc_stdio_flush(fp));
+       CHECK(isc_stdio_close(fp));
+       fp = NULL;
+       CHECK(isc_file_rename(tmp, view->new_zone_file));
+       return (result);
+
+ cleanup:
+       if (fp != NULL)
+               (void) isc_stdio_close(fp);
+       isc_file_remove(tmp);
+       return (result);
+}
+
+#else /* HAVE_LMDB */
+
+static void
+nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
+       dns_fixedname_t fixed;
+
+       dns_fixedname_init(&fixed);
+       dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
+       dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
+       
+       key->mv_data = namebuf;
+       key->mv_size = strlen(namebuf);
+}
+
+static void
+dumpzone(void *arg, const char *buf, int len) {
+       isc_buffer_t **text = arg;
+
+       putmem(text, buf, len);
+}
+
+static isc_result_t
+nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
+        const cfg_obj_t *zconfig)
+{
+       isc_result_t result;
+       int status;
+       dns_view_t *view;
+       isc_boolean_t commit = ISC_FALSE;
+       isc_buffer_t *text = NULL;
+       char namebuf[1024];
+       MDB_val key, data;
+
+       view = dns_zone_getview(zone);
+
+       nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
+
+       LOCK(&view->new_zone_lock);
+
+       if (zconfig == NULL) {
+               /* We're deleting the zone from the database */
+               status = mdb_del(*txnp, dbi, &key, NULL);
+               if (status != 0 && status != MDB_NOTFOUND) {
+                       isc_log_write(ns_g_lctx,
+                                     NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER,
+                                     ISC_LOG_ERROR,
+                                     "Error deleting zone %s "
+                                     "from NZD database: %s",
+                                     namebuf, mdb_strerror(status));
+                       result = ISC_R_FAILURE;
+                       goto cleanup;
+               } else if (status != MDB_NOTFOUND)
+                       commit = ISC_TRUE;
+       } else {
+               /* We're creating or overwriting the zone */
+               const cfg_obj_t *zoptions;
+
+               result = isc_buffer_allocate(view->mctx, &text, 256);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup;
+
+               zoptions = cfg_tuple_get(zconfig, "options");
+               if (zoptions == NULL) {
+                       result = ISC_R_FAILURE;
+                       goto cleanup;
+               }
+
+               cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &text);
+
+               data.mv_data = isc_buffer_base(text);
+               data.mv_size = isc_buffer_usedlength(text);
+
+               status = mdb_put(*txnp, dbi, &key, &data, 0);
+               if (status != 0) {
+                       isc_log_write(ns_g_lctx,
+                                     NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER,
+                                     ISC_LOG_ERROR,
+                                     "Error inserting zone in "
+                                     "NZD database: %s",
+                                     mdb_strerror(status));
+                       result = ISC_R_FAILURE;
                        goto cleanup;
                }
+
+               commit = ISC_TRUE;
        }
 
+       result = ISC_R_SUCCESS;
+
  cleanup:
-       if (ifp != NULL)
-               (void) isc_stdio_close(ifp);
-       if (ofp != NULL)
-               (void) isc_stdio_close(ofp);
+       if (!commit || result != ISC_R_SUCCESS)
+               (void) mdb_txn_abort(*txnp);
+       else {
+               status = mdb_txn_commit(*txnp);
+               if (status != 0)
+                       result = ISC_R_FAILURE;
+       }
+       *txnp = NULL;
 
+       UNLOCK(&view->new_zone_lock);
+
+       if (text != NULL)
+               isc_buffer_free(&text);
        return (result);
 }
-#endif
 
-static void
-dumpzone(void *arg, const char *buf, int len) {
-       FILE *fp = arg;
+static isc_result_t
+nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
+       int status;
+       MDB_txn *txn = NULL;
 
-       (void) isc_stdio_write(buf, len, 1, fp, NULL);
+       REQUIRE(view != NULL);
+       REQUIRE(txnp != NULL && *txnp == NULL);
+       REQUIRE(dbi != NULL);
+
+       status = mdb_txn_begin((MDB_env *) view->new_zone_dbenv, 0,
+                              flags, &txn);
+       if (status != 0) {
+               isc_log_write(ns_g_lctx,
+                             NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_WARNING, "mdb_txn_begin: %s",
+                             mdb_strerror(status));
+               goto cleanup;
+       }
+
+       status = mdb_dbi_open(txn, NULL, 0, dbi);
+       if (status != 0) {
+               isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_WARNING, "mdb_dbi_open: %s",
+                             mdb_strerror(status));
+               goto cleanup;
+       }
+
+       *txnp = txn;
+
+ cleanup:
+       if (status != 0) {
+               if (txn != NULL)
+                       mdb_txn_abort(txn);
+               return (ISC_R_FAILURE);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+nzd_close(MDB_txn **txnp, isc_boolean_t commit) {
+       isc_result_t result = ISC_R_SUCCESS;
+       int status;
+
+       REQUIRE(txnp != NULL);
+
+       if (*txnp != NULL) {
+               if (commit) {
+                       status = mdb_txn_commit(*txnp);
+                       if (status != 0)
+                               result = ISC_R_FAILURE;
+               } else
+                       mdb_txn_abort(*txnp);
+               *txnp = NULL;
+       }
+
+       return (result);
 }
 
 static isc_result_t
-nzf_append(FILE *fp, const char *viewname, const cfg_obj_t *zconfig) {
+nzd_count(dns_view_t *view, int *countp) {
        isc_result_t result;
-       off_t offset;
+       int status;
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+       MDB_stat stat;
 
-       CHECK(isc_stdio_seek(fp, 0, SEEK_END));
+       REQUIRE(countp != NULL);
 
-       CHECK(isc_stdio_tell(fp, &offset));
-       if (offset == 0)
-               CHECK(add_comment(fp, viewname));
+       result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
 
-       CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
-       cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
-       CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
+       status = mdb_stat(txn, dbi, &stat);
+       if (status != 0) {
+               isc_log_write(ns_g_lctx,
+                             NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_WARNING, "mdb_stat: %s",
+                             mdb_strerror(status));
+               result = ISC_R_FAILURE;
+               goto cleanup;
+       }
+
+       *countp = stat.ms_entries;
+
+ cleanup:
+       (void) nzd_close(&txn, ISC_FALSE);
+
+       return (result);
+}
+
+static isc_result_t
+migrate_nzf(dns_view_t *view) {
+       isc_result_t result;
+       cfg_obj_t *nzf_config = NULL;
+       int status, n;
+       isc_buffer_t *text = NULL;
+       isc_boolean_t commit = ISC_FALSE;
+       const cfg_obj_t *zonelist;
+       const cfg_listelt_t *element;
+       char tempname[PATH_MAX];
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+       MDB_val key, data;
+
+       /*
+        * If NZF file doesn't exist, or NZD DB exists and already
+        * has data, return without attempting migration.
+        */
+       if (!isc_file_exists(view->new_zone_file)) {
+               result = ISC_R_SUCCESS;
+               goto cleanup;
+       }
+
+       result = nzd_count(view, &n);
+       if (result == ISC_R_SUCCESS && n > 0) {
+               result = ISC_R_SUCCESS;
+               goto cleanup;
+       }
+
+       isc_log_write(ns_g_lctx,
+                     NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO,
+                     "Migrating zones from NZF file '%s' to "
+                     "NZD database '%s'",
+                     view->new_zone_file, view->new_zone_db);
+       /*
+        * Instead of blindly copying lines, we parse the NZF file using
+        * the configuration parser, because it validates it against the
+        * config type, giving us a guarantee that valid configuration
+        * will be written to DB.
+        */
+       cfg_parser_reset(ns_g_addparser);
+       result = cfg_parse_file(ns_g_addparser, view->new_zone_file,
+                               &cfg_type_addzoneconf, &nzf_config);
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(ns_g_lctx,
+                             NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                             ISC_LOG_ERROR,
+                             "Error parsing NZF file '%s': %s",
+                             view->new_zone_file,
+                             isc_result_totext(result));
+               goto cleanup;
+       }
+
+       zonelist = NULL;
+       CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
+       if (!cfg_obj_islist(zonelist))
+               CHECK(ISC_R_FAILURE);
+
+       CHECK(nzd_open(view, 0, &txn, &dbi));
+
+       CHECK(isc_buffer_allocate(view->mctx, &text, 256));
+
+       for (element = cfg_list_first(zonelist);
+            element != NULL;
+            element = cfg_list_next(element))
+       {
+               const cfg_obj_t *zconfig;
+               const cfg_obj_t *zoptions;
+               char zname[DNS_NAME_FORMATSIZE];
+               dns_fixedname_t fname;
+               dns_name_t *name;
+               const char *origin;
+               isc_buffer_t b;
+
+               zconfig = cfg_listelt_value(element);
+
+               origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
+               if (origin == NULL) {
+                       result = ISC_R_FAILURE;
+                       goto cleanup;
+               }
+
+               /* Normalize zone name */
+               isc_buffer_constinit(&b, origin, strlen(origin));
+               isc_buffer_add(&b, strlen(origin));
+               dns_fixedname_init(&fname);
+               name = dns_fixedname_name(&fname);
+               CHECK(dns_name_fromtext(name, &b, dns_rootname,
+                                       DNS_NAME_DOWNCASE, NULL));
+               dns_name_format(name, zname, sizeof(zname));
+
+               key.mv_data = zname;
+               key.mv_size = strlen(zname);
+
+               zoptions = cfg_tuple_get(zconfig, "options");
+               if (zoptions == NULL) {
+                       result = ISC_R_FAILURE;
+                       goto cleanup;
+               }
+
+               isc_buffer_clear(text);
+               cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &text);
+
+               data.mv_data = isc_buffer_base(text);
+               data.mv_size = isc_buffer_usedlength(text);
+
+               status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
+               if (status != 0) {
+                       isc_log_write(ns_g_lctx,
+                                     NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER,
+                                     ISC_LOG_ERROR,
+                                     "Error inserting zone in "
+                                     "NZD database: %s",
+                                     mdb_strerror(status));
+                       result = ISC_R_FAILURE;
+                       goto cleanup;
+               }
+
+               commit = ISC_TRUE;
+       }
+
+       result = ISC_R_SUCCESS;
+
+       /*
+        * Leaving the NZF file in place is harmless as we won't use it
+        * if an NZD database is found for the view. But we rename NZF file
+        * to a backup name here.
+        */
+       strlcpy(tempname, view->new_zone_file, sizeof(tempname));
+       if (strlen(tempname) < sizeof(tempname) - 1) {
+               strcat(tempname, "~");
+               isc_file_rename(view->new_zone_file, tempname);
+       }
 
  cleanup:
+       if (result != ISC_R_SUCCESS)
+               (void) nzd_close(&txn, ISC_FALSE);
+       else
+               result = nzd_close(&txn, commit);
+
+       if (text != NULL)
+               isc_buffer_free(&text);
+       if (nzf_config != NULL)
+               cfg_obj_destroy(ns_g_addparser, &nzf_config);
+
        return (result);
 }
 
+#endif /* HAVE_LMDB */
+
 static isc_result_t
 newzone_parse(ns_server_t *server, char *command, dns_view_t **viewp,
              cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
@@ -10428,57 +11022,34 @@ newzone_parse(ns_server_t *server, char *command, dns_view_t **viewp,
 }
 
 static isc_result_t
-nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
-       FILE *fp = NULL;
-       char tmp[1024];
-       isc_result_t result;
-
-       result = isc_file_template("", "nzf-XXXXXXXX", tmp, sizeof(tmp));
-       if (result == ISC_R_SUCCESS)
-               result = isc_file_openunique(tmp, &fp);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       CHECK(add_comment(fp, view->name));     /* force a comment */
-
-       cfg_printx(config, CFG_PRINTER_ONELINE, dumpzone, fp);
-
-       CHECK(isc_stdio_flush(fp));
-       CHECK(isc_stdio_close(fp));
-       fp = NULL;
-       CHECK(isc_file_rename(tmp, view->new_zone_file));
-       return (result);
-
- cleanup:
-       if (fp != NULL)
-               (void) isc_stdio_close(fp);
-       isc_file_remove(tmp);
-       return (result);
-}
-
-static isc_result_t
-delete_zoneconf(cfg_parser_t *pctx, const cfg_obj_t *config,
-               const dns_name_t *zname)
+delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx,
+               const cfg_obj_t *config, const dns_name_t *zname,
+               nzfwriter_t nzfwriter)
 {
+       isc_result_t result = ISC_R_NOTFOUND;
        const cfg_listelt_t *elt = NULL;
        const cfg_obj_t *zl = NULL;
        cfg_list_t *list;
-       dns_fixedname_t fixed;
+       dns_fixedname_t myfixed;
        dns_name_t *myname;
-       isc_result_t result;
 
+       REQUIRE(view != NULL);
        REQUIRE(pctx != NULL);
        REQUIRE(config != NULL);
        REQUIRE(zname != NULL);
 
+       LOCK(&view->new_zone_lock);
+
        cfg_map_get(config, "zone", &zl);
 
        if (! cfg_obj_islist(zl))
-               return (ISC_R_FAILURE);
+               CHECK(ISC_R_FAILURE);
+
        DE_CONST(&zl->value.list, list);
 
-       dns_fixedname_init(&fixed);
-       myname = dns_fixedname_name(&fixed);
+       dns_fixedname_init(&myfixed);
+       myname = dns_fixedname_name(&myfixed);
+
        for (elt = ISC_LIST_HEAD(*list);
             elt != NULL;
             elt = ISC_LIST_NEXT(elt, link))
@@ -10489,17 +11060,27 @@ delete_zoneconf(cfg_parser_t *pctx, const cfg_obj_t *config,
 
                zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
                result = dns_name_fromstring(myname, zn, 0, NULL);
-               if (result != ISC_R_SUCCESS || !dns_name_equal(zname, myname))
+               if (result != ISC_R_SUCCESS ||
+                   !dns_name_equal(zname, myname))
                        continue;
 
                DE_CONST(elt, e);
                ISC_LIST_UNLINK(*list, e, link);
                cfg_obj_destroy(pctx, &e->obj);
                isc_mem_put(pctx->mctx, e, sizeof(*e));
-               return (ISC_R_SUCCESS);
+               result = ISC_R_SUCCESS;
+               break;
        }
 
-       return (ISC_R_NOTFOUND);
+       /*
+        * Write config to NZF file if appropriate
+        */
+       if (nzfwriter != NULL && view->new_zone_file != NULL)
+               result = nzfwriter(config, view);
+
+ cleanup:
+       UNLOCK(&view->new_zone_lock);
+       return (result);
 }
 
 static isc_result_t
@@ -10509,7 +11090,14 @@ do_addzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
 {
        isc_result_t result, tresult;
        dns_zone_t *zone = NULL;
+#ifndef HAVE_LMDB
        FILE *fp = NULL;
+#else /* HAVE_LMDB */
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+
+       UNUSED(zoneconf);
+#endif /* HAVE_LMDB */
 
        /* Zone shouldn't already exist */
        result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
@@ -10523,25 +11111,45 @@ do_addzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        } else if (result != ISC_R_NOTFOUND)
                goto cleanup;
 
-       /* Make sure we can open the configuration save file */
+#ifndef HAVE_LMDB
+       /*
+        * Make sure we can open the configuration save file
+        */
        result = isc_stdio_open(view->new_zone_file, "a", &fp);
        if (result != ISC_R_SUCCESS) {
-               TCHECK(putstr(text, "unable to open '"));
+               TCHECK(putstr(text, "unable to create '"));
                TCHECK(putstr(text, view->new_zone_file));
                TCHECK(putstr(text, "': "));
                TCHECK(putstr(text, isc_result_totext(result)));
                goto cleanup;
        }
 
-       /* Mark view unfrozen so that zone can be added */
+       isc_stdio_close(fp);
+       fp = NULL;
+#else /* HAVE_LMDB */
+       /* Make sure we can open the NZD database */
+       result = nzd_open(view, 0, &txn, &dbi);
+       if (result != ISC_R_SUCCESS) {
+               TCHECK(putstr(text, "unable to open NZD database for '"));
+               TCHECK(putstr(text, view->new_zone_db));
+               TCHECK(putstr(text, "'"));
+               result = ISC_R_FAILURE;
+               goto cleanup;
+       }
+#endif /* HAVE_LMDB */
+
        result = isc_task_beginexclusive(server->task);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+       /* Mark view unfrozen and configure zone */
        dns_view_thaw(view);
        result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
                                server->mctx, view, NULL, cfg->actx,
                                ISC_TRUE, ISC_FALSE, ISC_FALSE);
        dns_view_freeze(view);
+
        isc_task_endexclusive(server->task);
+
        if (result != ISC_R_SUCCESS) {
                TCHECK(putstr(text, "configure_zone failed: "));
                TCHECK(putstr(text, isc_result_totext(result)));
@@ -10551,19 +11159,21 @@ do_addzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        /* Is it there yet? */
        CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
 
+#ifndef HAVE_LMDB
        /*
         * If there wasn't a previous newzone config, just save the one
         * we've created. If there was a previous one, merge the new
         * zone into it.
         */
-       if (cfg->nzconfig == NULL)
-               cfg_obj_attach(zoneconf, &cfg->nzconfig);
+       if (cfg->nzf_config == NULL)
+               cfg_obj_attach(zoneconf, &cfg->nzf_config);
        else {
                cfg_obj_t *z;
                DE_CONST(zoneobj, z);
                CHECK(cfg_parser_mapadd(cfg->add_parser,
-                                       cfg->nzconfig, z, "zone"));
+                                       cfg->nzf_config, z, "zone"));
        }
+#endif /* HAVE_LMDB */
 
        /*
         * Load the zone from the master file.  If this fails, we'll
@@ -10594,13 +11204,24 @@ do_addzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        /* Flag the zone as having been added at runtime */
        dns_zone_setadded(zone, ISC_TRUE);
 
-       /* Emit the zone configuration */
-       nzf_append(fp, view->name, zoneobj);
-       result = ISC_R_SUCCESS;
+#ifndef HAVE_LMDB
+       /* Append the zone configuration to the NZF */
+       result = nzf_append(view, zoneobj);
+#else /* HAVE_LMDB */
+       /* Save the new zone configuration into the NZD */
+       result = nzd_save(&txn, dbi, zone, zoneobj);
+#endif /* HAVE_LMDB */
 
  cleanup:
+
+#ifndef HAVE_LMDB
        if (fp != NULL)
                (void) isc_stdio_close(fp);
+#else /* HAVE_LMDB */
+       if (txn != NULL)
+               (void) nzd_close(&txn, ISC_FALSE);
+#endif /* HAVE_LMDB */
+
        if (zone != NULL)
                dns_zone_detach(&zone);
 
@@ -10615,8 +11236,14 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        isc_result_t result, tresult;
        dns_zone_t *zone = NULL;
        isc_boolean_t added;
+       isc_boolean_t exclusive = ISC_FALSE;
+#ifndef HAVE_LMDB
        FILE *fp = NULL;
        cfg_obj_t *z;
+#else /* HAVE_LMDB */
+       MDB_txn *txn = NULL;
+       MDB_dbi dbi;
+#endif /* HAVE_LMDB */
 
        /* Zone must already exist */
        result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
@@ -10626,6 +11253,19 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        added = dns_zone_getadded(zone);
        dns_zone_detach(&zone);
 
+#ifndef HAVE_LMDB
+       cfg = (ns_cfgctx_t *) view->new_zone_config;
+       if (cfg == NULL) {
+               TCHECK(putstr(text, "new zone config is not set"));
+               CHECK(ISC_R_FAILURE);
+       }
+#endif
+
+       result = isc_task_beginexclusive(server->task);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       exclusive = ISC_TRUE;
+
+#ifndef HAVE_LMDB
        /* Make sure we can open the configuration save file */
        result = isc_stdio_open(view->new_zone_file, "a", &fp);
        if (result != ISC_R_SUCCESS) {
@@ -10637,22 +11277,28 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        }
        isc_stdio_close(fp);
        fp = NULL;
-
-       cfg = (ns_cfgctx_t *) view->new_zone_config;
-       if (cfg == NULL) {
-               TCHECK(putstr(text, "new zone config is not set"));
-               CHECK(ISC_R_FAILURE);
+#else /* HAVE_LMDB */
+       /* Make sure we can open the NZD database */
+       result = nzd_open(view, 0, &txn, &dbi);
+       if (result != ISC_R_SUCCESS) {
+               TCHECK(putstr(text, "unable to open NZD database for '"));
+               TCHECK(putstr(text, view->new_zone_db));
+               TCHECK(putstr(text, "'"));
+               result = ISC_R_FAILURE;
+               goto cleanup;
        }
+#endif /* HAVE_LMDB */
 
        /* Reconfigure the zone */
-       result = isc_task_beginexclusive(server->task);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
        dns_view_thaw(view);
        result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
                                server->mctx, view, NULL, cfg->actx,
                                ISC_TRUE, ISC_FALSE, ISC_TRUE);
        dns_view_freeze(view);
+
+       exclusive = ISC_FALSE;
        isc_task_endexclusive(server->task);
+
        if (result != ISC_R_SUCCESS) {
                TCHECK(putstr(text, "configure_zone failed: "));
                TCHECK(putstr(text, isc_result_totext(result)));
@@ -10662,26 +11308,54 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        /* Is it there yet? */
        CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
 
+#ifndef HAVE_LMDB
        /* Remove old zone from configuration (and NZF file if applicable) */
        if (added) {
-               delete_zoneconf(cfg->add_parser, cfg->nzconfig,
-                               dns_zone_getorigin(zone));
-               nzf_writeconf(cfg->nzconfig, view);
-               /* nzf_remove(view->new_zone_file, view->name, zname); */
-       } else {
-               if (cfg->vconfig == NULL)
-                       delete_zoneconf(cfg->conf_parser, cfg->config,
-                                       dns_zone_getorigin(zone));
-               else {
+               result = delete_zoneconf(view, cfg->add_parser,
+                                        cfg->nzf_config,
+                                        dns_zone_getorigin(zone),
+                                        nzf_writeconf);
+               if (result != ISC_R_SUCCESS) {
+                       TCHECK(putstr(text, "former zone configuration "
+                                           "not deleted: "));
+                       TCHECK(putstr(text, isc_result_totext(result)));
+                       goto cleanup;
+               }
+       }
+#endif /* HAVE_LMDB */
+
+       if (!added) {
+               if (cfg->vconfig == NULL) {
+                       result = delete_zoneconf(view, cfg->conf_parser,
+                                                cfg->config,
+                                                dns_zone_getorigin(zone),
+                                                NULL);
+               } else {
                        const cfg_obj_t *voptions =
                                cfg_tuple_get(cfg->vconfig, "options");
-                       delete_zoneconf(cfg->conf_parser, voptions,
-                                       dns_zone_getorigin(zone));
+                       result = delete_zoneconf(view, cfg->conf_parser,
+                                                voptions,
+                                                dns_zone_getorigin(zone),
+                                                NULL);
+               }
+
+               if (result != ISC_R_SUCCESS) {
+                       TCHECK(putstr(text, "former zone configuration "
+                                           "not deleted: "));
+                       TCHECK(putstr(text, isc_result_totext(result)));
+                       goto cleanup;
                }
        }
 
        /* Load the zone from the master file if it needs reloading. */
        result = dns_zone_loadnew(zone);
+
+       /*
+        * Dynamic zones need no reloading, so we can pass this result.
+        */
+       if (result == DNS_R_DYNAMIC)
+               result = ISC_R_SUCCESS;
+
        if (result != ISC_R_SUCCESS) {
                dns_db_t *dbp = NULL;
 
@@ -10708,19 +11382,29 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
                goto cleanup;
        }
 
+#ifndef HAVE_LMDB
        /* Store the new zone configuration; also in NZF if applicable */
        DE_CONST(zoneobj, z);
-       CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzconfig, z, "zone"));
+       CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
+#endif /* HAVE_LMDB */
 
        if (added) {
+#ifndef HAVE_LMDB
                CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
-               nzf_append(fp, view->name, zoneobj);
-               (void) isc_stdio_close(fp);
-               fp = NULL;
+               result = nzf_append(view, zoneobj);
+               if (result != ISC_R_SUCCESS) {
+                       TCHECK(putstr(text, "\nNew zone config not saved: "));
+                       TCHECK(putstr(text, isc_result_totext(result)));
+                       goto cleanup;
+               }
+#else /* HAVE_LMDB */
+               nzd_save(&txn, dbi, zone, zoneobj);
+#endif /* HAVE_LMDB */
 
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zname));
                TCHECK(putstr(text, "' reconfigured."));
+
        } else {
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zname));
@@ -10729,8 +11413,17 @@ do_modzone(ns_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
        }
 
  cleanup:
+       if (exclusive)
+               isc_task_endexclusive(server->task);
+
+#ifndef HAVE_LMDB
        if (fp != NULL)
-               isc_stdio_close(fp);
+               (void) isc_stdio_close(fp);
+#else /* HAVE_LMDB */
+       if (txn != NULL)
+               (void) nzd_close(&txn, ISC_FALSE);
+#endif /* HAVE_LMDB */
+
        if (zone != NULL)
                dns_zone_detach(&zone);
 
@@ -10763,7 +11456,12 @@ ns_server_changezone(ns_server_t *server, char *command, isc_buffer_t **text) {
        CHECK(newzone_parse(server, command, &view, &zoneconf, &zoneobj, text));
 
        /* Are we accepting new zones in this view? */
-       if (view->new_zone_file == NULL) {
+#ifdef HAVE_LMDB
+       if (view->new_zone_db == NULL)
+#else
+       if (view->new_zone_file == NULL)
+#endif /* HAVE_LMDB */
+       {
                (void) putstr(text, "Not allowing new zones in view '");
                (void) putstr(text, view->name);
                (void) putstr(text, "'");
@@ -10829,23 +11527,164 @@ inuse(const char* file, isc_boolean_t first, isc_buffer_t **text) {
        return (first);
 }
 
+typedef struct {
+       dns_zone_t *zone;
+       isc_boolean_t cleanup;
+} ns_dzctx_t;
+
+/*
+ * Carry out a zone deletion scheduled by ns_server_addzone().
+ */
+static void
+rmzone(isc_task_t *task, isc_event_t *event) {
+       ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
+       dns_zone_t *zone, *raw = NULL, *mayberaw;
+       char zonename[DNS_NAME_FORMATSIZE];
+       dns_view_t *view;
+       ns_cfgctx_t *cfg;
+       dns_db_t *dbp = NULL;
+       isc_boolean_t added;
+       isc_result_t result;
+
+       REQUIRE(dz != NULL);
+
+       isc_event_free(&event);
+
+       /* Dig out configuration for this zone */
+       zone = dz->zone;
+       view = dns_zone_getview(zone);
+       cfg = (ns_cfgctx_t *) view->new_zone_config;
+       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,
+                     "deleting zone %s in view %s via delzone",
+                     zonename, view->name);
+
+       /* Remove the zone from configuration (and NZF file if applicable) */
+       added = dns_zone_getadded(zone);
+
+#ifndef HAVE_LMDB
+       if (added && cfg != NULL) {
+               result = delete_zoneconf(view, cfg->add_parser,
+                                        cfg->nzf_config,
+                                        dns_zone_getorigin(zone),
+                                        nzf_writeconf);
+               if (result != ISC_R_SUCCESS) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER,
+                                     ISC_LOG_WARNING, "unable to "
+                                     "delete zone configuration: %s",
+                                     isc_result_totext(result));
+               }
+       }
+#endif /* HAVE_LMDB */
+
+       if (!added && cfg != NULL) {
+               if (cfg->vconfig != NULL) {
+                       const cfg_obj_t *voptions =
+                               cfg_tuple_get(cfg->vconfig, "options");
+                       result = delete_zoneconf(view, cfg->conf_parser,
+                                                voptions,
+                                                dns_zone_getorigin(zone),
+                                                NULL);
+               } else {
+                       result = delete_zoneconf(view, cfg->conf_parser,
+                                                cfg->config,
+                                                dns_zone_getorigin(zone),
+                                                NULL);
+               }
+               if (result != ISC_R_SUCCESS){
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER,
+                                     ISC_LOG_WARNING, "unable to "
+                                     "delete zone configuration: %s",
+                                     isc_result_totext(result));
+               }
+       }
+
+       /* Unload zone database */
+       if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
+               dns_db_detach(&dbp);
+               dns_zone_unload(zone);
+       }
+
+       /* Clean up stub/slave zone files if requested to do so */
+       dns_zone_getraw(zone, &raw);
+       mayberaw = (raw != NULL) ? raw : zone;
+
+       if (added && dz->cleanup) {
+               const char *file;
+
+               file = dns_zone_getfile(mayberaw);
+               result = isc_file_remove(file);
+               if (result != ISC_R_SUCCESS) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
+                                     "file %s not removed: %s",
+                                     file, isc_result_totext(result));
+               }
+
+               file = dns_zone_getjournal(mayberaw);
+               result = isc_file_remove(file);
+               if (result != ISC_R_SUCCESS) {
+                       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                     NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
+                                     "file %s not removed: %s",
+                                     file, isc_result_totext(result));
+               }
+
+               if (zone != mayberaw) {
+                       file = dns_zone_getfile(zone);
+                       result = isc_file_remove(file);
+                       if (result != ISC_R_SUCCESS) {
+                               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                             NS_LOGMODULE_SERVER,
+                                             ISC_LOG_WARNING,
+                                             "file %s not removed: %s",
+                                             file, isc_result_totext(result));
+                       }
+
+                       file = dns_zone_getjournal(zone);
+                       result = isc_file_remove(file);
+                       if (result != ISC_R_SUCCESS) {
+                               isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                                             NS_LOGMODULE_SERVER,
+                                             ISC_LOG_WARNING,
+                                             "file %s not removed: %s",
+                                             file, isc_result_totext(result));
+                       }
+               }
+       }
+
+       if (raw != NULL)
+               dns_zone_detach(&raw);
+       dns_zone_detach(&zone);
+       isc_mem_put(ns_g_mctx, dz, sizeof(*dz));
+       isc_task_detach(&task);
+}
+
 /*
  * Act on a "delzone" command from the command channel.
  */
 isc_result_t
 ns_server_delzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
        isc_result_t result, tresult;
-       ns_cfgctx_t *cfg = NULL;
        dns_zone_t *zone = NULL;
        dns_zone_t *raw = NULL;
        dns_zone_t *mayberaw;
        dns_view_t *view = NULL;
-       dns_db_t *dbp = NULL;
        char zonename[DNS_NAME_FORMATSIZE];
        isc_boolean_t exclusive = ISC_FALSE;
        isc_boolean_t cleanup = ISC_FALSE;
-       const char *file, *ptr;
+       const char *ptr;
        isc_boolean_t added;
+       ns_dzctx_t *dz = NULL;
+       isc_event_t *dzevent = NULL;
+       isc_task_t *task = NULL;
+#ifdef HAVE_LMDB
+       MDB_txn *txn = NULL;
+#endif /* HAVE_LMDB */
 
        /* Skip the command name. */
        ptr = next_token(lex, text);
@@ -10881,75 +11720,53 @@ ns_server_delzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
                goto cleanup;
        }
 
-       result = isc_task_beginexclusive(server->task);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       exclusive = ISC_TRUE;
-
-       /* Dig out configuration for this zone */
        view = dns_zone_getview(zone);
-       cfg = (ns_cfgctx_t *) view->new_zone_config;
-
-       /* Remove the zone from the new_zone_file if applicable */
-       added = dns_zone_getadded(zone);
-       if (added && cfg != NULL) {
-               delete_zoneconf(cfg->add_parser, cfg->nzconfig,
-                               dns_zone_getorigin(zone));
-               if (view->new_zone_file != NULL)
-                       nzf_writeconf(cfg->nzconfig, view);
-       } else if (cfg != NULL) {
-               if (cfg->vconfig != NULL) {
-                       const cfg_obj_t *voptions =
-                               cfg_tuple_get(cfg->vconfig, "options");
-                       delete_zoneconf(cfg->conf_parser, voptions,
-                                       dns_zone_getorigin(zone));
-               } else {
-                       delete_zoneconf(cfg->conf_parser, cfg->config,
-                                       dns_zone_getorigin(zone));
-               }
-       }
-
-       /* Stop answering for this zone */
-       if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
-               dns_db_detach(&dbp);
-               dns_zone_unload(zone);
-       }
+       CHECK(dns_zt_unmount(view->zonetable, zone));
 
-       /* Clean up stub / slave zone files */
+       /* Send cleanup event */
+       dz = isc_mem_get(ns_g_mctx, sizeof(*dz));
+       if (dz == NULL)
+               CHECK(ISC_R_NOMEMORY);
+
+       dz->cleanup = cleanup;
+       dz->zone = NULL;
+       dns_zone_attach(zone, &dz->zone);
+       dzevent = isc_event_allocate(ns_g_mctx, server, NS_EVENT_DELZONE,
+                                    rmzone, dz, sizeof(isc_event_t));
+       if (dzevent == NULL)
+               CHECK(ISC_R_NOMEMORY);
+
+       dns_zone_gettask(zone, &task);
+       isc_task_send(task, &dzevent);
+       dz = NULL;
+       dzevent = NULL;
+
+       /* Inform user about cleaning up stub/slave zone files */
        dns_zone_getraw(zone, &raw);
        mayberaw = (raw != NULL) ? raw : zone;
 
+       added = dns_zone_getadded(zone);
        if (!added) {
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zonename));
-               TCHECK(putstr(text, "' is no longer loaded.\n"));
+               TCHECK(putstr(text,
+                             "' is no longer active and will be deleted.\n"));
                TCHECK(putstr(text, "To keep it from returning "));
                TCHECK(putstr(text, "when the server is restarted, it\n"));
                TCHECK(putstr(text, "must also be removed from named.conf."));
        } else if (cleanup) {
-               file = dns_zone_getfile(mayberaw);
-               isc_file_remove(file);
-
-               file = dns_zone_getjournal(mayberaw);
-               isc_file_remove(file);
-
-               if (zone != mayberaw) {
-                       file = dns_zone_getfile(zone);
-                       isc_file_remove(file);
-
-                       file = dns_zone_getjournal(zone);
-                       isc_file_remove(file);
-               }
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zonename));
-               TCHECK(putstr(text, "' and associated files were deleted."));
+               TCHECK(putstr(text, "' and associated files will be deleted."));
        } else if (dns_zone_gettype(mayberaw) == dns_zone_slave ||
                   dns_zone_gettype(mayberaw) == dns_zone_stub)
        {
                isc_boolean_t first;
+               const char *file;
 
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zonename));
-               TCHECK(putstr(text, "' was deleted."));
+               TCHECK(putstr(text, "' will be deleted."));
 
                file = dns_zone_getfile(mayberaw);
                first = inuse(file, ISC_TRUE, text);
@@ -10966,11 +11783,9 @@ ns_server_delzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
                }
        }
 
-       CHECK(dns_zt_unmount(view->zonetable, zone));
-
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
-                                 NS_LOGMODULE_SERVER, ISC_LOG_INFO,
-                                 "zone %s removed via delzone", zonename);
+                     NS_LOGMODULE_SERVER, ISC_LOG_INFO,
+                     "zone %s scheduled for removal via delzone", zonename);
 
        /* Removing a zone counts as reconfiguration */
        CHECK(isc_time_now(&ns_g_configtime));
@@ -10978,21 +11793,28 @@ ns_server_delzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
        result = ISC_R_SUCCESS;
 
  cleanup:
+       if (exclusive)
+               isc_task_endexclusive(server->task);
        if (isc_buffer_usedlength(*text) > 0)
                (void) putnull(text);
        if (raw != NULL)
                dns_zone_detach(&raw);
-       if (exclusive)
-               isc_task_endexclusive(server->task);
        if (zone != NULL)
                dns_zone_detach(&zone);
+       if (dzevent != NULL)
+               isc_event_free(&dzevent);
+       if (dz != NULL) {
+               dns_zone_detach(&dz->zone);
+               isc_mem_put(ns_g_mctx, dz, sizeof(*dz));
+       }
+#ifdef HAVE_LMDB
+       if (txn != NULL)
+               (void) nzd_close(&txn, ISC_FALSE);
+#endif /* HAVE_LMDB */
 
        return (result);
 }
 
-/*
- * Act on a "showzone" command from the command channel.
- */
 static const cfg_obj_t *
 find_name_in_list_from_map(const cfg_obj_t *config,
                           const char *map_key_for_list,
@@ -11049,6 +11871,9 @@ emitzone(void *arg, const char *buf, int len) {
        putmem(tpp, buf, len);
 }
 
+/*
+ * Act on a "showzone" command from the command channel.
+ */
 isc_result_t
 ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
        isc_result_t result;
@@ -11059,6 +11884,9 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
        dns_zone_t *zone = NULL;
        ns_cfgctx_t *cfg = NULL;
        isc_boolean_t exclusive = ISC_FALSE;
+#ifdef HAVE_LMDB
+       cfg_obj_t *nzconfig = NULL;
+#endif /* HAVE_LMDB */
 
        /* Parse parameters */
        CHECK(zone_from_args(server, lex, NULL, &zone, zonename,
@@ -11091,9 +11919,23 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
                map = cfg->config;
 
        zconfig = find_name_in_list_from_map(map, "zone", zonename);
-       if (zconfig == NULL && cfg->nzconfig != NULL)
-               zconfig = find_name_in_list_from_map(cfg->nzconfig,
+
+#ifndef HAVE_LMDB
+       if (zconfig == NULL && cfg->nzf_config != NULL)
+               zconfig = find_name_in_list_from_map(cfg->nzf_config,
                                                     "zone", zonename);
+#else /* HAVE_LMDB */
+       if (zconfig == NULL) {
+               const cfg_obj_t *zlist = NULL;
+               CHECK(get_newzone_config(view, zonename, &nzconfig));
+               CHECK(cfg_map_get(nzconfig, "zone", &zlist));
+               if (!cfg_obj_islist(zlist))
+                       CHECK(ISC_R_FAILURE);
+
+               zconfig = cfg_listelt_value(cfg_list_first(zlist));
+       }
+#endif /* HAVE_LMDB */
+
        if (zconfig == NULL)
                CHECK(ISC_R_NOTFOUND);
 
@@ -11104,6 +11946,10 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
        result = ISC_R_SUCCESS;
 
  cleanup:
+#ifdef HAVE_LMDB
+       if (nzconfig != NULL)
+               cfg_obj_destroy(ns_g_addparser, &nzconfig);
+#endif /* HAVE_LMDB */
        if (isc_buffer_usedlength(*text) > 0)
                (void) putnull(text);
        if (exclusive)
@@ -11115,6 +11961,7 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
 static void
 newzone_cfgctx_destroy(void **cfgp) {
        ns_cfgctx_t *cfg;
+       isc_mem_t *mctx;
 
        REQUIRE(cfgp != NULL && *cfgp != NULL);
 
@@ -11128,15 +11975,16 @@ newzone_cfgctx_destroy(void **cfgp) {
                cfg_parser_destroy(&cfg->conf_parser);
        }
        if (cfg->add_parser != NULL) {
-               if (cfg->nzconfig != NULL)
-                       cfg_obj_destroy(cfg->add_parser, &cfg->nzconfig);
+               if (cfg->nzf_config != NULL)
+                       cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
                cfg_parser_destroy(&cfg->add_parser);
        }
 
        if (cfg->actx != NULL)
                cfg_aclconfctx_detach(&cfg->actx);
 
-       isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
+       mctx = cfg->mctx;
+       isc_mem_putanddetach(&mctx, cfg, sizeof(*cfg));
        *cfgp = NULL;
 }
 
index f5da8f4ee446b0f75280e5dc97fa1551ee2b6826..0eac23e6f1045da99305a355b71589f549aa019d 100644 (file)
@@ -13,6 +13,8 @@ rm -f rndc.out*
 rm -f ns2/named.conf
 rm -f */named.memstats
 rm -f ns2/*.nzf
+rm -f ns2/*.nzf~
+rm -f ns2/*.nzd ns2/*.nzd-lock
 rm -f ns2/core*
 rm -f ns2/inline.db.jbk
 rm -f ns2/inline.db.signed
index 061ea4986774499ffa926f38591c0b9729129198..c1e3c2893254b1e78d7e090ee973d18d84884796 100755 (executable)
@@ -22,6 +22,8 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+# When LMDB support is compiled in, this tests that migration from
+# NZF to NZD occurs during named startup
 echo "I:checking previously added zone ($n)"
 ret=0
 $DIG $DIGOPTS @10.53.0.2 a.previous.example a > dig.out.ns2.$n || ret=1
@@ -31,6 +33,14 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+if [ -n "$NZD" ]; then
+    echo "I:checking that existing NZF file was renamed after migration ($n)"
+    [ -e ns2/3bf305731dd26307.nzf~ ] || ret=1
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
+
 echo "I:adding new zone ($n)"
 ret=0
 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 addzone 'added.example { type master; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
@@ -90,13 +100,15 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
-echo "I:verifying no comments in nzf file ($n)"
-ret=0
-hcount=`grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l`
-[ $hcount -eq 0 ] || ret=1
-n=`expr $n + 1`
-if [ $ret != 0 ]; then echo "I:failed"; fi
-status=`expr $status + $ret`
+if [ -z "$NZD" ]; then
+    echo "I:verifying no comments in NZF file ($n)"
+    ret=0
+    hcount=`grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l`
+    [ $hcount -eq 0 ] || ret=1
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
 
 echo "I:checking rndc showzone with previously added zone ($n)"
 ret=0
@@ -117,15 +129,17 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
-echo "I:checking nzf file now has comment ($n)"
-ret=0
-hcount=`grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l`
-[ $hcount -eq 1 ] || ret=1
-n=`expr $n + 1`
-if [ $ret != 0 ]; then echo "I:failed"; fi
-status=`expr $status + $ret`
+if [ -z "$NZD" ]; then
+    echo "I:checking NZF file now has comment ($n)"
+    ret=0
+    hcount=`grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l`
+    [ $hcount -eq 1 ] || ret=1
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
 
-echo "I:deleting newly added zone ($n)"
+echo "I:deleting newly added zone added.example ($n)"
 ret=0
 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 delzone added.example 2>&1 | sed 's/^/I:ns2 /'
 $DIG $DIGOPTS @10.53.0.2 a.added.example a > dig.out.ns2.$n
@@ -302,15 +316,26 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
-echo "I:checking new nzf file has comment ($n)"
-ret=0
-hcount=`grep "^# New zone file for view: external" ns2/external.nzf | wc -l`
-[ $hcount -eq 1 ] || ret=1
-n=`expr $n + 1`
-if [ $ret != 0 ]; then echo "I:failed"; fi
-status=`expr $status + $ret`
+if [ -z "$NZD" ]; then
+    echo "I:checking new NZF file has comment ($n)"
+    ret=0
+    hcount=`grep "^# New zone file for view: external" ns2/external.nzf | wc -l`
+    [ $hcount -eq 1 ] || ret=1
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
 
-echo "I:checking rndc reload causes named to reload the external view's NZF file ($n)"
+if [ -n "$NZD" ]; then
+    echo "I:verifying added.example in external view created an external.nzd DB ($n)"
+    ret=0
+    [ -e ns2/external.nzd ] || ret=1
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
+
+echo "I:checking rndc reload causes named to reload the external view's new zone config ($n)"
 ret=0
 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
 $DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a > dig.out.ns2.int.$n || ret=1
@@ -323,10 +348,20 @@ if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
 echo "I:checking rndc showzone with newly added zone ($n)"
-ret=0
-$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 showzone added.example in external > rndc.out.ns2.$n
-expected='zone "added.example" in external { type master; file "added.db"; };'
-[ "`cat rndc.out.ns2.$n`" = "$expected" ] || ret=1
+# loop because showzone may complain if zones are still being
+# loaded from the NZDB at this point.
+for try in 0 1 2 3 4 5; do
+    ret=0
+    $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 showzone added.example in external > rndc.out.ns2.$n
+    if [ -z "$NZD" ]; then
+      expected='zone "added.example" in external { type master; file "added.db"; };'
+    else
+      expected='zone "added.example" { type master; file "added.db"; };'
+    fi
+    [ "`cat rndc.out.ns2.$n`" = "$expected" ] || ret=1
+    [ $ret -eq 0 ] && break
+    sleep 1
+done
 n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
index b35f98e57b8d1d4ddab60f2a1346df66339d66ce..a4ccb43807dbb105738d1e79367e5daeb8eea9c0 100644 (file)
@@ -50,3 +50,6 @@ rm -f ns3/ttl*.db
 rm -f nsupdate.out
 rm -f signing.out.*
 rm -f settime.out.*
+rm -f ns3/*.nzd ns3/*.nzf
+rm -f digcomp.out.test*
+rm -f ns*/named.lock
index 999c8f3d6f80a28529ee4211f0c521ef2b5d41fb..e22523d1e491faab6884306b79717b1b6d74f088 100644 (file)
@@ -1141,13 +1141,11 @@ status=`expr $status + $ret`
 echo "I:test turning on auto-dnssec during reconfig ($n)"
 ret=0
 # first create a zone that doesn't have auto-dnssec
-rm -f ns3/*.nzf
 $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone reconf.example '{ type master; file "reconf.example.db"; };' 2>&1 | sed 's/^/I:ns3 /'
 rekey_calls=`grep "zone reconf.example.*next key event" ns3/named.run | wc -l`
 [ "$rekey_calls" -eq 0 ] || ret=1
 # ...then we add auto-dnssec and reconfigure
-nzf=`ls ns3/*.nzf`
-echo 'zone reconf.example { type master; file "reconf.example.db"; allow-update { any; }; auto-dnssec maintain; };' > $nzf
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 modzone reconf.example '{ type master; file "reconf.example.db"; allow-update { any; }; auto-dnssec maintain; };' 2>&1 | sed 's/^/I:ns3 /'
 $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 reconfig 2>&1 | sed 's/^/I:ns3 /'
 for i in 0 1 2 3 4 5 6 7 8 9; do
     lret=0
index 41455ef399567a114fd00d0939def74a1f250779..7acb26e88740a5020be227a6d04c171a8a0ef87c 100644 (file)
@@ -52,6 +52,7 @@ GENRANDOM=$TOP/bin/tools/genrandom
 NSLOOKUP=$TOP/bin/dig/nslookup
 DNSTAPREAD="$TOP/bin/tools/dnstap-read"
 MDIG="$TOP/bin/tools/mdig"
+NZD2NZF="$TOP/bin/tools/named-nzd2nzf"
 
 RANDFILE=$TOP/bin/tests/system/random.data
 
@@ -64,7 +65,11 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
         dname dns64 dnssec dsdigest dscp @DNSTAP@ dyndb ecdsa ednscompliance
         emptyzones fetchlimit filter-aaaa formerr forward geoip glue gost
         ixfr inline @KEYMGR@ legacy limits logfileconfig lwresd masterfile
-        masterformat metadata mkeys names notify nslookup nsupdate
+        masterformat metadata mkeys names notify nslookup nsupdate nzf2nzd
+        dname dns64 dnssec dsdigest dscp ecdsa ednscompliance
+        emptyzones filter-aaaa formerr forward geoip glue gost
+        ixfr inline legacy limits logfileconfig lwresd masterfile
+        masterformat metadata mkeys notify nslookup nsupdate nzf2nzd
         pending pipelined @PKCS11_TEST@ reclimit redirect resolver rndc
         rpz rpzrecurse rrl rrchecker rrsetorder rsabigexponent
         runtime sfcache smartsign sortlist spf staticstub statistics
@@ -110,6 +115,7 @@ CHECK_DSA=@CHECK_DSA@
 XMLSTATS=@XMLSTATS@
 JSONSTATS=@JSONSTATS@
 ZLIB=@ZLIB@
+NZD=@NZD_TOOLS@
 
 . ${TOP}/version
 
diff --git a/bin/tests/system/delzone/clean.sh b/bin/tests/system/delzone/clean.sh
new file mode 100644 (file)
index 0000000..9a21557
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Copyright (C) 2010, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+rm -f dig.out.*
+rm -f rndc.out*
+rm -f */named.memstats
+rm -f ns2/*.nzf
+rm -f ns2/*.nzd ns2/*nzd-lock
+rm -f ns2/core*
+rm -f ns2/inline.db.jbk
+rm -f ns2/inline.db.signed
+rm -f ns2/inlineslave.bk*
+rm -f ns*/named.lock
+rm -f ns2/nzf-*
diff --git a/bin/tests/system/delzone/ns1/inlineslave.db b/bin/tests/system/delzone/ns1/inlineslave.db
new file mode 100644 (file)
index 0000000..6638b1f
--- /dev/null
@@ -0,0 +1,29 @@
+; Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN inlineslave.example.
+$TTL 300       ; 5 minutes
+@                       IN SOA mname1. . (
+                               1          ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns2
+ns2                    A       10.53.0.2
+                       MX      10 mail
+
+a                      A       10.0.0.1
+mail                   A       10.0.0.2
diff --git a/bin/tests/system/delzone/ns1/named.conf b/bin/tests/system/delzone/ns1/named.conf
new file mode 100644 (file)
index 0000000..58956c7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+controls { /* empty */ };
+
+options {
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+       allow-query { any; };
+       recursion no;
+};
+
+zone "." {
+       type hint;
+       file "../../common/root.hint";
+};
+
+zone "inlineslave.example" {
+       type master;
+       file "inlineslave.db";
+};
diff --git a/bin/tests/system/delzone/ns2/added.db b/bin/tests/system/delzone/ns2/added.db
new file mode 100644 (file)
index 0000000..6e17487
--- /dev/null
@@ -0,0 +1,29 @@
+; Copyright (C) 2010, 2013  Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+;$ORIGIN added.example.
+$TTL 300       ; 5 minutes
+@                       IN SOA mname1. . (
+                               1          ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns2
+ns2                    A       10.53.0.2
+                       MX      10 mail
+
+a                      A       10.0.0.1
+mail                   A       10.0.0.2
diff --git a/bin/tests/system/delzone/ns2/named.args b/bin/tests/system/delzone/ns2/named.args
new file mode 100644 (file)
index 0000000..bff47a9
--- /dev/null
@@ -0,0 +1 @@
+-D ns2 -X named.lock -m record,size,mctx -T clienttest -c named.conf -g -U 4
diff --git a/bin/tests/system/delzone/ns2/named.conf b/bin/tests/system/delzone/ns2/named.conf
new file mode 100644 (file)
index 0000000..10a0e66
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+options {
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.2; };
+       listen-on-v6 { none; };
+        allow-query { any; };
+        recursion no;
+       allow-new-zones yes;
+};
+
+include "../../common/controls.conf";
+
+zone "." {
+       type hint;
+       file "../../common/root.hint";
+};
+
+zone "normal.example" {
+       type master;
+       file "normal.db";
+};
diff --git a/bin/tests/system/delzone/ns2/normal.db b/bin/tests/system/delzone/ns2/normal.db
new file mode 100644 (file)
index 0000000..52deb05
--- /dev/null
@@ -0,0 +1,29 @@
+; Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN normal.example.
+$TTL 300       ; 5 minutes
+@                       IN SOA mname1. . (
+                               1          ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns2
+ns2                    A       10.53.0.2
+                       MX      10 mail
+
+a                      A       10.0.0.1
+mail                   A       10.0.0.2
diff --git a/bin/tests/system/delzone/setup.sh b/bin/tests/system/delzone/setup.sh
new file mode 100644 (file)
index 0000000..98b3a53
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Copyright (C) 2010, 2012-2014  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+$SHELL clean.sh
diff --git a/bin/tests/system/delzone/tests.sh b/bin/tests/system/delzone/tests.sh
new file mode 100755 (executable)
index 0000000..e7e7716
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/sh
+#
+# Copyright (C) 2010-2015  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+DIGOPTS="+tcp +nosea +nostat +nocmd +norec +noques +noauth +noadd +nostats +dnssec -p 5300"
+status=0
+n=0
+
+echo "I:checking normally loaded zone ($n)"
+ret=0
+$DIG $DIGOPTS @10.53.0.2 a.normal.example a > dig.out.ns2.$n || ret=1
+grep 'status: NOERROR' dig.out.ns2.$n > /dev/null || ret=1
+grep '^a.normal.example' dig.out.ns2.$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+if [ -x "$PYTHON" ]; then 
+echo "I:adding and deleting 20000 new zones ($n)"
+ret=0
+    time (
+        echo "I:adding"
+        $PYTHON << EOF
+import sys
+sys.path.insert(0, '../../../../bin/python')
+from isc import rndc
+r = rndc(('10.53.0.2', 9953), 'hmac-sha256', '1234abcd8765')
+for i in range(20000):
+    res = r.call('addzone z%d.example { type master; file "added.db"; };' % i)
+    if 'text' in res:
+        print ('I:n2:' + res['text'])
+EOF
+    )
+    time (
+        echo "I:deleting"
+        $PYTHON << EOF
+import sys
+sys.path.insert(0, '../../../../bin/python')
+from isc import rndc
+r = rndc(('10.53.0.2', 9953), 'hmac-sha256', '1234abcd8765')
+for i in range(20000):
+    res = r.call('delzone z%d.example' % i)
+    if 'text' in res:
+        print ('I:n2:' + res['text'])
+EOF
+    )
+    n=`expr $n + 1`
+    if [ $ret != 0 ]; then echo "I:failed"; fi
+    status=`expr $status + $ret`
+fi
+
+echo "I:exit status: $status"
+exit $status
index 27fb9fc834cc6598739299868e26cfcde993ed74..292eeef3895346c42ae1c506673ad08e04620832 100644 (file)
@@ -73,7 +73,7 @@ rm -f dig.out.ns*
 rm -f signing.out*
 rm -f freeze.test*
 rm -f thaw.test*
-rm -f */*.nzf
+rm -f */*.nzd */*.nzf
 rm -f ns3/test-?.bk
 rm -f ns3/test-?.bk.signed
 rm -f ns3/test-?.bk.signed.jnl
diff --git a/bin/tests/system/nzd2nzf/clean.sh b/bin/tests/system/nzd2nzf/clean.sh
new file mode 100644 (file)
index 0000000..83dd60f
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# Copyright (C) 2010, 2012-2016  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+rm -f dig.out.*
+rm -f rndc.out*
+rm -f */named.memstats
+rm -f ns*/*.nzf
+rm -f ns*/*.nzd ns*/*.nzd-lock
diff --git a/bin/tests/system/nzd2nzf/ns1/added.db b/bin/tests/system/nzd2nzf/ns1/added.db
new file mode 100644 (file)
index 0000000..6e17487
--- /dev/null
@@ -0,0 +1,29 @@
+; Copyright (C) 2010, 2013  Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+;$ORIGIN added.example.
+$TTL 300       ; 5 minutes
+@                       IN SOA mname1. . (
+                               1          ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns2
+ns2                    A       10.53.0.2
+                       MX      10 mail
+
+a                      A       10.0.0.1
+mail                   A       10.0.0.2
diff --git a/bin/tests/system/nzd2nzf/ns1/named.conf b/bin/tests/system/nzd2nzf/ns1/named.conf
new file mode 100644 (file)
index 0000000..15475b7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+options {
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+        allow-query { any; };
+        recursion no;
+       allow-new-zones yes;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm hmac-sha256;
+};
+
+controls {
+       inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
+};
diff --git a/bin/tests/system/nzd2nzf/prereq.sh b/bin/tests/system/nzd2nzf/prereq.sh
new file mode 100644 (file)
index 0000000..d34fd30
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (C) 2016  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+if [ -z "$NZD" ]; then
+        echo "I:This test requires LMBD support (--with-lmdb)"
+        exit 255
+fi
+
+exit 0
diff --git a/bin/tests/system/nzd2nzf/setup.sh b/bin/tests/system/nzd2nzf/setup.sh
new file mode 100644 (file)
index 0000000..c82253d
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Copyright (C) 2016  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+$SHELL clean.sh
diff --git a/bin/tests/system/nzd2nzf/tests.sh b/bin/tests/system/nzd2nzf/tests.sh
new file mode 100644 (file)
index 0000000..a030e8b
--- /dev/null
@@ -0,0 +1,73 @@
+# Copyright (C) 2016  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+status=0
+n=0
+
+n=`expr $n + 1`
+echo "I:querying for non-existing zone data ($n)"
+ret=0
+$DIG $DIGOPTS @10.53.0.1 -p 5300 a.added.example a > dig.out.ns1.$n || ret=1
+grep 'status: REFUSED' dig.out.ns1.$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I:adding a new zone into default NZD using rndc addzone ($n)"
+$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 addzone "added.example { type master; file \"added.db\"; };" 2>&1 | sed 's/^/I:ns1 /';
+sleep 2
+
+n=`expr $n + 1`
+echo "I:querying for existing zone data ($n)"
+ret=0
+$DIG $DIGOPTS @10.53.0.1 -p 5300 a.added.example a > dig.out.ns1.$n || ret=1
+grep 'status: NOERROR' dig.out.ns1.$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:stopping ns1"
+$PERL $SYSTEMTESTTOP/stop.pl . ns1
+
+n=`expr $n + 1`
+echo "I:dumping _default.nzd to _default.nzf ($n)"
+$NZD2NZF ns1/_default.nzd > ns1/_default.nzf || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I:checking that _default.nzf contains the expected content ($n)"
+grep 'zone added.example { type master; file "added.db"; };' ns1/_default.nzf > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:deleting _default.nzd database"
+rm -f ns1/_default.nzd
+
+echo "I:starting ns1 which should migrate the .nzf to .nzd"
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns1
+
+n=`expr $n + 1`
+echo "I:querying for zone data from migrated zone config ($n)"
+ret=0
+$DIG $DIGOPTS @10.53.0.1 -p 5300 a.added.example a > dig.out.ns1.$n || ret=1
+grep 'status: NOERROR' dig.out.ns1.$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:exit status: $status"
+exit $status
index cff80a5bd7152fba8fcf28107ede3315e0a16cdb..b760aa3025432fb789086862382388fa45bc4f37 100644 (file)
@@ -4,5 +4,6 @@ genrandom
 isc-hmac-fixup
 mdig
 named-journalprint
+named-nzd2nzf
 named-rrchecker
 nsec3hash
index 0477b9f47e95e14e1efa1a442d3a328206e87680..69721b66a592efbb463361e04bca19df9a882b94 100644 (file)
@@ -37,23 +37,28 @@ NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@
 SUBDIRS =
 
 DNSTAPTARGETS =        dnstap-read@EXEEXT@
+NZDTARGETS =   named-nzd2nzf@EXEEXT@
 TARGETS =      arpaname@EXEEXT@ named-journalprint@EXEEXT@ \
                named-rrchecker@EXEEXT@  nsec3hash@EXEEXT@ \
                genrandom@EXEEXT@ isc-hmac-fixup@EXEEXT@ mdig@EXEEXT@ \
-               @DNSTAPTARGETS@
+               @DNSTAPTARGETS@ @NZDTARGETS@
 
 DNSTAPSRCS  =  dnstap-read.c
+NZDSRCS  =     named-nzd2nzf.c
 SRCS =         arpaname.c named-journalprint.c named-rrchecker.c \
                nsec3hash.c genrandom.c isc-hmac-fixup.c mdig.c \
-               @DNSTAPSRCS@
+               @DNSTAPSRCS@ @NZDSRCS@
 
 DNSTAPMAN =    dnstap-read.1
+NZDMAN =       named-nzd2nzf.8
 MANPAGES =     arpaname.1 named-journalprint.8 named-rrchecker.1 nsec3hash.8 \
-               genrandom.8 isc-hmac-fixup.8 mdig.1 @DNSTAPMAN@
+               genrandom.8 isc-hmac-fixup.8 mdig.1 @DNSTAPMAN@ @NZDMAN@
+
 DNSTAPHTML =   dnstap-read.html
+NZDHTML =      named-nzd2nzf.html
 HTMLPAGES =    arpaname.html named-journalprint.html named-rrchecker.html \
                nsec3hash.html genrandom.html isc-hmac-fixup.html \
-               mdig.html @DNSTAPHTML@
+               mdig.html @DNSTAPHTML@ @NZDHTML@
 MANOBJS =      ${MANPAGES} ${HTMLPAGES}
 
 @BIND9_MAKE_RULES@
@@ -94,6 +99,10 @@ mdig@EXEEXT@: mdig.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS}
 dnstap-read@EXEEXT@: dnstap-read.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        export BASEOBJS="dnstap-read.@O@"; \
        export LIBS0="${DNSLIBS}"; \
+
+named-nzd2nzf@EXEEXT@: named-nzd2nzf.@O@ ${NZDDEPLIBS}
+       export BASEOBJS="named-nzd2nzf.@O@"; \
+       export LIBS0="${ISCCFGLIBS} ${ISCCCLIBS} ${BIND9LIBS} ${DNSLIBS}"; \
        ${FINALBUILDCMD}
 
 doc man:: ${MANOBJS}
@@ -106,17 +115,23 @@ installdirs:
        $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man1
        $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
 
+nzd:
+       ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-nzd2nzf@EXEEXT@ \
+               ${DESTDIR}${sbindir}
+
 dnstap:
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} dnstap-read@EXEEXT@ \
                ${DESTDIR}${sbindir}
 
-install:: ${TARGETS} @DNSTAP@ installdirs
+install:: ${TARGETS} @DNSTAP@ @NZD_TOOLS@ installdirs
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} arpaname@EXEEXT@ \
                ${DESTDIR}${sbindir}
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-journalprint@EXEEXT@ \
                ${DESTDIR}${sbindir}
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-rrchecker@EXEEXT@ \
                ${DESTDIR}${sbindir}
+       ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-nzd2nzf@EXEEXT@ \
+               ${DESTDIR}${sbindir}
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} nsec3hash@EXEEXT@ \
                ${DESTDIR}${sbindir}
        ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} genrandom@EXEEXT@ \
@@ -129,6 +144,7 @@ install:: ${TARGETS} @DNSTAP@ installdirs
        ${INSTALL_DATA} ${srcdir}/isc-hmac-fixup.8 ${DESTDIR}${mandir}/man8
        ${INSTALL_DATA} ${srcdir}/named-journalprint.8 ${DESTDIR}${mandir}/man8
        ${INSTALL_DATA} ${srcdir}/named-rrchecker.1 ${DESTDIR}${mandir}/man1
+       ${INSTALL_DATA} ${srcdir}/named-nzd2nzf.8 ${DESTDIR}${mandir}/man8
        ${INSTALL_DATA} ${srcdir}/nsec3hash.8 ${DESTDIR}${mandir}/man8
        ${INSTALL_DATA} ${srcdir}/genrandom.8 ${DESTDIR}${mandir}/man8
        ${INSTALL_DATA} ${srcdir}/mdig.1 ${DESTDIR}${mandir}/man1
diff --git a/bin/tools/named-nzd2nzf.8 b/bin/tools/named-nzd2nzf.8
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/bin/tools/named-nzd2nzf.c b/bin/tools/named-nzd2nzf.c
new file mode 100644 (file)
index 0000000..65c3e6f
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifndef HAVE_LMDB
+#error This program requires the LMDBlibrary.
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <lmdb.h>
+
+int
+main (int argc, char *argv[]) {
+       int status;
+       const char *path;
+       MDB_env *env = NULL;
+       MDB_txn *txn = NULL;
+       MDB_cursor *cursor = NULL;
+       MDB_dbi dbi;
+       MDB_val key, data;
+
+       if (argc != 2) {
+               fprintf(stderr, "Usage: named-nzd2nzf <nzd-path>\n");
+               exit(1);
+       }
+
+       path = argv[1];
+
+       status = mdb_env_create(&env);
+       if (status != 0) {
+               fprintf(stderr, "named-nzd2nzf: mdb_env_create: %s",
+                       mdb_strerror(status));
+               exit(1);
+       }
+
+       status = mdb_env_open(env, path,
+                             MDB_RDONLY|MDB_NOTLS|MDB_NOSUBDIR, 0600);
+       if (status != 0) {
+               fprintf(stderr, "named-nzd2nzf: mdb_env_open: %s",
+                       mdb_strerror(status));
+               exit(1);
+       }
+
+       status = mdb_txn_begin(env, 0, MDB_RDONLY, &txn);
+       if (status != 0) {
+               fprintf(stderr, "named-nzd2nzf: mdb_txn_begin: %s",
+                       mdb_strerror(status));
+               exit(1);
+       }
+
+       status = mdb_dbi_open(txn, NULL, 0, &dbi);
+       if (status != 0) {
+               fprintf(stderr, "named-nzd2nzf: mdb_dbi_open: %s",
+                       mdb_strerror(status));
+               exit(1);
+       }
+
+       status = mdb_cursor_open(txn, dbi, &cursor);
+       if (status != 0) {
+               fprintf(stderr, "named-nzd2nzf: mdb_cursor_open: %s",
+                       mdb_strerror(status));
+               exit(1);
+       }
+
+       while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == 0) {
+               if (key.mv_data == NULL || key.mv_size == 0 ||
+                   data.mv_data == NULL || data.mv_size == 0)
+               {
+                       fprintf(stderr,
+                               "named-nzd2nzf: empty column found in "
+                               "database '%s'", path);
+                       exit(1);
+               }
+
+               /* zone zonename { config; }; */
+               printf("zone \"%.*s\" %.*s;\n",
+                      (int) key.mv_size, (char *) key.mv_data, 
+                      (int) data.mv_size, (char *) data.mv_data);
+       }
+
+       mdb_cursor_close(cursor);
+       mdb_txn_abort(txn);
+       mdb_env_close(env);
+       exit(0);
+}
diff --git a/bin/tools/named-nzd2nzf.docbook b/bin/tools/named-nzd2nzf.docbook
new file mode 100644 (file)
index 0000000..4aa3852
--- /dev/null
@@ -0,0 +1,97 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+              [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2009, 2014, 2016  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<refentry id="man.named-nzd2nzf">
+  <refentryinfo>
+    <date>May 5, 2016</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle><application>named-nzd2nzf</application></refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND9</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname><application>named-nzd2nzf</application></refname>
+    <refpurpose>
+      Convert an NZD database to NZF text format
+    </refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2016</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>named-nzd2nzf</command>
+      <arg choice="req">filename</arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      <command>named-nzd2nzf</command> converts an NZD database to NZF
+      format and prints it to standard output.  This can be used to
+      review the configuration of zones that were added to
+      <command>named</command> via <command>rndc addzone</command>.
+      It can also be used to restore the old file format
+      when rolling back from a newer version
+      of BIND to an older version.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>ARGUMENTS</title>
+    <variablelist>
+      <varlistentry>
+        <term>filename</term>
+        <listitem>
+          <para>
+            The name of the <filename>.nzd</filename> file whose contents
+            should be printed.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citetitle>BIND 9 Administrator Reference Manual</citetitle>,
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>AUTHOR</title>
+    <para><corpauthor>Internet Systems Consortium</corpauthor>
+    </para>
+  </refsect1>
+
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/bin/tools/named-nzd2nzf.html b/bin/tools/named-nzd2nzf.html
new file mode 100644 (file)
index 0000000..e69de29
index 436136b472775a847763926f2c48ac3cc98eced8..a733fae8f683200856add194a9b4f82f6ee693f3 100644 (file)
@@ -326,6 +326,9 @@ int sigwait(const unsigned int *set, int *sig);
 /* Define to 1 if you have the <linux/types.h> header file. */
 #undef HAVE_LINUX_TYPES_H
 
+/* Define if lmdb was found */
+#undef HAVE_LMDB
+
 /* Define to 1 if you have the <locale.h> header file. */
 #undef HAVE_LOCALE_H
 
index 27554e3da4ada3407d5555002cd509711e8f0d1e..1a035ae56a8121fa99ec135a98a47a27cb4fda76 100755 (executable)
--- a/configure
+++ b/configure
@@ -814,6 +814,11 @@ MKDEPCC
 ZLIB
 JSONSTATS
 XMLSTATS
+NZDHTML
+NZDMAN
+NZDTARGETS
+NZDSRCS
+NZD_TOOLS
 PKCS11_TEST
 PKCS11_GOST
 PKCS11_ECDSA
@@ -1013,6 +1018,7 @@ with_aes
 enable_openssl_hash
 with_cc_alg
 enable_openssl_version_check
+with_lmdb
 with_libxml2
 with_libjson
 with_zlib
@@ -1742,6 +1748,7 @@ Optional Packages:
   --with-gost             Crypto GOST yes|no|raw|asn1.
   --with-aes              Crypto AES
   --with-cc-alg=ALG      choose the algorithm for Client Cookie [aes|sha1|sha256]
+  --with-lmdb=PATH        build with LMDB library yes|no|path
   --with-libxml2=PATH     build with libxml2 library yes|no|path
   --with-libjson=PATH     build with libjson0 library yes|no|path
   --with-zlib=PATH        build with zlib for HTTP compression [default=yes]
@@ -16712,6 +16719,145 @@ if test "$have_clock_gt" = "rt"; then
        LIBS="-lrt $LIBS"
 fi
 
+#
+# was --with-lmdb specified?
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lmdb library" >&5
+$as_echo_n "checking for lmdb library... " >&6; }
+
+# Check whether --with-lmdb was given.
+if test "${with_lmdb+set}" = set; then :
+  withval=$with_lmdb; use_lmdb="$withval"
+else
+  use_lmdb="auto"
+fi
+
+
+have_lmdb=""
+case "$use_lmdb" in
+       no)
+               lmdb_libs=""
+               ;;
+       auto|yes)
+               for d in /usr /usr/local /opt/local
+               do
+                       if test -f "${d}/include/lmdb.h"
+                       then
+                               if test ${d} != /usr
+                               then
+                                       lmdb_cflags="-I ${d}/include"
+                                       LIBS="$LIBS -L${d}/lib"
+                               fi
+                               have_lmdb="yes"
+                       fi
+               done
+               ;;
+       *)
+               if test -f "${use_lmdb}/include/lmdb.h"
+               then
+                       lmdb_cflags="-I${use_lmdb}/include"
+                       LIBS="$LIBS -L${use_lmdb}/lib"
+                       have_lmdb="yes"
+               else
+                       as_fn_error $? "$use_lmdb/include/lmdb.h not found." "$LINENO" 5
+               fi
+               ;;
+esac
+
+if test "X${have_lmdb}" != "X"
+then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing mdb_env_create" >&5
+$as_echo_n "checking for library containing mdb_env_create... " >&6; }
+if ${ac_cv_search_mdb_env_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mdb_env_create ();
+int
+main ()
+{
+return mdb_env_create ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' lmdb; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_mdb_env_create=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_mdb_env_create+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_mdb_env_create+:} false; then :
+
+else
+  ac_cv_search_mdb_env_create=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_mdb_env_create" >&5
+$as_echo "$ac_cv_search_mdb_env_create" >&6; }
+ac_res=$ac_cv_search_mdb_env_create
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+  as_fn_error $? "found lmdb include but not library." "$LINENO" 5
+                       have_lmdb=""
+fi
+
+elif test "X$use_lmdb" = Xyes
+then
+       as_fn_error $? "include/lmdb.h not found." "$LINENO" 5
+else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+NZD_TOOLS=""
+NZDSRCS=
+NZDTARGETS=
+NZDMAN=
+NZDHTML=
+if test "X${have_lmdb}" != "X"
+then
+       CFLAGS="$CFLAGS $lmdb_cflags"
+
+$as_echo "#define HAVE_LMDB 1" >>confdefs.h
+
+       NZD_TOOLS="nzd"
+        NZDSRCS='${NZDSRCS}'
+        NZDTARGETS='${NZDTARGETS}'
+        NZDMAN='${NZDMAN}'
+        NZDHTML='${NZDHTML}'
+fi
+
+
+
+
+
+
 #
 # was --with-libxml2 specified?
 #
@@ -25381,9 +25527,9 @@ if test "${enable_full_report+set}" = set; then :
 fi
 
 
-echo "========================================================================"
+echo "==============================================================================="
 echo "Configuration summary:"
-echo "------------------------------------------------------------------------"
+echo "-------------------------------------------------------------------------------"
 echo "Optional features enabled:"
 if $use_threads; then
     echo "    Multiprocessing support (--enable-threads)"
@@ -25410,6 +25556,7 @@ if test "$enable_full_report" = "yes"; then
     test "X$XMLSTATS" = "X" || echo "    XML statistics (--with-libxml2)"
     test "X$JSONSTATS" = "X" || echo "    JSON statistics (--with-libjson)"
     test "X$ZLIB" = "X" || echo "    HTTP zlib compression (--with-zlib)"
+    test "X$NZD_TOOLS" = "X" || echo "    LMDB database to store configuration for 'addzone' zones (--with-lmdb)"
 fi
 
 if test "$use_pkcs11" != "no"; then
@@ -25501,6 +25648,7 @@ test "X$PYTHON" = "X" && echo "    Python tools (--with-python)"
 test "X$XMLSTATS" = "X" && echo "    XML statistics (--with-libxml2)"
 test "X$JSONSTATS" = "X" && echo "    JSON statistics (--with-libjson)"
 test "X$ZLIB" = "X" && echo "    HTTP zlib compression (--with-zlib)"
+test "X$NZD_TOOLS" = "X" && echo "    LMDB database to store configuration for 'addzone' zones (--with-lmdb)"
 
 if test "X$ac_unrecognized_opts" != "X"; then
     echo
@@ -25508,10 +25656,10 @@ if test "X$ac_unrecognized_opts" != "X"; then
     echo "    $ac_unrecognized_opts"
 fi
 if test "$enable_full_report" != "yes"; then
-    echo "------------------------------------------------------------------------"
+    echo "-------------------------------------------------------------------------------"
     echo "For more detail, use --enable-full-report."
 fi
-echo "========================================================================"
+echo "==============================================================================="
 
 if test "X$CRYPTO" = "X"; then
 cat << \EOF
index 1c4492cdb053be4f3a7479fa14db107e6c464955..0cabe41ad9562a646a6fda503bc2ab173be3586f 100644 (file)
@@ -2145,6 +2145,79 @@ if test "$have_clock_gt" = "rt"; then
        LIBS="-lrt $LIBS"
 fi
 
+#
+# was --with-lmdb specified?
+#
+AC_MSG_CHECKING(for lmdb library)
+AC_ARG_WITH(lmdb,
+[  --with-lmdb[=PATH]        build with LMDB library [yes|no|path]],
+    use_lmdb="$withval", use_lmdb="auto")
+
+have_lmdb=""
+case "$use_lmdb" in
+       no)
+               lmdb_libs=""
+               ;;
+       auto|yes)
+               for d in /usr /usr/local /opt/local
+               do
+                       if test -f "${d}/include/lmdb.h"
+                       then
+                               if test ${d} != /usr
+                               then
+                                       lmdb_cflags="-I ${d}/include"
+                                       LIBS="$LIBS -L${d}/lib"
+                               fi
+                               have_lmdb="yes"
+                       fi
+               done
+               ;;
+       *)
+               if test -f "${use_lmdb}/include/lmdb.h"
+               then
+                       lmdb_cflags="-I${use_lmdb}/include"
+                       LIBS="$LIBS -L${use_lmdb}/lib"
+                       have_lmdb="yes"
+               else
+                       AC_MSG_ERROR([$use_lmdb/include/lmdb.h not found.])
+               fi
+               ;;
+esac
+
+if test "X${have_lmdb}" != "X"
+then
+       AC_MSG_RESULT(yes)
+       AC_SEARCH_LIBS([mdb_env_create], [lmdb], [],
+                      [AC_MSG_ERROR([found lmdb include but not library.])
+                       have_lmdb=""])
+elif test "X$use_lmdb" = Xyes
+then
+       AC_MSG_ERROR([include/lmdb.h not found.])
+else
+       AC_MSG_RESULT(no)
+fi
+
+NZD_TOOLS=""
+NZDSRCS=
+NZDTARGETS=
+NZDMAN=
+NZDHTML=
+if test "X${have_lmdb}" != "X"
+then
+       CFLAGS="$CFLAGS $lmdb_cflags"
+       AC_DEFINE(HAVE_LMDB, 1, [Define if lmdb was found])
+       NZD_TOOLS="nzd"
+        NZDSRCS='${NZDSRCS}'
+        NZDTARGETS='${NZDTARGETS}'
+        NZDMAN='${NZDMAN}'
+        NZDHTML='${NZDHTML}'
+fi
+AC_SUBST(NZD_TOOLS)
+AC_SUBST(NZDSRCS)
+AC_SUBST(NZDTARGETS)
+AC_SUBST(NZDMAN)
+AC_SUBST(NZDHTML)
+
 #
 # was --with-libxml2 specified?
 #
@@ -5120,9 +5193,9 @@ esac
 AC_ARG_ENABLE(full-report,
        [  --enable-full-report   report values of all configure options])
 
-echo "========================================================================"
+echo "==============================================================================="
 echo "Configuration summary:"
-echo "------------------------------------------------------------------------"
+echo "-------------------------------------------------------------------------------"
 echo "Optional features enabled:"
 if $use_threads; then
     echo "    Multiprocessing support (--enable-threads)"
@@ -5149,6 +5222,7 @@ if test "$enable_full_report" = "yes"; then
     test "X$XMLSTATS" = "X" || echo "    XML statistics (--with-libxml2)"
     test "X$JSONSTATS" = "X" || echo "    JSON statistics (--with-libjson)"
     test "X$ZLIB" = "X" || echo "    HTTP zlib compression (--with-zlib)"
+    test "X$NZD_TOOLS" = "X" || echo "    LMDB database to store configuration for 'addzone' zones (--with-lmdb)"
 fi
 
 if test "$use_pkcs11" != "no"; then
@@ -5240,6 +5314,7 @@ test "X$PYTHON" = "X" && echo "    Python tools (--with-python)"
 test "X$XMLSTATS" = "X" && echo "    XML statistics (--with-libxml2)"
 test "X$JSONSTATS" = "X" && echo "    JSON statistics (--with-libjson)"
 test "X$ZLIB" = "X" && echo "    HTTP zlib compression (--with-zlib)"
+test "X$NZD_TOOLS" = "X" && echo "    LMDB database to store configuration for 'addzone' zones (--with-lmdb)"
 
 if test "X$ac_unrecognized_opts" != "X"; then
     echo
@@ -5247,10 +5322,10 @@ if test "X$ac_unrecognized_opts" != "X"; then
     echo "    $ac_unrecognized_opts"
 fi
 if test "$enable_full_report" != "yes"; then
-    echo "------------------------------------------------------------------------"
+    echo "-------------------------------------------------------------------------------"
     echo "For more detail, use --enable-full-report."
 fi
-echo "========================================================================"
+echo "==============================================================================="
 
 if test "X$CRYPTO" = "X"; then
 cat << \EOF                                                             
index c624d080ac1327bdc5ba18e850d12c280cb1dbc3..af20651d7ddecc92b5d6a898abee5e71a71b9a26 100644 (file)
          mechanism.
        </para>
        <para>
-      This feature should be considered experimental. It currently
+         This feature should be considered experimental. It currently
          supports only basic features; more advanced features such as
          ACLs and TSIG keys are not yet supported. Example catalog
          zone configurations can be found in the Chapter 9 of the
          BIND Administrator Reference Manual.
        </para>
-               <para>
+       <para>
          Support for master entries with TSIG keys has been added to catalog
          zones, as well as support for allow-query and allow-transfer.
-               </para>
+       </para>
       </listitem>
       <listitem>
        <para>
-         Added rndc python module.
+         Added an <command>isc.rndc</command> Python module, which allows
+         <command>rndc</command> commands to be sent from Python programs.
        </para>
       </listitem>
       <listitem>
          configuration for a specified zone.
        </para>
       </listitem>
+      <listitem>
+       <para>
+         When BIND is built with the <command>lmdb</command> library
+         (Lightning Memory-Mapped Database), <command>named</command>
+         will store the configuration information for zones
+         that are added via <command>rndc addzone</command>
+         in a database, rather than in a flat "NZF" file.  This
+         dramatically improves performance for
+         <command>rndc delzone</command> and
+         <command>rndc modzone</command>: deleting or changing 
+         the contents of a database is much faster than rewriting
+         a text file.
+       </para>
+       <para>
+         On startup, if <command>named</command> finds an existing
+         NZF file, it will automatically convert it to the new NZD
+         database format.
+       </para>
+       <para>
+         To view the contents of an NZD, or to convert an
+         NZD back to an NZF file (for example, to revert back
+         to an earlier version of BIND which did not support the
+         NZD format), use the new command <command>named-nzd2nzf</command>
+         [RT #39837]
+       </para>
+      </listitem>
       <listitem>
        <para>
          Added server-side support for pipelined TCP queries.  Clients
index 865fb695825293a6b6d2bf69a0ac26b2b3b34e32..7653b6f886f52aa25d67c0b7192ca34161cd3162 100644 (file)
@@ -197,8 +197,8 @@ struct dns_view {
        dns_zone_t *                    managed_keys;
        dns_zone_t *                    redirect;
        dns_name_t *                    redirectzone;   /* points to
-                                                          redirectfixed
-                                                          when valid */
+                                                        * redirectfixed
+                                                        * when valid */
        dns_fixedname_t                 redirectfixed;
 
        /*
@@ -209,8 +209,11 @@ struct dns_view {
         * named implements.
         */
        char *                          new_zone_file;
+       char *                          new_zone_db;
+       void *                          new_zone_dbenv;
        void *                          new_zone_config;
        void                            (*cfg_destroy)(void **);
+       isc_mutex_t                     new_zone_lock;
 
        unsigned char                   secret[32];     /* Client secret */
        unsigned int                    v6bias;
@@ -1206,7 +1209,7 @@ dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
  * \li 'dnskey' is valid.
  */
 
-void
+isc_result_t
 dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
                     void (*cfg_destroy)(void **));
 /*%<
@@ -1225,6 +1228,10 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
  *
  * Requires:
  * \li 'view' is valid.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS
+ * \li ISC_R_NOSPACE
  */
 
 void
index db43eb917de63b5f0655c89cafde5821a53c8001..7d51d3871397aab7dd8811e451e2a7c502f1d4fc 100644 (file)
 
 #include <config.h>
 
+#ifdef HAVE_LMDB
+#include <lmdb.h>
+#endif
+
 #include <isc/file.h>
 #include <isc/hash.h>
 #include <isc/lex.h>
@@ -230,8 +234,11 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
        view->sendcookie = ISC_TRUE;
        view->requireservercookie = ISC_FALSE;
        view->new_zone_file = NULL;
+       view->new_zone_db = NULL;
+       view->new_zone_dbenv = NULL;
        view->new_zone_config = NULL;
        view->cfg_destroy = NULL;
+       isc_mutex_init(&view->new_zone_lock);
        view->fail_ttl = 0;
        view->failcache = NULL;
        view->v6bias = 0;
@@ -493,9 +500,22 @@ destroy(dns_view_t *view) {
                dns_dt_detach(&view->dtenv);
 #endif /* HAVE_DNSTAP */
        dns_view_setnewzones(view, ISC_FALSE, NULL, NULL);
+       if (view->new_zone_file != NULL) {
+               isc_mem_free(view->mctx, view->new_zone_file);
+               view->new_zone_file = NULL;
+       }
+#ifdef HAVE_LMDB
+       if (view->new_zone_dbenv != NULL)
+               mdb_env_close((MDB_env *) view->new_zone_dbenv);
+       if (view->new_zone_db != NULL) {
+               isc_mem_free(view->mctx, view->new_zone_db);
+               view->new_zone_db = NULL;
+       }
+#endif /* HAVE_LMDB */
        dns_fwdtable_destroy(&view->fwdtable);
        dns_aclenv_destroy(&view->aclenv);
        dns_badcache_destroy(&view->failcache);
+       DESTROYLOCK(&view->new_zone_lock);
        DESTROYLOCK(&view->lock);
        isc_refcount_destroy(&view->references);
        isc_mem_free(view->mctx, view->nta_file);
@@ -1955,10 +1975,17 @@ dns_view_untrust(dns_view_t *view, dns_name_t *keyname,
        dst_key_free(&key);
 }
 
-void
+isc_result_t
 dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
                     void (*cfg_destroy)(void **))
 {
+       isc_result_t result;
+       char buffer[1024];
+#ifdef HAVE_LMDB
+       MDB_env *env = NULL;
+       int status;
+#endif
+
        REQUIRE(DNS_VIEW_VALID(view));
        REQUIRE((cfgctx != NULL && cfg_destroy != NULL) || !allow);
 
@@ -1967,24 +1994,79 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
                view->new_zone_file = NULL;
        }
 
+#ifdef HAVE_LMDB
+       if (view->new_zone_dbenv != NULL) {
+               mdb_env_close((MDB_env *) view->new_zone_dbenv);
+               view->new_zone_dbenv = NULL;
+       }
+
+       if (view->new_zone_db != NULL) {
+               isc_mem_free(view->mctx, view->new_zone_db);
+               view->new_zone_db = NULL;
+       }
+#endif /* HAVE_LMDB */
+
        if (view->new_zone_config != NULL) {
                view->cfg_destroy(&view->new_zone_config);
                view->cfg_destroy = NULL;
        }
 
-       if (allow) {
-               isc_result_t result;
-               char buffer[1024];
+       if (!allow)
+               return (ISC_R_SUCCESS);
 
-               result = isc_file_sanitize(NULL, view->name, "nzf",
-                                          buffer, sizeof(buffer));
-               if (result == ISC_R_SUCCESS) {
-                       view->new_zone_file = isc_mem_strdup(view->mctx,
-                                                            buffer);
-                       view->new_zone_config = cfgctx;
-                       view->cfg_destroy = cfg_destroy;
+       result = isc_file_sanitize(NULL, view->name, "nzf",
+                                  buffer, sizeof(buffer));
+       if (result != ISC_R_SUCCESS)
+               goto out;
+       view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
+
+#ifdef HAVE_LMDB
+       result = isc_file_sanitize(NULL, view->name, "nzd",
+                                  buffer, sizeof(buffer));
+       if (result != ISC_R_SUCCESS)
+               goto out;
+       view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
+
+       status = mdb_env_create(&env);
+       if (status != 0) {
+               result = ISC_R_FAILURE;
+               goto out;
+       }
+
+       status = mdb_env_open(env, view->new_zone_db,
+                             MDB_NOSUBDIR|MDB_CREATE, 0600);
+       if (status != 0) {
+               result = ISC_R_FAILURE;
+               goto out;
+       }
+
+       view->new_zone_dbenv = env;
+       env = NULL;
+#endif /* HAVE_LMDB */
+
+       view->new_zone_config = cfgctx;
+       view->cfg_destroy = cfg_destroy;
+
+ out:
+       if (result != ISC_R_SUCCESS) {
+               if (view->new_zone_file != NULL) {
+                       isc_mem_free(view->mctx, view->new_zone_file);
+                       view->new_zone_file = NULL;
                }
+
+#ifdef HAVE_LMDB
+               if (view->new_zone_db != NULL) {
+                       isc_mem_free(view->mctx, view->new_zone_db);
+                       view->new_zone_db = NULL;
+               }
+               if (env != NULL)
+                       mdb_env_close(env);
+#endif /* HAVE_LMDB */
+               view->new_zone_config = NULL;
+               view->cfg_destroy = NULL;
        }
+
+       return (result);
 }
 
 isc_result_t