2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

3176. [doc] Corrected example code and added a README to the

sample external DLZ module in contrib/dlz/example.
			[RT #26215]
This commit is contained in:
Evan Hunt 2011-10-20 22:01:48 +00:00
parent ada40193c8
commit 9336f01769
5 changed files with 663 additions and 237 deletions

View File

@ -1,3 +1,7 @@
3176. [doc] Corrected example code and added a README to the
sample external DLZ module in contrib/dlz/example.
[RT #26215]
3175. [bug] Fix how DNSSEC positive wildcard responses from a
NSEC3 signed zone are validated. Stop sending a
unnecessary NSEC3 record when generating such

180
contrib/dlz/example/README Normal file
View File

@ -0,0 +1,180 @@
OVERVIEW:
DLZ (Dynamically Loadable Zones) is an extention to BIND 9 that
allows zone data to be retrieved directly from an external database.
There is no required format or schema. DLZ drivers exist for several
different database backends including PostgreSQL, MySQL, and LDAP and
can be written for any other.
Historically, DLZ drivers had to be statically linked with the named
binary and were turned on via a configure option at compile time (for
example, "configure --with-dlz-ldap"). Currently, the drivers provided
in the BIND 9 tarball in contrib/dlz/drivers are still linked this way.
However, as of BIND 9.8, it is also possible to link some DLZ modules
dynamically at runtime, via the DLZ "dlopen" driver, which acts as a
generic wrapper around a shared object that implements the DLZ API. The
"dlopen" driver is linked into named by default, so configure options are
no longer necessary.
When the DLZ module provides data to named, it does so in text format.
The response is converted to DNS wire format by named. This conversion,
and the lack of any internal caching, places significant limits on the
query performance of DLZ modules. Consequently, DLZ is not recommended
for use on high-volume servers. However, it can be used in a hidden
master configuration, with slaves retrieving zone updates via AXFR.
(Note, however, that DLZ has no built-in support for DNS notify; slaves
are not automatically informed of changes to the zones in the database.)
EXAMPLE DRIVER:
This directory contains an example of an externally-lodable DLZ module,
dlz_example.c, which demonstrates the features of the DLZ API. It sets up
a single zone, whose name is configured in named.conf. The zone can answer
queries and AXFR requests, and accept DDNS updates.
By default, at runtime, the zone implemented by this driver will contain
an SOA, NS, and a single A record at the apex. If configured in named.conf
to use the name "example.nil", then, the zone will look like this:
example.nil. 3600 IN SOA example.nil. hostmaster.example.nil. (
123 900 600 86400 3600
)
example.nil. 3600 IN NS example.nil.
example.nil. 1800 IN A 10.53.0.1
The driver is also capable of retrieving information about the querying
client, and altering its response on the basis of this information. To
demonstrate this feature, the example driver responds to queries for
"source-addr.<zonename>/TXT" with the source address of the query.
Note, however, that this record will *not* be included in AXFR or ANY
responses. (Normally, this feature would be used to alter responses in
some other fashion, e.g., by providing different address records for
a particular name depending on the network from which the query arrived.)
IMPLEMENTATION NOTES:
The minimal set of type definitions, prototypes, and macros needed
for implementing a DLZ driver is in dlz_minimal.h. Copy this header
file into your source tree when creating an external DLZ module.
The DLZ dlopen driver provides a set of callback functions:
- void log(int level, const char *fmt, ...);
Writes the specified string to the named log, at the specified
log level. Uses printf() format semantics.
- isc_result_t putrr(dns_sdlzlookup_t *lookup, const char *type,
dns_ttl_t ttl, const char *data);
Puts a DNS resource record into the query response, which
referenced by the opaque structure 'lookup' provided by named.
- isc_result_t putnamedrr(dns_sdlzallnotes_t *allnodes,
const char *name, const char *type,
dns_ttl_t ttl, const char *data);
Puts a DNS resource record into an AXFR response, which is
referenced by the opaque structure 'allnodes' provided by named.
- isc_result_t writable_zone(dns_view_t *view, const char *zone_name);
Allows the DLZ module to inform named that a given zone can recieve
DDNS updates.
The external DLZ module can define the following functions (some of these
are mandatory, others optional).
- int dlz_version(unsigned int *flags);
Required for alL external DLZ modules, to indicate the version number
of the DLZ dlopen driver that this module supports. It should return
the value DLZ_DLOPEN_VERSION, which is defined in dlz_minimal.h and
is currently 2. 'flags' is updated to indicate capabilities
of the module. In particular, if the module is thread-safe then it
sets 'flags' to include DNS_SDLZFLAG_THREADSAFE. (Other capability
flags may be added in the future.)
- isc_result_t dlz_create(const char *dlzname,
unsigned int argc, char *argv[],
void **dbdata, ...);
Required for all external DLZ modules; this call initializes the
module.
- void dlz_destroy(void *dbdata);
Optional. If supplied, this will be called when the driver is
unloaded.
- isc_result_t dlz_findzonedb(void *dbdata, const char *name);
Required for all external DLZ modules. This indicates whether the
DLZ module can answer for a given zone. Returns ISC_R_SUCCESS if
so, otherwise ISC_R_NOTFOUND.
- isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata,
dns_sdlzlookup_t *lookup,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo);
Required for all external DLZ modules. This carries out the database
lookup for a query.
- isc_result_t dlz_allowzonexfr(void *dbdata, const char *name,
const char *client);
Optional. Supply this if you want the module to support AXFR
for the specified zone and client. A return value of ISC_R_SUCCESS
means AXFR is allowed, any other value means it isn't.
- isc_result_t dlz_allnodes(const char *zone, void *dbdata,
dns_sdlzallnodes_t *allnodes);
Optional, but must be supplied dlz_allowzonexfr() is. This function
returns all nodes in the zone in order to perform a zone transfer.
- isc_result_t dlz_newversion(const char *zone, void *dbdata,
void **versionp);
Optional. Supply this if you want the module to support DDNS
updates. This function starts a transaction in the database.
- void dlz_closeversion(const char *zone, isc_boolean_t commit,
void *dbdata, void **versionp);
Optional, but must be supplied if dlz_newversion() is. This function
closes a transaction. 'commit' indicates whether to commit the changes
to the database, or ignore them.
- isc_result_t dlz_configure(dns_view_t *view, void *dbdata);
Optional, but must be supplied in order to support DDNS updates.
- isc_boolean_t dlz_ssumatch(const char *signer, const char *name,
const char *tcpaddr, const char *type,
const char *key, uint32_t keydatalen,
uint8_t *keydata, void *dbdata);
Optional, but must be supplied in order to support DDNS updates.
- isc_result_t dlz_addrdataset(const char *name, const char *rdatastr,
void *dbdata, void *version);
Optional, but must be supplied in order to support DDNS updates.
Adds the data in 'rdatastr' to a database node.
- isc_result_t dlz_subrdataset(const char *name, const char *rdatastr,
void *dbdata, void *version);
Optional, but must be supplied in order to support DDNS updates.
Removes the data in 'rdatastr' from a database node.
- isc_result_t dlz_delrdataset(const char *name, const char *rdatastr,
void *dbdata, void *version);
Optional, but must be supplied in order to support DDNS updates.
Deletes all data matching the type specified in 'rdatastr' from
the database.

View File

@ -1,42 +1,48 @@
/*
* Copyright (C) 2010 Andrew Tridgell
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* 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.
* Permission to use, copy, modify, and/or 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 THE AUTHOR
* 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 SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/* $Id: dlz_example.c,v 1.3 2011/10/20 22:01:48 each Exp $ */
/*
this provides a very simple example of an external loadable DLZ
driver, with update support
* This provides a very simple example of an external loadable DLZ
* driver, with update support.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdint.h>
#include "dlz_minimal.h"
#ifdef WIN32
#define STRTOK_R(a, b, c) strtok_s(a, b, c)
#elif defined(_REENTRANT)
#define STRTOK_R(a, b, c) strtok_r(a, b, c)
#else
#define STRTOK_R(a, b, c) strtok(a, b)
#endif
/* for this simple example, use fixed sized strings */
/* For this simple example, use fixed sized strings */
struct record {
char name[100];
char type[10];
char data[200];
uint32_t ttl;
dns_ttl_t ttl;
};
#define MAX_RECORDS 100
@ -44,47 +50,46 @@ struct record {
struct dlz_example_data {
char *zone_name;
/* an example driver doesn't need good memory management :-) */
/* An example driver doesn't need good memory management :-) */
struct record current[MAX_RECORDS];
struct record adds[MAX_RECORDS];
struct record deletes[MAX_RECORDS];
bool transaction_started;
isc_boolean_t transaction_started;
/* helper functions from the dlz_dlopen driver */
void (*log)(int level, const char *fmt, ...);
isc_result_t (*putrr)(dns_sdlzlookup_t *handle, const char *type,
dns_ttl_t ttl, const char *data);
isc_result_t (*putnamedrr)(dns_sdlzlookup_t *handle, const char *name,
const char *type, dns_ttl_t ttl, const char *data);
isc_result_t (*writeable_zone)(dns_view_t *view, const char *zone_name);
/* Helper functions from the dlz_dlopen driver */
log_t *log;
dns_sdlz_putrr_t *putrr;
dns_sdlz_putnamedrr_t *putnamedrr;
dns_dlz_writeablezone_t *writeable_zone;
};
static bool single_valued(const char *type)
{
static isc_boolean_t
single_valued(const char *type) {
const char *single[] = { "soa", "cname", NULL };
int i;
for (i=0; single[i]; i++) {
for (i = 0; single[i]; i++) {
if (strcasecmp(single[i], type) == 0) {
return true;
return (ISC_TRUE);
}
}
return false;
return (ISC_FALSE);
}
/*
add a record to a list
* Add a record to a list
*/
static isc_result_t add_name(struct dlz_example_data *state,
struct record *list, const char *name, const char *type,
uint32_t ttl, const char *data)
static isc_result_t
add_name(struct dlz_example_data *state, struct record *list,
const char *name, const char *type, dns_ttl_t ttl, const char *data)
{
int i;
bool single = single_valued(type);
isc_boolean_t single = single_valued(type);
int first_empty = -1;
for (i=0; i<MAX_RECORDS; i++) {
if (first_empty == -1 && strlen(list[i].name) == 0) {
for (i = 0; i < MAX_RECORDS; i++) {
if (first_empty == -1 && strlen(list[i].name) == 0U) {
first_empty = i;
}
if (strcasecmp(list[i].name, name) != 0)
@ -100,24 +105,28 @@ static isc_result_t add_name(struct dlz_example_data *state,
}
if (i == MAX_RECORDS) {
state->log(ISC_LOG_ERROR, "dlz_example: out of record space");
return ISC_R_FAILURE;
return (ISC_R_FAILURE);
}
strcpy(list[i].name, name);
strcpy(list[i].type, type);
strcpy(list[i].data, data);
list[i].ttl = ttl;
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}
/*
delete a record from a list
* Delete a record from a list
*/
static isc_result_t del_name(struct dlz_example_data *state,
struct record *list, const char *name, const char *type,
uint32_t ttl, const char *data)
static isc_result_t
del_name(struct dlz_example_data *state, struct record *list,
const char *name, const char *type, dns_ttl_t ttl,
const char *data)
{
int i;
for (i=0; i<MAX_RECORDS; i++) {
UNUSED(state);
for (i = 0; i < MAX_RECORDS; i++) {
if (strcasecmp(name, list[i].name) == 0 &&
strcasecmp(type, list[i].type) == 0 &&
strcasecmp(data, list[i].data) == 0 &&
@ -126,59 +135,86 @@ static isc_result_t del_name(struct dlz_example_data *state,
}
}
if (i == MAX_RECORDS) {
return ISC_R_NOTFOUND;
return (ISC_R_NOTFOUND);
}
memset(&list[i], 0, sizeof(struct record));
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}
static isc_result_t
fmt_address(isc_sockaddr_t *addr, char *buffer, size_t size) {
char addr_buf[100];
const char *ret;
uint16_t port = 0;
switch (addr->type.sa.sa_family) {
case AF_INET:
port = ntohs(addr->type.sin.sin_port);
ret = inet_ntop(AF_INET, &addr->type.sin.sin_addr, addr_buf,
sizeof(addr_buf));
break;
case AF_INET6:
port = ntohs(addr->type.sin6.sin6_port);
ret = inet_ntop(AF_INET6, &addr->type.sin6.sin6_addr, addr_buf,
sizeof(addr_buf));
break;
default:
return (ISC_R_FAILURE);
}
if (ret == NULL)
return (ISC_R_FAILURE);
snprintf(buffer, size, "%s#%u", addr_buf, port);
return (ISC_R_SUCCESS);
}
/*
return the version of the API
* Return the version of the API
*/
int dlz_version(unsigned int *flags)
int
dlz_version(unsigned int *flags) {
UNUSED(flags);
return (DLZ_DLOPEN_VERSION);
}
/*
* Remember a helper function from the bind9 dlz_dlopen driver
*/
static void
b9_add_helper(struct dlz_example_data *state,
const char *helper_name, void *ptr)
{
return DLZ_DLOPEN_VERSION;
}
/*
remember a helper function from the bind9 dlz_dlopen driver
*/
static void b9_add_helper(struct dlz_example_data *state, const char *helper_name, void *ptr)
{
if (strcmp(helper_name, "log") == 0) {
state->log = ptr;
}
if (strcmp(helper_name, "putrr") == 0) {
state->putrr = ptr;
}
if (strcmp(helper_name, "putnamedrr") == 0) {
state->putnamedrr = ptr;
}
if (strcmp(helper_name, "writeable_zone") == 0) {
state->writeable_zone = ptr;
}
if (strcmp(helper_name, "log") == 0)
state->log = (log_t *)ptr;
if (strcmp(helper_name, "putrr") == 0)
state->putrr = (dns_sdlz_putrr_t *)ptr;
if (strcmp(helper_name, "putnamedrr") == 0)
state->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
if (strcmp(helper_name, "writeable_zone") == 0)
state->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
}
/*
called to initialise the driver
* Called to initialize the driver
*/
isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[],
void **dbdata, ...)
isc_result_t
dlz_create(const char *dlzname, unsigned int argc, char *argv[],
void **dbdata, ...)
{
struct dlz_example_data *state;
const char *helper_name;
va_list ap;
char soa_data[200];
state = calloc(1, sizeof(struct dlz_example_data));
if (state == NULL) {
return ISC_R_NOMEMORY;
}
UNUSED(dlzname);
/* fill in the helper functions */
state = calloc(1, sizeof(struct dlz_example_data));
if (state == NULL)
return (ISC_R_NOMEMORY);
/* Fill in the helper functions */
va_start(ap, dbdata);
while ((helper_name = va_arg(ap, const char *)) != NULL) {
b9_add_helper(state, helper_name, va_arg(ap, void*));
@ -186,8 +222,9 @@ isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[],
va_end(ap);
if (argc < 2) {
state->log(ISC_LOG_ERROR, "dlz_example: please specify a zone name");
return ISC_R_FAILURE;
state->log(ISC_LOG_ERROR,
"dlz_example: please specify a zone name");
return (ISC_R_FAILURE);
}
state->zone_name = strdup(argv[1]);
@ -195,151 +232,198 @@ isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[],
sprintf(soa_data, "%s hostmaster.%s 123 900 600 86400 3600",
state->zone_name, state->zone_name);
add_name(state, &state->current[0], state->zone_name, "soa", 3600, soa_data);
add_name(state, &state->current[0], state->zone_name, "ns", 3600, state->zone_name);
add_name(state, &state->current[0], state->zone_name, "a", 1800, "10.53.0.1");
add_name(state, &state->current[0], state->zone_name,
"soa", 3600, soa_data);
add_name(state, &state->current[0], state->zone_name,
"ns", 3600, state->zone_name);
add_name(state, &state->current[0], state->zone_name,
"a", 1800, "10.53.0.1");
state->log(ISC_LOG_INFO, "dlz_example: started for zone %s", state->zone_name);
state->log(ISC_LOG_INFO,
"dlz_example: started for zone %s",
state->zone_name);
*dbdata = state;
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}
/*
shutdown the backend
* Shut down the backend
*/
void dlz_destroy(void *dbdata)
{
void
dlz_destroy(void *dbdata) {
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
state->log(ISC_LOG_INFO, "dlz_example: shutting down zone %s", state->zone_name);
state->log(ISC_LOG_INFO,
"dlz_example: shutting down zone %s",
state->zone_name);
free(state->zone_name);
free(state);
}
/*
see if we handle a given zone
* See if we handle a given zone
*/
isc_result_t dlz_findzonedb(void *dbdata, const char *name)
{
isc_result_t
dlz_findzonedb(void *dbdata, const char *name) {
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (strcasecmp(state->zone_name, name) == 0) {
return ISC_R_SUCCESS;
}
return ISC_R_NOTFOUND;
if (strcasecmp(state->zone_name, name) == 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
/*
lookup one record
* Look up one record in the sample database.
*
* If the queryname is "source-addr", we add a TXT record containing
* the address of the client; this demonstrates the use of 'methods'
* and 'clientinfo'.
*/
isc_result_t dlz_lookup(const char *zone, const char *name,
void *dbdata, dns_sdlzlookup_t *lookup)
isc_result_t
dlz_lookup(const char *zone, const char *name, void *dbdata,
dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
isc_result_t result;
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
int i;
bool found = false;
isc_boolean_t found = ISC_FALSE;
isc_sockaddr_t *src;
char full_name[100];
int i;
if (strcmp(name, "@") == 0) {
UNUSED(zone);
if (strcmp(name, "@") == 0)
strcpy(full_name, state->zone_name);
} else {
else
sprintf(full_name, "%s.%s", name, state->zone_name);
if (strcmp(name, "source-addr") == 0) {
char buf[100];
strcpy(buf, "unknown");
if (methods != NULL &&
methods->version - methods->age >=
DNS_CLIENTINFOMETHODS_VERSION)
{
methods->sourceip(clientinfo, &src);
fmt_address(src, buf, sizeof(buf));
}
fprintf(stderr, "connection from: %s\n", buf);
found = ISC_TRUE;
result = state->putrr(lookup, "TXT", 0, buf);
if (result != ISC_R_SUCCESS)
return (result);
}
for (i=0; i<MAX_RECORDS; i++) {
for (i = 0; i < MAX_RECORDS; i++) {
if (strcasecmp(state->current[i].name, full_name) == 0) {
isc_result_t result;
found = true;
found = ISC_TRUE;
result = state->putrr(lookup, state->current[i].type,
state->current[i].ttl, state->current[i].data);
if (result != ISC_R_SUCCESS) {
return result;
}
state->current[i].ttl,
state->current[i].data);
if (result != ISC_R_SUCCESS)
return (result);
}
}
if (!found) {
return ISC_R_NOTFOUND;
}
return ISC_R_SUCCESS;
if (!found)
return (ISC_R_NOTFOUND);
return (ISC_R_SUCCESS);
}
/*
see if a zone transfer is allowed
* See if a zone transfer is allowed
*/
isc_result_t dlz_allowzonexfr(void *dbdata, const char *name, const char *client)
{
/* just say yes for all our zones */
return dlz_findzonedb(dbdata, name);
isc_result_t
dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
UNUSED(client);
/* Just say yes for all our zones */
return (dlz_findzonedb(dbdata, name));
}
/*
perform a zone transfer
* Perform a zone transfer
*/
isc_result_t dlz_allnodes(const char *zone, void *dbdata,
dns_sdlzallnodes_t *allnodes)
{
isc_result_t
dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
int i;
for (i=0; i<MAX_RECORDS; i++) {
UNUSED(zone);
for (i = 0; i < MAX_RECORDS; i++) {
isc_result_t result;
if (strlen(state->current[i].name) == 0) {
if (strlen(state->current[i].name) == 0U) {
continue;
}
result = state->putnamedrr(allnodes, state->current[i].name, state->current[i].type,
state->current[i].ttl, state->current[i].data);
if (result != ISC_R_SUCCESS) {
return result;
}
result = state->putnamedrr(allnodes, state->current[i].name,
state->current[i].type,
state->current[i].ttl,
state->current[i].data);
if (result != ISC_R_SUCCESS)
return (result);
}
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}
/*
start a transaction
* Start a transaction
*/
isc_result_t dlz_newversion(const char *zone, void *dbdata, void **versionp)
{
isc_result_t
dlz_newversion(const char *zone, void *dbdata, void **versionp) {
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (state->transaction_started) {
state->log(ISC_LOG_INFO, "dlz_example: transaction already started for zone %s", zone);
return ISC_R_FAILURE;
state->log(ISC_LOG_INFO,
"dlz_example: transaction already "
"started for zone %s", zone);
return (ISC_R_FAILURE);
}
state->transaction_started = true;
state->transaction_started = ISC_TRUE;
*versionp = (void *) &state->transaction_started;
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}
/*
end a transaction
* End a transaction
*/
void dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata, void **versionp)
void
dlz_closeversion(const char *zone, isc_boolean_t commit,
void *dbdata, void **versionp)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (!state->transaction_started) {
state->log(ISC_LOG_INFO, "dlz_example: transaction not started for zone %s", zone);
state->log(ISC_LOG_INFO,
"dlz_example: transaction not started for zone %s",
zone);
*versionp = NULL;
return;
}
state->transaction_started = false;
state->transaction_started = ISC_FALSE;
*versionp = NULL;
if (commit) {
int i;
state->log(ISC_LOG_INFO, "dlz_example: committing transaction on zone %s", zone);
for (i=0; i<MAX_RECORDS; i++) {
if (strlen(state->adds[i].name) > 0) {
state->log(ISC_LOG_INFO,
"dlz_example: committing transaction on zone %s",
zone);
for (i = 0; i < MAX_RECORDS; i++) {
if (strlen(state->adds[i].name) > 0U) {
add_name(state, &state->current[0],
state->adds[i].name,
state->adds[i].type,
@ -347,8 +431,8 @@ void dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata, void
state->adds[i].data);
}
}
for (i=0; i<MAX_RECORDS; i++) {
if (strlen(state->deletes[i].name) > 0) {
for (i = 0; i < MAX_RECORDS; i++) {
if (strlen(state->deletes[i].name) > 0U) {
del_name(state, &state->current[0],
state->deletes[i].name,
state->deletes[i].type,
@ -357,7 +441,9 @@ void dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata, void
}
}
} else {
state->log(ISC_LOG_INFO, "dlz_example: cancelling transaction on zone %s", zone);
state->log(ISC_LOG_INFO,
"dlz_example: cancelling transaction on zone %s",
zone);
}
memset(state->adds, 0, sizeof(state->adds));
memset(state->deletes, 0, sizeof(state->deletes));
@ -365,118 +451,155 @@ void dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata, void
/*
configure a writeable zone
* Configure a writeable zone
*/
isc_result_t dlz_configure(dns_view_t *view, void *dbdata)
{
isc_result_t
dlz_configure(dns_view_t *view, void *dbdata) {
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_result_t result;
state->log(ISC_LOG_INFO, "dlz_example: starting configure");
if (state->writeable_zone == NULL) {
state->log(ISC_LOG_INFO, "dlz_example: no writeable_zone method available");
return ISC_R_FAILURE;
state->log(ISC_LOG_INFO,
"dlz_example: no writeable_zone method available");
return (ISC_R_FAILURE);
}
result = state->writeable_zone(view, state->zone_name);
if (result != ISC_R_SUCCESS) {
state->log(ISC_LOG_ERROR, "dlz_example: failed to configure zone %s", state->zone_name);
return result;
state->log(ISC_LOG_ERROR,
"dlz_example: failed to configure zone %s",
state->zone_name);
return (result);
}
state->log(ISC_LOG_INFO, "dlz_example: configured writeable zone %s", state->zone_name);
return ISC_R_SUCCESS;
state->log(ISC_LOG_INFO,
"dlz_example: configured writeable zone %s",
state->zone_name);
return (ISC_R_SUCCESS);
}
/*
authorize a zone update
* Authorize a zone update
*/
isc_boolean_t dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
const char *type, const char *key, uint32_t keydatalen, uint8_t *keydata,
void *dbdata)
isc_boolean_t
dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
const char *type, const char *key, uint32_t keydatalen,
unsigned char *keydata, void *dbdata)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
UNUSED(tcpaddr);
UNUSED(type);
UNUSED(key);
UNUSED(keydatalen);
UNUSED(keydata);
if (strncmp(name, "deny.", 5) == 0) {
state->log(ISC_LOG_INFO, "dlz_example: denying update of name=%s by %s",
state->log(ISC_LOG_INFO,
"dlz_example: denying update of name=%s by %s",
name, signer);
return false;
return (ISC_FALSE);
}
state->log(ISC_LOG_INFO, "dlz_example: allowing update of name=%s by %s",
state->log(ISC_LOG_INFO,
"dlz_example: allowing update of name=%s by %s",
name, signer);
return true;
return (ISC_TRUE);
}
static isc_result_t modrdataset(struct dlz_example_data *state, const char *name, const char *rdatastr,
struct record *list)
static isc_result_t
modrdataset(struct dlz_example_data *state, const char *name,
const char *rdatastr, struct record *list)
{
char *full_name, *dclass, *type, *data, *ttlstr;
char *buf = strdup(rdatastr);
isc_result_t result;
#if defined(WIN32) || defined(_REENTRANT)
char *saveptr = NULL;
#endif
/*
the format is:
FULLNAME\tTTL\tDCLASS\tTYPE\tDATA
The DATA field is space separated, and is in the data format
for the type used by dig
* The format is:
* FULLNAME\tTTL\tDCLASS\tTYPE\tDATA
*
* The DATA field is space separated, and is in the data format
* for the type used by dig
*/
full_name = strtok_r(buf, "\t", &saveptr);
if (full_name == NULL) return ISC_R_FAILURE;
ttlstr = strtok_r(NULL, "\t", &saveptr);
if (ttlstr == NULL) return ISC_R_FAILURE;
dclass = strtok_r(NULL, "\t", &saveptr);
if (dclass == NULL) return ISC_R_FAILURE;
type = strtok_r(NULL, "\t", &saveptr);
if (type == NULL) return ISC_R_FAILURE;
data = strtok_r(NULL, "\t", &saveptr);
if (data == NULL) return ISC_R_FAILURE;
full_name = STRTOK_R(buf, "\t", &saveptr);
if (full_name == NULL)
return (ISC_R_FAILURE);
result = add_name(state, list, name, type, strtoul(ttlstr, NULL, 10), data);
ttlstr = STRTOK_R(NULL, "\t", &saveptr);
if (ttlstr == NULL)
return (ISC_R_FAILURE);
dclass = STRTOK_R(NULL, "\t", &saveptr);
if (dclass == NULL)
return (ISC_R_FAILURE);
type = STRTOK_R(NULL, "\t", &saveptr);
if (type == NULL)
return (ISC_R_FAILURE);
data = STRTOK_R(NULL, "\t", &saveptr);
if (data == NULL)
return (ISC_R_FAILURE);
result = add_name(state, list, name, type,
strtoul(ttlstr, NULL, 10), data);
free(buf);
return result;
return (result);
}
isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, void *dbdata, void *version)
isc_result_t
dlz_addrdataset(const char *name, const char *rdatastr,
void *dbdata, void *version)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (version != (void *) &state->transaction_started) {
return ISC_R_FAILURE;
}
if (version != (void *) &state->transaction_started)
return (ISC_R_FAILURE);
state->log(ISC_LOG_INFO, "dlz_example: adding rdataset %s '%s'", name, rdatastr);
state->log(ISC_LOG_INFO,
"dlz_example: adding rdataset %s '%s'",
name, rdatastr);
return modrdataset(state, name, rdatastr, &state->adds[0]);
return (modrdataset(state, name, rdatastr, &state->adds[0]));
}
isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, void *dbdata, void *version)
isc_result_t
dlz_subrdataset(const char *name, const char *rdatastr,
void *dbdata, void *version)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (version != (void *) &state->transaction_started) {
return ISC_R_FAILURE;
}
if (version != (void *) &state->transaction_started)
return (ISC_R_FAILURE);
state->log(ISC_LOG_INFO, "dlz_example: subtracting rdataset %s '%s'", name, rdatastr);
state->log(ISC_LOG_INFO,
"dlz_example: subtracting rdataset %s '%s'",
name, rdatastr);
return modrdataset(state, name, rdatastr, &state->deletes[0]);
return (modrdataset(state, name, rdatastr, &state->deletes[0]));
}
isc_result_t dlz_delrdataset(const char *name, const char *type, void *dbdata, void *version)
isc_result_t
dlz_delrdataset(const char *name, const char *type,
void *dbdata, void *version)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
if (version != (void *) &state->transaction_started) {
return ISC_R_FAILURE;
}
if (version != (void *) &state->transaction_started)
return (ISC_R_FAILURE);
state->log(ISC_LOG_INFO, "dlz_example: deleting rdataset %s of type %s", name, type);
state->log(ISC_LOG_INFO,
"dlz_example: deleting rdataset %s of type %s",
name, type);
return ISC_R_SUCCESS;
return (ISC_R_SUCCESS);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Andrew Tridgell
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the
@ -17,13 +17,23 @@
*/
/*
This header provides a minimal set of defines and typedefs needed
for building an external DLZ module for bind9. When creating a new
external DLZ driver, please copy this header into your own source
tree.
* This header provides a minimal set of defines and typedefs needed
* for building an external DLZ module for bind9. When creating a new
* external DLZ driver, please copy this header into your own source
* tree.
*/
#include <sys/types.h>
#include <sys/socket.h>
#ifdef ISC_PLATFORM_HAVESYSUNH
#include <sys/un.h>
#endif
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef unsigned int isc_result_t;
typedef bool isc_boolean_t;
typedef int isc_boolean_t;
typedef uint32_t dns_ttl_t;
#define DLZ_DLOPEN_VERSION 2
@ -37,6 +47,10 @@ typedef uint32_t dns_ttl_t;
#define ISC_R_NOTFOUND 23
#define ISC_R_FAILURE 25
/* boolean values */
#define ISC_TRUE 1
#define ISC_FALSE 0
/* log levels */
#define ISC_LOG_INFO (-1)
#define ISC_LOG_NOTICE (-2)
@ -44,20 +58,80 @@ typedef uint32_t dns_ttl_t;
#define ISC_LOG_ERROR (-4)
#define ISC_LOG_CRITICAL (-5)
/* some opaque structures */
/* other useful definitions */
#define UNUSED(x) (void)(x)
/* opaque structures */
typedef void *dns_sdlzlookup_t;
typedef void *dns_sdlzallnodes_t;
typedef void *dns_view_t;
typedef void *dns_dlzclientcallback_t;
/*
* prototypes for the functions you can include in your driver
* Method and type definitions needed for retrieval of client info
* from the caller.
*/
typedef struct isc_sockaddr {
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
#ifdef ISC_PLATFORM_HAVESYSUNH
struct sockaddr_un sunix;
#endif
} type;
unsigned int length;
void * link;
} isc_sockaddr_t;
#define DNS_CLIENTINFO_VERSION 1
typedef struct dns_clientinfo {
uint16_t version;
void *data;
} dns_clientinfo_t;
typedef isc_result_t (*dns_clientinfo_sourceip_t)(dns_clientinfo_t *client,
isc_sockaddr_t **addrp);
#define DNS_CLIENTINFOMETHODS_VERSION 1
#define DNS_CLIENTINFOMETHODS_AGE 0
typedef struct dns_clientinfomethods {
uint16_t version;
uint16_t age;
dns_clientinfo_sourceip_t sourceip;
} dns_clientinfomethods_t;
/*
* Method definitions for callbacks provided by the dlopen driver
*/
typedef void log_t(int level, const char *fmt, ...);
typedef isc_result_t dns_sdlz_putrr_t(dns_sdlzlookup_t *lookup,
const char *type,
dns_ttl_t ttl,
const char *data);
typedef isc_result_t dns_sdlz_putnamedrr_t(dns_sdlzallnodes_t *allnodes,
const char *name,
const char *type,
dns_ttl_t ttl,
const char *data);
typedef isc_result_t dns_dlz_writeablezone_t(dns_view_t *view,
const char *zone_name);
/*
* prototypes for the functions you can include in your module
*/
/*
* dlz_version() is required for all DLZ external drivers. It should
* return DLZ_DLOPEN_VERSION
* return DLZ_DLOPEN_VERSION. 'flags' is updated to indicate capabilities
* of the module. In particular, if the module is thread-safe then it
* sets 'flags' to include DNS_SDLZFLAG_THREADSAFE. Other capability
* flags may be added in the future.
*/
int
dlz_version(unsigned int *flags);
@ -87,7 +161,9 @@ dlz_findzonedb(void *dbdata, const char *name);
*/
isc_result_t
dlz_lookup(const char *zone, const char *name, void *dbdata,
dns_sdlzlookup_t *lookup);
dns_sdlzlookup_t *lookup,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo);
/*
* dlz_allowzonexfr() is optional, and should be supplied if you want to
@ -126,13 +202,6 @@ dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata,
isc_result_t
dlz_configure(dns_view_t *view, void *dbdata);
/*
* dlz_setclientcallback() is optional, but must be supplied if you want
* to retrieve information about the client before sending a reply.
*/
isc_result_t
dlz_setclientcallback(dns_dlzclientcallback_t callback);
/*
* dlz_ssumatch() is optional, but must be supplied if you want to support
* dynamic updates

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/* $Id: named.conf,v 1.2 2011/10/20 22:01:48 each Exp $ */
/*
* This is a sample named.conf file that uses the DLZ module defined in
* dlz_example.c. It sets up a zone 'example.nil' which can accept DDNS
* updates.
*
* By default, when run, the zone contains the following records:
*
* example.nil. 3600 IN SOA example.nil. hostmaster.example.nil. (
* 123 900 600 86400 3600
* )
* example.nil. 3600 IN NS example.nil.
* example.nil. 1800 IN A 10.53.0.1
*
* Additionally, a query for 'source-addr.example.nil/TXT' is always
* answered with the source address of the query. This is used to
* demonstrate the code that retreives client information from the
* caller.
*
* To use this driver, "dlz_external.so" must be moved into the working
* directory for named.
*/
options {
allow-transfer { any; };
allow-query { any; };
notify yes;
recursion no;
};
dlz "example" {
database "dlopen ./dlz_example.so example.nil";
};