From 22aa1c0bc258e6c2c7491e2e330e3c363daa2b80 Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Sat, 18 Nov 2000 00:14:34 +0000 Subject: [PATCH] added sample sdb driver where the zone data is specified algorithmically in Tcl code --- contrib/sdb/lookup.tcl | 17 ++++ contrib/sdb/tcl/lookup.tcl | 17 ++++ contrib/sdb/tcl/tcldb.c | 201 +++++++++++++++++++++++++++++++++++++ contrib/sdb/tcl/tcldb.h | 6 ++ contrib/sdb/tcldb.c | 201 +++++++++++++++++++++++++++++++++++++ contrib/sdb/tcldb.h | 6 ++ 6 files changed, 448 insertions(+) create mode 100644 contrib/sdb/lookup.tcl create mode 100644 contrib/sdb/tcl/lookup.tcl create mode 100644 contrib/sdb/tcl/tcldb.c create mode 100644 contrib/sdb/tcl/tcldb.h create mode 100644 contrib/sdb/tcldb.c create mode 100644 contrib/sdb/tcldb.h diff --git a/contrib/sdb/lookup.tcl b/contrib/sdb/lookup.tcl new file mode 100644 index 0000000000..2bd861e7bb --- /dev/null +++ b/contrib/sdb/lookup.tcl @@ -0,0 +1,17 @@ +# +# Sample lookup procedure for tcldb +# + +proc lookup {zone name} { + global dbargs + puts $zone + switch -- $name { + @ { return [list \ + {SOA 86400 "ns.isp.nil. hostmaster.isp.nil. 0 3600 1800 1814400 3600"} \ + {NS 86400 "ns1"} \ + {NS 86400 "ns2"} \ + {MX 86400 "10 mail.isp.nil."} ] } + www { return [list [list A 3600 $dbargs($zone)] ] } + } + return NXDOMAIN +} diff --git a/contrib/sdb/tcl/lookup.tcl b/contrib/sdb/tcl/lookup.tcl new file mode 100644 index 0000000000..2bd861e7bb --- /dev/null +++ b/contrib/sdb/tcl/lookup.tcl @@ -0,0 +1,17 @@ +# +# Sample lookup procedure for tcldb +# + +proc lookup {zone name} { + global dbargs + puts $zone + switch -- $name { + @ { return [list \ + {SOA 86400 "ns.isp.nil. hostmaster.isp.nil. 0 3600 1800 1814400 3600"} \ + {NS 86400 "ns1"} \ + {NS 86400 "ns2"} \ + {MX 86400 "10 mail.isp.nil."} ] } + www { return [list [list A 3600 $dbargs($zone)] ] } + } + return NXDOMAIN +} diff --git a/contrib/sdb/tcl/tcldb.c b/contrib/sdb/tcl/tcldb.c new file mode 100644 index 0000000000..67e5b8cfdf --- /dev/null +++ b/contrib/sdb/tcl/tcldb.c @@ -0,0 +1,201 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +/* + * A simple database driver that calls Tcl procedures to define + * the contents of the DNS namespace. + */ + +static dns_sdbimplementation_t *tcldb = NULL; + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) return (result); \ + } while (0) + +typedef struct tcldb_driver { + isc_mem_t *mctx; + Tcl_Interp *interp; +} tcldb_driver_t; + +static tcldb_driver_t *the_driver; + +static isc_result_t +tcldb_driver_create(isc_mem_t *mctx, tcldb_driver_t **driverp) { + int tclres; + tcldb_driver_t *driver = isc_mem_get(mctx, sizeof(tcldb_driver_t)); + if (driver == NULL) + return (ISC_R_NOMEMORY); + driver->mctx = mctx; + driver->interp = Tcl_CreateInterp(); + + tclres = Tcl_EvalFile(driver->interp, (char *) "lookup.tcl"); + if (tclres != TCL_OK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "initializing tcldb: " + "loading lookup.tcl failed: %s", + driver->interp->result); + return (ISC_R_FAILURE); + } + *driverp = driver; + return (ISC_R_SUCCESS); +} + +static void +tcldb_driver_destroy(tcldb_driver_t **driverp) { + tcldb_driver_t *driver = *driverp; + Tcl_DeleteInterp(driver->interp); + isc_mem_put(driver->mctx, driver, sizeof(tcldb_driver_t)); +} + +/* + * This database operates on relative names. + * + * Any name will be interpreted as a pathname offset from the tclectory + * specified in the configuration file. + */ +static isc_result_t +tcldb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +{ + isc_result_t result = ISC_R_SUCCESS; + int tclres; + int rrc; /* RR count */ + char **rrv; /* RR vector */ + int i; + char *cmdv[3]; + char *cmd; + + tcldb_driver_t *driver = (tcldb_driver_t *) dbdata; + + cmdv[0] = "lookup"; + cmdv[1] = zone; + cmdv[2] = name; + cmd = Tcl_Merge(3, cmdv); + tclres = Tcl_Eval(driver->interp, cmd); + Tcl_Free(cmd); + + if (tclres != TCL_OK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "zone '%s': tcl lookup function failed: %s", + zone, driver->interp->result); + return (ISC_R_FAILURE); + } + + if (strcmp(driver->interp->result, "NXDOMAIN") == 0) { + result = ISC_R_NOTFOUND; + goto fail; + } + + tclres = Tcl_SplitList(driver->interp, driver->interp->result, &rrc, &rrv); + if (tclres != TCL_OK) + goto malformed; + + for (i = 0; i < rrc; i++) { + isc_result_t tmpres; + int fieldc; /* Field count */ + char **fieldv; /* Field vector */ + tclres = Tcl_SplitList(driver->interp, rrv[i], &fieldc, &fieldv); + if (tclres != TCL_OK) { + tmpres = ISC_R_FAILURE; + goto failrr; + } + if (fieldc != 3) + goto malformed; + tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]), fieldv[2]); + Tcl_Free((char *) fieldv); + failrr: + if (tmpres != ISC_R_SUCCESS) + result = tmpres; + } + Tcl_Free((char *) rrv); + if (result == ISC_R_SUCCESS) + return (result); + + malformed: + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "zone '%s': malformed return value from tcl lookup function: %s", + zone, driver->interp->result); + result = ISC_R_FAILURE; + fail: + return (result); +} + +/* + * Each database stores the top-level tclectory as the dbdata opaque + * object. The create() function allocates it. argv[0] holds the top + * level tclectory. + */ +static isc_result_t +tcldb_create(const char *zone, int argc, char **argv, + void *driverdata, void **dbdata) +{ + tcldb_driver_t *driver = (tcldb_driver_t *) driverdata; + + char *list = Tcl_Merge(argc, argv); + + Tcl_SetVar2(driver->interp, (char *) "dbargs", (char *) zone, list, 0); + + Tcl_Free(list); + + *dbdata = driverdata; + + return (ISC_R_SUCCESS); +} + +/* + * This zone does not support zone transfer, so allnodes() is NULL. + */ +static dns_sdbmethods_t tcldb_methods = { + tcldb_lookup, + NULL, /* authority */ + NULL, /* allnodes */ + tcldb_create, + NULL /* destroy */ +}; + +/* + * Initialize the tcldb driver. + */ +isc_result_t +tcldb_init(void) { + isc_result_t result; + int flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA; + + result = tcldb_driver_create(ns_g_mctx, &the_driver); + if (result != ISC_R_SUCCESS) + return (result); + + return (dns_sdb_register("tcl", &tcldb_methods, the_driver, flags, + ns_g_mctx, &tcldb)); +} + +/* + * Wrapper around dns_sdb_unregister(). + */ +void +tcldb_clear(void) { + dns_sdb_unregister(&tcldb); + tcldb_driver_destroy(&the_driver); +} diff --git a/contrib/sdb/tcl/tcldb.h b/contrib/sdb/tcl/tcldb.h new file mode 100644 index 0000000000..b887acf749 --- /dev/null +++ b/contrib/sdb/tcl/tcldb.h @@ -0,0 +1,6 @@ + +#include + +isc_result_t tcldb_init(void); + +void tcldb_clear(void); diff --git a/contrib/sdb/tcldb.c b/contrib/sdb/tcldb.c new file mode 100644 index 0000000000..67e5b8cfdf --- /dev/null +++ b/contrib/sdb/tcldb.c @@ -0,0 +1,201 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +/* + * A simple database driver that calls Tcl procedures to define + * the contents of the DNS namespace. + */ + +static dns_sdbimplementation_t *tcldb = NULL; + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) return (result); \ + } while (0) + +typedef struct tcldb_driver { + isc_mem_t *mctx; + Tcl_Interp *interp; +} tcldb_driver_t; + +static tcldb_driver_t *the_driver; + +static isc_result_t +tcldb_driver_create(isc_mem_t *mctx, tcldb_driver_t **driverp) { + int tclres; + tcldb_driver_t *driver = isc_mem_get(mctx, sizeof(tcldb_driver_t)); + if (driver == NULL) + return (ISC_R_NOMEMORY); + driver->mctx = mctx; + driver->interp = Tcl_CreateInterp(); + + tclres = Tcl_EvalFile(driver->interp, (char *) "lookup.tcl"); + if (tclres != TCL_OK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "initializing tcldb: " + "loading lookup.tcl failed: %s", + driver->interp->result); + return (ISC_R_FAILURE); + } + *driverp = driver; + return (ISC_R_SUCCESS); +} + +static void +tcldb_driver_destroy(tcldb_driver_t **driverp) { + tcldb_driver_t *driver = *driverp; + Tcl_DeleteInterp(driver->interp); + isc_mem_put(driver->mctx, driver, sizeof(tcldb_driver_t)); +} + +/* + * This database operates on relative names. + * + * Any name will be interpreted as a pathname offset from the tclectory + * specified in the configuration file. + */ +static isc_result_t +tcldb_lookup(const char *zone, const char *name, void *dbdata, + dns_sdblookup_t *lookup) +{ + isc_result_t result = ISC_R_SUCCESS; + int tclres; + int rrc; /* RR count */ + char **rrv; /* RR vector */ + int i; + char *cmdv[3]; + char *cmd; + + tcldb_driver_t *driver = (tcldb_driver_t *) dbdata; + + cmdv[0] = "lookup"; + cmdv[1] = zone; + cmdv[2] = name; + cmd = Tcl_Merge(3, cmdv); + tclres = Tcl_Eval(driver->interp, cmd); + Tcl_Free(cmd); + + if (tclres != TCL_OK) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "zone '%s': tcl lookup function failed: %s", + zone, driver->interp->result); + return (ISC_R_FAILURE); + } + + if (strcmp(driver->interp->result, "NXDOMAIN") == 0) { + result = ISC_R_NOTFOUND; + goto fail; + } + + tclres = Tcl_SplitList(driver->interp, driver->interp->result, &rrc, &rrv); + if (tclres != TCL_OK) + goto malformed; + + for (i = 0; i < rrc; i++) { + isc_result_t tmpres; + int fieldc; /* Field count */ + char **fieldv; /* Field vector */ + tclres = Tcl_SplitList(driver->interp, rrv[i], &fieldc, &fieldv); + if (tclres != TCL_OK) { + tmpres = ISC_R_FAILURE; + goto failrr; + } + if (fieldc != 3) + goto malformed; + tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]), fieldv[2]); + Tcl_Free((char *) fieldv); + failrr: + if (tmpres != ISC_R_SUCCESS) + result = tmpres; + } + Tcl_Free((char *) rrv); + if (result == ISC_R_SUCCESS) + return (result); + + malformed: + isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_SDB, ISC_LOG_ERROR, + "zone '%s': malformed return value from tcl lookup function: %s", + zone, driver->interp->result); + result = ISC_R_FAILURE; + fail: + return (result); +} + +/* + * Each database stores the top-level tclectory as the dbdata opaque + * object. The create() function allocates it. argv[0] holds the top + * level tclectory. + */ +static isc_result_t +tcldb_create(const char *zone, int argc, char **argv, + void *driverdata, void **dbdata) +{ + tcldb_driver_t *driver = (tcldb_driver_t *) driverdata; + + char *list = Tcl_Merge(argc, argv); + + Tcl_SetVar2(driver->interp, (char *) "dbargs", (char *) zone, list, 0); + + Tcl_Free(list); + + *dbdata = driverdata; + + return (ISC_R_SUCCESS); +} + +/* + * This zone does not support zone transfer, so allnodes() is NULL. + */ +static dns_sdbmethods_t tcldb_methods = { + tcldb_lookup, + NULL, /* authority */ + NULL, /* allnodes */ + tcldb_create, + NULL /* destroy */ +}; + +/* + * Initialize the tcldb driver. + */ +isc_result_t +tcldb_init(void) { + isc_result_t result; + int flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA; + + result = tcldb_driver_create(ns_g_mctx, &the_driver); + if (result != ISC_R_SUCCESS) + return (result); + + return (dns_sdb_register("tcl", &tcldb_methods, the_driver, flags, + ns_g_mctx, &tcldb)); +} + +/* + * Wrapper around dns_sdb_unregister(). + */ +void +tcldb_clear(void) { + dns_sdb_unregister(&tcldb); + tcldb_driver_destroy(&the_driver); +} diff --git a/contrib/sdb/tcldb.h b/contrib/sdb/tcldb.h new file mode 100644 index 0000000000..b887acf749 --- /dev/null +++ b/contrib/sdb/tcldb.h @@ -0,0 +1,6 @@ + +#include + +isc_result_t tcldb_init(void); + +void tcldb_clear(void);