Commit aefb3e30 authored by Evan Hunt's avatar Evan Hunt
Browse files

[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]
parent 1deeb567
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
......
......@@ -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) {
/*
......
......@@ -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)
......
......@@ -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)
......
......@@ -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 '^;'`
......
......@@ -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
......
......@@ -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)
......
......@@ -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";
};
......@@ -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;