2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

2740. [func] Identify bad answers from GTLD servers and treat them

as referrals. [RT #18884]
This commit is contained in:
Mark Andrews 2009-10-27 23:05:53 +00:00
parent 95f2377b4f
commit e9d45c0a04
2 changed files with 105 additions and 31 deletions

View File

@ -1,3 +1,6 @@
2740. [func] Identify bad answers from GTLD servers and treat them
as referrals. [RT #18884]
2739. [cleanup] Clean up API for initializing and clearing trust 2739. [cleanup] Clean up API for initializing and clearing trust
anchors for a view. [RT #20211] anchors for a view. [RT #20211]

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: resolver.c,v 1.406 2009/10/27 22:46:13 each Exp $ */ /* $Id: resolver.c,v 1.407 2009/10/27 23:05:53 marka Exp $ */
/*! \file */ /*! \file */
@ -4819,7 +4819,9 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
} }
static isc_result_t static isc_result_t
check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type,
dns_section_t section)
{
fetchctx_t *fctx = arg; fetchctx_t *fctx = arg;
isc_result_t result; isc_result_t result;
dns_name_t *name; dns_name_t *name;
@ -4830,15 +4832,19 @@ check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
REQUIRE(VALID_FCTX(fctx)); REQUIRE(VALID_FCTX(fctx));
#if CHECK_FOR_GLUE_IN_ANSWER
if (section == DNS_SECTION_ANSWER && type != dns_rdatatype_a)
return (ISC_R_SUCCESS);
#endif
if (GLUING(fctx)) if (GLUING(fctx))
gluing = ISC_TRUE; gluing = ISC_TRUE;
else else
gluing = ISC_FALSE; gluing = ISC_FALSE;
name = NULL; name = NULL;
rdataset = NULL; rdataset = NULL;
result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL, result = dns_message_findname(fctx->rmessage, section, addname,
addname, dns_rdatatype_any, 0, &name, dns_rdatatype_any, 0, &name, NULL);
NULL);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
if (type == dns_rdatatype_a) { if (type == dns_rdatatype_a) {
@ -4876,6 +4882,21 @@ check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
static isc_result_t
check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
return (check_section(arg, addname, type, DNS_SECTION_ADDITIONAL));
}
#ifndef CHECK_FOR_GLUE_IN_ANSWER
#define CHECK_FOR_GLUE_IN_ANSWER 0
#endif
#if CHECK_FOR_GLUE_IN_ANSWER
static isc_result_t
check_answer(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
return (check_section(arg, addname, type, DNS_SECTION_ANSWER));
}
#endif
static void static void
chase_additional(fetchctx_t *fctx) { chase_additional(fetchctx_t *fctx) {
isc_boolean_t rescan; isc_boolean_t rescan;
@ -5103,14 +5124,13 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
/* /*
* Handle a no-answer response (NXDOMAIN, NXRRSET, or referral). * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
* If bind8_ns_resp is ISC_TRUE, this is a suspected BIND 8 * If look_in_answer is ISC_TRUE then we look in the answer section
* response to an NS query that should be treated as a referral * for the NS RRset if the query type is NS or look for glue incorrectly
* even though the NS records occur in the answer section * returned in the answer section for A and AAAA queries.
* rather than the authority section.
*/ */
static isc_result_t static isc_result_t
noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
isc_boolean_t bind8_ns_resp) isc_boolean_t look_in_answer)
{ {
isc_result_t result; isc_result_t result;
dns_message_t *message; dns_message_t *message;
@ -5118,11 +5138,15 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
dns_rdataset_t *rdataset, *ns_rdataset; dns_rdataset_t *rdataset, *ns_rdataset;
isc_boolean_t aa, negative_response; isc_boolean_t aa, negative_response;
dns_rdatatype_t type; dns_rdatatype_t type;
dns_section_t section = dns_section_t section;
bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
FCTXTRACE("noanswer_response"); FCTXTRACE("noanswer_response");
if (fctx->type == dns_rdatatype_ns && look_in_answer)
section = DNS_SECTION_ANSWER;
else
section = DNS_SECTION_AUTHORITY;
message = fctx->rmessage; message = fctx->rmessage;
/* /*
@ -5403,6 +5427,20 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
fctx->attributes |= FCTX_ATTR_GLUING; fctx->attributes |= FCTX_ATTR_GLUING;
(void)dns_rdataset_additionaldata(ns_rdataset, check_related, (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
fctx); fctx);
#if CHECK_FOR_GLUE_IN_ANSWER
/*
* Look in the answer section for "glue" that is incorrectly
* returned as a answer. This is needed if the server also
* minimizes the response size by not adding records to the
* additional section that are in the answer section or if
* the record gets dropped due to message size constraints.
*/
if (look_in_answer &&
(fctx->type == dns_rdatatype_aaaa ||
fctx->type == dns_rdatatype_a))
(void)dns_rdataset_additionaldata(ns_rdataset,
check_answer, fctx);
#endif
fctx->attributes &= ~FCTX_ATTR_GLUING; fctx->attributes &= ~FCTX_ATTR_GLUING;
/* /*
* NS rdatasets with 0 TTL cause problems. * NS rdatasets with 0 TTL cause problems.
@ -6137,6 +6175,16 @@ log_packet(dns_message_t *message, int level, isc_mem_t *mctx) {
isc_mem_put(mctx, buf, len); isc_mem_put(mctx, buf, len);
} }
static isc_boolean_t
iscname(fetchctx_t *fctx) {
isc_result_t result;
result = dns_message_findname(fctx->rmessage, DNS_SECTION_ANSWER,
&fctx->name, dns_rdatatype_cname, 0,
NULL, NULL);
return (result == ISC_R_SUCCESS ? ISC_TRUE : ISC_FALSE);
}
static void static void
resquery_response(isc_task_t *task, isc_event_t *event) { resquery_response(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
@ -6576,27 +6624,51 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
(message->rcode == dns_rcode_noerror || (message->rcode == dns_rcode_noerror ||
message->rcode == dns_rcode_nxdomain)) { message->rcode == dns_rcode_nxdomain)) {
/* /*
* We've got answers. However, if we sent * [normal case]
* a BIND 8 server an NS query, it may have * We've got answers. If it has an authoritative answer or an
* incorrectly responded with a non-authoritative * answer from a forwarder, we're done.
* answer instead of a referral. Since this
* answer lacks the SIGs necessary to do DNSSEC
* validation, we must invoke the following special
* kludge to treat it as a referral.
*/ */
if (fctx->type == dns_rdatatype_ns && if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 ||
(message->flags & DNS_MESSAGEFLAG_AA) == 0 && ISFORWARDER(query->addrinfo))
!ISFORWARDER(query->addrinfo)) result = answer_response(fctx);
{ else if (iscname(fctx) &&
result = noanswer_response(fctx, NULL, ISC_TRUE); fctx->type != dns_rdatatype_any &&
fctx->type != dns_rdatatype_cname) {
/*
* A BIND8 server could return a non-authoritative
* answer when a CNAME is followed. We should treat
* it as a valid answer.
*/
result = answer_response(fctx);
} else {
if (fctx->type == dns_rdatatype_ns) {
/*
* A BIND 8 server could incorrectly return a
* non-authoritative answer to an NS query
* instead of a referral. Since this answer
* lacks the SIGs necessary to do DNSSEC
* validation, we must invoke the following
* special kludge to treat it as a referral.
*/
result = noanswer_response(fctx, NULL,
ISC_TRUE);
} else {
/*
* Some other servers may still somehow include
* an answer when it should return a referral
* with an empty answer. Check to see if we can
* treat this as a referral by ignoring the
* answer.
*/
result = noanswer_response(fctx, NULL,
ISC_TRUE);
}
if (result != DNS_R_DELEGATION) { if (result != DNS_R_DELEGATION) {
/* /*
* The answer section must have contained * At this point, AA is not set, the response
* something other than the NS records * is not a referral, and the server is not a
* we asked for. Since AA is not set * forwarder. It is technically lame and it's
* and the server is not a forwarder, * easier to treat it as such than to figure out
* it is technically lame and it's easier
* to treat it as such than to figure out
* some more elaborate course of action. * some more elaborate course of action.
*/ */
broken_server = DNS_R_LAME; broken_server = DNS_R_LAME;
@ -6605,7 +6677,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
} }
goto force_referral; goto force_referral;
} }
result = answer_response(fctx);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
if (result == DNS_R_FORMERR) if (result == DNS_R_FORMERR)
keep_trying = ISC_TRUE; keep_trying = ISC_TRUE;