From b3d259107f3ff02bf08e40cdc4cb900385cdf1bd Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Tue, 17 Nov 2020 11:03:21 +1100 Subject: [PATCH] Fix DNAME when QTYPE is CNAME or ANY The synthesised CNAME is not supposed to be followed when the QTYPE is CNAME or ANY as the lookup is satisfied by the CNAME record. (cherry picked from commit e980affba0ed40476d977d284d142988633b6a7d) --- CHANGES | 3 ++ bin/tests/system/auth/ns1/example.com.db | 1 + bin/tests/system/auth/tests.sh | 48 ++++++++++++++++++++++++ doc/notes/notes-current.rst | 3 ++ lib/ns/query.c | 19 +++++++--- 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 69dc66cca05..cc8ffc33f35 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +5534. [bug] The synthesised CNAME from a DNAME was incorrectly + followed when the QTYPE was CNAME or ANY. [GL #2280] + 5533. [func] Add "stale-refresh-time" option, a time window that starts after a failed lookup, during which stale rrset will be served directly from cache before a new diff --git a/bin/tests/system/auth/ns1/example.com.db b/bin/tests/system/auth/ns1/example.com.db index a6c98de41c2..a61c88229e0 100644 --- a/bin/tests/system/auth/ns1/example.com.db +++ b/bin/tests/system/auth/ns1/example.com.db @@ -20,3 +20,4 @@ ns A 10.53.0.1 www CNAME server.example.net. inzone CNAME a.example.com. a A 10.53.0.1 +dname DNAME @ diff --git a/bin/tests/system/auth/tests.sh b/bin/tests/system/auth/tests.sh index 3b6f3f375bb..ea9e14d32ad 100644 --- a/bin/tests/system/auth/tests.sh +++ b/bin/tests/system/auth/tests.sh @@ -128,6 +128,54 @@ grep "a.example.com.*A.*10.53.0.1" dig.out.test$n > /dev/null || ret=1 [ $ret -eq 0 ] || echo_i "failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo_i "check that in-zone CNAME records does not return target data when QTYPE is CNAME (rd=1/ra=1) ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.2 -t cname inzone.example.com > dig.out.test$n || ret=1 +grep 'ANSWER: 1,' dig.out.test$n > /dev/null || ret=1 +grep 'flags: qr aa rd ra;' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.example\.com\..*CNAME.a\.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'a\.example\.com\..*A.10\.53\.0\.1' dig.out.test$n > /dev/null && ret=1 +[ $ret -eq 0 ] || echo_i "failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check that in-zone CNAME records does not return target data when QTYPE is ANY (rd=1/ra=1) ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.2 -t any inzone.example.com > dig.out.test$n || ret=1 +grep 'ANSWER: 1,' dig.out.test$n > /dev/null || ret=1 +grep 'flags: qr aa rd ra;' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.example\.com\..*CNAME.a\.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'a\.example\.com\..*A.10\.53\.0\.1' dig.out.test$n > /dev/null && ret=1 +[ $ret -eq 0 ] || echo_i "failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check that in-zone DNAME records does not return target data when QTYPE is CNAME (rd=1/ra=1) ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.2 -t cname inzone.dname.example.com > dig.out.test$n || ret=1 +grep 'ANSWER: 2,' dig.out.test$n > /dev/null || ret=1 +grep 'flags: qr aa rd ra;' dig.out.test$n > /dev/null || ret=1 +grep 'dname\.example\.com\..*DNAME.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.dname\.example\.com\..*CNAME.inzone\.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.example\.com\..*CNAME.a\.example\.com\.' dig.out.test$n > /dev/null && ret=1 +grep 'a\.example\.com\..*A.10\.53\.0\.1' dig.out.test$n > /dev/null && ret=1 +[ $ret -eq 0 ] || echo_i "failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "check that in-zone DNAME records does not return target data when QTYPE is ANY (rd=1/ra=1) ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.2 -t any inzone.dname.example.com > dig.out.test$n || ret=1 +grep 'ANSWER: 2,' dig.out.test$n > /dev/null || ret=1 +grep 'flags: qr aa rd ra;' dig.out.test$n > /dev/null || ret=1 +grep 'dname\.example\.com\..*DNAME.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.dname\.example\.com\..*CNAME.inzone\.example\.com\.' dig.out.test$n > /dev/null || ret=1 +grep 'inzone\.example\.com.*CNAME.a\.example\.com\.' dig.out.test$n > /dev/null && ret=1 +grep 'a\.example\.com.*A.10\.53\.0\.1' dig.out.test$n > /dev/null && ret=1 +[ $ret -eq 0 ] || echo_i "failed" +status=`expr $status + $ret` + n=`expr $n + 1` echo_i "check that CHAOS addresses are compared correctly ($n)" ret=0 diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 81ecc772cbf..c9aa97d1a6e 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -46,3 +46,6 @@ Bug Fixes - ``named`` could crash with an assertion failure if a TCP connection is closed while the request is still processing. [GL #2227] + +- The synthesised CNAME from a DNAME was incorrectly followed when the QTYPE + was CNAME or ANY. [GL #2280] diff --git a/lib/ns/query.c b/lib/ns/query.c index 8e26ff5762f..159122488d9 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -9890,13 +9890,20 @@ query_dname(query_ctx_t *qctx) { } /* - * Switch to the new qname and restart. + * If the original query was not for a CNAME or ANY then follow the + * CNAME. */ - ns_client_qnamereplace(qctx->client, qctx->fname); - qctx->fname = NULL; - qctx->want_restart = true; - if (!WANTRECURSION(qctx->client)) { - qctx->options |= DNS_GETDB_NOLOG; + if (qctx->qtype != dns_rdatatype_cname && + qctx->qtype != dns_rdatatype_any) { + /* + * Switch to the new qname and restart. + */ + ns_client_qnamereplace(qctx->client, qctx->fname); + qctx->fname = NULL; + qctx->want_restart = true; + if (!WANTRECURSION(qctx->client)) { + qctx->options |= DNS_GETDB_NOLOG; + } } query_addauth(qctx); -- 2.47.3