dlz_bdbhpt_driver.c [plain text]
#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_bdbhpt_driver.h>
#include <db.h>
static dns_sdlzimplementation_t *dlz_bdbhpt = NULL;
#ifdef ISC_PLATFORM_USETHREADS
#define bdbhpt_threads DB_THREAD
#else
#define bdbhpt_threads 0
#endif
#define dlz_data "dns_data"
#define dlz_zone "dns_zone"
#define dlz_xfr "dns_xfr"
#define dlz_client "dns_client"
typedef struct bdbhpt_instance {
DB_ENV *dbenv;
DB *data;
DB *zone;
DB *xfr;
DB *client;
isc_mem_t *mctx;
} bdbhpt_instance_t;
typedef struct bdbhpt_parsed_data {
char *host;
char *type;
int ttl;
char *data;
} bdbhpt_parsed_data_t;
static isc_result_t
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name);
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;
}
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)];
tmp = strchr(tmp, ' ');
if (tmp == NULL)
return ISC_R_FAILURE;
if (++tmp > lastchar)
return ISC_R_FAILURE;
pd->host = tmp;
tmp = strchr(tmp, ' ');
if (tmp == NULL)
return ISC_R_FAILURE;
tmp[0] = '\0';
if (++tmp > lastchar)
return ISC_R_FAILURE;
ttlStr = tmp;
tmp = strchr(tmp, ' ');
if (tmp == NULL)
return ISC_R_FAILURE;
tmp[0] = '\0';
if (++tmp > lastchar)
return ISC_R_FAILURE;
pd->type = tmp;
tmp = strchr(tmp, ' ');
if (tmp == NULL)
return ISC_R_FAILURE;
tmp[0] = '\0';
if (++tmp > lastchar)
return ISC_R_FAILURE;
pd->data = tmp;
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 postive number");
return ISC_R_FAILURE;
}
return ISC_R_SUCCESS;
}
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;
result = bdbhpt_findzone(driverarg, dbdata, name);
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:
if (key.data != NULL)
free(key.data);
if (data.data != NULL)
free(data.data);
return result;
}
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);
if (db->xfr->cursor(db->xfr, NULL, &xfr_cursor, 0) != 0) {
result = ISC_R_FAILURE;
goto allnodes_cleanup;
}
if (db->data->cursor(db->data, NULL, &dns_cursor, 0) != 0) {
result = ISC_R_FAILURE;
goto allnodes_cleanup;
}
xfr_flags = DB_SET;
while ((bdbhptres = xfr_cursor->c_get(xfr_cursor, &xfr_key, &xfr_data,
xfr_flags)) == 0) {
xfr_flags = DB_NEXT_DUP;
dns_key.size = xfr_data.size + xfr_key.size + 1;
dns_key.data = tmp_zone_host = malloc(dns_key.size + 1);
if (dns_key.data == NULL)
goto allnodes_cleanup;
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;
tmp = realloc(tmp, dns_data.size + 1);
if (tmp == NULL)
goto allnodes_cleanup;
strncpy(tmp, dns_data.data, dns_data.size);
tmp[dns_data.size] = '\0';
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;
}
if (tmp_zone_host != NULL) {
free(tmp_zone_host);
tmp_zone_host = NULL;
}
}
allnodes_cleanup:
if (tmp != NULL)
free(tmp);
if (tmp_zone_host != NULL)
free(tmp_zone_host);
if (tmp_zone != NULL)
free(tmp_zone);
if (xfr_cursor != NULL)
xfr_cursor->c_close(xfr_cursor);
if (dns_cursor != NULL)
dns_cursor->c_close(dns_cursor);
return result;
}
static void
bdbhpt_cleanup(bdbhpt_instance_t *db) {
isc_mem_t *mctx;
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);
if (db->dbenv != NULL)
db->dbenv->close(db->dbenv, 0);
if (db->mctx != NULL) {
mctx = db->mctx;
isc_mem_put(mctx, db, sizeof(bdbhpt_instance_t));
isc_mem_detach(&mctx);
}
}
static isc_result_t
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name)
{
isc_result_t result;
bdbhpt_instance_t *db = (bdbhpt_instance_t *) dbdata;
DBT key, data;
UNUSED(driverarg);
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.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;
}
if (key.data != NULL)
free(key.data);
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)
{
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);
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
key.size = strlen(zone) + strlen(name) + 1;
key.data = keyStr = malloc((key.size + 1) * sizeof(char));
if (keyStr == NULL)
return ISC_R_NOMEMORY;
strcpy(keyStr, zone);
strcat(keyStr, " ");
strcat(keyStr, name);
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;
}
lookup_cleanup:
if (data_cursor != NULL)
data_cursor->c_close(data_cursor);
if (keyStr != NULL)
free(keyStr);
if (tmp != NULL)
free(tmp);
return result;
}
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;
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;
}
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;
}
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);
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]) {
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;
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;
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);
}
db = isc_mem_get(ns_g_mctx, sizeof(bdbhpt_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(bdbhpt_instance_t));
isc_mem_attach(ns_g_mctx, &db->mctx);
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;
}
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;
}
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;
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;
result = bdbhpt_opendb(db->dbenv, DB_UNKNOWN, &db->zone,
dlz_zone, argv[3], 0);
if (result != ISC_R_SUCCESS)
goto init_cleanup;
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);
}
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,
};
isc_result_t
dlz_bdbhpt_init(void) {
isc_result_t result;
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,
ns_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;
}
void
dlz_bdbhpt_clear(void) {
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