diff --git a/CHANGES b/CHANGES index 0a88c20f1f..61eb82a4d1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +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] diff --git a/bin/named/query.c b/bin/named/query.c index 41917ffb93..d88f73a53c 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -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) { /* diff --git a/bin/named/unix/dlz_dlopen_driver.c b/bin/named/unix/dlz_dlopen_driver.c index 9ff7649a97..fc5ab8669f 100644 --- a/bin/named/unix/dlz_dlopen_driver.c +++ b/bin/named/unix/dlz_dlopen_driver.c @@ -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) { diff --git a/bin/named/win32/dlz_dlopen_driver.c b/bin/named/win32/dlz_dlopen_driver.c index 0c192b4769..051d511f09 100644 --- a/bin/named/win32/dlz_dlopen_driver.c +++ b/bin/named/win32/dlz_dlopen_driver.c @@ -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) { diff --git a/bin/tests/system/dlzexternal/driver.c b/bin/tests/system/dlzexternal/driver.c index cdda7c406e..ddc658903c 100644 --- a/bin/tests/system/dlzexternal/driver.c +++ b/bin/tests/system/dlzexternal/driver.c @@ -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)); } /* diff --git a/bin/tests/system/dlzexternal/tests.sh b/bin/tests/system/dlzexternal/tests.sh index 38327d4dab..34311128eb 100644 --- a/bin/tests/system/dlzexternal/tests.sh +++ b/bin/tests/system/dlzexternal/tests.sh @@ -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 diff --git a/contrib/dlz/drivers/dlz_bdb_driver.c b/contrib/dlz/drivers/dlz_bdb_driver.c index 50abb28779..e72060c5a0 100644 --- a/contrib/dlz/drivers/dlz_bdb_driver.c +++ b/contrib/dlz/drivers/dlz_bdb_driver.c @@ -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)); diff --git a/contrib/dlz/drivers/dlz_bdbhpt_driver.c b/contrib/dlz/drivers/dlz_bdbhpt_driver.c index a3a2bc4de4..ff0809802b 100644 --- a/contrib/dlz/drivers/dlz_bdbhpt_driver.c +++ b/contrib/dlz/drivers/dlz_bdbhpt_driver.c @@ -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)); diff --git a/contrib/dlz/drivers/dlz_filesystem_driver.c b/contrib/dlz/drivers/dlz_filesystem_driver.c index 3a03798877..73b7976921 100644 --- a/contrib/dlz/drivers/dlz_filesystem_driver.c +++ b/contrib/dlz/drivers/dlz_filesystem_driver.c @@ -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) { diff --git a/contrib/dlz/drivers/dlz_ldap_driver.c b/contrib/dlz/drivers/dlz_ldap_driver.c index 160895a190..9bd34bd3bb 100644 --- a/contrib/dlz/drivers/dlz_ldap_driver.c +++ b/contrib/dlz/drivers/dlz_ldap_driver.c @@ -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)); } diff --git a/contrib/dlz/drivers/dlz_mysql_driver.c b/contrib/dlz/drivers/dlz_mysql_driver.c index 00e472799a..97deeabeef 100644 --- a/contrib/dlz/drivers/dlz_mysql_driver.c +++ b/contrib/dlz/drivers/dlz_mysql_driver.c @@ -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); diff --git a/contrib/dlz/drivers/dlz_odbc_driver.c b/contrib/dlz/drivers/dlz_odbc_driver.c index 9c1ff4613c..283998d85e 100644 --- a/contrib/dlz/drivers/dlz_odbc_driver.c +++ b/contrib/dlz/drivers/dlz_odbc_driver.c @@ -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); diff --git a/contrib/dlz/drivers/dlz_postgres_driver.c b/contrib/dlz/drivers/dlz_postgres_driver.c index 4149bff71b..8bd061236a 100644 --- a/contrib/dlz/drivers/dlz_postgres_driver.c +++ b/contrib/dlz/drivers/dlz_postgres_driver.c @@ -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); diff --git a/contrib/dlz/drivers/dlz_stub_driver.c b/contrib/dlz/drivers/dlz_stub_driver.c index a41697e344..e25ef33741 100644 --- a/contrib/dlz/drivers/dlz_stub_driver.c +++ b/contrib/dlz/drivers/dlz_stub_driver.c @@ -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; diff --git a/contrib/dlz/example/dlz_example.c b/contrib/dlz/example/dlz_example.c index 58194fe8b4..c1eb980c90 100644 --- a/contrib/dlz/example/dlz_example.c +++ b/contrib/dlz/example/dlz_example.c @@ -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); if (strcmp(name, "source-addr") == 0) { char buf[100]; strcpy(buf, "unknown"); if (methods != NULL && + methods->sourceip != NULL && methods->version - methods->age >= DNS_CLIENTINFOMETHODS_VERSION) { @@ -317,7 +394,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); @@ -351,7 +428,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)); } /* @@ -364,6 +441,9 @@ dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) { UNUSED(zone); + if (state->putnamedrr == NULL) + return (ISC_R_NOTIMPLEMENTED); + for (i = 0; i < MAX_RECORDS; i++) { isc_result_t result; if (strlen(state->current[i].name) == 0U) { @@ -389,9 +469,10 @@ 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); + if (state->log != NULL) + state->log(ISC_LOG_INFO, + "dlz_example: transaction already " + "started for zone %s", zone); return (ISC_R_FAILURE); } @@ -411,9 +492,9 @@ dlz_closeversion(const char *zone, isc_boolean_t commit, 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); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: transaction not " + "started for zone %s", zone); *versionp = NULL; return; } @@ -424,31 +505,31 @@ dlz_closeversion(const char *zone, isc_boolean_t commit, if (commit) { int i; - state->log(ISC_LOG_INFO, - "dlz_example: committing transaction on zone %s", - zone); + if (state->log != NULL) + 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, - state->adds[i].ttl, - state->adds[i].data); + if (strlen(state->deletes[i].name) > 0U) { + (void)del_name(state, &state->current[0], + state->deletes[i].name, + state->deletes[i].type, + state->deletes[i].ttl, + state->deletes[i].data); } } 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, - state->deletes[i].ttl, - state->deletes[i].data); + if (strlen(state->adds[i].name) > 0U) { + (void)add_name(state, &state->current[0], + state->adds[i].name, + state->adds[i].type, + state->adds[i].ttl, + state->adds[i].data); } } } else { - state->log(ISC_LOG_INFO, - "dlz_example: cancelling transaction on zone %s", - zone); + if (state->log != NULL) + 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)); @@ -459,30 +540,31 @@ dlz_closeversion(const char *zone, isc_boolean_t commit, * Configure a writeable zone */ isc_result_t -dlz_configure(dns_view_t *view, void *dbdata) { +dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *dbdata) { struct dlz_example_data *state = (struct dlz_example_data *)dbdata; isc_result_t result; + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: starting configure"); - 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"); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: no " + "writeable_zone method available"); return (ISC_R_FAILURE); } - result = state->writeable_zone(view, view->dlzdatabase, - state->zone_name); + result = state->writeable_zone(view, dlzdb, state->zone_name); if (result != ISC_R_SUCCESS) { - state->log(ISC_LOG_ERROR, - "dlz_example: failed to configure zone %s", - state->zone_name); + if (state->log != NULL) + 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); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: configured writeable " + "zone %s", state->zone_name); return (ISC_R_SUCCESS); } @@ -503,14 +585,14 @@ dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr, UNUSED(keydata); if (strncmp(name, "deny.", 5) == 0) { - state->log(ISC_LOG_INFO, - "dlz_example: denying update of name=%s by %s", - name, signer); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: denying update " + "of name=%s by %s", name, signer); return (ISC_FALSE); } - state->log(ISC_LOG_INFO, - "dlz_example: allowing update of name=%s by %s", - name, signer); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: allowing update of " + "name=%s by %s", name, signer); return (ISC_TRUE); } @@ -519,13 +601,16 @@ 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); + char *full_name, *dclass, *type, *data, *ttlstr, *buf; isc_result_t result; #if defined(WIN32) || defined(_REENTRANT) char *saveptr = NULL; #endif + buf = strdup(rdatastr); + if (buf == NULL) + return (ISC_R_FAILURE); + /* * The format is: * FULLNAME\tTTL\tDCLASS\tTYPE\tDATA @@ -536,28 +621,32 @@ modrdataset(struct dlz_example_data *state, const char *name, full_name = STRTOK_R(buf, "\t", &saveptr); if (full_name == NULL) - return (ISC_R_FAILURE); + goto error; ttlstr = STRTOK_R(NULL, "\t", &saveptr); if (ttlstr == NULL) - return (ISC_R_FAILURE); + goto error; dclass = STRTOK_R(NULL, "\t", &saveptr); if (dclass == NULL) - return (ISC_R_FAILURE); + goto error; type = STRTOK_R(NULL, "\t", &saveptr); if (type == NULL) - return (ISC_R_FAILURE); + goto error; data = STRTOK_R(NULL, "\t", &saveptr); if (data == NULL) - return (ISC_R_FAILURE); + goto error; result = add_name(state, list, name, type, strtoul(ttlstr, NULL, 10), data); free(buf); return (result); + + error: + free(buf); + return (ISC_R_FAILURE); } @@ -570,9 +659,9 @@ dlz_addrdataset(const char *name, const char *rdatastr, if (version != (void *) &state->transaction_started) return (ISC_R_FAILURE); - state->log(ISC_LOG_INFO, - "dlz_example: adding rdataset %s '%s'", - name, rdatastr); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: adding rdataset %s '%s'", + name, rdatastr); return (modrdataset(state, name, rdatastr, &state->adds[0])); } @@ -586,9 +675,9 @@ dlz_subrdataset(const char *name, const char *rdatastr, if (version != (void *) &state->transaction_started) return (ISC_R_FAILURE); - state->log(ISC_LOG_INFO, - "dlz_example: subtracting rdataset %s '%s'", - name, rdatastr); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: subtracting rdataset " + "%s '%s'", name, rdatastr); return (modrdataset(state, name, rdatastr, &state->deletes[0])); } @@ -603,9 +692,9 @@ dlz_delrdataset(const char *name, const char *type, 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); + if (state->log != NULL) + state->log(ISC_LOG_INFO, "dlz_example: deleting rdataset %s " + "of type %s", name, type); return (ISC_R_SUCCESS); } diff --git a/contrib/dlz/example/dlz_minimal.h b/contrib/dlz/example/dlz_minimal.h index c72c1d4c75..3972094ad8 100644 --- a/contrib/dlz/example/dlz_minimal.h +++ b/contrib/dlz/example/dlz_minimal.h @@ -36,7 +36,7 @@ typedef unsigned int isc_result_t; typedef int isc_boolean_t; typedef uint32_t dns_ttl_t; -#define DLZ_DLOPEN_VERSION 2 +#define DLZ_DLOPEN_VERSION 3 /* return this in flags to dlz_version() if thread safe */ #define DNS_SDLZFLAG_THREADSAFE 0x00000001U @@ -45,8 +45,10 @@ typedef uint32_t dns_ttl_t; #define ISC_R_SUCCESS 0 #define ISC_R_NOMEMORY 1 #define ISC_R_NOPERM 6 +#define ISC_R_NOSPACE 19 #define ISC_R_NOTFOUND 23 #define ISC_R_FAILURE 25 +#define ISC_R_NOTIMPLEMENTED 27 #define ISC_R_NOMORE 29 /* boolean values */ @@ -67,6 +69,7 @@ typedef uint32_t dns_ttl_t; typedef void *dns_sdlzlookup_t; typedef void *dns_sdlzallnodes_t; typedef void *dns_view_t; +typedef void *dns_dlzdb_t; /* * Method and type definitions needed for retrieval of client info @@ -120,9 +123,9 @@ typedef isc_result_t dns_sdlz_putnamedrr_t(dns_sdlzallnodes_t *allnodes, const char *data); typedef isc_result_t dns_dlz_writeablezone_t(dns_view_t *view, + dns_dlzdb_t *dlzdb, const char *zone_name); - /* * prototypes for the functions you can include in your module */ @@ -156,7 +159,9 @@ dlz_destroy(void *dbdata); * dlz_findzonedb is required for all DLZ external drivers */ 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); /* * dlz_lookup is required for all DLZ external drivers @@ -202,7 +207,7 @@ dlz_closeversion(const char *zone, isc_boolean_t commit, void *dbdata, * dynamic updates */ isc_result_t -dlz_configure(dns_view_t *view, void *dbdata); +dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *dbdata); /* * dlz_ssumatch() is optional, but must be supplied if you want to support diff --git a/lib/dns/dlz.c b/lib/dns/dlz.c index f8066baac6..bb26537195 100644 --- a/lib/dns/dlz.c +++ b/lib/dns/dlz.c @@ -273,92 +273,6 @@ dns_dlzdestroy(dns_dlzdb_t **dbp) { *dbp = NULL; } - -isc_result_t -dns_dlzfindzone(dns_view_t *view, dns_name_t *name, - unsigned int minlabels, dns_db_t **dbp) -{ - dns_fixedname_t fname; - dns_name_t *zonename; - unsigned int namelabels; - unsigned int i; - isc_result_t result; - dns_dlzfindzone_t findzone; - dns_dlzdb_t *dlzdb; - dns_db_t *db, *best = NULL; - - /* - * Performs checks to make sure data is as we expect it to be. - */ - REQUIRE(view != NULL); - REQUIRE(name != NULL); - REQUIRE(dbp != NULL && *dbp == NULL); - - /* setup a "fixed" dns name */ - dns_fixedname_init(&fname); - zonename = dns_fixedname_name(&fname); - - /* count the number of labels in the name */ - namelabels = dns_name_countlabels(name); - - for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); - dlzdb != NULL; - dlzdb = ISC_LIST_NEXT(dlzdb, link)) - { - REQUIRE(DNS_DLZ_VALID(dlzdb)); - - /* - * loop through starting with the longest domain name and - * trying shorter names portions of the name until we find a - * match, have an error, or are below the 'minlabels' - * threshold. minlabels is 0, if neither the standard - * database nor any previous DLZ database had a zone name - * match. Otherwise minlabels is the number of labels - * in that name. We need to beat that for a "better" - * match for this DLZ database to be authoritative. - */ - for (i = namelabels; i > minlabels && i > 1; i--) { - if (i == namelabels) { - result = dns_name_copy(name, zonename, NULL); - if (result != ISC_R_SUCCESS) - return (result); - } else - dns_name_split(name, i, NULL, zonename); - - /* ask SDLZ driver if the zone is supported */ - db = NULL; - findzone = dlzdb->implementation->methods->findzone; - result = (*findzone)(dlzdb->implementation->driverarg, - dlzdb->dbdata, dlzdb->mctx, - view->rdclass, zonename, &db); - - if (result != ISC_R_NOTFOUND) { - if (best != NULL) - dns_db_detach(&best); - if (result == ISC_R_SUCCESS) { - INSIST(db != NULL); - dns_db_attach(db, &best); - dns_db_detach(&db); - minlabels = i; - } else { - if (db != NULL) - dns_db_detach(&db); - break; - } - } else if (db != NULL) - dns_db_detach(&db); - } - } - - if (best != NULL) { - dns_db_attach(best, dbp); - dns_db_detach(&best); - return (ISC_R_SUCCESS); - } - - return (ISC_R_NOTFOUND); -} - /*% * Registers a DLZ driver. This basically just adds the dlz * driver to the list of available drivers in the dlz_implementations list. diff --git a/lib/dns/include/dns/dlz.h b/lib/dns/include/dns/dlz.h index 0414c27542..02e1b6ccd0 100644 --- a/lib/dns/include/dns/dlz.h +++ b/lib/dns/include/dns/dlz.h @@ -84,6 +84,7 @@ ***** Imports *****/ +#include #include #include #include @@ -140,10 +141,11 @@ typedef void typedef isc_result_t (*dns_dlzfindzone_t)(void *driverarg, void *dbdata, isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_name_t *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, dns_db_t **dbp); /*%< - * Method prototype. Drivers implementing the DLZ interface MUST * supply a find zone method. This method is called when the DNS * server is performing a query. The find zone method will be called @@ -265,15 +267,6 @@ dns_dlzdestroy(dns_dlzdb_t **dbp); * methods, this function will call it. */ -isc_result_t -dns_dlzfindzone(dns_view_t *view, dns_name_t *name, - unsigned int minlabels, dns_db_t **dbp); - -/*%< - * This method is called when the DNS server is performing a query. - * It will call the DLZ driver's find zone method. - */ - isc_result_t dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods, void *driverarg, isc_mem_t *mctx, diff --git a/lib/dns/include/dns/dlz_dlopen.h b/lib/dns/include/dns/dlz_dlopen.h index c6301457e6..6d47b2b7ff 100644 --- a/lib/dns/include/dns/dlz_dlopen.h +++ b/lib/dns/include/dns/dlz_dlopen.h @@ -30,142 +30,144 @@ ISC_LANG_BEGINDECLS * for the entry points of an external DLZ module for bind9. */ -#define DLZ_DLOPEN_VERSION 2 +#define DLZ_DLOPEN_VERSION 3 /* * dlz_dlopen_version() is required for all DLZ external drivers. It * should return DLZ_DLOPEN_VERSION */ -typedef int dlz_dlopen_version_t (unsigned int *flags); +typedef int dlz_dlopen_version_t(unsigned int *flags); /* * dlz_dlopen_create() is required for all DLZ external drivers. */ -typedef isc_result_t dlz_dlopen_create_t (const char *dlzname, - unsigned int argc, - char *argv[], - void **dbdata, - ...); +typedef isc_result_t dlz_dlopen_create_t(const char *dlzname, + unsigned int argc, + char *argv[], + void **dbdata, + ...); /* * dlz_dlopen_destroy() is optional, and will be called when the * driver is unloaded if supplied */ -typedef void dlz_dlopen_destroy_t (void *dbdata); +typedef void dlz_dlopen_destroy_t(void *dbdata); /* * dlz_dlopen_findzonedb() is required for all DLZ external drivers */ -typedef isc_result_t dlz_dlopen_findzonedb_t (void *dbdata, - const char *name); +typedef isc_result_t dlz_dlopen_findzonedb_t(void *dbdata, + const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); /* * dlz_dlopen_lookup() is required for all DLZ external drivers */ -typedef isc_result_t dlz_dlopen_lookup_t (const char *zone, - const char *name, - void *dbdata, - dns_sdlzlookup_t *lookup, - dns_clientinfomethods_t *methods, - dns_clientinfo_t *clientinfo); +typedef isc_result_t dlz_dlopen_lookup_t(const char *zone, + const char *name, + void *dbdata, + dns_sdlzlookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); /* * dlz_dlopen_authority is optional() if dlz_dlopen_lookup() * supplies authority information for the dns record */ -typedef isc_result_t dlz_dlopen_authority_t (const char *zone, - void *dbdata, - dns_sdlzlookup_t *lookup); +typedef isc_result_t dlz_dlopen_authority_t(const char *zone, + void *dbdata, + dns_sdlzlookup_t *lookup); /* * dlz_dlopen_allowzonexfr() is optional, and should be supplied if * you want to support zone transfers */ -typedef isc_result_t dlz_dlopen_allowzonexfr_t (void *dbdata, - const char *name, - const char *client); +typedef isc_result_t dlz_dlopen_allowzonexfr_t(void *dbdata, + const char *name, + const char *client); /* * dlz_dlopen_allnodes() is optional, but must be supplied if supply a * dlz_dlopen_allowzonexfr() function */ -typedef isc_result_t dlz_dlopen_allnodes_t (const char *zone, - void *dbdata, - dns_sdlzallnodes_t *allnodes); +typedef isc_result_t dlz_dlopen_allnodes_t(const char *zone, + void *dbdata, + dns_sdlzallnodes_t *allnodes); /* * dlz_dlopen_newversion() is optional. It should be supplied if you * want to support dynamic updates. */ -typedef isc_result_t dlz_dlopen_newversion_t (const char *zone, - void *dbdata, - void **versionp); +typedef isc_result_t dlz_dlopen_newversion_t(const char *zone, + void *dbdata, + void **versionp); /* * dlz_closeversion() is optional, but must be supplied if you supply * a dlz_newversion() function */ -typedef void dlz_dlopen_closeversion_t (const char *zone, - isc_boolean_t commit, - void *dbdata, - void **versionp); +typedef void dlz_dlopen_closeversion_t(const char *zone, + isc_boolean_t commit, + void *dbdata, + void **versionp); /* * dlz_dlopen_configure() is optional, but must be supplied if you * want to support dynamic updates */ -typedef isc_result_t dlz_dlopen_configure_t (dns_view_t *view, - dns_dlzdb_t *dlzdb, - void *dbdata); +typedef isc_result_t dlz_dlopen_configure_t(dns_view_t *view, + dns_dlzdb_t *dlzdb, + void *dbdata); /* * dlz_dlopen_setclientcallback() is optional, but must be supplied if you * want to retrieve information about the client (e.g., source address) * before sending a replay. */ -typedef isc_result_t dlz_dlopen_setclientcallback_t (dns_view_t *view, - void *dbdata); +typedef isc_result_t dlz_dlopen_setclientcallback_t(dns_view_t *view, + void *dbdata); /* * dlz_dlopen_ssumatch() is optional, but must be supplied if you want * to support dynamic updates */ -typedef isc_boolean_t dlz_dlopen_ssumatch_t (const char *signer, - const char *name, - const char *tcpaddr, - const char *type, - const char *key, - isc_uint32_t keydatalen, - unsigned char *keydata, - void *dbdata); +typedef isc_boolean_t dlz_dlopen_ssumatch_t(const char *signer, + const char *name, + const char *tcpaddr, + const char *type, + const char *key, + isc_uint32_t keydatalen, + unsigned char *keydata, + void *dbdata); /* * dlz_dlopen_addrdataset() is optional, but must be supplied if you * want to support dynamic updates */ -typedef isc_result_t dlz_dlopen_addrdataset_t (const char *name, - const char *rdatastr, - void *dbdata, - void *version); +typedef isc_result_t dlz_dlopen_addrdataset_t(const char *name, + const char *rdatastr, + void *dbdata, + void *version); /* * dlz_dlopen_subrdataset() is optional, but must be supplied if you * want to support dynamic updates */ -typedef isc_result_t dlz_dlopen_subrdataset_t (const char *name, - const char *rdatastr, - void *dbdata, - void *version); +typedef isc_result_t dlz_dlopen_subrdataset_t(const char *name, + const char *rdatastr, + void *dbdata, + void *version); /* * dlz_dlopen_delrdataset() is optional, but must be supplied if you * want to support dynamic updates */ -typedef isc_result_t dlz_dlopen_delrdataset_t (const char *name, - const char *type, - void *dbdata, - void *version); +typedef isc_result_t dlz_dlopen_delrdataset_t(const char *name, + const char *type, + void *dbdata, + void *version); ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/sdlz.h b/lib/dns/include/dns/sdlz.h index c6b396ab10..9108bb3482 100644 --- a/lib/dns/include/dns/sdlz.h +++ b/lib/dns/include/dns/sdlz.h @@ -152,8 +152,9 @@ typedef void (*dns_sdlzdestroy_t)(void *driverarg, void *dbdata); */ typedef isc_result_t -(*dns_sdlzfindzone_t)(void *driverarg, void *dbdata, const char *name); - +(*dns_sdlzfindzone_t)(void *driverarg, void *dbdata, const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); /*%< * Method prototype. Drivers implementing the SDLZ interface MUST * supply a find zone method. This method is called when the DNS diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 5962a75278..5865d4a7f9 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -72,6 +72,7 @@ #include #include +#include #include #include #include @@ -1136,6 +1137,29 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, void dns_view_restorekeyring(dns_view_t *view); +isc_result_t +dns_view_searchdlz(dns_view_t *view, dns_name_t *name, + unsigned int minlabels, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_db_t **dbp); + +/*%< + * Search through the DLZ database(s) in view->dlz_searched to find + * one that can answer a query for 'name', using the DLZ driver's + * findzone method. If successful, '*dbp' is set to point to the + * DLZ database. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOTFOUND + * + * Requires: + * \li 'view' is valid. + * \li 'name' is not NULL. + * \li 'dbp' is not NULL and *dbp is NULL. + */ + ISC_LANG_ENDDECLS #endif /* DNS_VIEW_H */ diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index d509364c51..c80cce1caa 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1628,7 +1628,10 @@ dns_sdlzdestroy(void *driverdata, void **dbdata) { static isc_result_t dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx, - dns_rdataclass_t rdclass, dns_name_t *name, dns_db_t **dbp) + dns_rdataclass_t rdclass, dns_name_t *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_db_t **dbp) { isc_buffer_t b; char namestr[DNS_NAME_MAXTEXT + 1]; @@ -1656,7 +1659,8 @@ dns_sdlzfindzone(void *driverarg, void *dbdata, isc_mem_t *mctx, /* Call SDLZ driver's find zone method */ MAYBE_LOCK(imp); - result = imp->methods->findzone(imp->driverarg, dbdata, namestr); + result = imp->methods->findzone(imp->driverarg, dbdata, namestr, + methods, clientinfo); MAYBE_UNLOCK(imp); /* diff --git a/lib/dns/view.c b/lib/dns/view.c index b9fd09ead4..4562c1bcbc 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1868,3 +1868,91 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, UNUSED(cfg_destroy); #endif } + +isc_result_t +dns_view_searchdlz(dns_view_t *view, dns_name_t *name, unsigned int minlabels, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_db_t **dbp) +{ + dns_fixedname_t fname; + dns_name_t *zonename; + unsigned int namelabels; + unsigned int i; + isc_result_t result; + dns_dlzfindzone_t findzone; + dns_dlzdb_t *dlzdb; + dns_db_t *db, *best = NULL; + + /* + * Performs checks to make sure data is as we expect it to be. + */ + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(name != NULL); + REQUIRE(dbp != NULL && *dbp == NULL); + + /* setup a "fixed" dns name */ + dns_fixedname_init(&fname); + zonename = dns_fixedname_name(&fname); + + /* count the number of labels in the name */ + namelabels = dns_name_countlabels(name); + + for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); + dlzdb != NULL; + dlzdb = ISC_LIST_NEXT(dlzdb, link)) + { + REQUIRE(DNS_DLZ_VALID(dlzdb)); + + /* + * loop through starting with the longest domain name and + * trying shorter names portions of the name until we find a + * match, have an error, or are below the 'minlabels' + * threshold. minlabels is 0, if neither the standard + * database nor any previous DLZ database had a zone name + * match. Otherwise minlabels is the number of labels + * in that name. We need to beat that for a "better" + * match for this DLZ database to be authoritative. + */ + for (i = namelabels; i > minlabels && i > 1; i--) { + if (i == namelabels) { + result = dns_name_copy(name, zonename, NULL); + if (result != ISC_R_SUCCESS) + return (result); + } else + dns_name_split(name, i, NULL, zonename); + + /* ask SDLZ driver if the zone is supported */ + db = NULL; + findzone = dlzdb->implementation->methods->findzone; + result = (*findzone)(dlzdb->implementation->driverarg, + dlzdb->dbdata, dlzdb->mctx, + view->rdclass, zonename, + methods, clientinfo, &db); + + if (result != ISC_R_NOTFOUND) { + if (best != NULL) + dns_db_detach(&best); + if (result == ISC_R_SUCCESS) { + INSIST(db != NULL); + dns_db_attach(db, &best); + dns_db_detach(&db); + minlabels = i; + } else { + if (db != NULL) + dns_db_detach(&db); + break; + } + } else if (db != NULL) + dns_db_detach(&db); + } + } + + if (best != NULL) { + dns_db_attach(best, dbp); + dns_db_detach(&best); + return (ISC_R_SUCCESS); + } + + return (ISC_R_NOTFOUND); +} diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 4895e01202..eec36f7615 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -203,7 +203,6 @@ dns_dlzallowzonexfr dns_dlzconfigure dns_dlzcreate dns_dlzdestroy -dns_dlzfindzone dns_dlzregister dns_dlzstrtoargv dns_dlzunregister @@ -774,6 +773,7 @@ dns_view_issecuredomain dns_view_load dns_view_loadnew dns_view_restorekeyring +dns_view_searchdlz dns_view_setcache dns_view_setcache2 dns_view_setdstport diff --git a/lib/dns/zone.c b/lib/dns/zone.c index a28043a2d8..a1a5d1b5ad 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -1670,7 +1670,8 @@ zone_load(dns_zone_t *zone, unsigned int flags) { findzone = dlzdb->implementation->methods->findzone; result = (*findzone)(dlzdb->implementation->driverarg, dlzdb->dbdata, dlzdb->mctx, - zone->view->rdclass, &zone->origin, &db); + zone->view->rdclass, &zone->origin, + NULL, NULL, &db); if (result != ISC_R_NOTFOUND) { if (zone->db != NULL) zone_detachdb(zone);