From cbd1fa092ea66bfa9990c5e515725646295396c5 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 22 Jan 2013 15:13:08 -0800 Subject: [PATCH] [master] DLZ fixes - handle malformed answers from DLZ better: - handle dlz_lookup errors better: when the first lookup of a name returns an unexpected failure code, we return it to the caller rather than continuing on to look up the wildcard. we now only continue processing if the return from the first lookup was either ISC_R_SUCCESS or ISC_R_NOTFOUND. - improved backward-compatibility for dlz_version: added a DLZ_DLOPEN_AGE value indicating how many versions back from the current DLZ_DLOPEN_VERSION named will support --- bin/named/unix/dlz_dlopen_driver.c | 10 ++++++---- bin/named/win32/dlz_dlopen_driver.c | 10 ++++++---- bin/tests/system/dlzexternal/driver.c | 17 +++++++++++++++-- bin/tests/system/dlzexternal/tests.sh | 7 +++++++ contrib/dlz/example/dlz_example.c | 17 +++++++++++++++-- contrib/dlz/example/dlz_minimal.h | 1 + lib/dns/include/dns/dlz_dlopen.h | 1 + lib/dns/sdlz.c | 7 ++++--- 8 files changed, 55 insertions(+), 15 deletions(-) diff --git a/bin/named/unix/dlz_dlopen_driver.c b/bin/named/unix/dlz_dlopen_driver.c index fc5ab8669f..552f698332 100644 --- a/bin/named/unix/dlz_dlopen_driver.c +++ b/bin/named/unix/dlz_dlopen_driver.c @@ -326,11 +326,13 @@ dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[], /* Check the version of the API is the same */ cd->version = cd->dlz_version(&cd->flags); - if (cd->version != DLZ_DLOPEN_VERSION) { + if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) || + cd->version > DLZ_DLOPEN_VERSION) + { dlopen_log(ISC_LOG_ERROR, - "dlz_dlopen: incorrect version %d " - "should be %d in '%s'", - cd->version, DLZ_DLOPEN_VERSION, cd->dl_path); + "dlz_dlopen: %s: incorrect driver API version %d, " + "requires %d", + cd->dl_path, cd->version, DLZ_DLOPEN_VERSION); goto failed; } diff --git a/bin/named/win32/dlz_dlopen_driver.c b/bin/named/win32/dlz_dlopen_driver.c index 6c9ecb8116..a73c65f574 100644 --- a/bin/named/win32/dlz_dlopen_driver.c +++ b/bin/named/win32/dlz_dlopen_driver.c @@ -310,11 +310,13 @@ dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[], /* Check the version of the API is the same */ cd->version = cd->dlz_version(&cd->flags); - if (cd->version != DLZ_DLOPEN_VERSION) { + if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) || + cd->version > DLZ_DLOPEN_VERSION) + { dlopen_log(ISC_LOG_ERROR, - "dlz_dlopen: incorrect version %d " - "should be %d in '%s'", - cd->version, DLZ_DLOPEN_VERSION, cd->dl_path); + "dlz_dlopen: %s: incorrect driver API version %d, " + "requires %d", + cd->dl_path, cd->version, DLZ_DLOPEN_VERSION); goto failed; } diff --git a/bin/tests/system/dlzexternal/driver.c b/bin/tests/system/dlzexternal/driver.c index ee208d8c76..765f32fad1 100644 --- a/bin/tests/system/dlzexternal/driver.c +++ b/bin/tests/system/dlzexternal/driver.c @@ -368,8 +368,11 @@ dlz_findzonedb(void *dbdata, const char *name, /* * Look up one record in the sample database. * - * If the queryname is "source-addr", we add a TXT record containing + * If the queryname is "source-addr", send back a TXT record containing * the address of the client, to test the use of 'methods' and 'clientinfo' + * + * If the queryname is "too-long", send back a TXT record that's too long + * to process; this should result in a SERVFAIL when queried. */ isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata, @@ -381,6 +384,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, isc_boolean_t found = ISC_FALSE; isc_sockaddr_t *src; char full_name[256]; + char buf[512]; int i; UNUSED(zone); @@ -395,7 +399,6 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, 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 && @@ -415,6 +418,16 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, return (result); } + if (strcmp(name, "too-long") == 0) { + for (i = 0; i < 511; i++) + buf[i] = 'x'; + buf[i] = '\0'; + found = ISC_TRUE; + result = state->putrr(lookup, "TXT", 0, buf); + if (result != ISC_R_SUCCESS) + return (result); + } + for (i = 0; i < MAX_RECORDS; i++) { if (strcasecmp(state->current[i].name, full_name) == 0) { found = ISC_TRUE; diff --git a/bin/tests/system/dlzexternal/tests.sh b/bin/tests/system/dlzexternal/tests.sh index 34311128eb..c8beb537ff 100644 --- a/bin/tests/system/dlzexternal/tests.sh +++ b/bin/tests/system/dlzexternal/tests.sh @@ -136,4 +136,11 @@ lines=`grep "dlz_findzonedb.*example\.net.*alternate.nil" ns1/named.run | wc -l` [ "$ret" -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +ret=0 +echo "I:testing zone returning oversized data" +$DIG $DIGOPTS txt too-long.example.nil > dig.out.ns1.6 2>&1 || ret=1 +grep "status: SERVFAIL" dig.out.ns1.6 > /dev/null || ret=1 +[ "$ret" -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + exit $status diff --git a/contrib/dlz/example/dlz_example.c b/contrib/dlz/example/dlz_example.c index 0212f884f3..0f381ba5c9 100644 --- a/contrib/dlz/example/dlz_example.c +++ b/contrib/dlz/example/dlz_example.c @@ -357,9 +357,12 @@ dlz_findzonedb(void *dbdata, const char *name, /* * Look up one record in the sample database. * - * If the queryname is "source-addr", we add a TXT record containing + * If the queryname is "source-addr", send back a TXT record containing * the address of the client; this demonstrates the use of 'methods' * and 'clientinfo'. + * + * If the queryname is "too-long", send back a TXT record that's too long + * to process; this should result in a SERVFAIL when queried. */ isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata, @@ -371,6 +374,7 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, isc_boolean_t found = ISC_FALSE; isc_sockaddr_t *src; char full_name[256]; + char buf[512]; int i; UNUSED(zone); @@ -385,7 +389,6 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, 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 && @@ -406,6 +409,16 @@ dlz_lookup(const char *zone, const char *name, void *dbdata, return (result); } + if (strcmp(name, "too-long") == 0) { + for (i = 0; i < 511; i++) + buf[i] = 'x'; + buf[i] = '\0'; + found = ISC_TRUE; + result = state->putrr(lookup, "TXT", 0, buf); + if (result != ISC_R_SUCCESS) + return (result); + } + for (i = 0; i < MAX_RECORDS; i++) { if (strcasecmp(state->current[i].name, full_name) == 0) { found = ISC_TRUE; diff --git a/contrib/dlz/example/dlz_minimal.h b/contrib/dlz/example/dlz_minimal.h index 3972094ad8..50eb99eff5 100644 --- a/contrib/dlz/example/dlz_minimal.h +++ b/contrib/dlz/example/dlz_minimal.h @@ -37,6 +37,7 @@ typedef int isc_boolean_t; typedef uint32_t dns_ttl_t; #define DLZ_DLOPEN_VERSION 3 +#define DLZ_DLOPEN_AGE 0 /* return this in flags to dlz_version() if thread safe */ #define DNS_SDLZFLAG_THREADSAFE 0x00000001U diff --git a/lib/dns/include/dns/dlz_dlopen.h b/lib/dns/include/dns/dlz_dlopen.h index 6d47b2b7ff..738b5e921a 100644 --- a/lib/dns/include/dns/dlz_dlopen.h +++ b/lib/dns/include/dns/dlz_dlopen.h @@ -31,6 +31,7 @@ ISC_LANG_BEGINDECLS */ #define DLZ_DLOPEN_VERSION 3 +#define DLZ_DLOPEN_AGE 0 /* * dlz_dlopen_version() is required for all DLZ external drivers. It diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 7ff4ee7264..db129d062e 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -605,7 +605,7 @@ findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create, * if the host (namestr) was not found, try to lookup a * "wildcard" host. */ - if (result != ISC_R_SUCCESS && !create) + if (result == ISC_R_NOTFOUND && !create) result = sdlz->dlzimp->methods->lookup(zonestr, "*", sdlz->dlzimp->driverarg, sdlz->dbdata, node, @@ -878,10 +878,11 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_name_getlabelsequence(name, nlabels - i, i, xname); result = findnodeext(db, xname, ISC_FALSE, methods, clientinfo, &node); - if (result != ISC_R_SUCCESS) { + if (result == ISC_R_NOTFOUND) { result = DNS_R_NXDOMAIN; continue; - } + } else if (result != ISC_R_SUCCESS) + break; /* * Look for a DNAME at the current label, unless this is