mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch '3678-serve-stale-servfailing-unexpectedly-v9_18' into 'v9_18'
[9.18] Resolve "stale-serve and RPZ put in SERVFAIL cache unexpected record" See merge request isc-projects/bind9!7310
This commit is contained in:
commit
815ac08a26
5 changed files with 122 additions and 2 deletions
5
CHANGES
5
CHANGES
|
|
@ -1,3 +1,8 @@
|
|||
6059. [bug] In some serve stale scenarios, like when following an
|
||||
expired CNAME record, named could return SERVFAIL if the
|
||||
previous request wasn't successful. Consider non-stale
|
||||
data when in serve-stale mode. [GL #3678]
|
||||
|
||||
6058. [bug] Prevent named from crashing when "rndc delzone"
|
||||
attempts to delete a zone added by a catalog zone.
|
||||
[GL #3745]
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ my $CAA = "othertype.example 2 IN CAA 0 issue \"ca1.example.net\"";
|
|||
my $negSOA = "example 2 IN SOA . . 0 0 0 0 300";
|
||||
my $CNAME = "cname.example 7 IN CNAME target.example";
|
||||
my $TARGET = "target.example 9 IN A $localaddr";
|
||||
my $SHORTCNAME = "shortttl.cname.example 1 IN CNAME longttl.target.example";
|
||||
my $LONGTARGET = "longttl.target.example 600 IN A $localaddr";
|
||||
|
||||
sub reply_handler {
|
||||
my ($qname, $qclass, $qtype) = @_;
|
||||
|
|
@ -166,6 +168,28 @@ sub reply_handler {
|
|||
push @auth, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "shortttl.cname.example") {
|
||||
if ($qtype eq "A") {
|
||||
my $rr = new Net::DNS::RR($SHORTCNAME);
|
||||
push @ans, $rr;
|
||||
} else {
|
||||
my $rr = new Net::DNS::RR($negSOA);
|
||||
push @auth, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "longttl.target.example") {
|
||||
if ($slow_response) {
|
||||
print " Sleeping 3 seconds\n";
|
||||
sleep(3);
|
||||
}
|
||||
if ($qtype eq "A") {
|
||||
my $rr = new Net::DNS::RR($LONGTARGET);
|
||||
push @ans, $rr;
|
||||
} else {
|
||||
my $rr = new Net::DNS::RR($negSOA);
|
||||
push @auth, $rr;
|
||||
}
|
||||
$rcode = "NOERROR";
|
||||
} elsif ($qname eq "longttl.example") {
|
||||
if ($qtype eq "TXT") {
|
||||
my $rr = new Net::DNS::RR($LONGTXT);
|
||||
|
|
|
|||
|
|
@ -1829,6 +1829,80 @@ grep "data\.example\..*[12].*IN.*TXT.*A text record with a 2 second ttl" dig.out
|
|||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status+ret))
|
||||
|
||||
##############################################################
|
||||
# Test for stale-answer-client-timeout off and CNAME record. #
|
||||
##############################################################
|
||||
echo_i "test stale-answer-client-timeout (0) and CNAME record"
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "prime cache shortttl.cname.example (stale-answer-client-timeout off) ($n)"
|
||||
ret=0
|
||||
$DIG -p ${PORT} @10.53.0.3 shortttl.cname.example A > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "ANSWER: 2," dig.out.test$n > /dev/null || ret=1
|
||||
grep "shortttl\.cname\.example\..*1.*IN.*CNAME.*longttl\.target\.example\." dig.out.test$n > /dev/null || ret=1
|
||||
grep "longttl\.target\.example\..*600.*IN.*A.*10\.53\.0\.2" dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status+ret))
|
||||
|
||||
# Allow RRset to become stale.
|
||||
sleep 1
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "disable responses from authoritative server ($n)"
|
||||
ret=0
|
||||
$DIG -p ${PORT} @10.53.0.2 txt disable > dig.out.test$n
|
||||
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
|
||||
grep "TXT.\"0\"" dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
ret=0
|
||||
echo_i "check stale shortttl.cname.example comes from cache (stale-answer-client-timeout off) ($n)"
|
||||
nextpart ns3/named.run > /dev/null
|
||||
$DIG -p ${PORT} @10.53.0.3 shortttl.cname.example A > dig.out.test$n
|
||||
wait_for_log 5 "shortttl.cname.example resolver failure, stale answer used" ns3/named.run || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n > /dev/null || ret=1
|
||||
grep "ANSWER: 2," dig.out.test$n > /dev/null || ret=1
|
||||
grep "shortttl\.cname\.example\..*3.*IN.*CNAME.*longttl\.target\.example\." dig.out.test$n > /dev/null || ret=1
|
||||
# We can't reliably test the TTL of the longttl.target.example A record.
|
||||
grep "longttl\.target\.example\..*IN.*A.*10\.53\.0\.2" dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "enable responses from authoritative server ($n)"
|
||||
ret=0
|
||||
$DIG -p ${PORT} @10.53.0.2 txt enable > dig.out.test$n
|
||||
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
|
||||
grep "TXT.\"1\"" dig.out.test$n > /dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "check server is alive or restart ($n)"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.3 status > rndc.out.test$n 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "failed"
|
||||
echo_i "restart ns3"
|
||||
start_server --noclean --restart --port ${PORT} serve-stale ns3
|
||||
fi
|
||||
status=$((status+ret))
|
||||
|
||||
n=$((n+1))
|
||||
echo_i "check server is alive or restart ($n)"
|
||||
ret=0
|
||||
$RNDCCMD 10.53.0.3 status > rndc.out.test$n 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "failed"
|
||||
echo_i "restart ns3"
|
||||
start_server --noclean --restart --port ${PORT} serve-stale ns3
|
||||
fi
|
||||
status=$((status+ret))
|
||||
|
||||
#############################################
|
||||
# Test for stale-answer-client-timeout 0. #
|
||||
#############################################
|
||||
|
|
|
|||
|
|
@ -156,6 +156,11 @@ struct dns_rdataset {
|
|||
*
|
||||
* \def DNS_RDATASETATTR_LOADORDER
|
||||
* Output the RRset in load order.
|
||||
*
|
||||
* \def DNS_RDATASETATTR_STALE_ADDED
|
||||
* Set on rdatasets that were added during a stale-answer-client-timeout
|
||||
* lookup. In other words, the RRset was added during a lookup of stale
|
||||
* data and does not necessarily mean that the rdataset itself is stale.
|
||||
*/
|
||||
|
||||
#define DNS_RDATASETATTR_NONE 0x00000000 /*%< No ordering. */
|
||||
|
|
|
|||
|
|
@ -5866,6 +5866,7 @@ query_lookup(query_ctx_t *qctx) {
|
|||
dns_ttl_t stale_refresh = 0;
|
||||
bool dbfind_stale = false;
|
||||
bool stale_timeout = false;
|
||||
bool answer_found = false;
|
||||
bool stale_found = false;
|
||||
bool stale_refresh_window = false;
|
||||
uint16_t ede = 0;
|
||||
|
|
@ -5973,6 +5974,14 @@ query_lookup(query_ctx_t *qctx) {
|
|||
*/
|
||||
stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
|
||||
|
||||
if (dns_rdataset_isassociated(qctx->rdataset) &&
|
||||
dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
|
||||
{
|
||||
/* Found non-stale usable rdataset. */
|
||||
answer_found = true;
|
||||
goto gotanswer;
|
||||
}
|
||||
|
||||
if (dbfind_stale || stale_refresh_window || stale_timeout) {
|
||||
dns_name_format(qctx->client->query.qname, namebuf,
|
||||
sizeof(namebuf));
|
||||
|
|
@ -6099,7 +6108,8 @@ query_lookup(query_ctx_t *qctx) {
|
|||
}
|
||||
}
|
||||
|
||||
if (stale_timeout && stale_found) {
|
||||
gotanswer:
|
||||
if (stale_timeout && (answer_found || stale_found)) {
|
||||
/*
|
||||
* Mark RRsets that we are adding to the client message on a
|
||||
* lookup during 'stale-answer-client-timeout', so we can
|
||||
|
|
@ -9592,7 +9602,9 @@ query_nxdomain(query_ctx_t *qctx, isc_result_t res) {
|
|||
{
|
||||
ttl = 0;
|
||||
}
|
||||
if (!qctx->nxrewrite || qctx->rpz_st->m.rpz->addsoa) {
|
||||
if (!qctx->nxrewrite ||
|
||||
(qctx->rpz_st != NULL && qctx->rpz_st->m.rpz->addsoa))
|
||||
{
|
||||
result = query_addsoa(qctx, ttl, section);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
QUERY_ERROR(qctx, result);
|
||||
|
|
|
|||
Loading…
Reference in a new issue