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