diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/sdb/sqlite/README.sdb_sqlite | 67 | ||||
-rw-r--r-- | contrib/sdb/sqlite/sqlitedb.c | 325 | ||||
-rw-r--r-- | contrib/sdb/sqlite/sqlitedb.h | 15 | ||||
-rw-r--r-- | contrib/sdb/sqlite/zone2sqlite.c | 296 |
4 files changed, 703 insertions, 0 deletions
diff --git a/contrib/sdb/sqlite/README.sdb_sqlite b/contrib/sdb/sqlite/README.sdb_sqlite new file mode 100644 index 0000000..36128e1 --- /dev/null +++ b/contrib/sdb/sqlite/README.sdb_sqlite @@ -0,0 +1,67 @@ + SQLite BIND SDB driver + +The SQLite BIND SDB "driver" is intended as an alternative both to the +pgsqldb and dirdb drivers, for situations that would like the management +simplicity and convenience of single filesystem files, with the additional +capability of SQL databases. It is also intended as an alternative to +the standard dynamic DNS update capability in bind, which effectively +requires use of DNSSEC keys for authorization and is limited to 'nsupdate' +for updates. An sqlite database, by contrast, uses and requires only +normal filesystem permissions, and may be updated however a typical SQLite +database might be updated, e.g., via a web service with an SQLite backend. + +This driver is not considered suitable for very high volume public +nameserver use, while likely useful for smaller private nameserver +applications, whether or not in a production environment. It should +generally be suitable wherever SQLite is preferable over larger database +engines, and not suitable where SQLite is not preferable. + +Usage: + +o Use the named_sdb process ( put ENABLE_SDB=yes in /etc/sysconfig/named ) + +o Edit your named.conf to contain a database zone, eg.: + +zone "mydomain.net." IN { + type master; + database "sqlite /etc/named.d/mydomain.db mydomain"; + # ^- DB file ^-Table +}; + +o Create the database zone table + The table must contain the columns "name", "rdtype", and "rdata", and + is expected to contain a properly constructed zone. The program + "zone2sqlite" creates such a table. + + zone2sqlite usage: + + zone2sqlite origin zonefile dbfile dbtable + + where + origin : zone origin, eg "mydomain.net." + zonefile : master zone database file, eg. mydomain.net.zone + dbfile : name of SQLite database file + dbtable : name of table in database + +--- +# mydomain.net.zone: +$TTL 1H +@ SOA localhost. root.localhost. ( 1 + 3H + 1H + 1W + 1H ) + NS localhost. +host1 A 192.168.2.1 +host2 A 192.168.2.2 +host3 A 192.168.2.3 +host4 A 192.168.2.4 +host5 A 192.168.2.5 +host6 A 192.168.2.6 +host7 A 192.168.2.7 +--- + +# zone2sqlite mydomain.net. mydomain.net.zone mydomain.net.db mydomain + +will create/update the 'mydomain' table in database file 'mydomain.net.db'. + diff --git a/contrib/sdb/sqlite/sqlitedb.c b/contrib/sdb/sqlite/sqlitedb.c new file mode 100644 index 0000000..dc93db4 --- /dev/null +++ b/contrib/sdb/sqlite/sqlitedb.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2007, 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/. + */ + + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <sqlite3.h> + +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/util.h> + +#include <dns/sdb.h> +#include <dns/result.h> + +#include <named/globals.h> + +#include "sqlitedb.h" + +/* + * A simple database driver that interfaces to a SQLite database. + * + * The table must contain the fields "name", "rdtype", and "rdata", and + * is expected to contain a properly constructed zone. The program "zonetodb" + * creates such a table. + */ + +static dns_sdbimplementation_t *sqlitedb = NULL; + +typedef struct _dbinfo { + sqlite3 *db; + char *filename; + char *table; +} dbinfo_t; + + +static isc_result_t +db_connect(dbinfo_t *dbi) +{ + if (sqlite3_open(dbi->filename, &dbi->db) == SQLITE_OK) { + return (ISC_R_SUCCESS); + } else { + /* a connection is returned even if the open fails */ + sqlite3_close(dbi->db); + dbi->db = NULL; + return (ISC_R_FAILURE); + } +} + + +typedef struct _lookup_parm_t { + int i; + dns_sdblookup_t *lookup; + isc_result_t result; +} lookup_parm_t; + + +static int +sqlitedb_lookup_cb(void *p, int cc, char **cv, char **cn) +{ + lookup_parm_t *parm = p; + dns_ttl_t ttl; + char *endp; + + /* FIXME - check these(num/names); I'm assuming a mapping for now */ + char *ttlstr = cv[0]; + char *type = cv[1]; + char *data = cv[2]; + + UNUSED(cc); + UNUSED(cn); + + ttl = strtol(ttlstr, &endp, 10); + if (*endp) { + parm->result = DNS_R_BADTTL; + return 1; + } + + parm->result = dns_sdb_putrr(parm->lookup, type, ttl, data); + + if (parm->result != ISC_R_SUCCESS) + return 1; + + (parm->i)++; + + return 0; +} + + +#ifdef DNS_CLIENTINFO_VERSION +static isc_result_t +sqlitedb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo) +#else +static isc_result_t +sqlitedb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +#endif /* DNS_CLIENTINFO_VERSION */ +/* + * synchronous absolute name lookup + */ +{ + dbinfo_t *dbi = (dbinfo_t *) dbdata; + char *sql; + lookup_parm_t parm = { 0, lookup, ISC_R_SUCCESS }; + char *errmsg = NULL; + int result; + + UNUSED(zone); +#ifdef DNS_CLIENTINFO_VERSION + UNUSED(methods); + UNUSED(clientinfo); +#endif /* DNS_CLIENTINFO_VERSION */ + + sql = sqlite3_mprintf( + "SELECT TTL,RDTYPE,RDATA FROM \"%q\" WHERE " + "lower(NAME) = lower('%q')", + dbi->table, name); + + result = sqlite3_exec(dbi->db, sql, + &sqlitedb_lookup_cb, &parm, + &errmsg); + sqlite3_free(sql); + + if (result != SQLITE_OK) + return (ISC_R_FAILURE); + if (parm.i == 0) + return (ISC_R_NOTFOUND); + + return (ISC_R_SUCCESS); +} + + +typedef struct _allnodes_parm_t { + int i; + dns_sdballnodes_t *allnodes; + isc_result_t result; +} allnodes_parm_t; + + +static int +sqlitedb_allnodes_cb(void *p, int cc, char **cv, char **cn) +{ + allnodes_parm_t *parm = p; + dns_ttl_t ttl; + char *endp; + + /* FIXME - check these(num/names); I'm assuming a mapping for now */ + char *ttlstr = cv[0]; + char *name = cv[1]; + char *type = cv[2]; + char *data = cv[3]; + + UNUSED(cc); + UNUSED(cn); + + ttl = strtol(ttlstr, &endp, 10); + if (*endp) { + parm->result = DNS_R_BADTTL; + return 1; + } + + parm->result = dns_sdb_putnamedrr(parm->allnodes, name, type, ttl, data); + + if (parm->result != ISC_R_SUCCESS) + return 1; + + (parm->i)++; + + return 0; +} + + +static isc_result_t +sqlitedb_allnodes(const char *zone, + void *dbdata, + dns_sdballnodes_t *allnodes) +{ + dbinfo_t *dbi = (dbinfo_t *) dbdata; + char *sql; + allnodes_parm_t parm = { 0, allnodes, ISC_R_SUCCESS }; + char *errmsg = NULL; + int result; + + UNUSED(zone); + + sql = sqlite3_mprintf( + "SELECT TTL,NAME,RDTYPE,RDATA FROM \"%q\" ORDER BY NAME", + dbi->table); + + result = sqlite3_exec(dbi->db, sql, + &sqlitedb_allnodes_cb, &parm, + &errmsg); + sqlite3_free(sql); + + if (result != SQLITE_OK) + return (ISC_R_FAILURE); + if (parm.i == 0) + return (ISC_R_NOTFOUND); + + return (ISC_R_SUCCESS); +} + + +static void +sqlitedb_destroy(const char *zone, void *driverdata, void **dbdata) +{ + dbinfo_t *dbi = *dbdata; + + UNUSED(zone); + UNUSED(driverdata); + + if (dbi->db != NULL) + sqlite3_close(dbi->db); + if (dbi->table != NULL) + isc_mem_free(ns_g_mctx, dbi->table); + if (dbi->filename != NULL) + isc_mem_free(ns_g_mctx, dbi->filename); + + isc_mem_put(ns_g_mctx, dbi, sizeof(dbinfo_t)); +} + + +#define STRDUP_OR_FAIL(target, source) \ + do { \ + target = isc_mem_strdup(ns_g_mctx, source); \ + if (target == NULL) { \ + result = ISC_R_NOMEMORY; \ + goto cleanup; \ + } \ + } while (0); + +/* + * Create a connection to the database and save any necessary information + * in dbdata. + * + * argv[0] is the name of the database file + * argv[1] is the name of the table + */ +static isc_result_t +sqlitedb_create(const char *zone, + int argc, char **argv, + void *driverdata, void **dbdata) +{ + dbinfo_t *dbi; + isc_result_t result; + + UNUSED(zone); + UNUSED(driverdata); + + if (argc < 2) + return (ISC_R_FAILURE); + + dbi = isc_mem_get(ns_g_mctx, sizeof(dbinfo_t)); + if (dbi == NULL) + return (ISC_R_NOMEMORY); + dbi->db = NULL; + dbi->filename = NULL; + dbi->table = NULL; + + STRDUP_OR_FAIL(dbi->filename, argv[0]); + STRDUP_OR_FAIL(dbi->table, argv[1]); + + result = db_connect(dbi); + if (result != ISC_R_SUCCESS) + goto cleanup; + + *dbdata = dbi; + return (ISC_R_SUCCESS); + +cleanup: + sqlitedb_destroy(zone, driverdata, (void **)&dbi); + return (result); +} + + +/* + * Since the SQL database corresponds to a zone, the authority data should + * be returned by the lookup() function. Therefore the authority() function + * is NULL. + */ +static dns_sdbmethods_t sqlitedb_methods = { + sqlitedb_lookup, + NULL, /* authority */ + sqlitedb_allnodes, + sqlitedb_create, + sqlitedb_destroy, + NULL /* lookup2 */ +}; + + +/* + * Wrapper around dns_sdb_register(). + */ +isc_result_t +sqlitedb_init(void) +{ + unsigned int flags; + flags = 0; + return (dns_sdb_register("sqlite", &sqlitedb_methods, NULL, flags, + ns_g_mctx, &sqlitedb)); +} + + +/* + * Wrapper around dns_sdb_unregister(). + */ +void +sqlitedb_clear(void) +{ + if (sqlitedb != NULL) + dns_sdb_unregister(&sqlitedb); +} diff --git a/contrib/sdb/sqlite/sqlitedb.h b/contrib/sdb/sqlite/sqlitedb.h new file mode 100644 index 0000000..34f63dc --- /dev/null +++ b/contrib/sdb/sqlite/sqlitedb.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2000-2002, 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/. + */ + + +#include <isc/types.h> + +isc_result_t sqlitedb_init(void); + +void sqlitedb_clear(void); + diff --git a/contrib/sdb/sqlite/zone2sqlite.c b/contrib/sdb/sqlite/zone2sqlite.c new file mode 100644 index 0000000..86d577e --- /dev/null +++ b/contrib/sdb/sqlite/zone2sqlite.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007, 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/. + */ + +#include <stdlib.h> +#include <string.h> + +#include <isc/buffer.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/result.h> + +#include <dns/db.h> +#include <dns/dbiterator.h> +#include <isc/entropy.h> +#include <dns/fixedname.h> +#include <isc/hash.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataset.h> +#include <dns/rdatasetiter.h> +#include <dns/rdatatype.h> +#include <dns/result.h> + +#include <sqlite3.h> + +#ifndef UNUSED +#define UNUSED(x) (x) = (x) +#endif + +/* + * Generate an SQLite table from a zone. + */ + +typedef struct _dbinfo { + sqlite3 *db; + char *filename; + char *table; +} dbinfo_t; + +dbinfo_t dbi = { NULL, NULL, NULL }; + + +static void +closeandexit(int status) +{ + if (dbi.db) { + sqlite3_close(dbi.db); + dbi.db = NULL; + } + exit(status); +} + +static void +check_result(isc_result_t result, const char *message) +{ + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s: %s\n", message, + isc_result_totext(result)); + closeandexit(1); + } +} + +static isc_result_t +db_connect(dbinfo_t *dbi) +{ + if (sqlite3_open(dbi->filename, &dbi->db) == SQLITE_OK) { + return (ISC_R_SUCCESS); + } else { + /* a connection is returned even if the open fails */ + sqlite3_close(dbi->db); + dbi->db = NULL; + return (ISC_R_FAILURE); + } +} + +static int +add_rdata_cb(void *parm, int cc, char **cv, char **cn) +{ + UNUSED(parm); + UNUSED(cc); + UNUSED(cv); + UNUSED(cn); + + return 0; +} + + +static void +addrdata(dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) +{ + unsigned char namearray[DNS_NAME_MAXTEXT + 1]; + unsigned char typearray[20]; + unsigned char dataarray[2048]; + isc_buffer_t b; + isc_result_t result; + char *sql; + char *errmsg = NULL; + int res; + + isc_buffer_init(&b, namearray, sizeof(namearray) - 1); + result = dns_name_totext(name, true, &b); + check_result(result, "dns_name_totext"); + namearray[isc_buffer_usedlength(&b)] = 0; + + isc_buffer_init(&b, typearray, sizeof(typearray) - 1); + result = dns_rdatatype_totext(rdata->type, &b); + check_result(result, "dns_rdatatype_totext"); + typearray[isc_buffer_usedlength(&b)] = 0; + + isc_buffer_init(&b, dataarray, sizeof(dataarray) - 1); + result = dns_rdata_totext(rdata, NULL, &b); + check_result(result, "dns_rdata_totext"); + dataarray[isc_buffer_usedlength(&b)] = 0; + + sql = sqlite3_mprintf( + "INSERT INTO %Q (NAME, TTL, RDTYPE, RDATA)" + " VALUES ('%q', %d, '%q', '%q') ", + dbi.table, + namearray, ttl, typearray, dataarray); + printf("%s\n", sql); + res = sqlite3_exec(dbi.db, sql, add_rdata_cb, NULL, &errmsg); + sqlite3_free(sql); + + if (res != SQLITE_OK) { + fprintf(stderr, "INSERT failed: %s\n", errmsg); + closeandexit(1); + } +} + +int +main(int argc, char *argv[]) +{ + char *sql; + int res; + char *errmsg = NULL; + char *porigin, *zonefile; + dns_fixedname_t forigin, fname; + dns_name_t *origin, *name; + dns_db_t *db = NULL; + dns_dbiterator_t *dbiter; + dns_dbnode_t *node; + dns_rdatasetiter_t *rdsiter; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_mem_t *mctx = NULL; + isc_entropy_t *ectx = NULL; + isc_buffer_t b; + isc_result_t result; + + if (argc != 5) { + printf("usage: %s <zone> <zonefile> <dbfile> <dbtable>\n", argv[0]); + exit(1); + } + + porigin = argv[1]; + zonefile = argv[2]; + + dbi.filename = argv[3]; + dbi.table = argv[4]; + + dns_result_register(); + + result = isc_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create"); + result = isc_entropy_create(mctx, &ectx); + check_result(result, "isc_entropy_create"); + result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); + check_result(result, "isc_hash_create"); + + isc_buffer_init(&b, porigin, strlen(porigin)); + isc_buffer_add(&b, strlen(porigin)); + origin = dns_fixedname_initname(&forigin); + result = dns_name_fromtext(origin, &b, dns_rootname, 0, NULL); + check_result(result, "dns_name_fromtext"); + + db = NULL; + result = dns_db_create(mctx, "rbt", origin, dns_dbtype_zone, + dns_rdataclass_in, 0, NULL, &db); + check_result(result, "dns_db_create"); + + result = dns_db_load(db, zonefile); + if (result == DNS_R_SEENINCLUDE) + result = ISC_R_SUCCESS; + check_result(result, "dns_db_load"); + + printf("Connecting to '%s'\n", dbi.filename); + + if ((result = db_connect(&dbi)) != ISC_R_SUCCESS) { + fprintf(stderr, "Connection to database '%s' failed\n", + dbi.filename); + closeandexit(1); + } + + sql = sqlite3_mprintf("DROP TABLE %Q ", dbi.table); + printf("%s\n", sql); + res = sqlite3_exec(dbi.db, sql, NULL, NULL, &errmsg); + sqlite3_free(sql); +#if 0 + if (res != SQLITE_OK) { + fprintf(stderr, "DROP TABLE %s failed: %s\n", + dbi.table, errmsg); + } +#endif + +#if 0 + sql = sqlite3_mprintf(sql, "BEGIN TRANSACTION"); + printf("%s\n", sql); + res = sqlite3_exec(dbi.db, sql, NULL, NULL, &errmsg); + sqlite3_free(sql); + if (res != SQLITE_OK) { + fprintf(stderr, "BEGIN TRANSACTION failed: %s\n", errmsg); + closeandexit(1); + } +#endif + + sql = sqlite3_mprintf( + "CREATE TABLE %Q " + "(NAME TEXT, TTL INTEGER, RDTYPE TEXT, RDATA TEXT) ", + dbi.table); + printf("%s\n", sql); + res = sqlite3_exec(dbi.db, sql, NULL, NULL, &errmsg); + sqlite3_free(sql); + if (res != SQLITE_OK) { + fprintf(stderr, "CREATE TABLE %s failed: %s\n", + dbi.table, errmsg); + closeandexit(1); + } + + dbiter = NULL; + result = dns_db_createiterator(db, 0, &dbiter); + check_result(result, "dns_db_createiterator()"); + + result = dns_dbiterator_first(dbiter); + check_result(result, "dns_dbiterator_first"); + + name = dns_fixedname_initname(&fname); + dns_rdataset_init(&rdataset); + dns_rdata_init(&rdata); + + while (result == ISC_R_SUCCESS) { + node = NULL; + result = dns_dbiterator_current(dbiter, &node, name); + if (result == ISC_R_NOMORE) + break; + check_result(result, "dns_dbiterator_current"); + + rdsiter = NULL; + result = dns_db_allrdatasets(db, node, NULL, 0, &rdsiter); + check_result(result, "dns_db_allrdatasets"); + + result = dns_rdatasetiter_first(rdsiter); + + while (result == ISC_R_SUCCESS) { + dns_rdatasetiter_current(rdsiter, &rdataset); + result = dns_rdataset_first(&rdataset); + check_result(result, "dns_rdataset_first"); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(&rdataset, &rdata); + addrdata(name, rdataset.ttl, &rdata); + dns_rdata_reset(&rdata); + result = dns_rdataset_next(&rdataset); + } + dns_rdataset_disassociate(&rdataset); + result = dns_rdatasetiter_next(rdsiter); + } + dns_rdatasetiter_destroy(&rdsiter); + dns_db_detachnode(db, &node); + result = dns_dbiterator_next(dbiter); + } + +#if 0 + sql = sqlite3_mprintf(sql, "COMMIT TRANSACTION "); + printf("%s\n", sql); + res = sqlite3_exec(dbi.db, sql, NULL, NULL, &errmsg); + sqlite3_free(sql); + if (res != SQLITE_OK) { + fprintf(stderr, "COMMIT TRANSACTION failed: %s\n", errmsg); + closeandexit(1); + } +#endif + + dns_dbiterator_destroy(&dbiter); + dns_db_detach(&db); + isc_hash_destroy(); + isc_entropy_detach(&ectx); + isc_mem_destroy(&mctx); + + closeandexit(0); + + exit(0); +} |