You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1126 lines
35 KiB
1126 lines
35 KiB
From 93aec4d3d80a0d1cdb6553f70f35a2e2cb1fbaa8 Mon Sep 17 00:00:00 2001 |
|
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com> |
|
Date: Tue, 11 Apr 2017 16:19:51 +0200 |
|
Subject: [PATCH 2/3] 4578. [security] Some chaining (CNAME or DNAME) |
|
responses to upstream queries could trigger assertion |
|
failures. (CVE-2017-3137) [RT #44734] |
|
|
|
(including part of commit fea8a9d) |
|
--- |
|
bin/tests/system/dname/ans3/ans.pl | 16 +- |
|
bin/tests/system/dname/ns1/root.db | 2 +- |
|
bin/tests/system/dname/ns2/example.db | 3 +- |
|
bin/tests/system/dname/tests.sh | 17 +- |
|
lib/dns/name.c | 2 - |
|
lib/dns/resolver.c | 850 +++++++++++++--------------------- |
|
6 files changed, 349 insertions(+), 541 deletions(-) |
|
|
|
diff --git a/bin/tests/system/dname/ans3/ans.pl b/bin/tests/system/dname/ans3/ans.pl |
|
index 271fc7d..af338fe 100644 |
|
--- a/bin/tests/system/dname/ans3/ans.pl |
|
+++ b/bin/tests/system/dname/ans3/ans.pl |
|
@@ -1,10 +1,18 @@ |
|
#!/usr/bin/env perl |
|
# |
|
-# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") |
|
+# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") |
|
# |
|
-# This Source Code Form is subject to the terms of the Mozilla Public |
|
-# License, v. 2.0. If a copy of the MPL was not distributed with this |
|
-# file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
+# Permission to use, copy, modify, and/or distribute this software for any |
|
+# purpose with or without fee is hereby granted, provided that the above |
|
+# copyright notice and this permission notice appear in all copies. |
|
+# |
|
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
|
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
|
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
|
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
+# PERFORMANCE OF THIS SOFTWARE. |
|
|
|
use strict; |
|
use warnings; |
|
diff --git a/bin/tests/system/dname/ns1/root.db b/bin/tests/system/dname/ns1/root.db |
|
index 2e84ae0..3d55ace 100644 |
|
--- a/bin/tests/system/dname/ns1/root.db |
|
+++ b/bin/tests/system/dname/ns1/root.db |
|
@@ -1,4 +1,4 @@ |
|
-; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") |
|
+; Copyright (C) 2011, 2017 Internet Systems Consortium, Inc. ("ISC") |
|
; |
|
; Permission to use, copy, modify, and/or distribute this software for any |
|
; purpose with or without fee is hereby granted, provided that the above |
|
diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db |
|
index 4289134..c0193de 100644 |
|
--- a/bin/tests/system/dname/ns2/example.db |
|
+++ b/bin/tests/system/dname/ns2/example.db |
|
@@ -1,4 +1,4 @@ |
|
-; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") |
|
+; Copyright (C) 2011, 2017 Internet Systems Consortium, Inc. ("ISC") |
|
; |
|
; Permission to use, copy, modify, and/or distribute this software for any |
|
; purpose with or without fee is hereby granted, provided that the above |
|
@@ -29,6 +29,7 @@ a.short A 10.0.0.1 |
|
short-dname DNAME short |
|
a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 |
|
long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong |
|
+toolong-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong |
|
cname CNAME a.cnamedname |
|
cnamedname DNAME target |
|
a.target A 10.0.0.3 |
|
diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh |
|
index 6dc9e88..1487bd9 100644 |
|
--- a/bin/tests/system/dname/tests.sh |
|
+++ b/bin/tests/system/dname/tests.sh |
|
@@ -1,6 +1,6 @@ |
|
#!/bin/sh |
|
# |
|
-# Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") |
|
+# Copyright (C) 2011, 2012, 2017 Internet Systems Consortium, Inc. ("ISC") |
|
# |
|
# Permission to use, copy, modify, and/or distribute this software for any |
|
# purpose with or without fee is hereby granted, provided that the above |
|
@@ -57,10 +57,19 @@ grep "status: YXDOMAIN" dig.out.ns2.toolong > /dev/null || ret=1 |
|
if [ $ret != 0 ]; then echo "I:failed"; fi |
|
status=`expr $status + $ret` |
|
|
|
-echo "I:checking (too) long dname from recursive" |
|
+echo "I:checking (too) long dname from recursive with cached DNAME" |
|
ret=0 |
|
-$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.toolong || ret=1 |
|
-grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 |
|
+$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cachedtoolong || ret=1 |
|
+grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1 |
|
+grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1 |
|
+if [ $ret != 0 ]; then echo "I:failed"; fi |
|
+status=`expr $status + $ret` |
|
+ |
|
+echo "I:checking (too) long dname from recursive without cached DNAME" |
|
+ret=0 |
|
+$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.uncachedtoolong || ret=1 |
|
+grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1 |
|
+grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1 |
|
if [ $ret != 0 ]; then echo "I:failed"; fi |
|
status=`expr $status + $ret` |
|
|
|
diff --git a/lib/dns/name.c b/lib/dns/name.c |
|
index 93173ee..d02e713 100644 |
|
--- a/lib/dns/name.c |
|
+++ b/lib/dns/name.c |
|
@@ -2119,11 +2119,9 @@ dns_name_split(dns_name_t *name, unsigned int suffixlabels, |
|
REQUIRE(prefix != NULL || suffix != NULL); |
|
REQUIRE(prefix == NULL || |
|
(VALID_NAME(prefix) && |
|
- prefix->buffer != NULL && |
|
BINDABLE(prefix))); |
|
REQUIRE(suffix == NULL || |
|
(VALID_NAME(suffix) && |
|
- suffix->buffer != NULL && |
|
BINDABLE(suffix))); |
|
|
|
splitlabel = name->labels - suffixlabels; |
|
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c |
|
index c3607fa..860a792 100644 |
|
--- a/lib/dns/resolver.c |
|
+++ b/lib/dns/resolver.c |
|
@@ -3817,6 +3817,7 @@ is_lame(fetchctx_t *fctx) { |
|
isc_result_t result; |
|
|
|
if (message->rcode != dns_rcode_noerror && |
|
+ message->rcode != dns_rcode_yxdomain && |
|
message->rcode != dns_rcode_nxdomain) |
|
return (ISC_FALSE); |
|
|
|
@@ -5386,79 +5387,6 @@ chase_additional(fetchctx_t *fctx) { |
|
goto again; |
|
} |
|
|
|
-static inline isc_result_t |
|
-cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { |
|
- isc_result_t result; |
|
- dns_rdata_t rdata = DNS_RDATA_INIT; |
|
- dns_rdata_cname_t cname; |
|
- |
|
- result = dns_rdataset_first(rdataset); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- dns_rdataset_current(rdataset, &rdata); |
|
- result = dns_rdata_tostruct(&rdata, &cname, NULL); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- dns_name_init(tname, NULL); |
|
- dns_name_clone(&cname.cname, tname); |
|
- dns_rdata_freestruct(&cname); |
|
- |
|
- return (ISC_R_SUCCESS); |
|
-} |
|
- |
|
-/*% |
|
- * Construct the synthesised CNAME from the existing QNAME and |
|
- * the DNAME RR and store it in 'target'. |
|
- */ |
|
-static inline isc_result_t |
|
-dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, |
|
- unsigned int nlabels, dns_name_t *target) |
|
-{ |
|
- isc_result_t result; |
|
- dns_rdata_t rdata = DNS_RDATA_INIT; |
|
- dns_rdata_dname_t dname; |
|
- dns_fixedname_t prefix; |
|
- |
|
- /* |
|
- * Get the target name of the DNAME. |
|
- */ |
|
- result = dns_rdataset_first(rdataset); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- dns_rdataset_current(rdataset, &rdata); |
|
- result = dns_rdata_tostruct(&rdata, &dname, NULL); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- |
|
- dns_fixedname_init(&prefix); |
|
- dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); |
|
- result = dns_name_concatenate(dns_fixedname_name(&prefix), |
|
- &dname.dname, target, NULL); |
|
- dns_rdata_freestruct(&dname); |
|
- return (result); |
|
-} |
|
- |
|
-/*% |
|
- * Check if it was possible to construct 'qname' from 'lastcname' |
|
- * and 'rdataset'. |
|
- */ |
|
-static inline isc_result_t |
|
-fromdname(dns_rdataset_t *rdataset, dns_name_t *lastcname, |
|
- unsigned int nlabels, const dns_name_t *qname) |
|
-{ |
|
- dns_fixedname_t fixed; |
|
- isc_result_t result; |
|
- dns_name_t *target; |
|
- |
|
- dns_fixedname_init(&fixed); |
|
- target = dns_fixedname_name(&fixed); |
|
- result = dname_target(rdataset, lastcname, nlabels, target); |
|
- if (result != ISC_R_SUCCESS || !dns_name_equal(qname, target)) |
|
- return (ISC_R_NOTFOUND); |
|
- |
|
- return (ISC_R_SUCCESS); |
|
-} |
|
- |
|
static isc_boolean_t |
|
is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, |
|
dns_rdataset_t *rdataset) |
|
@@ -5534,9 +5462,8 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, |
|
} |
|
|
|
static isc_boolean_t |
|
-is_answertarget_allowed(dns_view_t *view, dns_name_t *name, |
|
- dns_rdatatype_t type, dns_name_t *tname, |
|
- dns_name_t *domain) |
|
+is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, |
|
+ dns_rdataset_t *rdataset, isc_boolean_t *chainingp) |
|
{ |
|
isc_result_t result; |
|
dns_rbtnode_t *node = NULL; |
|
@@ -5544,8 +5471,57 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, |
|
char tnamebuf[DNS_NAME_FORMATSIZE]; |
|
char classbuf[64]; |
|
char typebuf[64]; |
|
+ dns_name_t *tname = NULL; |
|
+ dns_rdata_cname_t cname; |
|
+ dns_rdata_dname_t dname; |
|
+ dns_view_t *view = fctx->res->view; |
|
+ dns_rdata_t rdata = DNS_RDATA_INIT; |
|
+ unsigned int nlabels; |
|
+ dns_fixedname_t fixed; |
|
+ dns_name_t prefix; |
|
+ |
|
+ REQUIRE(rdataset != NULL); |
|
+ REQUIRE(rdataset->type == dns_rdatatype_cname || |
|
+ rdataset->type == dns_rdatatype_dname); |
|
+ |
|
+ /* |
|
+ * By default, we allow any target name. |
|
+ * If newqname != NULL we also need to extract the newqname. |
|
+ */ |
|
+ if (chainingp == NULL && view->denyanswernames == NULL) |
|
+ return (ISC_TRUE); |
|
+ |
|
+ result = dns_rdataset_first(rdataset); |
|
+ RUNTIME_CHECK(result == ISC_R_SUCCESS); |
|
+ dns_rdataset_current(rdataset, &rdata); |
|
+ switch (rdataset->type) { |
|
+ case dns_rdatatype_cname: |
|
+ result = dns_rdata_tostruct(&rdata, &cname, NULL); |
|
+ RUNTIME_CHECK(result == ISC_R_SUCCESS); |
|
+ tname = &cname.cname; |
|
+ break; |
|
+ case dns_rdatatype_dname: |
|
+ result = dns_rdata_tostruct(&rdata, &dname, NULL); |
|
+ RUNTIME_CHECK(result == ISC_R_SUCCESS); |
|
+ dns_name_init(&prefix, NULL); |
|
+ dns_fixedname_init(&fixed); |
|
+ tname = dns_fixedname_name(&fixed); |
|
+ nlabels = dns_name_countlabels(qname) - |
|
+ dns_name_countlabels(rname); |
|
+ dns_name_split(qname, nlabels, &prefix, NULL); |
|
+ result = dns_name_concatenate(&prefix, &dname.dname, tname, |
|
+ NULL); |
|
+ if (result == DNS_R_NAMETOOLONG) |
|
+ return (ISC_TRUE); |
|
+ RUNTIME_CHECK(result == ISC_R_SUCCESS); |
|
+ break; |
|
+ default: |
|
+ INSIST(0); |
|
+ } |
|
+ |
|
+ if (chainingp != NULL) |
|
+ *chainingp = ISC_TRUE; |
|
|
|
- /* By default, we allow any target name. */ |
|
if (view->denyanswernames == NULL) |
|
return (ISC_TRUE); |
|
|
|
@@ -5554,8 +5530,8 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, |
|
* or partially, allow it. |
|
*/ |
|
if (view->answernames_exclude != NULL) { |
|
- result = dns_rbt_findnode(view->answernames_exclude, name, NULL, |
|
- &node, NULL, 0, NULL, NULL); |
|
+ result = dns_rbt_findnode(view->answernames_exclude, qname, |
|
+ NULL, &node, NULL, 0, NULL, NULL); |
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) |
|
return (ISC_TRUE); |
|
} |
|
@@ -5563,7 +5539,7 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, |
|
/* |
|
* If the target name is a subdomain of the search domain, allow it. |
|
*/ |
|
- if (dns_name_issubdomain(tname, domain)) |
|
+ if (dns_name_issubdomain(tname, &fctx->domain)) |
|
return (ISC_TRUE); |
|
|
|
/* |
|
@@ -5572,9 +5548,9 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, |
|
result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node, |
|
NULL, 0, NULL, NULL); |
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { |
|
- dns_name_format(name, qnamebuf, sizeof(qnamebuf)); |
|
+ dns_name_format(qname, qnamebuf, sizeof(qnamebuf)); |
|
dns_name_format(tname, tnamebuf, sizeof(tnamebuf)); |
|
- dns_rdatatype_format(type, typebuf, sizeof(typebuf)); |
|
+ dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf)); |
|
dns_rdataclass_format(view->rdclass, classbuf, |
|
sizeof(classbuf)); |
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, |
|
@@ -6057,473 +6033,301 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, |
|
return (ISC_R_SUCCESS); |
|
} |
|
|
|
+static isc_boolean_t |
|
+validinanswer(dns_rdataset_t *rdataset, fetchctx_t *fctx) { |
|
+ if (rdataset->type == dns_rdatatype_nsec3) { |
|
+ /* |
|
+ * NSEC3 records are not allowed to |
|
+ * appear in the answer section. |
|
+ */ |
|
+ log_formerr(fctx, "NSEC3 in answer"); |
|
+ return (ISC_FALSE); |
|
+ } |
|
+ if (rdataset->type == dns_rdatatype_tkey) { |
|
+ /* |
|
+ * TKEY is not a valid record in a |
|
+ * response to any query we can make. |
|
+ */ |
|
+ log_formerr(fctx, "TKEY in answer"); |
|
+ return (ISC_FALSE); |
|
+ } |
|
+ if (rdataset->rdclass != fctx->res->rdclass) { |
|
+ log_formerr(fctx, "Mismatched class in answer"); |
|
+ return (ISC_FALSE); |
|
+ } |
|
+ return (ISC_TRUE); |
|
+} |
|
+ |
|
static isc_result_t |
|
answer_response(fetchctx_t *fctx) { |
|
isc_result_t result; |
|
- dns_message_t *message; |
|
- dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; |
|
- dns_name_t *cname = NULL, *lastcname = NULL; |
|
- dns_rdataset_t *rdataset, *ns_rdataset; |
|
- isc_boolean_t done, external, aa, found, want_chaining; |
|
- isc_boolean_t have_answer, found_cname, found_dname, found_type; |
|
- isc_boolean_t wanted_chaining; |
|
- unsigned int aflag, chaining; |
|
+ dns_message_t *message = NULL; |
|
+ dns_name_t *name = NULL, *qname = NULL, *ns_name = NULL; |
|
+ dns_name_t *aname = NULL, *cname = NULL, *dname = NULL; |
|
+ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; |
|
+ dns_rdataset_t *ardataset = NULL, *crdataset = NULL; |
|
+ dns_rdataset_t *drdataset = NULL, *ns_rdataset = NULL; |
|
+ isc_boolean_t done = ISC_FALSE, aa; |
|
+ unsigned int dname_labels, domain_labels; |
|
+ isc_boolean_t chaining = ISC_FALSE; |
|
dns_rdatatype_t type; |
|
- dns_fixedname_t fdname, fqname; |
|
- dns_view_t *view; |
|
+ dns_view_t *view = NULL; |
|
+ dns_trust_t trust; |
|
+ |
|
+ REQUIRE(VALID_FCTX(fctx)); |
|
|
|
FCTXTRACE("answer_response"); |
|
|
|
message = fctx->rmessage; |
|
+ qname = &fctx->name; |
|
+ view = fctx->res->view; |
|
+ type = fctx->type; |
|
|
|
/* |
|
- * Examine the answer section, marking those rdatasets which are |
|
- * part of the answer and should be cached. |
|
+ * There can be multiple RRSIG and SIG records at a name so |
|
+ * we treat these types as a subset of ANY. |
|
*/ |
|
+ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) { |
|
+ type = dns_rdatatype_any; |
|
+ } |
|
|
|
- done = ISC_FALSE; |
|
- found_cname = ISC_FALSE; |
|
- found_dname = ISC_FALSE; |
|
- found_type = ISC_FALSE; |
|
- have_answer = ISC_FALSE; |
|
- want_chaining = ISC_FALSE; |
|
- chaining = 0; |
|
- POST(want_chaining); |
|
- if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) |
|
- aa = ISC_TRUE; |
|
- else |
|
- aa = ISC_FALSE; |
|
- qname = &fctx->name; |
|
- type = fctx->type; |
|
- view = fctx->res->view; |
|
- result = dns_message_firstname(message, DNS_SECTION_ANSWER); |
|
- while (!done && result == ISC_R_SUCCESS) { |
|
- dns_namereln_t namereln, lastreln; |
|
- int order, lastorder; |
|
- unsigned int nlabels, lastnlabels; |
|
+ /* |
|
+ * Bigger than any valid DNAME label count. |
|
+ */ |
|
+ dname_labels = dns_name_countlabels(qname); |
|
+ domain_labels = dns_name_countlabels(&fctx->domain); |
|
+ |
|
+ /* |
|
+ * Perform a single pass looking for the answer, cname or covering |
|
+ * dname. |
|
+ */ |
|
+ for (result = dns_message_firstname(message, DNS_SECTION_ANSWER); |
|
+ result == ISC_R_SUCCESS; |
|
+ result = dns_message_nextname(message, DNS_SECTION_ANSWER)) |
|
+ { |
|
+ int order; |
|
+ unsigned int nlabels; |
|
+ dns_namereln_t namereln; |
|
|
|
name = NULL; |
|
dns_message_currentname(message, DNS_SECTION_ANSWER, &name); |
|
- external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); |
|
namereln = dns_name_fullcompare(qname, name, &order, &nlabels); |
|
- |
|
- if (namereln == dns_namereln_equal) { |
|
- wanted_chaining = ISC_FALSE; |
|
+ switch (namereln) { |
|
+ case dns_namereln_equal: |
|
for (rdataset = ISC_LIST_HEAD(name->list); |
|
rdataset != NULL; |
|
- rdataset = ISC_LIST_NEXT(rdataset, link)) { |
|
- found = ISC_FALSE; |
|
- want_chaining = ISC_FALSE; |
|
- aflag = 0; |
|
- if (rdataset->type == dns_rdatatype_nsec3) { |
|
- /* |
|
- * NSEC3 records are not allowed to |
|
- * appear in the answer section. |
|
- */ |
|
- log_formerr(fctx, "NSEC3 in answer"); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- if (rdataset->type == dns_rdatatype_tkey) { |
|
- /* |
|
- * TKEY is not a valid record in a |
|
- * response to any query we can make. |
|
- */ |
|
- log_formerr(fctx, "TKEY in answer"); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- if (rdataset->rdclass != fctx->res->rdclass) { |
|
- log_formerr(fctx, "Mismatched class " |
|
- "in answer"); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- |
|
- /* |
|
- * Apply filters, if given, on answers to reject |
|
- * a malicious attempt of rebinding. |
|
- */ |
|
- if ((rdataset->type == dns_rdatatype_a || |
|
- rdataset->type == dns_rdatatype_aaaa) && |
|
- !is_answeraddress_allowed(view, name, |
|
- rdataset)) { |
|
- return (DNS_R_SERVFAIL); |
|
- } |
|
- |
|
- if (rdataset->type == type && !found_cname) { |
|
- /* |
|
- * We've found an ordinary answer. |
|
- */ |
|
- found = ISC_TRUE; |
|
- found_type = ISC_TRUE; |
|
- done = ISC_TRUE; |
|
- aflag = DNS_RDATASETATTR_ANSWER; |
|
- } else if (type == dns_rdatatype_any) { |
|
- /* |
|
- * We've found an answer matching |
|
- * an ANY query. There may be |
|
- * more. |
|
- */ |
|
- found = ISC_TRUE; |
|
- aflag = DNS_RDATASETATTR_ANSWER; |
|
- } else if (rdataset->type == dns_rdatatype_rrsig |
|
- && rdataset->covers == type |
|
- && !found_cname) { |
|
- /* |
|
- * We've found a signature that |
|
- * covers the type we're looking for. |
|
- */ |
|
- found = ISC_TRUE; |
|
- found_type = ISC_TRUE; |
|
- aflag = DNS_RDATASETATTR_ANSWERSIG; |
|
- } else if (rdataset->type == |
|
- dns_rdatatype_cname |
|
- && !found_type) { |
|
- /* |
|
- * We're looking for something else, |
|
- * but we found a CNAME. |
|
- * |
|
- * Getting a CNAME response for some |
|
- * query types is an error, see |
|
- * RFC 4035, Section 2.5. |
|
- */ |
|
- if (type == dns_rdatatype_rrsig || |
|
- type == dns_rdatatype_key || |
|
- type == dns_rdatatype_nsec) { |
|
- char buf[DNS_RDATATYPE_FORMATSIZE]; |
|
- dns_rdatatype_format(fctx->type, |
|
- buf, sizeof(buf)); |
|
- log_formerr(fctx, |
|
- "CNAME response " |
|
- "for %s RR", buf); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- found = ISC_TRUE; |
|
- found_cname = ISC_TRUE; |
|
- want_chaining = ISC_TRUE; |
|
- aflag = DNS_RDATASETATTR_ANSWER; |
|
- result = cname_target(rdataset, |
|
- &tname); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- /* Apply filters on the target name. */ |
|
- if (!is_answertarget_allowed(view, |
|
- name, |
|
- rdataset->type, |
|
- &tname, |
|
- &fctx->domain)) { |
|
- return (DNS_R_SERVFAIL); |
|
+ rdataset = ISC_LIST_NEXT(rdataset, link)) |
|
+ { |
|
+ if (rdataset->type == type || |
|
+ type == dns_rdatatype_any) |
|
+ { |
|
+ aname = name; |
|
+ if (type != dns_rdatatype_any) { |
|
+ ardataset = rdataset; |
|
} |
|
- lastcname = name; |
|
- } else if (rdataset->type == dns_rdatatype_rrsig |
|
- && rdataset->covers == |
|
- dns_rdatatype_cname |
|
- && !found_type) { |
|
- /* |
|
- * We're looking for something else, |
|
- * but we found a SIG CNAME. |
|
- */ |
|
- found = ISC_TRUE; |
|
- found_cname = ISC_TRUE; |
|
- aflag = DNS_RDATASETATTR_ANSWERSIG; |
|
+ break; |
|
} |
|
- |
|
- if (found) { |
|
- /* |
|
- * We've found an answer to our |
|
- * question. |
|
- */ |
|
- name->attributes |= |
|
- DNS_NAMEATTR_CACHE; |
|
- rdataset->attributes |= |
|
- DNS_RDATASETATTR_CACHE; |
|
- rdataset->trust = dns_trust_answer; |
|
- if (chaining == 0) { |
|
- /* |
|
- * This data is "the" answer |
|
- * to our question only if |
|
- * we're not chaining (i.e. |
|
- * if we haven't followed |
|
- * a CNAME or DNAME). |
|
- */ |
|
- INSIST(!external); |
|
- /* |
|
- * Don't use found_cname here |
|
- * as we have just set it |
|
- * above. |
|
- */ |
|
- if (cname == NULL && |
|
- !found_dname && |
|
- aflag == |
|
- DNS_RDATASETATTR_ANSWER) |
|
- { |
|
- have_answer = ISC_TRUE; |
|
- if (found_cname && |
|
- cname == NULL) |
|
- cname = name; |
|
- name->attributes |= |
|
- DNS_NAMEATTR_ANSWER; |
|
- } |
|
- rdataset->attributes |= aflag; |
|
- if (aa) |
|
- rdataset->trust = |
|
- dns_trust_authanswer; |
|
- } else if (external) { |
|
- /* |
|
- * This data is outside of |
|
- * our query domain, and |
|
- * may not be cached. |
|
- */ |
|
- rdataset->attributes |= |
|
- DNS_RDATASETATTR_EXTERNAL; |
|
- } |
|
- |
|
- /* |
|
- * Mark any additional data related |
|
- * to this rdataset. |
|
- */ |
|
- (void)dns_rdataset_additionaldata( |
|
- rdataset, |
|
- check_related, |
|
- fctx); |
|
- |
|
- /* |
|
- * CNAME chaining. |
|
- */ |
|
- if (want_chaining) { |
|
- wanted_chaining = ISC_TRUE; |
|
- name->attributes |= |
|
- DNS_NAMEATTR_CHAINING; |
|
- rdataset->attributes |= |
|
- DNS_RDATASETATTR_CHAINING; |
|
- qname = &tname; |
|
- } |
|
+ if (rdataset->type == dns_rdatatype_cname) { |
|
+ cname = name; |
|
+ crdataset = rdataset; |
|
+ break; |
|
} |
|
- /* |
|
- * We could add an "else" clause here and |
|
- * log that we're ignoring this rdataset. |
|
- */ |
|
} |
|
+ break; |
|
+ |
|
+ case dns_namereln_subdomain: |
|
/* |
|
- * If wanted_chaining is true, we've done |
|
- * some chaining as the result of processing |
|
- * this node, and thus we need to set |
|
- * chaining to true. |
|
- * |
|
- * We don't set chaining inside of the |
|
- * rdataset loop because doing that would |
|
- * cause us to ignore the signatures of |
|
- * CNAMEs. |
|
+ * In-scope DNAME records must have at least |
|
+ * as many labels as the domain being queried. |
|
+ * They also must be less that qname's labels |
|
+ * and any previously found dname. |
|
*/ |
|
- if (wanted_chaining && chaining < 2U) |
|
- chaining++; |
|
- } else { |
|
- dns_rdataset_t *dnameset = NULL; |
|
- isc_boolean_t synthcname = ISC_FALSE; |
|
- |
|
- if (lastcname != NULL) { |
|
- lastreln = dns_name_fullcompare(lastcname, |
|
- name, |
|
- &lastorder, |
|
- &lastnlabels); |
|
- if (lastreln == dns_namereln_subdomain && |
|
- lastnlabels == dns_name_countlabels(name)) |
|
- synthcname = ISC_TRUE; |
|
+ if (nlabels >= dname_labels || nlabels < domain_labels) |
|
+ { |
|
+ continue; |
|
} |
|
|
|
/* |
|
- * Look for a DNAME (or its SIG). Anything else is |
|
- * ignored. |
|
+ * We are looking for the shortest DNAME if there |
|
+ * are multiple ones (which there shouldn't be). |
|
*/ |
|
- wanted_chaining = ISC_FALSE; |
|
for (rdataset = ISC_LIST_HEAD(name->list); |
|
rdataset != NULL; |
|
rdataset = ISC_LIST_NEXT(rdataset, link)) |
|
{ |
|
- if (rdataset->rdclass != fctx->res->rdclass) { |
|
- log_formerr(fctx, "Mismatched class " |
|
- "in answer"); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- |
|
- /* |
|
- * Only pass DNAME or RRSIG(DNAME). |
|
- */ |
|
- if (rdataset->type != dns_rdatatype_dname && |
|
- (rdataset->type != dns_rdatatype_rrsig || |
|
- rdataset->covers != dns_rdatatype_dname)) |
|
+ if (rdataset->type != dns_rdatatype_dname) { |
|
continue; |
|
- |
|
- /* |
|
- * If we're not chaining, then the DNAME and |
|
- * its signature should not be external. |
|
- */ |
|
- if (chaining == 0 && external) { |
|
- char qbuf[DNS_NAME_FORMATSIZE]; |
|
- char obuf[DNS_NAME_FORMATSIZE]; |
|
- |
|
- dns_name_format(name, qbuf, |
|
- sizeof(qbuf)); |
|
- dns_name_format(&fctx->domain, obuf, |
|
- sizeof(obuf)); |
|
- log_formerr(fctx, "external DNAME or " |
|
- "RRSIG covering DNAME " |
|
- "in answer: %s is " |
|
- "not in %s", qbuf, obuf); |
|
- return (DNS_R_FORMERR); |
|
- } |
|
- |
|
- /* |
|
- * If DNAME + synthetic CNAME then the |
|
- * namereln is dns_namereln_subdomain. |
|
- */ |
|
- if (namereln != dns_namereln_subdomain && |
|
- !synthcname) |
|
- { |
|
- char qbuf[DNS_NAME_FORMATSIZE]; |
|
- char obuf[DNS_NAME_FORMATSIZE]; |
|
- |
|
- dns_name_format(qname, qbuf, |
|
- sizeof(qbuf)); |
|
- dns_name_format(name, obuf, |
|
- sizeof(obuf)); |
|
- log_formerr(fctx, "unrelated DNAME " |
|
- "in answer: %s is " |
|
- "not in %s", qbuf, obuf); |
|
- return (DNS_R_FORMERR); |
|
} |
|
+ dname = name; |
|
+ drdataset = rdataset; |
|
+ dname_labels = nlabels; |
|
+ break; |
|
+ } |
|
+ break; |
|
+ default: |
|
+ break; |
|
+ } |
|
+ } |
|
|
|
- aflag = 0; |
|
- if (rdataset->type == dns_rdatatype_dname) { |
|
- want_chaining = ISC_TRUE; |
|
- POST(want_chaining); |
|
- aflag = DNS_RDATASETATTR_ANSWER; |
|
- dns_fixedname_init(&fdname); |
|
- dname = dns_fixedname_name(&fdname); |
|
- if (synthcname) { |
|
- result = fromdname(rdataset, |
|
- lastcname, |
|
- lastnlabels, |
|
- qname); |
|
- } else { |
|
- result = dname_target(rdataset, |
|
- qname, |
|
- nlabels, |
|
- dname); |
|
- } |
|
- if (result == ISC_R_NOSPACE) { |
|
- /* |
|
- * We can't construct the |
|
- * DNAME target. Do not |
|
- * try to continue. |
|
- */ |
|
- want_chaining = ISC_FALSE; |
|
- POST(want_chaining); |
|
- } else if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- else |
|
- dnameset = rdataset; |
|
+ if (dname != NULL) { |
|
+ aname = NULL; |
|
+ ardataset = NULL; |
|
+ cname = NULL; |
|
+ crdataset = NULL; |
|
+ } else if (aname != NULL) { |
|
+ cname = NULL; |
|
+ crdataset = NULL; |
|
+ } |
|
|
|
- if (!synthcname && |
|
- !is_answertarget_allowed(view, |
|
- qname, rdataset->type, |
|
- dname, &fctx->domain)) |
|
- { |
|
- return (DNS_R_SERVFAIL); |
|
- } |
|
- } else { |
|
- /* |
|
- * We've found a signature that |
|
- * covers the DNAME. |
|
- */ |
|
- aflag = DNS_RDATASETATTR_ANSWERSIG; |
|
- } |
|
+ aa = ISC_TF((message->flags & DNS_MESSAGEFLAG_AA) != 0); |
|
+ trust = aa ? dns_trust_authanswer : dns_trust_answer; |
|
|
|
- /* |
|
- * We've found an answer to our |
|
- * question. |
|
- */ |
|
- name->attributes |= DNS_NAMEATTR_CACHE; |
|
- rdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
- rdataset->trust = dns_trust_answer; |
|
- /* |
|
- * If we are not chaining or the first CNAME |
|
- * is a synthesised CNAME before the DNAME. |
|
- */ |
|
- if ((chaining == 0) || |
|
- (chaining == 1U && synthcname)) |
|
- { |
|
- /* |
|
- * This data is "the" answer to |
|
- * our question only if we're |
|
- * not chaining. |
|
- */ |
|
- INSIST(!external); |
|
- if (aflag == DNS_RDATASETATTR_ANSWER) { |
|
- have_answer = ISC_TRUE; |
|
- found_dname = ISC_TRUE; |
|
- if (cname != NULL && |
|
- synthcname) |
|
- { |
|
- cname->attributes &= |
|
- ~DNS_NAMEATTR_ANSWER; |
|
- } |
|
- name->attributes |= |
|
- DNS_NAMEATTR_ANSWER; |
|
- } |
|
- rdataset->attributes |= aflag; |
|
- if (aa) |
|
- rdataset->trust = |
|
- dns_trust_authanswer; |
|
- } else if (external) { |
|
- rdataset->attributes |= |
|
- DNS_RDATASETATTR_EXTERNAL; |
|
- } |
|
+ if (aname != NULL && type == dns_rdatatype_any) { |
|
+ for (rdataset = ISC_LIST_HEAD(aname->list); |
|
+ rdataset != NULL; |
|
+ rdataset = ISC_LIST_NEXT(rdataset, link)) |
|
+ { |
|
+ if (!validinanswer(rdataset, fctx)) { |
|
+ return (DNS_R_FORMERR); |
|
} |
|
- |
|
- /* |
|
- * DNAME chaining. |
|
- */ |
|
- if (dnameset != NULL) { |
|
- if (!synthcname) { |
|
- /* |
|
- * Copy the dname into the qname fixed |
|
- * name. |
|
- * |
|
- * Although we check for failure of the |
|
- * copy operation, in practice it |
|
- * should never fail since we already |
|
- * know that the result fits in a |
|
- * fixedname. |
|
- */ |
|
- dns_fixedname_init(&fqname); |
|
- qname = dns_fixedname_name(&fqname); |
|
- result = dns_name_copy(dname, qname, |
|
- NULL); |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- } |
|
- wanted_chaining = ISC_TRUE; |
|
- name->attributes |= DNS_NAMEATTR_CHAINING; |
|
- dnameset->attributes |= |
|
- DNS_RDATASETATTR_CHAINING; |
|
+ if ((fctx->type == dns_rdatatype_sig || |
|
+ fctx->type == dns_rdatatype_rrsig) && |
|
+ rdataset->type != fctx->type) |
|
+ { |
|
+ continue; |
|
} |
|
- /* |
|
- * Ensure that we can't ever get chaining == 1 |
|
- * above if we have processed a DNAME. |
|
- */ |
|
- if (wanted_chaining && chaining < 2U) |
|
- chaining += 2; |
|
+ if ((rdataset->type == dns_rdatatype_a || |
|
+ rdataset->type == dns_rdatatype_aaaa) && |
|
+ !is_answeraddress_allowed(view, aname, rdataset)) |
|
+ { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ if ((rdataset->type == dns_rdatatype_cname || |
|
+ rdataset->type == dns_rdatatype_dname) && |
|
+ !is_answertarget_allowed(fctx, qname, aname, |
|
+ rdataset, NULL)) |
|
+ { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ aname->attributes |= DNS_NAMEATTR_CACHE; |
|
+ aname->attributes |= DNS_NAMEATTR_ANSWER; |
|
+ rdataset->attributes |= DNS_RDATASETATTR_ANSWER; |
|
+ rdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ rdataset->trust = trust; |
|
+ (void)dns_rdataset_additionaldata(rdataset, |
|
+ check_related, |
|
+ fctx); |
|
} |
|
- result = dns_message_nextname(message, DNS_SECTION_ANSWER); |
|
- } |
|
- if (result == ISC_R_NOMORE) |
|
- result = ISC_R_SUCCESS; |
|
- if (result != ISC_R_SUCCESS) |
|
- return (result); |
|
- |
|
- /* |
|
- * We should have found an answer. |
|
- */ |
|
- if (!have_answer) { |
|
+ } else if (aname != NULL) { |
|
+ if (!validinanswer(ardataset, fctx)) |
|
+ return (DNS_R_FORMERR); |
|
+ if ((ardataset->type == dns_rdatatype_a || |
|
+ ardataset->type == dns_rdatatype_aaaa) && |
|
+ !is_answeraddress_allowed(view, aname, ardataset)) { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ if ((ardataset->type == dns_rdatatype_cname || |
|
+ ardataset->type == dns_rdatatype_dname) && |
|
+ !is_answertarget_allowed(fctx, qname, aname, ardataset, |
|
+ NULL)) |
|
+ { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ aname->attributes |= DNS_NAMEATTR_CACHE; |
|
+ aname->attributes |= DNS_NAMEATTR_ANSWER; |
|
+ ardataset->attributes |= DNS_RDATASETATTR_ANSWER; |
|
+ ardataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ ardataset->trust = trust; |
|
+ (void)dns_rdataset_additionaldata(ardataset, check_related, |
|
+ fctx); |
|
+ for (sigrdataset = ISC_LIST_HEAD(aname->list); |
|
+ sigrdataset != NULL; |
|
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { |
|
+ if (!validinanswer(sigrdataset, fctx)) |
|
+ return (DNS_R_FORMERR); |
|
+ if (sigrdataset->type != dns_rdatatype_rrsig || |
|
+ sigrdataset->covers != type) |
|
+ continue; |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ sigrdataset->trust = trust; |
|
+ break; |
|
+ } |
|
+ } else if (cname != NULL) { |
|
+ if (!validinanswer(crdataset, fctx)) { |
|
+ return (DNS_R_FORMERR); |
|
+ } |
|
+ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_key || |
|
+ type == dns_rdatatype_nsec) |
|
+ { |
|
+ char buf[DNS_RDATATYPE_FORMATSIZE]; |
|
+ dns_rdatatype_format(type, buf, sizeof(buf)); |
|
+ log_formerr(fctx, "CNAME response for %s RR", buf); |
|
+ return (DNS_R_FORMERR); |
|
+ } |
|
+ if (!is_answertarget_allowed(fctx, qname, cname, crdataset, |
|
+ NULL)) |
|
+ { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ cname->attributes |= DNS_NAMEATTR_CACHE; |
|
+ cname->attributes |= DNS_NAMEATTR_ANSWER; |
|
+ cname->attributes |= DNS_NAMEATTR_CHAINING; |
|
+ crdataset->attributes |= DNS_RDATASETATTR_ANSWER; |
|
+ crdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ crdataset->attributes |= DNS_RDATASETATTR_CHAINING; |
|
+ crdataset->trust = trust; |
|
+ for (sigrdataset = ISC_LIST_HEAD(cname->list); |
|
+ sigrdataset != NULL; |
|
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) |
|
+ { |
|
+ if (!validinanswer(sigrdataset, fctx)) { |
|
+ return (DNS_R_FORMERR); |
|
+ } |
|
+ if (sigrdataset->type != dns_rdatatype_rrsig || |
|
+ sigrdataset->covers != dns_rdatatype_cname) |
|
+ { |
|
+ continue; |
|
+ } |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ sigrdataset->trust = trust; |
|
+ break; |
|
+ } |
|
+ chaining = ISC_TRUE; |
|
+ } else if (dname != NULL) { |
|
+ if (!validinanswer(drdataset, fctx)) { |
|
+ return (DNS_R_FORMERR); |
|
+ } |
|
+ if (!is_answertarget_allowed(fctx, qname, dname, drdataset, |
|
+ &chaining)) { |
|
+ return (DNS_R_SERVFAIL); |
|
+ } |
|
+ dname->attributes |= DNS_NAMEATTR_CACHE; |
|
+ dname->attributes |= DNS_NAMEATTR_ANSWER; |
|
+ dname->attributes |= DNS_NAMEATTR_CHAINING; |
|
+ drdataset->attributes |= DNS_RDATASETATTR_ANSWER; |
|
+ drdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ drdataset->attributes |= DNS_RDATASETATTR_CHAINING; |
|
+ drdataset->trust = trust; |
|
+ for (sigrdataset = ISC_LIST_HEAD(dname->list); |
|
+ sigrdataset != NULL; |
|
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) |
|
+ { |
|
+ if (!validinanswer(sigrdataset, fctx)) { |
|
+ return (DNS_R_FORMERR); |
|
+ } |
|
+ if (sigrdataset->type != dns_rdatatype_rrsig || |
|
+ sigrdataset->covers != dns_rdatatype_dname) |
|
+ { |
|
+ continue; |
|
+ } |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; |
|
+ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; |
|
+ sigrdataset->trust = trust; |
|
+ break; |
|
+ } |
|
+ } else { |
|
log_formerr(fctx, "reply has no answer"); |
|
return (DNS_R_FORMERR); |
|
} |
|
@@ -6536,14 +6340,8 @@ answer_response(fetchctx_t *fctx) { |
|
/* |
|
* Did chaining end before we got the final answer? |
|
*/ |
|
- if (chaining != 0) { |
|
- /* |
|
- * Yes. This may be a negative reply, so hand off |
|
- * authority section processing to the noanswer code. |
|
- * If it isn't a noanswer response, no harm will be |
|
- * done. |
|
- */ |
|
- return (noanswer_response(fctx, qname, 0)); |
|
+ if (chaining) { |
|
+ return (ISC_R_SUCCESS); |
|
} |
|
|
|
/* |
|
@@ -6562,11 +6360,9 @@ answer_response(fetchctx_t *fctx) { |
|
* We expect there to be only one owner name for all the rdatasets |
|
* in this section, and we expect that it is not external. |
|
*/ |
|
- done = ISC_FALSE; |
|
- ns_name = NULL; |
|
- ns_rdataset = NULL; |
|
result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); |
|
while (!done && result == ISC_R_SUCCESS) { |
|
+ isc_boolean_t external; |
|
name = NULL; |
|
dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); |
|
external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); |
|
@@ -6585,12 +6381,13 @@ answer_response(fetchctx_t *fctx) { |
|
DNS_NAMEATTR_CACHE; |
|
rdataset->attributes |= |
|
DNS_RDATASETATTR_CACHE; |
|
- if (aa && chaining == 0) |
|
+ if (aa && !chaining) { |
|
rdataset->trust = |
|
dns_trust_authauthority; |
|
- else |
|
+ } else { |
|
rdataset->trust = |
|
dns_trust_additional; |
|
+ } |
|
|
|
if (rdataset->type == dns_rdatatype_ns) |
|
{ |
|
@@ -7249,6 +7046,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { |
|
* Is the remote server broken, or does it dislike us? |
|
*/ |
|
if (message->rcode != dns_rcode_noerror && |
|
+ message->rcode != dns_rcode_yxdomain && |
|
message->rcode != dns_rcode_nxdomain) { |
|
if (((message->rcode == dns_rcode_formerr || |
|
message->rcode == dns_rcode_notimp) || |
|
@@ -7293,13 +7091,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { |
|
log_formerr(fctx, "server sent FORMERR"); |
|
result = DNS_R_FORMERR; |
|
} |
|
- } else if (message->rcode == dns_rcode_yxdomain) { |
|
- /* |
|
- * DNAME mapping failed because the new name |
|
- * was too long. There's no chance of success |
|
- * for this fetch. |
|
- */ |
|
- result = DNS_R_YXDOMAIN; |
|
} else if (message->rcode == dns_rcode_badvers) { |
|
unsigned int flags, mask; |
|
unsigned int version; |
|
@@ -7404,6 +7195,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { |
|
*/ |
|
if (message->counts[DNS_SECTION_ANSWER] > 0 && |
|
(message->rcode == dns_rcode_noerror || |
|
+ message->rcode == dns_rcode_yxdomain || |
|
message->rcode == dns_rcode_nxdomain)) { |
|
/* |
|
* [normal case] |
|
-- |
|
2.9.3 |
|
|
|
|