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

[master] better DDNS in DLZ; mysqldyn

3821.	[contrib]	Added a new "mysqldyn" DLZ module with dynamic
			update and transaction support. Thanks to Marty
			Lee for the contribution. [RT #35656]

3820.	[func]		The DLZ API doesn't pass the database version to
			the lookup() function; this can cause DLZ modules
			that allow dynamic updates to mishandle prerequisite
			checks. This has been corrected by adding a
			'dbversion' field to the dns_clientinfo_t
			structure. [RT #35656]
This commit is contained in:
Evan Hunt 2014-04-25 13:06:30 -07:00
parent 1deeb567fa
commit aefb3e308b
20 changed files with 2134 additions and 50 deletions

11
CHANGES
View File

@ -1,3 +1,14 @@
3821. [contrib] Added a new "mysqldyn" DLZ module with dynamic
update and transaction support. Thanks to Marty
Lee for the contribution. [RT #35656]
3820. [func] The DLZ API doesn't pass the database version to
the lookup() function; this can cause DLZ modules
that allow dynamic updates to mishandle prerequisite
checks. This has been corrected by adding a
'dbversion' field to the dns_clientinfo_t
structure. [RT #35656]
3819. [bug] NSEC3 hashes need to be able to be entered and
displayed without padding. This is not a issue for
currently defined algorithms but may be for future

View File

@ -1118,7 +1118,7 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
tresult = dns_view_searchdlz(client->view, name,
zonelabels, &cm, &ci, &tdbp);
@ -1254,7 +1254,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
zone = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* We treat type A additional section processing as if it
@ -1733,7 +1733,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
additionaltype = dns_rdatasetadditional_fromauth;
dns_name_init(&cfname, NULL);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
CTRACE("query_addadditional2");
@ -2606,7 +2606,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
node = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Don't add the SOA record for test which set "-T nosoa".
@ -2731,7 +2731,7 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
dns_fixedname_init(&foundname);
fname = dns_fixedname_name(&foundname);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Get resources and make 'name' be the database origin.
@ -2899,7 +2899,7 @@ mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
rdataset->trust = dns_trust_secure;
sigrdataset->trust = dns_trust_secure;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Save the updated secure state. Ignore failures.
@ -2936,7 +2936,7 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
if (!dns_rdataset_isassociated(keyrdataset)) {
result = dns_db_findnodeext(db, &rrsig->signer, ISC_FALSE,
@ -3084,7 +3084,7 @@ query_addbestns(ns_client_t *client) {
use_zone = ISC_FALSE;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Find the right database.
@ -3410,7 +3410,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db,
node = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Get the NOQNAME proof then if !ispositive
@ -4141,8 +4141,9 @@ rpz_get_zbits(ns_client_t *client,
*/
static isc_result_t
rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
dns_rpz_type_t rpz_type, dns_db_t **dbp, dns_dbversion_t *version,
dns_rdataset_t **rdatasetp, isc_boolean_t resuming)
dns_rpz_type_t rpz_type, dns_db_t **dbp,
dns_dbversion_t *version, dns_rdataset_t **rdatasetp,
isc_boolean_t resuming)
{
dns_rpz_st_t *st;
isc_boolean_t is_zone;
@ -4153,6 +4154,9 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
st = client->query.rpz_st;
if ((st->state & DNS_RPZ_RECURSING) != 0) {
INSIST(st->r.r_type == type);
@ -4207,7 +4211,7 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
dns_fixedname_init(&fixed);
found = dns_fixedname_name(&fixed);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
result = dns_db_findext(*dbp, name, version, type, DNS_DBFIND_GLUEOK,
client->now, &node, found,
&cm, &ci, *rdatasetp, NULL);
@ -4345,6 +4349,9 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
REQUIRE(nodep != NULL);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client, NULL);
/*
* Try to find either a CNAME or the type of record demanded by the
* request from the policy zone.
@ -4359,8 +4366,7 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
return (DNS_R_NXDOMAIN);
dns_fixedname_init(&foundf);
found = dns_fixedname_name(&foundf);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
result = dns_db_findext(*dbp, p_name, *versionp, dns_rdatatype_any, 0,
client->now, nodep, found, &cm, &ci,
*rdatasetp, NULL);
@ -5761,7 +5767,7 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
dns_name_clone(qname, &name);
labels = dns_name_countlabels(&name);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
/*
* Map unknown algorithm to known value.
@ -5966,7 +5972,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
dns_rdataset_init(&trdataset);
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
return (ISC_FALSE);
@ -6119,7 +6125,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
is_staticstub_zone = ISC_FALSE;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
dns_clientinfo_init(&ci, client, NULL);
if (event != NULL) {
/*

View File

@ -541,9 +541,21 @@ foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
isc_result_t result;
dns_dbnode_t *node;
dns_rdatasetiter_t *iter;
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
dns_dbversion_t *oldver = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
/*
* Only set the clientinfo 'versionp' if the new version is
* different from the current version
*/
dns_db_currentversion(db, &oldver);
dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
node = NULL;
result = dns_db_findnode(db, name, ISC_FALSE, &node);
result = dns_db_findnodeext(db, name, ISC_FALSE, &cm, &ci, &node);
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
@ -620,6 +632,18 @@ foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
isc_result_t result;
dns_dbnode_t *node;
dns_rdataset_t rdataset;
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
dns_dbversion_t *oldver = NULL;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
/*
* Only set the clientinfo 'versionp' if the new version is
* different from the current version
*/
dns_db_currentversion(db, &oldver);
dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
if (type == dns_rdatatype_any)
return (foreach_node_rr(db, ver, name,
@ -630,7 +654,8 @@ foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
(type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
else
result = dns_db_findnode(db, name, ISC_FALSE, &node);
result = dns_db_findnodeext(db, name, ISC_FALSE,
&cm, &ci, &node);
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)

View File

@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*
* This provides a very simple example of an external loadable DLZ
* driver, with update support.
@ -251,7 +249,7 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
}
va_end(ap);
if (argc < 2) {
if (argc < 2 || argv[1][0] == '\0') {
if (state->log != NULL)
state->log(ISC_LOG_ERROR,
"dlz_example: please specify a zone name");
@ -259,11 +257,16 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
return (ISC_R_FAILURE);
}
state->zone_name = strdup(argv[1]);
/* Ensure zone name is absolute */
state->zone_name = malloc(strlen(argv[1]) + 2);
if (state->zone_name == NULL) {
free(state);
return (ISC_R_NOMEMORY);
}
if (argv[1][strlen(argv[1]) - 1] == '.')
strcpy(state->zone_name, argv[1]);
else
sprintf(state->zone_name, "%s.", argv[1]);
if (strcmp(state->zone_name, ".") == 0)
extra = ".root";
@ -313,7 +316,6 @@ dlz_destroy(void *dbdata) {
free(state);
}
/*
* See if we handle a given zone
*/
@ -325,6 +327,7 @@ dlz_findzonedb(void *dbdata, const char *name,
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_sockaddr_t *src;
char addrbuf[100];
char absolute[1024];
strcpy(addrbuf, "unknown");
if (methods != NULL &&
@ -335,11 +338,11 @@ dlz_findzonedb(void *dbdata, const char *name,
methods->sourceip(clientinfo, &src);
fmt_address(src, addrbuf, sizeof(addrbuf));
}
fprintf(stderr, "findzonedb: connection from: %s\n", addrbuf);
state->log(ISC_LOG_INFO,
"dlz_example: dlz_findzonedb called with name '%s' "
"in zone DB '%s'", name, state->zone_name);
"in zone DB '%s' from %s",
name, state->zone_name, addrbuf);
/*
* Returning ISC_R_NOTFOUND will cause the query logic to
@ -374,6 +377,10 @@ dlz_findzonedb(void *dbdata, const char *name,
if (strcasecmp(state->zone_name, name) == 0)
return (ISC_R_SUCCESS);
snprintf(absolute, sizeof(absolute), "%s.", name);
if (strcasecmp(state->zone_name, absolute) == 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
@ -394,6 +401,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
isc_result_t result;
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_boolean_t found = ISC_FALSE;
void *dbversion = NULL;
isc_sockaddr_t *src;
char full_name[256];
char buf[512];
@ -410,6 +418,30 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
} else
snprintf(full_name, 255, "%s.%s", name, state->zone_name);
/*
* If we need to know the database version (as set in
* the 'newversion' dlz function) we can pick it up from the
* clientinfo.
*
* This allows a lookup to query the correct version of the DNS
* data, if the DLZ can differentiate between versions.
*
* For example, if a new database transaction is created by
* 'newversion', the lookup should query within the same
* transaction scope if it can.
*
* If the DLZ only operates on 'live' data, then version
* wouldn't necessarily be needed.
*/
if (clientinfo != NULL &&
clientinfo->version >= DNS_CLIENTINFO_VERSION) {
dbversion = clientinfo->dbversion;
if (dbversion != NULL && *(isc_boolean_t *)dbversion)
state->log(ISC_LOG_INFO,
"dlz_example: lookup against live "
"transaction\n");
}
if (strcmp(name, "source-addr") == 0) {
strcpy(buf, "unknown");
if (methods != NULL &&
@ -422,7 +454,8 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
fmt_address(src, buf, sizeof(buf));
}
fprintf(stderr, "lookup: connection from: %s\n", buf);
state->log(ISC_LOG_INFO,
"dlz_example: lookup connection from %s\n", buf);
found = ISC_TRUE;
result = state->putrr(lookup, "TXT", 0, buf);
@ -642,6 +675,7 @@ modrdataset(struct dlz_example_data *state, const char *name,
const char *rdatastr, struct record *list)
{
char *full_name, *dclass, *type, *data, *ttlstr, *buf;
char absolute[1024];
isc_result_t result;
#if defined(WIN32) || defined(_REENTRANT)
char *saveptr = NULL;
@ -679,6 +713,11 @@ modrdataset(struct dlz_example_data *state, const char *name,
if (data == NULL)
goto error;
if (name[strlen(name) - 1] != '.') {
snprintf(absolute, sizeof(absolute), "%s.", name);
name = absolute;
}
result = add_name(state, list, name, type,
strtoul(ttlstr, NULL, 10), data);
free(buf);
@ -722,7 +761,6 @@ dlz_subrdataset(const char *name, const char *rdatastr,
return (modrdataset(state, name, rdatastr, &state->deletes[0]));
}
isc_result_t
dlz_delrdataset(const char *name, const char *type,
void *dbdata, void *version)

View File

@ -67,6 +67,20 @@ status=`expr $status + $ret`
test_update deny.example.nil. TXT "86400 TXT helloworld" "helloworld" should_fail && ret=1
status=`expr $status + $ret`
echo "I:testing prerequisites are checked correctly"
ret=0
cat > ns1/update.txt << EOF
server 10.53.0.1 5300
prereq nxdomain testdc3.example.nil
update add testdc3.example.nil 86500 in a 10.53.0.12
send
EOF
$NSUPDATE -k ns1/ddns.key ns1/update.txt > /dev/null 2>&1 && ret=1
out=`$DIG $DIGOPTS +short a testdc3.example.nil`
[ "$out" = "10.53.0.12" ] && ret=1
[ "$ret" -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
echo "I:testing passing client info into DLZ driver"
ret=0
out=`$DIG $DIGOPTS +short -t txt -q source-addr.example.nil | grep -v '^;'`

View File

@ -87,6 +87,27 @@ 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.)
DYNAMIC UPDATES AND TRANSACTIONS:
If a DLZ module wants to implement dynamic DNS updates (DDNS), the
normal calling sequence is
- dlz_newversion (start a 'transaction')
- dlz_addrdataset (add records)
- dlz_subrdataset (remove records)
- dlz_closeversion (end a 'transaction')
However, BIND may also query the database during the transaction
(e.g., to check prerequisites), and your DLZ might need to know whether
the lookup is against the pre-existing data, or the new data.
dlz_lookup() doesn't give you access to the 'versionp' pointer
directly, so it must be passed via 'clientinfo' structure if
it is needed.
The dlz_example.c code has sample code to show how to get the 'versionp'
pointer from within dlz_lookup(). If it's set to NULL, we query
the standard database; if non-NULL, we query against the in-flight
data within the appropriate uncommitted transaction.
IMPLEMENTATION NOTES:
The minimal set of type definitions, prototypes, and macros needed

View File

@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id$ */
/*
* This provides a very simple example of an external loadable DLZ
* driver, with update support.
@ -27,7 +25,7 @@
#include <stdarg.h>
#include <stdint.h>
#include "../modules/dlz_minimal.h"
#include "../modules/include/dlz_minimal.h"
#ifdef WIN32
#define STRTOK_R(a, b, c) strtok_s(a, b, c)
@ -239,7 +237,7 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
}
va_end(ap);
if (argc < 2) {
if (argc < 2 || argv[1][0] == '\0') {
if (state->log != NULL)
state->log(ISC_LOG_ERROR,
"dlz_example: please specify a zone name");
@ -247,11 +245,16 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
return (ISC_R_FAILURE);
}
state->zone_name = strdup(argv[1]);
/* Ensure zone name is absolute */
state->zone_name = malloc(strlen(argv[1]) + 2);
if (state->zone_name == NULL) {
free(state);
return (ISC_R_NOMEMORY);
}
if (argv[1][strlen(argv[1]) - 1] == '.')
strcpy(state->zone_name, argv[1]);
else
sprintf(state->zone_name, "%s.", argv[1]);
if (strcmp(state->zone_name, ".") == 0)
extra = ".root";
@ -301,7 +304,6 @@ dlz_destroy(void *dbdata) {
free(state);
}
/*
* See if we handle a given zone
*/
@ -313,6 +315,7 @@ dlz_findzonedb(void *dbdata, const char *name,
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_sockaddr_t *src;
char addrbuf[100];
char absolute[1024];
strcpy(addrbuf, "unknown");
if (methods != NULL &&
@ -324,7 +327,7 @@ dlz_findzonedb(void *dbdata, const char *name,
fmt_address(src, addrbuf, sizeof(addrbuf));
}
state->log(ISC_LOG_INFO,
"dlz_example: findzonedb connection from: %s\n", addrbuf);
"dlz_example: findzonedb connection from: %s", addrbuf);
state->log(ISC_LOG_INFO,
"dlz_example: dlz_findzonedb called with name '%s' "
@ -351,6 +354,10 @@ dlz_findzonedb(void *dbdata, const char *name,
if (strcasecmp(state->zone_name, name) == 0)
return (ISC_R_SUCCESS);
snprintf(absolute, sizeof(absolute), "%s.", name);
if (strcasecmp(state->zone_name, absolute) == 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
@ -372,6 +379,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
isc_result_t result;
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_boolean_t found = ISC_FALSE;
void *dbversion = NULL;
isc_sockaddr_t *src;
char full_name[256];
char buf[512];
@ -388,6 +396,30 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
} else
snprintf(full_name, 255, "%s.%s", name, state->zone_name);
/*
* If we need to know the database version (as set in
* the 'newversion' dlz function) we can pick it up from the
* clientinfo.
*
* This allows a lookup to query the correct version of the DNS
* data, if the DLZ can differentiate between versions.
*
* For example, if a new database transaction is created by
* 'newversion', the lookup should query within the same
* transaction scope if it can.
*
* If the DLZ only operates on 'live' data, then version
* wouldn't necessarily be needed.
*/
if (clientinfo != NULL &&
clientinfo->version >= DNS_CLIENTINFO_VERSION) {
dbversion = clientinfo->dbversion;
if (dbversion != NULL && *(isc_boolean_t *)dbversion)
state->log(ISC_LOG_INFO,
"dlz_example: lookup against live "
"transaction\n");
}
if (strcmp(name, "source-addr") == 0) {
strcpy(buf, "unknown");
if (methods != NULL &&
@ -401,7 +433,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
}
state->log(ISC_LOG_INFO,
"dlz_example: lookup connection from: %s\n", buf);
"dlz_example: lookup connection from: %s", buf);
found = ISC_TRUE;
result = state->putrr(lookup, "TXT", 0, buf);
@ -619,6 +651,7 @@ modrdataset(struct dlz_example_data *state, const char *name,
const char *rdatastr, struct record *list)
{
char *full_name, *dclass, *type, *data, *ttlstr, *buf;
char absolute[1024];
isc_result_t result;
#if defined(WIN32) || defined(_REENTRANT)
char *saveptr = NULL;
@ -656,6 +689,11 @@ modrdataset(struct dlz_example_data *state, const char *name,
if (data == NULL)
goto error;
if (name[strlen(name) - 1] != '.') {
snprintf(absolute, sizeof(absolute), "%s.", name);
name = absolute;
}
result = add_name(state, list, name, type,
strtoul(ttlstr, NULL, 10), data);
free(buf);
@ -699,7 +737,6 @@ dlz_subrdataset(const char *name, const char *rdatastr,
return (modrdataset(state, name, rdatastr, &state->deletes[0]));
}
isc_result_t
dlz_delrdataset(const char *name, const char *type,
void *dbdata, void *version)

View File

@ -14,8 +14,6 @@
* 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
@ -45,6 +43,21 @@ options {
recursion no;
};
/*
* To test dynamic updates, create a DDNS key:
*
* ddns-confgen -q -z example.nil > ddns.key
*
* Then uncomment the following line:
*
* include "ddns.key";
*
* Use "nsupdate -k ddns.key" when sending updates. (NOTE: This driver does
* not check the key that's used: as long as the update is signed by a key
* known to named, the update will be accepted. Only updates to names
* that begin with "deny." are rejected.)
*/
dlz "example" {
database "dlopen ./dlz_example.so example.nil";
};

View File

@ -80,6 +80,12 @@ typedef uint32_t dns_ttl_t;
/* other useful definitions */
#define UNUSED(x) (void)(x)
#define DE_CONST(konst, var) \
do { \
union { const void *k; void *v; } _u; \
_u.k = konst; \
var = _u.v; \
} while (0)
/* opaque structures */
typedef void *dns_sdlzlookup_t;
@ -105,22 +111,26 @@ typedef struct isc_sockaddr {
void * link;
} isc_sockaddr_t;
#define DNS_CLIENTINFO_VERSION 1
#define DNS_CLIENTINFO_VERSION 2
typedef struct dns_clientinfo {
uint16_t version;
void *data;
void *dbversion;
} 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 isc_result_t (*dns_clientinfo_version_t)(dns_clientinfo_t *client,
void **addrp);
#define DNS_CLIENTINFOMETHODS_VERSION 2
#define DNS_CLIENTINFOMETHODS_AGE 1
typedef struct dns_clientinfomethods {
uint16_t version;
uint16_t age;
dns_clientinfo_sourceip_t sourceip;
dns_clientinfo_version_t dbversion;
} dns_clientinfomethods_t;
#endif /* DLZ_DLOPEN_VERSION > 1 */

View File

@ -25,12 +25,14 @@
#define dlz_mutex_t pthread_mutex_t
#define dlz_mutex_init pthread_mutex_init
#define dlz_mutex_destroy pthread_mutex_destroy
#define dlz_mutex_lock pthread_mutex_lock
#define dlz_mutex_trylock pthread_mutex_trylock
#define dlz_mutex_unlock pthread_mutex_unlock
#else /* !PTHREADS */
#define dlz_mutex_t void
#define dlz_mutex_init(a, b) (0)
#define dlz_mutex_destroy(a) (0)
#define dlz_mutex_lock(a) (0)
#define dlz_mutex_trylock(a) (0)
#define dlz_mutex_unlock(a) (0)
#endif

View File

@ -0,0 +1,21 @@
prefix = /usr
libdir = $(prefix)/lib/bind9
CFLAGS=-fPIC -g -I../include
MYSQL_LIBS=-lmysqlclient
all: dlz_mysqldyn_mod.so
dlz_dbi.o: ../common/dlz_dbi.c
$(CC) $(CFLAGS) -c ../common/dlz_dbi.c
dlz_mysqldyn_mod.so: dlz_mysqldyn_mod.c dlz_dbi.o
$(CC) $(CFLAGS) -shared -o dlz_mysqldyn_mod.so \
dlz_mysqldyn_mod.c dlz_dbi.o $(MYSQL_LIBS)
clean:
rm -f dlz_mysqldyn_mod.so *.o
install: dlz_mysqldyn_mod.so
mkdir -p $(DESTDIR)$(libdir)
install dlz_mysqldyn_mod.so $(DESTDIR)$(libdir)

View File

@ -0,0 +1,60 @@
BIND 9 DLZ MySQL module with support for dynamic DNS (DDNS)
Adapted from code contributed by Marty Lee, Maui Systems Ltd.
This is a dynamically loadable zone (DLZ) plugin that uses a fixed-
schema MySQL database for back-end storage. It allows zone data
to be updated via dynamic DNS updates, and sends DNS NOTIFY packets
to other name servers when appropriate.
The database for this module uses the following schema:
CREATE TABLE `Zones` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain` varchar(128) NOT NULL DEFAULT '',
`host` varchar(128) NOT NULL DEFAULT '',
`admin` varchar(128) NOT NULL DEFAULT '',
`serial` int(11) NOT NULL DEFAULT '1',
`expire` int(11) NOT NULL DEFAULT '86400',
`refresh` int(11) NOT NULL DEFAULT '86400',
`retry` int(11) NOT NULL DEFAULT '86400',
`minimum` int(11) NOT NULL DEFAULT '86400',
`ttl` int(11) NOT NULL DEFAULT '86400',
`writeable` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `domain_idx` (`domain`)
);
CREATE TABLE `ZoneData` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zone_id` int(11) NOT NULL,
`name` varchar(128) NOT NULL DEFAULT '',
`type` varchar(16) NOT NULL DEFAULT '',
`ttl` int(11) NOT NULL DEFAULT '86400',
`data` varchar(128) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `zone_idx` (`zone_id`),
KEY `name_idx` (`zone_id`, `name`),
KEY `type_idx` (`type`)
);
'Zones' contains information about specific zones:
- domain: the zone name
- admin: the zone administrator
- serial, expire, reresh, retry, minimum: values in the SOA record
- ttl: default zone TTL
- writeable: set to true if the zone can be updated via DDNS
'ZoneData' contains the individual records within the zone:
- zone_id: the 'id' from the corresponding record in Zones
- name: domain name, relative to the zone apex. (Data at the zone
apex itself may use a blank name or "@".)
- type: the RR type, expressed as text
- ttl: the record's TTL
- data: the records rdata, expressed as text.
To configure this module in named.conf:
dlz "mysqldlz" {
database "dlopen <path to>/dlz_mysqldyn_mod.so <dbname> [dbhost [dbuser [dbpass]]]";
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
These files were used for testing on Ubuntu Linux using MySQL
To set up a test server:
- Install MySQL: sudo apt-get install mysql-server
- Run "mysql --user=USER --password=PASSWORD < dlz.schema" to set up database
- Run "mysql --user=USER --password=PASSWORD < dlz.data" to populate it
- Update named.conf with correct USER and PASSWORD
- Generate a TSIG key: "ddns-confgen -qz example.com"
To query the database, use "dig -p 5300 @localhost"
To send dynamic updates, use "nsupdate -p 5300 -k ddns.key"

View File

@ -0,0 +1,18 @@
use BindDB;
insert into `Zones`
( `id`, `domain`, `host`, `admin`, `serial`, `expire`,
`refresh`, `retry`, `minimum`, `ttl`, `writeable`) VALUES
(1, 'example.com', '@', 'info', 2014040100, 10800,
7200, 604800, 86400, 86400, 1);
insert into `ZoneData`
(`id`, `zone_id`, `name`, `type`, `data`) VALUES
('', 1, '@', 'NS', 'ns1.example.com.'),
('', 1, '@', 'NS', 'ns2.example.com.'),
('', 1, '@', 'MX', '10 mail.example.com.'),
('', 1, '@', 'A', '192.168.0.2'),
('', 1, '@', 'TXT', '"v=spf1 ip:192.168.0.3 ~all"'),
('', 1, 'www', 'CNAME', 'example.com.'),
('', 1, 'mail', 'A', '192.168.0.3'),
('', 1, 'ns1', 'A', '192.168.1.111'),
('', 1, 'ns2', 'A', '192.168.1.222');

View File

@ -0,0 +1,31 @@
CREATE DATABASE `BindDB` DEFAULT CHARACTER SET latin1;
USE `BindDB`;
CREATE TABLE `ZoneData` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zone_id` int(11) NOT NULL,
`name` varchar(128) NOT NULL DEFAULT '',
`type` varchar(16) NOT NULL DEFAULT '',
`data` varchar(128) NOT NULL DEFAULT '',
`ttl` int(11) NOT NULL DEFAULT '86400',
PRIMARY KEY (`id`),
KEY `zone_idx` (`zone_id`),
KEY `name_idx` (`zone_id`, `name`),
KEY `type_idx` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `Zones` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`domain` varchar(128) NOT NULL DEFAULT '',
`host` varchar(128) NOT NULL DEFAULT '',
`admin` varchar(128) NOT NULL DEFAULT '',
`serial` int(11) NOT NULL DEFAULT '1',
`expire` int(11) NOT NULL DEFAULT '86400',
`refresh` int(11) NOT NULL DEFAULT '86400',
`retry` int(11) NOT NULL DEFAULT '86400',
`minimum` int(11) NOT NULL DEFAULT '86400',
`ttl` int(11) NOT NULL DEFAULT '86400',
`writeable` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `domain_idx` (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 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.
*/
controls { };
options {
directory ".";
port 5300;
pid-file "named.pid";
session-keyfile "session.key";
listen-on { any; };
listen-on-v6 { none; };
recursion no;
};
include "ddns.key";
key rndc_key {
secret "1234abcd8765";
algorithm hmac-md5;
};
controls {
inet 127.0.0.1 port 9953 allow { any; } keys { rndc_key; };
};
dlz "test" {
database "dlopen ../dlz_mysqldyn_mod.so BindDB localhost root password";
};

View File

@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: clientinfo.c,v 1.3 2011/10/11 00:25:12 marka Exp $ */
/*! \file */
#include "config.h"
@ -32,7 +30,8 @@ dns_clientinfomethods_init(dns_clientinfomethods_t *methods,
}
void
dns_clientinfo_init(dns_clientinfo_t *ci, void *data) {
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, void *versionp) {
ci->version = DNS_CLIENTINFO_VERSION;
ci->data = data;
ci->dbversion = versionp;
}

View File

@ -52,10 +52,11 @@ ISC_LANG_BEGINDECLS
***** Types
*****/
#define DNS_CLIENTINFO_VERSION 1
#define DNS_CLIENTINFO_VERSION 2
typedef struct dns_clientinfo {
isc_uint16_t version;
void *data;
void *dbversion;
} dns_clientinfo_t;
typedef isc_result_t (*dns_clientinfo_sourceip_t)(dns_clientinfo_t *client,
@ -78,7 +79,7 @@ dns_clientinfomethods_init(dns_clientinfomethods_t *methods,
dns_clientinfo_sourceip_t sourceip);
void
dns_clientinfo_init(dns_clientinfo_t *ci, void *data);
dns_clientinfo_init(dns_clientinfo_t *ci, void *data, void *versionp);
ISC_LANG_ENDDECLS

View File

@ -426,8 +426,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
}
static void
attachversion(dns_db_t *db, dns_dbversion_t *source,
dns_dbversion_t **targetp)
attachversion(dns_db_t *db, dns_dbversion_t *source, dns_dbversion_t **targetp)
{
dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
@ -854,7 +853,9 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
REQUIRE(VALID_SDLZDB(sdlz));
REQUIRE(nodep == NULL || *nodep == NULL);
REQUIRE(version == NULL || version == (void*)&sdlz->dummy_version);
REQUIRE(version == NULL ||
version == (void*)&sdlz->dummy_version ||
version == sdlz->future_version);
UNUSED(options);
UNUSED(sdlz);