mirror of
https://gitlab.isc.org/isc-projects/bind9.git
synced 2025-04-18 09:44:09 +03:00
870 lines
21 KiB
C
870 lines
21 KiB
C
/*
|
|
* 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 <db.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <isc/mem.h>
|
|
#include <isc/print.h>
|
|
#include <isc/result.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/log.h>
|
|
#include <dns/result.h>
|
|
#include <dns/sdlz.h>
|
|
|
|
#include <dlz/dlz_bdbhpt_driver.h>
|
|
#include <named/globals.h>
|
|
|
|
static dns_sdlzimplementation_t *dlz_bdbhpt = NULL;
|
|
|
|
/* should the bdb driver use threads. */
|
|
#define bdbhpt_threads DB_THREAD
|
|
|
|
/* bdbhpt database names */
|
|
#define dlz_data "dns_data"
|
|
#define dlz_zone "dns_zone"
|
|
#define dlz_xfr "dns_xfr"
|
|
#define dlz_client "dns_client"
|
|
|
|
/* This structure contains all the Berkeley DB handles
|
|
* for this instance of the bdbhpt driver.
|
|
*/
|
|
|
|
typedef struct bdbhpt_instance {
|
|
DB_ENV *dbenv; /*%< bdbhpt environment */
|
|
DB *data; /*%< dns_data database handle */
|
|
DB *zone; /*%< zone database handle */
|
|
DB *xfr; /*%< zone xfr database handle */
|
|
DB *client; /*%< client database handle */
|
|
isc_mem_t *mctx; /*%< memory context */
|
|
} bdbhpt_instance_t;
|
|
|
|
typedef struct bdbhpt_parsed_data {
|
|
char *host;
|
|
char *type;
|
|
int ttl;
|
|
char *data;
|
|
} bdbhpt_parsed_data_t;
|
|
|
|
/* forward reference */
|
|
|
|
static isc_result_t
|
|
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name,
|
|
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo);
|
|
|
|
/*%
|
|
* Reverses a string in place.
|
|
*/
|
|
|
|
static char *
|
|
bdbhpt_strrev(char *str) {
|
|
char *p1, *p2;
|
|
|
|
if (!str || !*str) {
|
|
return (str);
|
|
}
|
|
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
|
|
*p1 ^= *p2;
|
|
*p2 ^= *p1;
|
|
*p1 ^= *p2;
|
|
}
|
|
return (str);
|
|
}
|
|
|
|
/*%
|
|
* Parses the DBT from the Berkeley DB into a parsed_data record
|
|
* The parsed_data record should be allocated before and passed into the
|
|
* bdbhpt_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
|
|
bdbhpt_parse_data(char *in, bdbhpt_parsed_data_t *pd) {
|
|
char *endp, *ttlStr;
|
|
char *tmp = in;
|
|
char *lastchar = (char *)&tmp[strlen(tmp)];
|
|
|
|
/*%
|
|
* String should be formatted as:
|
|
* replication_id
|
|
* (a space)
|
|
* host_name
|
|
* (a space)
|
|
* ttl
|
|
* (a space)
|
|
* type
|
|
* (a space)
|
|
* remaining data
|
|
*
|
|
* examples:
|
|
*
|
|
* 9191 host 10 A 127.0.0.1
|
|
* server1_212 host 10 A 127.0.0.2
|
|
* {xxxx-xxxx-xxxx-xxxx-xxxx} host 10 MX 20 mail.example.com
|
|
*/
|
|
|
|
/*
|
|
* we don't need the replication id, so don't
|
|
* bother saving a pointer to it.
|
|
*/
|
|
|
|
/* find space after replication id */
|
|
tmp = strchr(tmp, ' ');
|
|
/* verify we found a space */
|
|
if (tmp == NULL) {
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
/* 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 host 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 ttl string */
|
|
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 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 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,
|
|
"bdbhpt driver ttl must be a positive number");
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
|
|
/* if we get this far everything should have worked. */
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* DLZ methods
|
|
*/
|
|
|
|
static isc_result_t
|
|
bdbhpt_allowzonexfr(void *driverarg, void *dbdata, const char *name,
|
|
const char *client) {
|
|
isc_result_t result;
|
|
bdbhpt_instance_t *db = (bdbhpt_instance_t *)dbdata;
|
|
DBT key, data;
|
|
|
|
/* check to see if we are authoritative for the zone first. */
|
|
result = bdbhpt_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);
|
|
|
|
switch (db->client->get(db->client, NULL, &key, &data, DB_GET_BOTH)) {
|
|
case DB_NOTFOUND:
|
|
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);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
/*%
|
|
* BDB does not allow a secondary index on a database that allows
|
|
* duplicates. We have a few options:
|
|
*
|
|
* 1) kill speed by having lookup method use a secondary db which
|
|
* is associated to the primary DB with the DNS data. Then have
|
|
* another secondary db for zone transfer which also points to
|
|
* the dns_data primary. NO - The point of this driver is
|
|
* lookup performance.
|
|
*
|
|
* 2) Blow up database size by storing DNS data twice. Once for
|
|
* the lookup (dns_data) database, and a second time for the zone
|
|
* transfer (dns_xfr) database. NO - That would probably require
|
|
* a larger cache to provide good performance. Also, that would
|
|
* make the DB larger on disk potentially slowing it as well.
|
|
*
|
|
* 3) Loop through the dns_xfr database with a cursor to get
|
|
* all the different hosts in a zone. Then use the zone & host
|
|
* together to lookup the data in the dns_data database. YES -
|
|
* This may slow down zone xfr's a little, but that's ok they
|
|
* don't happen as often and don't need to be as fast. We can
|
|
* also use this table when deleting a zone (The BDB driver
|
|
* is read only - the delete would be used during replication
|
|
* updates by a separate process).
|
|
*/
|
|
|
|
static isc_result_t
|
|
bdbhpt_allnodes(const char *zone, void *driverarg, void *dbdata,
|
|
dns_sdlzallnodes_t *allnodes) {
|
|
isc_result_t result = ISC_R_NOTFOUND;
|
|
bdbhpt_instance_t *db = (bdbhpt_instance_t *)dbdata;
|
|
DBC *xfr_cursor = NULL;
|
|
DBC *dns_cursor = NULL;
|
|
DBT xfr_key, xfr_data, dns_key, dns_data;
|
|
int xfr_flags;
|
|
int dns_flags;
|
|
int bdbhptres;
|
|
bdbhpt_parsed_data_t pd;
|
|
char *tmp = NULL, *tmp_zone, *tmp_zone_host = NULL;
|
|
|
|
UNUSED(driverarg);
|
|
|
|
memset(&xfr_key, 0, sizeof(DBT));
|
|
memset(&xfr_data, 0, sizeof(DBT));
|
|
memset(&dns_key, 0, sizeof(DBT));
|
|
memset(&dns_data, 0, sizeof(DBT));
|
|
|
|
xfr_key.data = tmp_zone = strdup(zone);
|
|
if (xfr_key.data == NULL) {
|
|
return (ISC_R_NOMEMORY);
|
|
}
|
|
|
|
xfr_key.size = strlen(xfr_key.data);
|
|
|
|
/* get a cursor to loop through dns_xfr table */
|
|
if (db->xfr->cursor(db->xfr, NULL, &xfr_cursor, 0) != 0) {
|
|
result = ISC_R_FAILURE;
|
|
goto allnodes_cleanup;
|
|
}
|
|
|
|
/* get a cursor to loop through dns_data table */
|
|
if (db->data->cursor(db->data, NULL, &dns_cursor, 0) != 0) {
|
|
result = ISC_R_FAILURE;
|
|
goto allnodes_cleanup;
|
|
}
|
|
|
|
xfr_flags = DB_SET;
|
|
|
|
/* loop through xfr table for specified zone. */
|
|
while ((bdbhptres = xfr_cursor->c_get(xfr_cursor, &xfr_key, &xfr_data,
|
|
xfr_flags)) == 0)
|
|
{
|
|
xfr_flags = DB_NEXT_DUP;
|
|
|
|
/* +1 to allow for space between zone and host names */
|
|
dns_key.size = xfr_data.size + xfr_key.size + 1;
|
|
|
|
/* +1 to allow for null term at end of string. */
|
|
dns_key.data = tmp_zone_host = malloc(dns_key.size + 1);
|
|
if (dns_key.data == NULL) {
|
|
goto allnodes_cleanup;
|
|
}
|
|
|
|
/*
|
|
* construct search key for dns_data.
|
|
* zone_name(a space)host_name
|
|
*/
|
|
strcpy(dns_key.data, zone);
|
|
strcat(dns_key.data, " ");
|
|
strncat(dns_key.data, xfr_data.data, xfr_data.size);
|
|
|
|
dns_flags = DB_SET;
|
|
|
|
while ((bdbhptres = dns_cursor->c_get(dns_cursor, &dns_key,
|
|
&dns_data, dns_flags)) ==
|
|
0)
|
|
{
|
|
dns_flags = DB_NEXT_DUP;
|
|
|
|
/* +1 to allow for null term at end of string. */
|
|
tmp = realloc(tmp, dns_data.size + 1);
|
|
if (tmp == NULL) {
|
|
goto allnodes_cleanup;
|
|
}
|
|
|
|
/* copy data to tmp string, and append null term. */
|
|
strncpy(tmp, dns_data.data, dns_data.size);
|
|
tmp[dns_data.size] = '\0';
|
|
|
|
/* split string into dns data parts. */
|
|
if (bdbhpt_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 inner while loop */
|
|
|
|
/* clean up memory */
|
|
if (tmp_zone_host != NULL) {
|
|
free(tmp_zone_host);
|
|
tmp_zone_host = NULL;
|
|
}
|
|
} /* end outer while loop */
|
|
|
|
allnodes_cleanup:
|
|
|
|
/* free any memory */
|
|
if (tmp != NULL) {
|
|
free(tmp);
|
|
}
|
|
|
|
if (tmp_zone_host != NULL) {
|
|
free(tmp_zone_host);
|
|
}
|
|
|
|
if (tmp_zone != NULL) {
|
|
free(tmp_zone);
|
|
}
|
|
|
|
/* get rid of cursors */
|
|
if (xfr_cursor != NULL) {
|
|
xfr_cursor->c_close(xfr_cursor);
|
|
}
|
|
|
|
if (dns_cursor != NULL) {
|
|
dns_cursor->c_close(dns_cursor);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
/*%
|
|
* Performs bdbhpt cleanup.
|
|
* Used by bdbhpt_create if there is an error starting up.
|
|
* Used by bdbhpt_destroy when the driver is shutting down.
|
|
*/
|
|
|
|
static void
|
|
bdbhpt_cleanup(bdbhpt_instance_t *db) {
|
|
isc_mem_t *mctx;
|
|
|
|
/* close databases */
|
|
if (db->data != NULL) {
|
|
db->data->close(db->data, 0);
|
|
}
|
|
if (db->xfr != NULL) {
|
|
db->xfr->close(db->xfr, 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_putanddetach(&mctx, db, sizeof(bdbhpt_instance_t));
|
|
}
|
|
}
|
|
|
|
static isc_result_t
|
|
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name,
|
|
dns_clientinfomethods_t *methods,
|
|
dns_clientinfo_t *clientinfo) {
|
|
isc_result_t result;
|
|
bdbhpt_instance_t *db = (bdbhpt_instance_t *)dbdata;
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* reverse string to take advantage of BDB locality of reference
|
|
* if we need further lookups because the zone doesn't match the
|
|
* first time.
|
|
*/
|
|
key.data = bdbhpt_strrev(key.data);
|
|
key.size = strlen(key.data);
|
|
|
|
switch (db->zone->get(db->zone, NULL, &key, &data, 0)) {
|
|
case DB_NOTFOUND:
|
|
result = ISC_R_NOTFOUND;
|
|
break;
|
|
case 0:
|
|
result = ISC_R_SUCCESS;
|
|
break;
|
|
default:
|
|
result = ISC_R_FAILURE;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
static isc_result_t
|
|
bdbhpt_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;
|
|
bdbhpt_instance_t *db = (bdbhpt_instance_t *)dbdata;
|
|
DBC *data_cursor = NULL;
|
|
DBT key, data;
|
|
int bdbhptres;
|
|
int flags;
|
|
|
|
bdbhpt_parsed_data_t pd;
|
|
char *tmp = NULL;
|
|
char *keyStr = NULL;
|
|
|
|
UNUSED(driverarg);
|
|
UNUSED(methods);
|
|
UNUSED(clientinfo);
|
|
|
|
memset(&key, 0, sizeof(DBT));
|
|
memset(&data, 0, sizeof(DBT));
|
|
|
|
key.size = strlen(zone) + strlen(name) + 1;
|
|
|
|
/* allocate mem for key */
|
|
key.data = keyStr = malloc((key.size + 1) * sizeof(char));
|
|
|
|
if (keyStr == NULL) {
|
|
return (ISC_R_NOMEMORY);
|
|
}
|
|
|
|
strcpy(keyStr, zone);
|
|
strcat(keyStr, " ");
|
|
strcat(keyStr, name);
|
|
|
|
/* get a cursor to loop through data */
|
|
if (db->data->cursor(db->data, NULL, &data_cursor, 0) != 0) {
|
|
result = ISC_R_FAILURE;
|
|
goto lookup_cleanup;
|
|
}
|
|
|
|
result = ISC_R_NOTFOUND;
|
|
|
|
flags = DB_SET;
|
|
while ((bdbhptres = data_cursor->c_get(data_cursor, &key, &data,
|
|
flags)) == 0) {
|
|
flags = DB_NEXT_DUP;
|
|
tmp = realloc(tmp, data.size + 1);
|
|
if (tmp == NULL) {
|
|
goto lookup_cleanup;
|
|
}
|
|
|
|
strncpy(tmp, data.data, data.size);
|
|
tmp[data.size] = '\0';
|
|
|
|
if (bdbhpt_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:
|
|
|
|
/* get rid of cursor */
|
|
if (data_cursor != NULL) {
|
|
data_cursor->c_close(data_cursor);
|
|
}
|
|
|
|
free(keyStr);
|
|
if (tmp != NULL) {
|
|
free(tmp);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
/*% Initializes, sets flags and then opens Berkeley databases. */
|
|
|
|
static isc_result_t
|
|
bdbhpt_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,
|
|
"bdbhpt could not initialize %s database. "
|
|
"bdbhpt 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,
|
|
"bdbhpt could not set flags for %s database. "
|
|
"bdbhpt 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 | bdbhpt_threads, 0)) != 0)
|
|
{
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"bdbhpt could not open %s database in %s. "
|
|
"bdbhpt error: %s",
|
|
db_name, db_file, db_strerror(result));
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static isc_result_t
|
|
bdbhpt_create(const char *dlzname, unsigned int argc, char *argv[],
|
|
void *driverarg, void **dbdata) {
|
|
isc_result_t result;
|
|
int bdbhptres;
|
|
int bdbFlags = 0;
|
|
bdbhpt_instance_t *db = NULL;
|
|
|
|
UNUSED(dlzname);
|
|
UNUSED(driverarg);
|
|
|
|
/* verify we have 4 arg's passed to the driver */
|
|
if (argc != 4) {
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"bdbhpt driver requires at least "
|
|
"3 command line args.");
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
|
|
switch ((char)*argv[1]) {
|
|
/*
|
|
* Transactional mode. Highest safety - lowest speed.
|
|
*/
|
|
case 'T':
|
|
case 't':
|
|
bdbFlags = DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG |
|
|
DB_INIT_TXN;
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
|
|
"bdbhpt driver using transactional mode.");
|
|
break;
|
|
/*
|
|
* Concurrent mode. Lower safety (no rollback) -
|
|
* higher speed.
|
|
*/
|
|
case 'C':
|
|
case 'c':
|
|
bdbFlags = DB_INIT_CDB | DB_INIT_MPOOL;
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
|
|
"bdbhpt driver using concurrent mode.");
|
|
break;
|
|
/*
|
|
* Private mode. No inter-process communication & no locking.
|
|
* Lowest safety - highest speed.
|
|
*/
|
|
case 'P':
|
|
case 'p':
|
|
bdbFlags = DB_PRIVATE | DB_INIT_MPOOL;
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
|
|
"bdbhpt driver using private mode.");
|
|
break;
|
|
default:
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"bdbhpt driver requires the operating mode "
|
|
"be set to P or C or T. You specified '%s'",
|
|
argv[1]);
|
|
return (ISC_R_FAILURE);
|
|
}
|
|
|
|
/* allocate and zero memory for driver structure */
|
|
db = isc_mem_get(named_g_mctx, sizeof(bdbhpt_instance_t));
|
|
memset(db, 0, sizeof(bdbhpt_instance_t));
|
|
|
|
/* attach to the memory context */
|
|
isc_mem_attach(named_g_mctx, &db->mctx);
|
|
|
|
/*
|
|
* create bdbhpt environment
|
|
* Basically bdbhpt allocates and assigns memory to db->dbenv
|
|
*/
|
|
bdbhptres = db_env_create(&db->dbenv, 0);
|
|
if (bdbhptres != 0) {
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"bdbhpt environment could not be created. "
|
|
"bdbhpt error: %s",
|
|
db_strerror(bdbhptres));
|
|
result = ISC_R_FAILURE;
|
|
goto init_cleanup;
|
|
}
|
|
|
|
/* open bdbhpt environment */
|
|
bdbhptres = db->dbenv->open(db->dbenv, argv[2],
|
|
bdbFlags | bdbhpt_threads | DB_CREATE, 0);
|
|
if (bdbhptres != 0) {
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
|
|
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
|
|
"bdbhpt environment at '%s' could not be opened."
|
|
" bdbhpt error: %s",
|
|
argv[2], db_strerror(bdbhptres));
|
|
result = ISC_R_FAILURE;
|
|
goto init_cleanup;
|
|
}
|
|
|
|
/* open dlz_data database. */
|
|
result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->data, dlz_data,
|
|
argv[3], DB_DUP | DB_DUPSORT);
|
|
if (result != ISC_R_SUCCESS) {
|
|
goto init_cleanup;
|
|
}
|
|
|
|
/* open dlz_xfr database. */
|
|
result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->xfr, dlz_xfr,
|
|
argv[3], DB_DUP | DB_DUPSORT);
|
|
if (result != ISC_R_SUCCESS) {
|
|
goto init_cleanup;
|
|
}
|
|
|
|
/* open dlz_zone database. */
|
|
result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->zone, dlz_zone,
|
|
argv[3], 0);
|
|
if (result != ISC_R_SUCCESS) {
|
|
goto init_cleanup;
|
|
}
|
|
|
|
/* open dlz_client database. */
|
|
result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->client, dlz_client,
|
|
argv[3], DB_DUP | DB_DUPSORT);
|
|
if (result != ISC_R_SUCCESS) {
|
|
goto init_cleanup;
|
|
}
|
|
|
|
*dbdata = db;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
init_cleanup:
|
|
|
|
bdbhpt_cleanup(db);
|
|
return (result);
|
|
}
|
|
|
|
static void
|
|
bdbhpt_destroy(void *driverarg, void *dbdata) {
|
|
UNUSED(driverarg);
|
|
|
|
bdbhpt_cleanup((bdbhpt_instance_t *)dbdata);
|
|
}
|
|
|
|
/*
|
|
* bdbhpt_authority not needed as authority data is returned by lookup
|
|
*/
|
|
static dns_sdlzmethods_t dlz_bdbhpt_methods = {
|
|
bdbhpt_create,
|
|
bdbhpt_destroy,
|
|
bdbhpt_findzone,
|
|
bdbhpt_lookup,
|
|
NULL,
|
|
bdbhpt_allnodes,
|
|
bdbhpt_allowzonexfr,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
/*%
|
|
* Wrapper around dns_sdlzregister().
|
|
*/
|
|
isc_result_t
|
|
dlz_bdbhpt_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 bdbhpt driver.");
|
|
|
|
result = dns_sdlzregister("bdbhpt", &dlz_bdbhpt_methods, NULL,
|
|
DNS_SDLZFLAG_RELATIVEOWNER |
|
|
DNS_SDLZFLAG_RELATIVERDATA |
|
|
DNS_SDLZFLAG_THREADSAFE,
|
|
named_g_mctx, &dlz_bdbhpt);
|
|
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_bdbhpt_clear(void) {
|
|
/*
|
|
* Write debugging message to log
|
|
*/
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
|
|
ISC_LOG_DEBUG(2), "Unregistering DLZ bdbhpt driver.");
|
|
|
|
if (dlz_bdbhpt != NULL) {
|
|
dns_sdlzunregister(&dlz_bdbhpt);
|
|
}
|
|
}
|
|
|
|
#endif /* ifdef DLZ_BDB */
|