From 60cb462c56536f307fac4db8bdebf1247e2b5f66 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 9 Dec 2016 12:50:18 +1100 Subject: [PATCH] 4530. [bug] Change 4489 broke the handling of CNAME -> DNAME in responses resulting in SERVFAIL being returned. [RT #43779] --- CHANGES | 4 +++ bin/tests/system/dname/ns2/example.db | 4 ++- bin/tests/system/dname/tests.sh | 18 +++++++++++++ lib/dns/resolver.c | 37 +++++++++++++++++---------- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index 3b9b7273c5..d6d06ebcd3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4530. [bug] Change 4489 broke the handling of CNAME -> DNAME + in responses resulting in SERVFAIL being returned. + [RT #43779] + 4529. [cleanup] Silence noisy log warning when DSCP probe fails due to firewall rules. [RT #43847] diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db index 3366123b73..e54218b174 100644 --- a/bin/tests/system/dname/ns2/example.db +++ b/bin/tests/system/dname/ns2/example.db @@ -21,4 +21,6 @@ a.short A 10.0.0.1 short-dname DNAME short a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 long-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 871a9d7808..d97da66b81 100644 --- a/bin/tests/system/dname/tests.sh +++ b/bin/tests/system/dname/tests.sh @@ -55,6 +55,24 @@ grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:checking cname to dname from authoritative" +ret=0 +$DIG cname.example @10.53.0.2 a -p 5300 > dig.out.ns2.cname +grep "status: NOERROR" dig.out.ns2.cname > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +echo "I:checking cname to dname from recursive" +ret=0 +$DIG cname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cname +grep "status: NOERROR" dig.out.ns4.cname > /dev/null || ret=1 +grep '^cname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^a.cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index f5153206b9..bdaee29258 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -6807,7 +6807,7 @@ static isc_result_t answer_response(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message; - dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; + dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; dns_name_t *cname = NULL; dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t done, external, chaining, aa, found, want_chaining; @@ -6815,7 +6815,7 @@ answer_response(fetchctx_t *fctx) { isc_boolean_t wanted_chaining; unsigned int aflag; dns_rdatatype_t type; - dns_fixedname_t fdname, fqname, fqdname; + dns_fixedname_t fdname, fqname; dns_view_t *view; FCTXTRACE("answer_response"); @@ -6839,13 +6839,12 @@ answer_response(fetchctx_t *fctx) { aa = ISC_TRUE; else aa = ISC_FALSE; - dqname = qname = &fctx->name; + qname = &fctx->name; type = fctx->type; view = fctx->res->view; - dns_fixedname_init(&fqdname); result = dns_message_firstname(message, DNS_SECTION_ANSWER); while (!done && result == ISC_R_SUCCESS) { - dns_namereln_t namereln, dnamereln; + dns_namereln_t namereln; int order; unsigned int nlabels; @@ -6853,8 +6852,6 @@ answer_response(fetchctx_t *fctx) { 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); - dnamereln = dns_name_fullcompare(dqname, name, &order, - &nlabels); if (namereln == dns_namereln_equal) { wanted_chaining = ISC_FALSE; for (rdataset = ISC_LIST_HEAD(name->list); @@ -7084,11 +7081,24 @@ answer_response(fetchctx_t *fctx) { return (DNS_R_FORMERR); } - if (dnamereln != dns_namereln_subdomain) { + /* + * If DNAME + synthetic CNAME then the + * namereln is dns_namereln_subdomain. + * + * If synthetic CNAME + DNAME then the + * namereln is dns_namereln_commonancestor + * and the number of label must match the + * DNAME. This order is not RFC compliant. + */ + + if (namereln != dns_namereln_subdomain && + (namereln != dns_namereln_commonancestor || + nlabels != dns_name_countlabels(name))) + { char qbuf[DNS_NAME_FORMATSIZE]; char obuf[DNS_NAME_FORMATSIZE]; - dns_name_format(dqname, qbuf, + dns_name_format(qname, qbuf, sizeof(qbuf)); dns_name_format(name, obuf, sizeof(obuf)); @@ -7103,7 +7113,7 @@ answer_response(fetchctx_t *fctx) { want_chaining = ISC_TRUE; POST(want_chaining); aflag = DNS_RDATASETATTR_ANSWER; - result = dname_target(rdataset, dqname, + result = dname_target(rdataset, qname, nlabels, &fdname); if (result == ISC_R_NOSPACE) { /* @@ -7120,13 +7130,11 @@ answer_response(fetchctx_t *fctx) { dname = dns_fixedname_name(&fdname); if (!is_answertarget_allowed(view, - dqname, rdataset->type, + qname, rdataset->type, dname, &fctx->domain)) { return (DNS_R_SERVFAIL); } - dqname = dns_fixedname_name(&fqdname); - dns_name_copy(dname, dqname, NULL); } else { /* * We've found a signature that @@ -7272,7 +7280,8 @@ answer_response(fetchctx_t *fctx) { rdataset->trust = dns_trust_additional; - if (rdataset->type == dns_rdatatype_ns) { + if (rdataset->type == dns_rdatatype_ns) + { ns_name = name; ns_rdataset = rdataset; }