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

[master] pass client info to DLZ findzone method

3434.   [bug]           Pass client info to the DLZ findzone() entry
                        point in addition to lookup().  This makes it
                        possible for a database to answer differently
                        whether it's authoritative for a name depending
                        on the address of the client.  [RT #31775]
parent 177be355
3434. [bug] Pass client info to the DLZ findzone() entry
point in addition to lookup(). This makes it
possible for a database to answer differently
whether it's authoritative for a name depending
on the address of the client. [RT #31775]
3433. [bug] dlz_findzone() did not correctly handle
ISC_R_NOMORE. [RT #31172]
......
......@@ -1066,8 +1066,14 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
if (zonelabels < namelabels &&
!ISC_LIST_EMPTY(client->view->dlz_searched))
{
tresult = dns_dlzfindzone(client->view, name,
zonelabels, &tdbp);
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
dns_clientinfo_init(&ci, client);
tresult = dns_view_searchdlz(client->view, name,
zonelabels, &cm, &ci, &tdbp);
/* If we successful, we found a better match. */
if (tresult == ISC_R_SUCCESS) {
/*
......
......@@ -161,7 +161,9 @@ dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata,
}
static isc_result_t
dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
dlopen_data_t *cd = (dlopen_data_t *) dbdata;
isc_result_t result;
......@@ -169,7 +171,7 @@ dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
UNUSED(driverarg);
MAYBE_LOCK(cd);
result = cd->dlz_findzonedb(cd->dbdata, name);
result = cd->dlz_findzonedb(cd->dbdata, name, methods, clientinfo);
MAYBE_UNLOCK(cd);
return (result);
}
......@@ -289,6 +291,7 @@ dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
dl_load_symbol(cd, "dlz_findzonedb", ISC_TRUE);
if (cd->dlz_create == NULL ||
cd->dlz_version == NULL ||
cd->dlz_lookup == NULL ||
cd->dlz_findzonedb == NULL)
{
......
......@@ -277,6 +277,7 @@ dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
dl_load_symbol(cd, "dlz_findzonedb", ISC_TRUE);
if (cd->dlz_create == NULL ||
cd->dlz_version == NULL ||
cd->dlz_lookup == NULL ||
cd->dlz_findzonedb == NULL)
{
......
......@@ -318,11 +318,26 @@ dlz_destroy(void *dbdata) {
* See if we handle a given zone
*/
isc_result_t
dlz_findzonedb(void *dbdata, const char *name) {
dlz_findzonedb(void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_sockaddr_t *src;
char addrbuf[100];
strcpy(addrbuf, "unknown");
if (methods != NULL &&
methods->sourceip != NULL &&
methods->version - methods->age >= DNS_CLIENTINFOMETHODS_VERSION)
{
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'"
"dlz_example: dlz_findzonedb called with name '%s' "
"in zone DB '%s'", name, state->zone_name);
/*
......@@ -335,6 +350,14 @@ dlz_findzonedb(void *dbdata, const char *name) {
if (strcasecmp(name, "test.example.com") == 0)
return (ISC_R_NOMORE);
/*
* For example.net, only return ISC_R_NOMORE when queried
* from 10.53.0.1.
*/
if (strcasecmp(name, "test.example.net") == 0 &&
strncmp(addrbuf, "10.53.0.1", 9) == 0)
return (ISC_R_NOMORE);
if (strcasecmp(state->zone_name, name) == 0)
return (ISC_R_SUCCESS);
......@@ -342,7 +365,10 @@ dlz_findzonedb(void *dbdata, const char *name) {
}
/*
* Look up 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, to test the use of 'methods' and 'clientinfo'
*/
isc_result_t
dlz_lookup(const char *zone, const char *name, void *dbdata,
......@@ -371,6 +397,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
char buf[100];
strcpy(buf, "unknown");
if (methods != NULL &&
methods->sourceip != NULL &&
methods->version - methods->age >=
DNS_CLIENTINFOMETHODS_VERSION)
{
......@@ -378,7 +405,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
fmt_address(src, buf, sizeof(buf));
}
fprintf(stderr, "connection from: %s\n", buf);
fprintf(stderr, "lookup: connection from: %s\n", buf);
found = ISC_TRUE;
result = state->putrr(lookup, "TXT", 0, buf);
......@@ -412,7 +439,7 @@ dlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
UNUSED(client);
/* Just say yes for all our zones */
return (dlz_findzonedb(dbdata, name));
return (dlz_findzonedb(dbdata, name, NULL, NULL));
}
/*
......
......@@ -112,11 +112,28 @@ ret=0
echo "I:testing correct behavior with findzone returning ISC_R_NOMORE"
$DIG $DIGOPTS +noall a test.example.com > /dev/null 2>&1 || ret=1
# we should only find one logged lookup per searched DLZ database
lines=`grep "dlz_findzonedb.*example\.com.*example.nil" ns1/named.run | wc -l`
lines=`grep "dlz_findzonedb.*test\.example\.com.*example.nil" ns1/named.run | wc -l`
[ $lines -eq 1 ] || ret=1
lines=`grep "dlz_findzonedb.*example\.com.*alternate.nil" ns1/named.run | wc -l`
lines=`grep "dlz_findzonedb.*test\.example\.com.*alternate.nil" ns1/named.run | wc -l`
[ $lines -eq 1 ] || ret=1
[ "$ret" -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
ret=0
echo "I:testing findzone can return different results per client"
$DIG $DIGOPTS -b 10.53.0.1 +noall a test.example.net > /dev/null 2>&1 || ret=1
# we should only find one logged lookup per searched DLZ database
lines=`grep "dlz_findzonedb.*example\.net.*example.nil" ns1/named.run | wc -l`
[ $lines -eq 1 ] || ret=1
lines=`grep "dlz_findzonedb.*example\.net.*alternate.nil" ns1/named.run | wc -l`
[ $lines -eq 1 ] || ret=1
$DIG $DIGOPTS -b 10.53.0.2 +noall a test.example.net > /dev/null 2>&1 || ret=1
# we should find several logged lookups this time
lines=`grep "dlz_findzonedb.*example\.net.*example.nil" ns1/named.run | wc -l`
[ $lines -gt 2 ] || ret=1
lines=`grep "dlz_findzonedb.*example\.net.*alternate.nil" ns1/named.run | wc -l`
[ $lines -gt 2 ] || ret=1
[ "$ret" -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
exit $status
......@@ -114,7 +114,8 @@ typedef struct parsed_data {
/* forward reference */
static isc_result_t
bdb_findzone(void *driverarg, void *dbdata, const char *name);
bdb_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo);
/*%
* Parses the DBT from the Berkeley DB into a parsed_data record
......@@ -226,7 +227,7 @@ bdb_allowzonexfr(void *driverarg, void *dbdata, const char *name,
DBT key, data;
/* check to see if we are authoritative for the zone first. */
result = bdb_findzone(driverarg, dbdata, name);
result = bdb_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
......@@ -393,7 +394,8 @@ bdb_cleanup(bdb_instance_t *db) {
}
static isc_result_t
bdb_findzone(void *driverarg, void *dbdata, const char *name)
bdb_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
{
isc_result_t result;
......@@ -402,6 +404,8 @@ bdb_findzone(void *driverarg, void *dbdata, const char *name)
DBT key, data;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
......
......@@ -112,7 +112,8 @@ typedef struct bdbhpt_parsed_data {
/* forward reference */
static isc_result_t
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name);
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo);
/*%
* Reverses a string in place.
......@@ -252,7 +253,7 @@ bdbhpt_allowzonexfr(void *driverarg, void *dbdata, const char *name,
DBT key, data;
/* check to see if we are authoritative for the zone first. */
result = bdbhpt_findzone(driverarg, dbdata, name);
result = bdbhpt_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
......@@ -483,7 +484,8 @@ bdbhpt_cleanup(bdbhpt_instance_t *db) {
}
static isc_result_t
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name)
bdbhpt_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
{
isc_result_t result;
......@@ -491,6 +493,8 @@ bdbhpt_findzone(void *driverarg, void *dbdata, const char *name)
DBT key, data;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
......
......@@ -749,7 +749,8 @@ fs_allnodes(const char *zone, void *driverarg, void *dbdata,
}
static isc_result_t
fs_findzone(void *driverarg, void *dbdata, const char *name)
fs_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
{
isc_result_t result;
......@@ -758,6 +759,8 @@ fs_findzone(void *driverarg, void *dbdata, const char *name)
path = NULL;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
if (create_path(name, NULL, NULL, (config_data_t *) dbdata,
&path) != ISC_R_SUCCESS) {
......
......@@ -117,7 +117,9 @@ typedef struct {
/* forward references */
static isc_result_t
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name);
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo);
static void
dlz_ldap_destroy(void *driverarg, void *dbdata);
......@@ -878,7 +880,7 @@ dlz_ldap_allowzonexfr(void *driverarg, void *dbdata, const char *name,
UNUSED(driverarg);
/* check to see if we are authoritative for the zone first */
result = dlz_ldap_findzone(driverarg, dbdata, name);
result = dlz_ldap_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS) {
return (result);
}
......@@ -905,8 +907,13 @@ dlz_ldap_authority(const char *zone, void *driverarg, void *dbdata,
}
static isc_result_t
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name) {
dlz_ldap_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
return (ldap_get_results(name, NULL, NULL, FINDZONE, dbdata, NULL));
}
......
......@@ -503,13 +503,16 @@ mysql_process_rs(dns_sdlzlookup_t *lookup, MYSQL_RES *rs)
/*% determine if the zone is supported by (in) the database */
static isc_result_t
mysql_findzone(void *driverarg, void *dbdata, const char *name)
mysql_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
{
isc_result_t result;
MYSQL_RES *rs = NULL;
my_ulonglong rows;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
/* run the query and get the result set from the database. */
result = mysql_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs);
......@@ -550,7 +553,7 @@ mysql_allowzonexfr(void *driverarg, void *dbdata, const char *name,
UNUSED(driverarg);
/* first check if the zone is supported by the database. */
result = mysql_findzone(driverarg, dbdata, name);
result = mysql_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
......
......@@ -963,13 +963,16 @@ odbc_process_rs(dns_sdlzlookup_t *lookup, dbinstance_t *dbi)
/*% determine if the zone is supported by (in) the database */
static isc_result_t
odbc_findzone(void *driverarg, void *dbdata, const char *name)
odbc_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
{
isc_result_t result;
dbinstance_t *dbi = NULL;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
/* run the query and get the result set from the database. */
/* if result != ISC_R_SUCCESS cursor and mutex already cleaned up. */
......@@ -1007,7 +1010,7 @@ odbc_allowzonexfr(void *driverarg, void *dbdata, const char *name,
UNUSED(driverarg);
/* first check if the zone is supported by the database. */
result = odbc_findzone(driverarg, dbdata, name);
result = odbc_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
......
......@@ -770,12 +770,17 @@ postgres_process_rs(dns_sdlzlookup_t *lookup, PGresult *rs)
/*% determine if the zone is supported by (in) the database */
static isc_result_t
postgres_findzone(void *driverarg, void *dbdata, const char *name)
postgres_findzone(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
isc_result_t result;
PGresult *rs = NULL;
unsigned int rows;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
/* run the query and get the result set from the database. */
result = postgres_get_resultset(name, NULL, NULL,
......@@ -814,7 +819,7 @@ postgres_allowzonexfr(void *driverarg, void *dbdata, const char *name,
UNUSED(driverarg);
/* first check if the zone is supported by the database. */
result = postgres_findzone(driverarg, dbdata, name);
result = postgres_findzone(driverarg, dbdata, name, NULL, NULL);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
......
......@@ -147,12 +147,16 @@ stub_dlz_authority(const char *zone, void *driverarg, void *dbdata,
}
static isc_result_t
stub_dlz_findzonedb(void *driverarg, void *dbdata, const char *name)
stub_dlz_findzonedb(void *driverarg, void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
config_data_t *cd;
UNUSED(driverarg);
UNUSED(methods);
UNUSED(clientinfo);
cd = (config_data_t *) dbdata;
......
......@@ -37,6 +37,13 @@
#define STRTOK_R(a, b, c) strtok(a, b)
#endif
#define CHECK(x) \
do { \
result = (x); \
if (result != ISC_R_SUCCESS) \
goto failure; \
} while (0)
/* For this simple example, use fixed sized strings */
struct record {
char name[100];
......@@ -104,13 +111,22 @@ add_name(struct dlz_example_data *state, struct record *list,
i = first_empty;
}
if (i == MAX_RECORDS) {
state->log(ISC_LOG_ERROR, "dlz_example: out of record space");
if (state->log != NULL)
state->log(ISC_LOG_ERROR,
"dlz_example: out of record space");
return (ISC_R_FAILURE);
}
strcpy(list[i].name, name);
strcpy(list[i].type, type);
strcpy(list[i].data, data);
if (strlen(name) >= sizeof(list[i].name) ||
strlen(type) >= sizeof(list[i].type) ||
strlen(data) >= sizeof(list[i].data))
return (ISC_R_NOSPACE);
strncpy(list[i].name, name, sizeof(list[i].name));
strncpy(list[i].type, type, sizeof(list[i].type));
strncpy(list[i].data, data, sizeof(list[i].data));
list[i].ttl = ttl;
return (ISC_R_SUCCESS);
}
......@@ -195,7 +211,6 @@ b9_add_helper(struct dlz_example_data *state,
state->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
}
/*
* Called to initialize the driver
*/
......@@ -208,6 +223,8 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
va_list ap;
char soa_data[200];
const char *extra;
isc_result_t result;
int n;
UNUSED(dlzname);
......@@ -218,24 +235,36 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
/* 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*));
b9_add_helper(state, helper_name, va_arg(ap, void *));
}
va_end(ap);
if (argc < 2) {
state->log(ISC_LOG_ERROR,
"dlz_example: please specify a zone name");
if (state->log != NULL)
state->log(ISC_LOG_ERROR,
"dlz_example: please specify a zone name");
dlz_destroy(state);
return (ISC_R_FAILURE);
}
state->zone_name = strdup(argv[1]);
if (state->zone_name == NULL) {
free(state);
return (ISC_R_NOMEMORY);
}
if (strcmp(state->zone_name, ".") == 0)
extra = ".root";
else
extra = ".";
sprintf(soa_data, "%s hostmaster%s%s 123 900 600 86400 3600",
state->zone_name, extra, state->zone_name);
n = sprintf(soa_data, "%s hostmaster%s%s 123 900 600 86400 3600",
state->zone_name, extra, state->zone_name);
if (n < 0)
CHECK(ISC_R_FAILURE);
if ((unsigned)n >= sizeof(soa_data))
CHECK(ISC_R_NOSPACE);
add_name(state, &state->current[0], state->zone_name,
"soa", 3600, soa_data);
......@@ -244,12 +273,17 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[],
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);
if (state->log != NULL)
state->log(ISC_LOG_INFO, "dlz_example: started for zone %s",
state->zone_name);
*dbdata = state;
return (ISC_R_SUCCESS);
failure:
free(state);
return (result);
}
/*
......@@ -259,9 +293,10 @@ 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);
if (state->log != NULL)
state->log(ISC_LOG_INFO,
"dlz_example: shutting down zone %s",
state->zone_name);
free(state->zone_name);
free(state);
}
......@@ -271,8 +306,45 @@ dlz_destroy(void *dbdata) {
* See if we handle a given zone
*/
isc_result_t
dlz_findzonedb(void *dbdata, const char *name) {
dlz_findzonedb(void *dbdata, const char *name,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_sockaddr_t *src;
char addrbuf[100];
strcpy(addrbuf, "unknown");
if (methods != NULL &&
methods->sourceip != NULL &&
methods->version - methods->age >= DNS_CLIENTINFOMETHODS_VERSION)
{
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);
/*
* Returning ISC_R_NOTFOUND will cause the query logic to
* check the database for parent names, looking for zone cuts.
*
* Returning ISC_R_NOMORE prevents the query logic from doing
* this; it will move onto the next database after a single query.
*/
if (strcasecmp(name, "test.example.com") == 0)
return (ISC_R_NOMORE);
/*
* For example.net, only return ISC_R_NOMORE when queried
* from 10.53.0.1.
*/
if (strcasecmp(name, "test.example.net") == 0 &&
strncmp(addrbuf, "10.53.0.1", 9) == 0)
return (ISC_R_NOMORE);
if (strcasecmp(state->zone_name, name) == 0)
return (ISC_R_SUCCESS);
......@@ -296,20 +368,25 @@ dlz_lookup(const char *zone, const char *name, void *dbdata,
struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
isc_boolean_t found = ISC_FALSE;
isc_sockaddr_t *src;
char full_name[100];
char full_name[256];
int i;
UNUSED(zone);
if (strcmp(name, "@") == 0)
strcpy(full_name, state->zone_name);
else
sprintf(full_name, "%s.%s", name, state->zone_name);
if (state->putrr == NULL)
return (ISC_R_NOTIMPLEMENTED);
if (strcmp(name, "@") == 0) {
strncpy(full_name, state->zone_name, 255);
full_name[255] = '\0';
} else
snprintf(full_name, 255, "%s.%s", name, state->zone_name);