From: Mark Andrews Date: Thu, 26 May 2016 23:59:46 +0000 (+1000) Subject: 4377. [bug] Don't reuse zero TTL responses beyond the current X-Git-Tag: v9.11.0a3~37 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=aabcb1fde0ca255ff30f0a5c10cbd39f798cc5b7;p=thirdparty%2Fbind9.git 4377. [bug] Don't reuse zero TTL responses beyond the current client set (excludes ANY/SIG/RRSIG queries). [RT #42142] --- diff --git a/CHANGES b/CHANGES index e69d2f8d5df..c7e451091f7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4377. [bug] Don't reuse zero TTL responses beyond the current + client set (excludes ANY/SIG/RRSIG queries). + [RT #42142] + 4376. [experimental] Added support for Catalog Zones, a new method for provisioning secondary servers in which a list of zones to be served is stored in a DNS zone and can diff --git a/bin/named/query.c b/bin/named/query.c index 88d14ad0812..20e99edc777 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -8065,6 +8065,38 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) goto cleanup; case DNS_R_CNAME: + /* + * If we have a zero ttl from the cache refetch it. + */ + if (!is_zone && event == NULL && rdataset->ttl == 0 && + RECURSIONOK(client)) + { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + INSIST(!REDIRECT(client)); + result = query_recurse(client, qtype, + client->query.qname, + NULL, NULL, resuming); + if (result == ISC_R_SUCCESS) { + client->query.attributes |= + NS_QUERYATTR_RECURSING; + if (dns64) + client->query.attributes |= + NS_QUERYATTR_DNS64; + if (dns64_exclude) + client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } else + RECURSE_ERROR(result); + goto cleanup; + } + /* * Keep a copy of the rdataset. We have to do this because * query_addrrset may clear 'rdataset' (to prevent the @@ -8505,6 +8537,38 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * we know the answer. */ + /* + * If we have a zero ttl from the cache refetch it. + */ + if (!is_zone && event == NULL && rdataset->ttl == 0 && + RECURSIONOK(client)) + { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); + if (sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + + INSIST(!REDIRECT(client)); + result = query_recurse(client, qtype, + client->query.qname, + NULL, NULL, resuming); + if (result == ISC_R_SUCCESS) { + client->query.attributes |= + NS_QUERYATTR_RECURSING; + if (dns64) + client->query.attributes |= + NS_QUERYATTR_DNS64; + if (dns64_exclude) + client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } else + RECURSE_ERROR(result); + goto cleanup; + } + #ifdef ALLOW_FILTER_AAAA /* * Optionally hide AAAAs from IPv4 clients if there is an A. diff --git a/bin/tests/system/zero/ans5/ans.pl b/bin/tests/system/zero/ans5/ans.pl new file mode 100644 index 00000000000..9dfa18e4443 --- /dev/null +++ b/bin/tests/system/zero/ans5/ans.pl @@ -0,0 +1,81 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2015 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 +# 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. + +# +# Don't respond if the "norespond" file exists; otherwise respond to +# any A or AAAA query. +# + +use IO::File; +use IO::Socket; +use Net::DNS; +use Net::DNS::Packet; + +my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.5", + LocalPort => 5300, Proto => "udp") or die "$!"; + +my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; +print $pidf "$$\n" or die "cannot write pid file: $!"; +$pidf->close or die "cannot close pid file: $!"; +sub rmpid { unlink "ans.pid"; exit 1; }; + +$SIG{INT} = \&rmpid; +$SIG{TERM} = \&rmpid; + +my $octet = 0; + +for (;;) { + $sock->recv($buf, 512); + + print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n"; + + my $packet; + + if ($Net::DNS::VERSION > 0.68) { + $packet = new Net::DNS::Packet(\$buf, 0); + $@ and die $@; + } else { + my $err; + ($packet, $err) = new Net::DNS::Packet(\$buf, 0); + $err and die $err; + } + + print "REQUEST:\n"; + $packet->print; + + $packet->header->qr(1); + + my @questions = $packet->question; + my $qname = $questions[0]->qname; + my $qtype = $questions[0]->qtype; + + $packet->header->aa(1); + if ($qtype eq "A") { + $packet->push("answer", + new Net::DNS::RR($qname . + " 0 A 192.0.2." . $octet)); + $octet = $octet + 1; + } elsif ($qtype eq "AAAA") { + $packet->push("answer", + new Net::DNS::RR($qname . + " 300 AAAA 2001:db8:beef::1")); + } + + $sock->send($packet->data); + print "RESPONSE:\n"; + $packet->print; + print "\n"; +} diff --git a/bin/tests/system/zero/ns1/root.db b/bin/tests/system/zero/ns1/root.db index 69aca86fb85..beb97cb693e 100644 --- a/bin/tests/system/zero/ns1/root.db +++ b/bin/tests/system/zero/ns1/root.db @@ -22,3 +22,5 @@ example. NS ns2.example. ns2.example. A 10.53.0.2 example. NS ns4.example. ns4.example. A 10.53.0.4 +increment. NS incrementns. +incrementns A 10.53.0.5 diff --git a/bin/tests/system/zero/tests.sh b/bin/tests/system/zero/tests.sh index 15c2906a928..bbb78f0fd82 100644 --- a/bin/tests/system/zero/tests.sh +++ b/bin/tests/system/zero/tests.sh @@ -44,5 +44,18 @@ done if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:check repeated recursive lookups of non recurring zero ttl responses get new values" +count=`( +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +dig +short -p 5300 @10.53.0.3 foo.increment +) | sort -u | wc -l ` +if [ $count -ne 7 ] ; then echo "I:failed (count=$count)"; ret=1; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status