mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 06:55:30 +00:00
When handling the response to an ANY query in a secure zone, deal with
the multiple answer RRsets by validating each one separately. Also, eliminated the "done" variable in answer_response() because in the rare situations where it got set to ISC_TRUE, it caused the function to return prematurely by exiting a loop with a result of ISC_R_SUCCESS and hitting a "if (result != ISC_R_NOMORE) return (result);" test immediately following following the loop. This should fix [RT #109], "ANY query in secure zone crashes server".
This commit is contained in:
@@ -15,7 +15,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: resolver.c,v 1.149 2000/07/16 18:26:18 gson Exp $ */
|
/* $Id: resolver.c,v 1.150 2000/07/19 23:19:05 gson Exp $ */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
@@ -170,7 +170,6 @@ struct fetchctx {
|
|||||||
dns_adbaddrinfolist_t forwaddrs;
|
dns_adbaddrinfolist_t forwaddrs;
|
||||||
isc_sockaddrlist_t forwarders;
|
isc_sockaddrlist_t forwarders;
|
||||||
isc_sockaddrlist_t bad;
|
isc_sockaddrlist_t bad;
|
||||||
dns_validator_t * validator;
|
|
||||||
/*
|
/*
|
||||||
* # of events we're waiting for.
|
* # of events we're waiting for.
|
||||||
*/
|
*/
|
||||||
@@ -678,7 +677,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
|
|||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
return (result);
|
return (result);
|
||||||
|
|
||||||
INSIST(fctx->validator == NULL); /* Validator needs rmessage. */
|
|
||||||
dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
|
dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
|
||||||
|
|
||||||
query = isc_mem_get(res->mctx, sizeof *query);
|
query = isc_mem_get(res->mctx, sizeof *query);
|
||||||
@@ -1693,7 +1691,6 @@ fctx_destroy(fetchctx_t *fctx) {
|
|||||||
REQUIRE(fctx->pending == 0);
|
REQUIRE(fctx->pending == 0);
|
||||||
REQUIRE(fctx->validating == 0);
|
REQUIRE(fctx->validating == 0);
|
||||||
REQUIRE(fctx->references == 0);
|
REQUIRE(fctx->references == 0);
|
||||||
REQUIRE(fctx->validator == NULL);
|
|
||||||
|
|
||||||
FCTXTRACE("destroy");
|
FCTXTRACE("destroy");
|
||||||
|
|
||||||
@@ -2049,7 +2046,6 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
|
|||||||
ISC_LIST_INIT(fctx->forwaddrs);
|
ISC_LIST_INIT(fctx->forwaddrs);
|
||||||
ISC_LIST_INIT(fctx->forwarders);
|
ISC_LIST_INIT(fctx->forwarders);
|
||||||
ISC_LIST_INIT(fctx->bad);
|
ISC_LIST_INIT(fctx->bad);
|
||||||
fctx->validator = NULL;
|
|
||||||
fctx->find = NULL;
|
fctx->find = NULL;
|
||||||
fctx->pending = 0;
|
fctx->pending = 0;
|
||||||
fctx->validating = 0;
|
fctx->validating = 0;
|
||||||
@@ -2270,6 +2266,7 @@ validated(isc_task_t *task, isc_event_t *event) {
|
|||||||
dns_rdataset_t *ardataset = NULL;
|
dns_rdataset_t *ardataset = NULL;
|
||||||
dns_rdataset_t *asigrdataset = NULL;
|
dns_rdataset_t *asigrdataset = NULL;
|
||||||
dns_dbnode_t *node = NULL;
|
dns_dbnode_t *node = NULL;
|
||||||
|
isc_boolean_t negative;
|
||||||
|
|
||||||
UNUSED(task); /* for now */
|
UNUSED(task); /* for now */
|
||||||
|
|
||||||
@@ -2279,17 +2276,18 @@ validated(isc_task_t *task, isc_event_t *event) {
|
|||||||
REQUIRE(fctx->validating > 0);
|
REQUIRE(fctx->validating > 0);
|
||||||
|
|
||||||
vevent = (dns_validatorevent_t *)event;
|
vevent = (dns_validatorevent_t *)event;
|
||||||
INSIST(vevent->validator == fctx->validator);
|
|
||||||
|
|
||||||
fctx->validating--;
|
FCTXTRACE("received validation completion event");
|
||||||
|
|
||||||
INSIST(fctx->validating == 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy the validator early so that we can
|
* Destroy the validator early so that we can
|
||||||
* destroy the fctx if necessary.
|
* destroy the fctx if necessary.
|
||||||
*/
|
*/
|
||||||
dns_validator_destroy(&fctx->validator);
|
dns_validator_destroy(&vevent->validator);
|
||||||
|
|
||||||
|
fctx->validating--;
|
||||||
|
|
||||||
|
negative = ISC_TF(vevent->rdataset == NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If shutting down, ignore the results. Check to see if we're
|
* If shutting down, ignore the results. Check to see if we're
|
||||||
@@ -2304,13 +2302,21 @@ validated(isc_task_t *task, isc_event_t *event) {
|
|||||||
/*
|
/*
|
||||||
* We're not shutting down.
|
* We're not shutting down.
|
||||||
*/
|
*/
|
||||||
FCTXTRACE("received validation completion event");
|
|
||||||
|
|
||||||
hevent = ISC_LIST_HEAD(fctx->events);
|
hevent = ISC_LIST_HEAD(fctx->events);
|
||||||
if (hevent != NULL) {
|
if (hevent != NULL) {
|
||||||
|
if (!negative &&
|
||||||
|
(fctx->type == dns_rdatatype_any ||
|
||||||
|
fctx->type == dns_rdatatype_sig)) {
|
||||||
|
/*
|
||||||
|
* Don't bind rdatasets; the caller
|
||||||
|
* will iterate the node.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
ardataset = hevent->rdataset;
|
ardataset = hevent->rdataset;
|
||||||
asigrdataset = hevent->sigrdataset;
|
asigrdataset = hevent->sigrdataset;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (vevent->result != ISC_R_SUCCESS) {
|
if (vevent->result != ISC_R_SUCCESS) {
|
||||||
FCTXTRACE("validation failed");
|
FCTXTRACE("validation failed");
|
||||||
@@ -2320,7 +2326,7 @@ validated(isc_task_t *task, isc_event_t *event) {
|
|||||||
|
|
||||||
isc_stdtime_get(&now);
|
isc_stdtime_get(&now);
|
||||||
|
|
||||||
if (vevent->rdataset == NULL) {
|
if (negative) {
|
||||||
dns_rdatatype_t covers;
|
dns_rdatatype_t covers;
|
||||||
FCTXTRACE("nonexistence validation OK");
|
FCTXTRACE("nonexistence validation OK");
|
||||||
|
|
||||||
@@ -2375,6 +2381,18 @@ validated(isc_task_t *task, isc_event_t *event) {
|
|||||||
goto noanswer_response;
|
goto noanswer_response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fctx->validating > 0) {
|
||||||
|
INSIST(!negative);
|
||||||
|
INSIST(fctx->type == dns_rdatatype_any ||
|
||||||
|
fctx->type == dns_rdatatype_sig);
|
||||||
|
/*
|
||||||
|
* Don't send a response yet - we have
|
||||||
|
* more rdatasets that still need to
|
||||||
|
* be validated.
|
||||||
|
*/
|
||||||
|
goto cleanup_event;
|
||||||
|
}
|
||||||
|
|
||||||
result = ISC_R_SUCCESS;
|
result = ISC_R_SUCCESS;
|
||||||
|
|
||||||
answer_response:
|
answer_response:
|
||||||
@@ -2419,6 +2437,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
dns_fetchevent_t *event;
|
dns_fetchevent_t *event;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
isc_task_t *task;
|
isc_task_t *task;
|
||||||
|
dns_validator_t *validator;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The appropriate bucket lock must be held.
|
* The appropriate bucket lock must be held.
|
||||||
@@ -2428,6 +2447,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
need_validation = ISC_FALSE;
|
need_validation = ISC_FALSE;
|
||||||
have_answer = ISC_FALSE;
|
have_answer = ISC_FALSE;
|
||||||
eresult = ISC_R_SUCCESS;
|
eresult = ISC_R_SUCCESS;
|
||||||
|
task = res->buckets[fctx->bucketnum].task;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is DNSSEC validation required for this name?
|
* Is DNSSEC validation required for this name?
|
||||||
@@ -2550,8 +2570,10 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ANSWER(rdataset)) {
|
if (ANSWER(rdataset)) {
|
||||||
|
if (fctx->type != dns_rdatatype_any &&
|
||||||
|
fctx->type != dns_rdatatype_sig) {
|
||||||
/*
|
/*
|
||||||
* This is the answer. We will
|
* This is The Answer. We will
|
||||||
* validate it, but first we cache
|
* validate it, but first we cache
|
||||||
* the rest of the response - it may
|
* the rest of the response - it may
|
||||||
* contain useful keys.
|
* contain useful keys.
|
||||||
@@ -2560,6 +2582,33 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
valsigrdataset == NULL);
|
valsigrdataset == NULL);
|
||||||
valrdataset = rdataset;
|
valrdataset = rdataset;
|
||||||
valsigrdataset = sigrdataset;
|
valsigrdataset = sigrdataset;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* This is one of (potentially)
|
||||||
|
* multiple answers to an ANY
|
||||||
|
* or SIG query. To keep things
|
||||||
|
* simple, we just start the
|
||||||
|
* validator right away rather
|
||||||
|
* than caching first and
|
||||||
|
* having to remember which
|
||||||
|
* rdatasets needed validation.
|
||||||
|
*/
|
||||||
|
validator = NULL;
|
||||||
|
result = dns_validator_create(
|
||||||
|
res->view,
|
||||||
|
name,
|
||||||
|
rdataset->type,
|
||||||
|
rdataset,
|
||||||
|
sigrdataset,
|
||||||
|
fctx->rmessage,
|
||||||
|
0,
|
||||||
|
task,
|
||||||
|
validated,
|
||||||
|
fctx,
|
||||||
|
&validator);
|
||||||
|
if (result == ISC_R_SUCCESS)
|
||||||
|
fctx->validating++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!EXTERNAL(rdataset)) {
|
} else if (!EXTERNAL(rdataset)) {
|
||||||
/*
|
/*
|
||||||
@@ -2624,7 +2673,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (valrdataset != NULL) {
|
if (valrdataset != NULL) {
|
||||||
task = res->buckets[fctx->bucketnum].task;
|
validator = NULL;
|
||||||
result = dns_validator_create(res->view,
|
result = dns_validator_create(res->view,
|
||||||
name,
|
name,
|
||||||
fctx->type,
|
fctx->type,
|
||||||
@@ -2635,12 +2684,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
|
|||||||
task,
|
task,
|
||||||
validated,
|
validated,
|
||||||
fctx,
|
fctx,
|
||||||
&fctx->validator);
|
&validator);
|
||||||
if (result == ISC_R_SUCCESS)
|
if (result == ISC_R_SUCCESS)
|
||||||
fctx->validating++;
|
fctx->validating++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (result == ISC_R_SUCCESS && have_answer) {
|
if (result == ISC_R_SUCCESS && have_answer) {
|
||||||
fctx->attributes |= FCTX_ATTR_HAVEANSWER;
|
fctx->attributes |= FCTX_ATTR_HAVEANSWER;
|
||||||
if (event != NULL) {
|
if (event != NULL) {
|
||||||
@@ -2778,12 +2826,13 @@ ncache_message(fetchctx_t *fctx, dns_rdatatype_t covers, isc_stdtime_t now) {
|
|||||||
/*
|
/*
|
||||||
* Do negative response validation.
|
* Do negative response validation.
|
||||||
*/
|
*/
|
||||||
|
dns_validator_t *validator = NULL;
|
||||||
isc_task_t *task = res->buckets[fctx->bucketnum].task;
|
isc_task_t *task = res->buckets[fctx->bucketnum].task;
|
||||||
result = dns_validator_create(res->view, name, fctx->type,
|
result = dns_validator_create(res->view, name, fctx->type,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
fctx->rmessage, 0, task,
|
fctx->rmessage, 0, task,
|
||||||
validated, fctx,
|
validated, fctx,
|
||||||
&fctx->validator);
|
&validator);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
return (result);
|
return (result);
|
||||||
fctx->validating++;
|
fctx->validating++;
|
||||||
@@ -3227,7 +3276,6 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
* part of the answer and should be cached.
|
* part of the answer and should be cached.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
done = ISC_FALSE;
|
|
||||||
chaining = ISC_FALSE;
|
chaining = ISC_FALSE;
|
||||||
have_answer = ISC_FALSE;
|
have_answer = ISC_FALSE;
|
||||||
want_chaining = ISC_FALSE;
|
want_chaining = ISC_FALSE;
|
||||||
@@ -3238,7 +3286,7 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
qname = &fctx->name;
|
qname = &fctx->name;
|
||||||
type = fctx->type;
|
type = fctx->type;
|
||||||
result = dns_message_firstname(message, DNS_SECTION_ANSWER);
|
result = dns_message_firstname(message, DNS_SECTION_ANSWER);
|
||||||
while (!done && result == ISC_R_SUCCESS) {
|
while (result == ISC_R_SUCCESS) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
|
dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
|
||||||
external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
|
external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
|
||||||
@@ -3255,7 +3303,6 @@ answer_response(fetchctx_t *fctx) {
|
|||||||
* We've found an ordinary answer.
|
* We've found an ordinary answer.
|
||||||
*/
|
*/
|
||||||
found = ISC_TRUE;
|
found = ISC_TRUE;
|
||||||
done = ISC_TRUE;
|
|
||||||
aflag = DNS_RDATASETATTR_ANSWER;
|
aflag = DNS_RDATASETATTR_ANSWER;
|
||||||
} else if (rdataset->type == dns_rdatatype_sig
|
} else if (rdataset->type == dns_rdatatype_sig
|
||||||
&& rdataset->covers == type) {
|
&& rdataset->covers == type) {
|
||||||
|
Reference in New Issue
Block a user