From eca74c52c1e9cf4244f772ee49e3127c155b5710 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 21 Jul 2016 11:13:03 -0700 Subject: [PATCH] [master] store "addzone" zone config in a NZD database 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] --- CHANGES | 12 + bin/Makefile.in | 2 +- bin/named/include/named/server.h | 1 + bin/named/server.c | 1482 +++++++++++++++---- bin/tests/system/addzone/clean.sh | 2 + bin/tests/system/addzone/tests.sh | 89 +- bin/tests/system/autosign/clean.sh | 3 + bin/tests/system/autosign/tests.sh | 4 +- bin/tests/system/conf.sh.in | 8 +- bin/tests/system/delzone/clean.sh | 27 + bin/tests/system/delzone/ns1/inlineslave.db | 29 + bin/tests/system/delzone/ns1/named.conf | 36 + bin/tests/system/delzone/ns2/added.db | 29 + bin/tests/system/delzone/ns2/named.args | 1 + bin/tests/system/delzone/ns2/named.conf | 37 + bin/tests/system/delzone/ns2/normal.db | 29 + bin/tests/system/delzone/setup.sh | 20 + bin/tests/system/delzone/tests.sh | 68 + bin/tests/system/inline/clean.sh | 2 +- bin/tests/system/nzd2nzf/clean.sh | 21 + bin/tests/system/nzd2nzf/ns1/added.db | 29 + bin/tests/system/nzd2nzf/ns1/named.conf | 34 + bin/tests/system/nzd2nzf/prereq.sh | 23 + bin/tests/system/nzd2nzf/setup.sh | 20 + bin/tests/system/nzd2nzf/tests.sh | 73 + bin/tools/.gitignore | 1 + bin/tools/Makefile.in | 26 +- bin/tools/named-nzd2nzf.8 | 0 bin/tools/named-nzd2nzf.c | 100 ++ bin/tools/named-nzd2nzf.docbook | 97 ++ bin/tools/named-nzd2nzf.html | 0 config.h.in | 3 + configure | 156 +- configure.in | 83 +- doc/arm/notes.xml | 35 +- lib/dns/include/dns/view.h | 13 +- lib/dns/view.c | 106 +- 37 files changed, 2319 insertions(+), 382 deletions(-) create mode 100644 bin/tests/system/delzone/clean.sh create mode 100644 bin/tests/system/delzone/ns1/inlineslave.db create mode 100644 bin/tests/system/delzone/ns1/named.conf create mode 100644 bin/tests/system/delzone/ns2/added.db create mode 100644 bin/tests/system/delzone/ns2/named.args create mode 100644 bin/tests/system/delzone/ns2/named.conf create mode 100644 bin/tests/system/delzone/ns2/normal.db create mode 100644 bin/tests/system/delzone/setup.sh create mode 100755 bin/tests/system/delzone/tests.sh create mode 100644 bin/tests/system/nzd2nzf/clean.sh create mode 100644 bin/tests/system/nzd2nzf/ns1/added.db create mode 100644 bin/tests/system/nzd2nzf/ns1/named.conf create mode 100644 bin/tests/system/nzd2nzf/prereq.sh create mode 100644 bin/tests/system/nzd2nzf/setup.sh create mode 100644 bin/tests/system/nzd2nzf/tests.sh create mode 100644 bin/tools/named-nzd2nzf.8 create mode 100644 bin/tools/named-nzd2nzf.c create mode 100644 bin/tools/named-nzd2nzf.docbook create mode 100644 bin/tools/named-nzd2nzf.html diff --git a/CHANGES b/CHANGES index 401c08601b..782a4150e3 100644 --- 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] diff --git a/bin/Makefile.in b/bin/Makefile.in index 4d8eaa119d..f3cbed3f78 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -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@ diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index da32df70c4..2ecd888578 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -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. diff --git a/bin/named/server.c b/bin/named/server.c index e9e639a8e5..3d6f367a46 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -99,7 +100,9 @@ #include #include #include +#ifdef HAVE_GEOIP #include +#endif /* HAVE_GEOIP */ #include #include #include @@ -115,9 +118,17 @@ #include #include #endif -#ifdef HAVE_GEOIP -#include -#endif /* HAVE_GEOIP */ + +#ifdef HAVE_LMDB +#include +#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 -add_comment(FILE *fp, const char *viewname); +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 +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. - */ - 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 = ISC_R_SUCCESS; + 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_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,138 +10526,6 @@ 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 isc_result_t -nzf_remove(const char *nzfile, const char *viewname, const char *zonename) { - 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; - - /* - * 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; - - /* This is a zone; find its name. */ - while (*p && - ((*p == '"') || isspace((unsigned char)*p))) - p++; - - /* - * 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; - } - - /* - * 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; - } - - /* Copy the buffer out and continue */ - fputs(buf, ofp); - } - - /* 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; - } - - /* 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); - } - - /* - * 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; - - /* 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); - goto cleanup; - } - } - - cleanup: - if (ifp != NULL) - (void) isc_stdio_close(ifp); - if (ofp != NULL) - (void) isc_stdio_close(ofp); - - return (result); -} -#endif - static void dumpzone(void *arg, const char *buf, int len) { FILE *fp = arg; @@ -10328,24 +10534,412 @@ dumpzone(void *arg, const char *buf, int len) { } static isc_result_t -nzf_append(FILE *fp, const char *viewname, const cfg_obj_t *zconfig) { +nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) { isc_result_t result; off_t offset; + FILE *fp = NULL; + LOCK(&view->new_zone_lock); + + CHECK(isc_stdio_open(view->new_zone_file, "a", &fp)); CHECK(isc_stdio_seek(fp, 0, SEEK_END)); CHECK(isc_stdio_tell(fp, &offset)); if (offset == 0) - CHECK(add_comment(fp, viewname)); + CHECK(add_comment(fp, view->name)); 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)); cleanup: + isc_stdio_flush(fp); + isc_stdio_close(fp); + UNLOCK(&view->new_zone_lock); return (result); } +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); +} + +#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 (!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); +} + +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; + + 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 +nzd_count(dns_view_t *view, int *countp) { + isc_result_t result; + int status; + MDB_txn *txn = NULL; + MDB_dbi dbi; + MDB_stat stat; + + REQUIRE(countp != NULL); + + result = nzd_open(view, MDB_RDONLY, &txn, &dbi); + if (result != ISC_R_SUCCESS) + goto cleanup; + + 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; + CHECK(dns_zt_unmount(view->zonetable, zone)); - /* 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)); - } - } + /* Send cleanup event */ + dz = isc_mem_get(ns_g_mctx, sizeof(*dz)); + if (dz == NULL) + CHECK(ISC_R_NOMEMORY); - /* Stop answering for this zone */ - if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) { - dns_db_detach(&dbp); - dns_zone_unload(zone); - } + 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); - /* Clean up stub / slave zone files */ + 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; } diff --git a/bin/tests/system/addzone/clean.sh b/bin/tests/system/addzone/clean.sh index f5da8f4ee4..0eac23e6f1 100644 --- a/bin/tests/system/addzone/clean.sh +++ b/bin/tests/system/addzone/clean.sh @@ -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 diff --git a/bin/tests/system/addzone/tests.sh b/bin/tests/system/addzone/tests.sh index 061ea49867..c1e3c28932 100755 --- a/bin/tests/system/addzone/tests.sh +++ b/bin/tests/system/addzone/tests.sh @@ -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` diff --git a/bin/tests/system/autosign/clean.sh b/bin/tests/system/autosign/clean.sh index b35f98e57b..a4ccb43807 100644 --- a/bin/tests/system/autosign/clean.sh +++ b/bin/tests/system/autosign/clean.sh @@ -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 diff --git a/bin/tests/system/autosign/tests.sh b/bin/tests/system/autosign/tests.sh index 999c8f3d6f..e22523d1e4 100644 --- a/bin/tests/system/autosign/tests.sh +++ b/bin/tests/system/autosign/tests.sh @@ -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 diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 41455ef399..7acb26e887 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -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 index 0000000000..9a21557ff1 --- /dev/null +++ b/bin/tests/system/delzone/clean.sh @@ -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 index 0000000000..6638b1f1a3 --- /dev/null +++ b/bin/tests/system/delzone/ns1/inlineslave.db @@ -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 index 0000000000..58956c7135 --- /dev/null +++ b/bin/tests/system/delzone/ns1/named.conf @@ -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 index 0000000000..6e17487229 --- /dev/null +++ b/bin/tests/system/delzone/ns2/added.db @@ -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 index 0000000000..bff47a9469 --- /dev/null +++ b/bin/tests/system/delzone/ns2/named.args @@ -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 index 0000000000..10a0e66471 --- /dev/null +++ b/bin/tests/system/delzone/ns2/named.conf @@ -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 index 0000000000..52deb05eac --- /dev/null +++ b/bin/tests/system/delzone/ns2/normal.db @@ -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 index 0000000000..98b3a539ee --- /dev/null +++ b/bin/tests/system/delzone/setup.sh @@ -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 index 0000000000..e7e7716137 --- /dev/null +++ b/bin/tests/system/delzone/tests.sh @@ -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 diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh index 27fb9fc834..292eeef389 100644 --- a/bin/tests/system/inline/clean.sh +++ b/bin/tests/system/inline/clean.sh @@ -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 index 0000000000..83dd60fcd7 --- /dev/null +++ b/bin/tests/system/nzd2nzf/clean.sh @@ -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 index 0000000000..6e17487229 --- /dev/null +++ b/bin/tests/system/nzd2nzf/ns1/added.db @@ -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 index 0000000000..15475b7fc2 --- /dev/null +++ b/bin/tests/system/nzd2nzf/ns1/named.conf @@ -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 index 0000000000..d34fd30f7e --- /dev/null +++ b/bin/tests/system/nzd2nzf/prereq.sh @@ -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 index 0000000000..c82253db3e --- /dev/null +++ b/bin/tests/system/nzd2nzf/setup.sh @@ -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 index 0000000000..a030e8b145 --- /dev/null +++ b/bin/tests/system/nzd2nzf/tests.sh @@ -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 diff --git a/bin/tools/.gitignore b/bin/tools/.gitignore index cff80a5bd7..b760aa3025 100644 --- a/bin/tools/.gitignore +++ b/bin/tools/.gitignore @@ -4,5 +4,6 @@ genrandom isc-hmac-fixup mdig named-journalprint +named-nzd2nzf named-rrchecker nsec3hash diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in index 0477b9f47e..69721b66a5 100644 --- a/bin/tools/Makefile.in +++ b/bin/tools/Makefile.in @@ -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 index 0000000000..e69de29bb2 diff --git a/bin/tools/named-nzd2nzf.c b/bin/tools/named-nzd2nzf.c new file mode 100644 index 0000000000..65c3e6f6c8 --- /dev/null +++ b/bin/tools/named-nzd2nzf.c @@ -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 +#include +#include + +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 \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 index 0000000000..4aa3852556 --- /dev/null +++ b/bin/tools/named-nzd2nzf.docbook @@ -0,0 +1,97 @@ +]> + + + + + May 5, 2016 + + + + named-nzd2nzf + 8 + BIND9 + + + + named-nzd2nzf + + Convert an NZD database to NZF text format + + + + + + 2016 + Internet Systems Consortium, Inc. ("ISC") + + + + + + named-nzd2nzf + filename + + + + + DESCRIPTION + + named-nzd2nzf 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 + named via rndc addzone. + It can also be used to restore the old file format + when rolling back from a newer version + of BIND to an older version. + + + + + ARGUMENTS + + + filename + + + The name of the .nzd file whose contents + should be printed. + + + + + + + + SEE ALSO + + BIND 9 Administrator Reference Manual, + + + + + AUTHOR + Internet Systems Consortium + + + + diff --git a/bin/tools/named-nzd2nzf.html b/bin/tools/named-nzd2nzf.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/config.h.in b/config.h.in index 436136b472..a733fae8f6 100644 --- a/config.h.in +++ b/config.h.in @@ -326,6 +326,9 @@ int sigwait(const unsigned int *set, int *sig); /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H +/* Define if lmdb was found */ +#undef HAVE_LMDB + /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H diff --git a/configure b/configure index 27554e3da4..1a035ae56a 100755 --- 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 diff --git a/configure.in b/configure.in index 1c4492cdb0..0cabe41ad9 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index c624d080ac..af20651d7d 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -102,20 +102,21 @@ mechanism. - 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. - + Support for master entries with TSIG keys has been added to catalog zones, as well as support for allow-query and allow-transfer. - + - Added rndc python module. + Added an isc.rndc Python module, which allows + rndc commands to be sent from Python programs. @@ -469,6 +470,32 @@ configuration for a specified zone. + + + When BIND is built with the lmdb library + (Lightning Memory-Mapped Database), named + will store the configuration information for zones + that are added via rndc addzone + in a database, rather than in a flat "NZF" file. This + dramatically improves performance for + rndc delzone and + rndc modzone: deleting or changing + the contents of a database is much faster than rewriting + a text file. + + + On startup, if named finds an existing + NZF file, it will automatically convert it to the new NZD + database format. + + + 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 named-nzd2nzf + [RT #39837] + + Added server-side support for pipelined TCP queries. Clients diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 865fb69582..7653b6f886 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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 diff --git a/lib/dns/view.c b/lib/dns/view.c index db43eb917d..7d51d38713 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -10,6 +10,10 @@ #include +#ifdef HAVE_LMDB +#include +#endif + #include #include #include @@ -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