diff options
Diffstat (limited to 'contrib/dlz/drivers/dlz_bdb_driver.c')
-rw-r--r-- | contrib/dlz/drivers/dlz_bdb_driver.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/contrib/dlz/drivers/dlz_bdb_driver.c b/contrib/dlz/drivers/dlz_bdb_driver.c new file mode 100644 index 0000000..f68bd9e --- /dev/null +++ b/contrib/dlz/drivers/dlz_bdb_driver.c @@ -0,0 +1,800 @@ +/* + * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + * + * Permission to use, copy, modify, and 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 STICHTING NLNET + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * STICHTING NLNET 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. + * + * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was + * conceived and contributed by Rob Butler. + * + * Permission to use, copy, modify, and 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 ROB BUTLER + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * ROB BUTLER 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. + */ + +/* + * Copyright (C) 1999-2001, 2016 Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifdef DLZ_BDB + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <dns/log.h> +#include <dns/sdlz.h> +#include <dns/result.h> + +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/util.h> + +#include <named/globals.h> + +#include <dlz/dlz_bdb_driver.h> + +#include <db.h> + +static dns_sdlzimplementation_t *dlz_bdb = NULL; + +/* should the bdb driver use threads. */ +#ifdef ISC_PLATFORM_USETHREADS +#define bdb_threads DB_THREAD +#else +#define bdb_threads 0 +#endif + +/* BDB database names */ +#define dlz_data "dns_data" +#define dlz_zone "dns_zone" +#define dlz_host "dns_host" +#define dlz_client "dns_client" + +/*% + * This structure contains all the Berkeley DB handles + * for this instance of the BDB driver. + */ + +typedef struct bdb_instance { + DB_ENV *dbenv; /*%< BDB environment */ + DB *data; /*%< dns_data database handle */ + DB *zone; /*%< zone database handle */ + DB *host; /*%< host database handle */ + DB *client; /*%< client database handle */ + isc_mem_t *mctx; /*%< memory context */ + +} bdb_instance_t; + +typedef struct parsed_data { + char *zone; + char *host; + char *type; + int ttl; + char *data; +} parsed_data_t; + + +/* forward reference */ + +static isc_result_t +bdb_findzone(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo); + +/*% + * Parses the DBT from the Berkeley DB into a parsed_data record + * The parsed_data record should be allocated before and passed into the + * bdb_parse_data function. The char (type & data) fields should not + * be "free"d as that memory is part of the DBT data field. It will be + * "free"d when the DBT is freed. + */ + +static isc_result_t +bdb_parse_data(char *in, parsed_data_t *pd) { + + char *endp, *ttlStr; + char *tmp = in; + char *lastchar = (char *) &tmp[strlen(tmp) + 1]; + + /*% + * String should be formated as: + * zone(a space)host(a space)ttl(a space)type(a space)remaining data + * examples: + * example.com www 10 A 127.0.0.1 + * example.com mail 10 A 127.0.0.2 + * example.com @ 10 MX 20 mail.example.com + */ + + /* save pointer to zone */ + pd->zone = tmp; + + /* find space after zone and change it to a '\0' */ + tmp = strchr(tmp, ' '); + /* verify we found a space */ + if (tmp == NULL) + return ISC_R_FAILURE; + /* change the space to a null (string terminator) */ + tmp[0] = '\0'; + /* make sure it is safe to increment pointer */ + if (++tmp > lastchar) + return ISC_R_FAILURE; + + /* save pointer to host */ + pd->host = tmp; + + /* find space after type and change it to a '\0' */ + tmp = strchr(tmp, ' '); + /* verify we found a space */ + if (tmp == NULL) + return ISC_R_FAILURE; + /* change the space to a null (string terminator) */ + tmp[0] = '\0'; + /* make sure it is safe to increment pointer */ + if (++tmp > lastchar) + return ISC_R_FAILURE; + + /* save pointer to dns type */ + pd->type = tmp; + + /* find space after type and change it to a '\0' */ + tmp = strchr(tmp, ' '); + /* verify we found a space */ + if (tmp == NULL) + return ISC_R_FAILURE; + /* change the space to a null (string terminator) */ + tmp[0] = '\0'; + /* make sure it is safe to increment pointer */ + if (++tmp > lastchar) + return ISC_R_FAILURE; + + /* save pointer to dns ttl */ + ttlStr = tmp; + + /* find space after ttl and change it to a '\0' */ + tmp = strchr(tmp, ' '); + /* verify we found a space */ + if (tmp == NULL) + return ISC_R_FAILURE; + /* change the space to a null (string terminator) */ + tmp[0] = '\0'; + /* make sure it is safe to increment pointer */ + if (++tmp > lastchar) + return ISC_R_FAILURE; + + /* save pointer to remainder of DNS data */ + pd->data = tmp; + + /* convert ttl string to integer */ + pd->ttl = strtol(ttlStr, &endp, 10); + if (*endp != '\0' || pd->ttl < 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB driver ttl must be a postive number"); + return ISC_R_FAILURE; + } + + /* if we get this far everything should have worked. */ + return ISC_R_SUCCESS; +} + +/* + * DLZ methods + */ + +static isc_result_t +bdb_allowzonexfr(void *driverarg, void *dbdata, const char *name, + const char *client) +{ + isc_result_t result; + bdb_instance_t *db = (bdb_instance_t *) dbdata; + DBC *client_cursor = NULL; + DBT key, data; + + /* check to see if we are authoritative for the zone first. */ + result = bdb_findzone(driverarg, dbdata, name, NULL, NULL); + if (result != ISC_R_SUCCESS) + return (ISC_R_NOTFOUND); + + memset(&key, 0, sizeof(DBT)); + key.flags = DB_DBT_MALLOC; + key.data = strdup(name); + if (key.data == NULL) { + result = ISC_R_NOMEMORY; + goto xfr_cleanup; + } + key.size = strlen(key.data); + + memset(&data, 0, sizeof(DBT)); + data.flags = DB_DBT_MALLOC; + data.data = strdup(client); + if (data.data == NULL) { + result = ISC_R_NOMEMORY; + goto xfr_cleanup; + } + data.size = strlen(data.data); + + /* get a cursor to loop through zone data */ + if (db->client->cursor(db->client, NULL, &client_cursor, 0) != 0) { + result = ISC_R_FAILURE; + goto xfr_cleanup; + } + + switch(client_cursor->c_get(client_cursor, &key, &data, DB_GET_BOTH)) { + case DB_NOTFOUND: + case DB_SECONDARY_BAD: + result = ISC_R_NOTFOUND; + break; + case 0: + result = ISC_R_SUCCESS; + break; + default: + result = ISC_R_FAILURE; + } + + xfr_cleanup: + + /* free any memory duplicate string in the key field */ + if (key.data != NULL) + free(key.data); + + /* free any memory allocated to the data field. */ + if (data.data != NULL) + free(data.data); + + /* get rid of zone_cursor */ + if (client_cursor != NULL) + client_cursor->c_close(client_cursor); + + return result; + +} + +static isc_result_t +bdb_allnodes(const char *zone, void *driverarg, void *dbdata, + dns_sdlzallnodes_t *allnodes) +{ + + isc_result_t result = ISC_R_NOTFOUND; + bdb_instance_t *db = (bdb_instance_t *) dbdata; + DBC *zone_cursor = NULL; + DBT key, data; + int flags; + int bdbres; + parsed_data_t pd; + char *tmp = NULL, *tmp_zone; + + UNUSED(driverarg); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + key.data = tmp_zone = strdup(zone); + + if (key.data == NULL) + return (ISC_R_NOMEMORY); + + key.size = strlen(key.data); + + /* get a cursor to loop through zone data */ + if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) { + result = ISC_R_FAILURE; + goto allnodes_cleanup; + } + + flags = DB_SET; + + while ((bdbres = zone_cursor->c_get(zone_cursor, &key, &data, + flags)) == 0) { + + flags = DB_NEXT_DUP; + + tmp = realloc(tmp, data.size + 1); + if (tmp == NULL) + goto allnodes_cleanup; + + strncpy(tmp, data.data, data.size); + tmp[data.size] = '\0'; + + if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS) + goto allnodes_cleanup; + + result = dns_sdlz_putnamedrr(allnodes, pd.host, pd.type, + pd.ttl, pd.data); + if (result != ISC_R_SUCCESS) + goto allnodes_cleanup; + + } /* end while loop */ + + allnodes_cleanup: + + if (tmp != NULL) + free(tmp); + + /* free any memory duplicate string in the key field */ + if (tmp_zone != NULL) + free(tmp_zone); + + /* get rid of zone_cursor */ + if (zone_cursor != NULL) + zone_cursor->c_close(zone_cursor); + + return result; + +} + +/*% + * Performs BDB cleanup. + * Used by bdb_create if there is an error starting up. + * Used by bdb_destroy when the driver is shutting down. + */ + +static void +bdb_cleanup(bdb_instance_t *db) { + + isc_mem_t *mctx; + + /* close databases */ + if (db->data != NULL) + db->data->close(db->data, 0); + if (db->host != NULL) + db->host->close(db->host, 0); + if (db->zone != NULL) + db->zone->close(db->zone, 0); + if (db->client != NULL) + db->client->close(db->client, 0); + + /* close environment */ + if (db->dbenv != NULL) + db->dbenv->close(db->dbenv, 0); + + /* cleanup memory */ + if (db->mctx != NULL) { + /* save mctx for later */ + mctx = db->mctx; + /* return, and detach the memory */ + isc_mem_put(mctx, db, sizeof(bdb_instance_t)); + isc_mem_detach(&mctx); + } +} + +static isc_result_t +bdb_findzone(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo) +{ + + isc_result_t result; + bdb_instance_t *db = (bdb_instance_t *) dbdata; + DBC *zone_cursor = NULL; + DBT key, data; + + UNUSED(driverarg); + UNUSED(methods); + UNUSED(clientinfo); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + data.flags = DB_DBT_MALLOC; + + key.data = strdup(name); + + if (key.data == NULL) + return (ISC_R_NOMEMORY); + + key.size = strlen(key.data); + + /* get a cursor to loop through zone data */ + if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) { + result = ISC_R_NOTFOUND; + goto findzone_cleanup; + } + + switch(zone_cursor->c_get(zone_cursor, &key, &data, DB_SET)) { + case DB_NOTFOUND: + case DB_SECONDARY_BAD: + result = ISC_R_NOTFOUND; + break; + case 0: + result = ISC_R_SUCCESS; + break; + default: + result = ISC_R_FAILURE; + } + + findzone_cleanup: + + /* free any memory duplicate string in the key field */ + if (key.data != NULL) + free(key.data); + + /* free any memory allocated to the data field. */ + if (data.data != NULL) + free(data.data); + + /* get rid of zone_cursor */ + if (zone_cursor != NULL) + zone_cursor->c_close(zone_cursor); + + return result; +} + +static isc_result_t +bdb_lookup(const char *zone, const char *name, void *driverarg, + void *dbdata, dns_sdlzlookup_t *lookup, + dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo) +{ + + isc_result_t result = ISC_R_NOTFOUND; + bdb_instance_t *db = (bdb_instance_t *) dbdata; + DBC *zone_cursor = NULL; + DBC *host_cursor = NULL; + DBC *join_cursor = NULL; + DBT key, data; + DBC *cur_arr[3]; + int bdbres; + parsed_data_t pd; + char *tmp_zone, *tmp_host = NULL; + char *tmp = NULL; + + UNUSED(driverarg); + UNUSED(methods); + UNUSED(clientinfo); + + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + + /* set zone key */ + key.data = tmp_zone = strdup(zone); + if (key.data == NULL) { + result = ISC_R_NOMEMORY; + goto lookup_cleanup; + } + key.size = strlen(key.data); + + /* get a cursor to loop through zone data */ + if (db->zone->cursor(db->zone, NULL, &zone_cursor, 0) != 0) { + result = ISC_R_FAILURE; + goto lookup_cleanup; + } + + /* initialize zone_cursor with zone_key */ + if (zone_cursor->c_get(zone_cursor, &key, &data, DB_SET) != 0) { + result = ISC_R_NOTFOUND; + goto lookup_cleanup; + } + + /* set host key */ + key.data = tmp_host = strdup(name); + if (key.data == NULL) { + result = ISC_R_NOMEMORY; + goto lookup_cleanup; + } + key.size = strlen(key.data); + + /* get a cursor to loop through host data */ + if (db->host->cursor(db->host, NULL, &host_cursor, 0) != 0) { + result = ISC_R_FAILURE; + goto lookup_cleanup; + } + + /* initialize host_cursor with host_key */ + if (host_cursor->c_get(host_cursor, &key, &data, DB_SET) != 0) { + result = ISC_R_NOTFOUND; + goto lookup_cleanup; + } + + cur_arr[0] = zone_cursor; + cur_arr[1] = host_cursor; + cur_arr[2] = NULL; + + db->data->join(db->data, cur_arr, &join_cursor, 0); + + while ((bdbres = join_cursor->c_get(join_cursor, &key, + &data, 0)) == 0) { + + tmp = realloc(tmp, data.size + 1); + if (tmp == NULL) + goto lookup_cleanup; + + strncpy(tmp, data.data, data.size); + tmp[data.size] = '\0'; + + if (bdb_parse_data(tmp, &pd) != ISC_R_SUCCESS) + goto lookup_cleanup; + + result = dns_sdlz_putrr(lookup, pd.type, pd.ttl, pd.data); + + if (result != ISC_R_SUCCESS) + goto lookup_cleanup; + } /* end while loop */ + + lookup_cleanup: + + if (tmp != NULL) + free(tmp); + if (tmp_zone != NULL) + free(tmp_zone); + if (tmp_host != NULL) + free(tmp_host); + + /* get rid of the joined cusor */ + if (join_cursor != NULL) + join_cursor->c_close(join_cursor); + + /* get rid of zone_cursor */ + if (zone_cursor != NULL) + zone_cursor->c_close(zone_cursor); + + /* get rid of host_cursor */ + if (host_cursor != NULL) + host_cursor->c_close(host_cursor); + + return result; +} + + +/*% Initializes, sets flags and then opens Berkeley databases. */ + +static isc_result_t +bdb_opendb(DB_ENV *db_env, DBTYPE db_type, DB **db, const char *db_name, + char *db_file, int flags) { + + int result; + + /* Initialize the database. */ + if ((result = db_create(db, db_env, 0)) != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB could not initialize %s database. " + "BDB error: %s", + db_name, db_strerror(result)); + return ISC_R_FAILURE; + } + + /* set database flags. */ + if ((result = (*db)->set_flags(*db, flags)) != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB could not set flags for %s database. " + "BDB error: %s", + db_name, db_strerror(result)); + return ISC_R_FAILURE; + } + + /* open the database. */ + if ((result = (*db)->open(*db, NULL, db_file, db_name, db_type, + DB_RDONLY | bdb_threads, 0)) != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB could not open %s database in %s. " + "BDB error: %s", + db_name, db_file, db_strerror(result)); + return ISC_R_FAILURE; + } + + return ISC_R_SUCCESS; +} + +static isc_result_t +bdb_create(const char *dlzname, unsigned int argc, char *argv[], + void *driverarg, void **dbdata) +{ + isc_result_t result; + int bdbres; + bdb_instance_t *db = NULL; + + UNUSED(dlzname); + UNUSED(driverarg); + + /* verify we have 3 arg's passed to the driver */ + if (argc != 3) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Berkeley DB driver requires at least " + "2 command line args."); + return (ISC_R_FAILURE); + } + + /* allocate and zero memory for driver structure */ + db = isc_mem_get(ns_g_mctx, sizeof(bdb_instance_t)); + if (db == NULL) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "Could not allocate memory for " + "database instance object."); + return (ISC_R_NOMEMORY); + } + memset(db, 0, sizeof(bdb_instance_t)); + + /* attach to the memory context */ + isc_mem_attach(ns_g_mctx, &db->mctx); + + /* create BDB environment + * Basically BDB allocates and assigns memory to db->dbenv + */ + bdbres = db_env_create(&db->dbenv, 0); + if (bdbres != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB environment could not be created. " + "BDB error: %s", + db_strerror(bdbres)); + result = ISC_R_FAILURE; + goto init_cleanup; + } + + /* open BDB environment */ + bdbres = db->dbenv->open(db->dbenv, argv[1], + DB_INIT_CDB | DB_INIT_MPOOL | + bdb_threads | DB_CREATE, + 0); + if (bdbres != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB environment at '%s' could not be opened. " + "BDB error: %s", + argv[1], db_strerror(bdbres)); + result = ISC_R_FAILURE; + goto init_cleanup; + } + + /* open dlz_data database. */ + result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->data, + dlz_data, argv[2], 0); + if (result != ISC_R_SUCCESS) + goto init_cleanup; + + /* open dlz_host database. */ + result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->host, + dlz_host, argv[2], + DB_DUP | DB_DUPSORT); + if (result != ISC_R_SUCCESS) + goto init_cleanup; + + /* open dlz_zone database. */ + result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->zone, + dlz_zone, argv[2], + DB_DUP | DB_DUPSORT); + if (result != ISC_R_SUCCESS) + goto init_cleanup; + + /* open dlz_client database. */ + result = bdb_opendb(db->dbenv, DB_UNKNOWN, &db->client, + dlz_client, argv[2], DB_DUP | DB_DUPSORT); + if (result != ISC_R_SUCCESS) + goto init_cleanup; + + /* associate the host secondary database with the primary database */ + bdbres = db->data->associate(db->data, NULL, db->host, NULL, 0); + if (bdbres != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB could not associate %s database with %s. " + "BDB error: %s", + dlz_host, dlz_data, db_strerror(bdbres)); + result = ISC_R_FAILURE; + goto init_cleanup; + } + + /* associate the zone secondary database with the primary database */ + bdbres = db->data->associate(db->data, NULL, db->zone, NULL, 0); + if (bdbres != 0) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, + "BDB could not associate %s database with %s. " + "BDB error: %s", + dlz_zone, dlz_data, db_strerror(bdbres)); + result = ISC_R_FAILURE; + goto init_cleanup; + } + + *dbdata = db; + + return(ISC_R_SUCCESS); + + init_cleanup: + + bdb_cleanup(db); + return result; +} + +static void +bdb_destroy(void *driverarg, void *dbdata) +{ + UNUSED(driverarg); + + bdb_cleanup((bdb_instance_t *) dbdata); +} + +/* bdb_authority not needed as authority data is returned by lookup */ +static dns_sdlzmethods_t dlz_bdb_methods = { + bdb_create, + bdb_destroy, + bdb_findzone, + bdb_lookup, + NULL, + bdb_allnodes, + bdb_allowzonexfr, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +/*% + * Wrapper around dns_sdlzregister(). + */ +isc_result_t +dlz_bdb_init(void) { + isc_result_t result; + + /* + * Write debugging message to log + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), + "Registering DLZ bdb driver."); + + result = dns_sdlzregister("bdb", &dlz_bdb_methods, NULL, + DNS_SDLZFLAG_RELATIVEOWNER | + DNS_SDLZFLAG_RELATIVERDATA | + DNS_SDLZFLAG_THREADSAFE, + ns_g_mctx, &dlz_bdb); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "dns_sdlzregister() failed: %s", + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + } + + + return result; +} + +/*% + * Wrapper around dns_sdlzunregister(). + */ +void +dlz_bdb_clear(void) { + + /* + * Write debugging message to log + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, + DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), + "Unregistering DLZ bdb driver."); + + if (dlz_bdb != NULL) + dns_sdlzunregister(&dlz_bdb); +} + +#endif |