Merge branch '101-dumpdb-stale-ttl' into 'master'

Resolve "[Support#12071] [RT#46548] Output stale/expired data with 'rndc dumpdb'"

Closes #101

See merge request isc-projects/bind9!1387
This commit is contained in:
Matthijs Mekking 2019-01-31 04:25:20 -05:00
commit dfb2a72e1a
11 changed files with 96 additions and 41 deletions

View file

@ -1,3 +1,7 @@
5149. [func] "rndc dumpdb" now prints a line above a stale RRset
indicating how long the data will be retained in the
cache for emergency use. [GL #101]
5148. [bug] named did not sign the TKEY response. [GL #821]
5147. [bug] dnssec-keymgr: Add a five-minute margin to better

View file

@ -46,6 +46,7 @@ my $A = "ns.example 300 IN A $localaddr";
# Records to be TTL stretched
#
my $TXT = "data.example 1 IN TXT \"A text record with a 1 second ttl\"";
my $LONGTXT = "longttl.example 600 IN TXT \"A text record with a 600 second ttl\"";
my $negSOA = "example 1 IN SOA . . 0 0 0 0 300";
sub reply_handler {
@ -115,6 +116,15 @@ sub reply_handler {
push @auth, $rr;
}
$rcode = "NOERROR";
} elsif ($qname eq "longttl.example") {
if ($qtype eq "TXT") {
my $rr = new Net::DNS::RR($LONGTXT);
push @ans, $rr;
} else {
my $rr = new Net::DNS::RR($negSOA);
push @auth, $rr;
}
$rcode = "NOERROR";
} elsif ($qname eq "nxdomain.example") {
my $rr = new Net::DNS::RR($negSOA);
push @auth, $rr;

View file

@ -14,3 +14,4 @@ rm -f ns3/root.bk
rm -f rndc.out.test*
rm -f */named.run */named.memstats
rm -f ns*/managed-keys.bind*
rm -f ns*/named_dump*

View file

@ -27,8 +27,9 @@ options {
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
dump-file "named_dump1.db";
max-stale-ttl 3600;
stale-answer-ttl 1;
stale-answer-ttl 2;
stale-answer-enable yes;
};

View file

@ -26,9 +26,10 @@ options {
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
dump-file "named_dump1.db";
recursion yes;
max-stale-ttl 7200;
stale-answer-ttl 2;
stale-answer-ttl 3;
stale-answer-enable yes;
};

View file

@ -27,8 +27,8 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
// max-stale-ttl 3600;
// stale-answer-ttl 3;
dump-file "named_dump3.db";
// This configuration has no serve-stale options set.
};
zone "." {

View file

@ -27,10 +27,19 @@ n=0
#$DIG -p ${PORT} @10.53.0.2 ns.example AAAA
#$DIG -p ${PORT} @10.53.0.2 txt enable
#$DIG -p ${PORT} @10.53.0.2 ns.example AAAA
##$DIG -p ${PORT} @10.53.0.2 data.example TXT
#$DIG -p ${PORT} @10.53.0.2 data.example TXT
#$DIG -p ${PORT} @10.53.0.2 nodata.example TXT
#$DIG -p ${PORT} @10.53.0.2 nxdomain.example TXT
n=`expr $n + 1`
echo_i "prime cache longttl.example ($n)"
ret=0
$DIG -p ${PORT} @10.53.0.1 longttl.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "prime cache data.example ($n)"
ret=0
@ -73,7 +82,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: on (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: on (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -83,7 +92,16 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*2.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
# Run rndc dumpdb, test whether the stale data has correct comment printed.
# The max-stale-ttl is 3600 seconds, so the comment should say the data is
# stale for somewhere between 3500-3599 seconds.
$RNDCCMD 10.53.0.1 dumpdb > rndc.out.test$n 2>&1 || ret=1
awk '/; stale/ { x=$0; getline; print x, $0}' ns1/named_dump1.db |
grep "; stale (will be retained for 35.. more seconds) data\.example.*A text record with a 1 second ttl" > /dev/null 2>&1 || ret=1
# Also make sure the not expired data does not have a stale comment.
awk '/; answer/ { x=$0; getline; print x, $0}' ns1/named_dump1.db |
grep "; answer longttl\.example.*A text record with a 600 second ttl" > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -93,7 +111,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -103,7 +121,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -118,7 +136,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: off (rndc) (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: off (rndc) (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -159,7 +177,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: on (rndc) (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: on (rndc) (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -169,7 +187,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*2.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -179,7 +197,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -189,7 +207,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -204,7 +222,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: off (rndc) (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: off (rndc) (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -243,7 +261,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: on (rndc) (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: on (rndc) (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -253,7 +271,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*2.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -263,7 +281,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -273,7 +291,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -295,7 +313,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: on (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: on (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -305,7 +323,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*2.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -315,7 +333,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -325,7 +343,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*2.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -340,7 +358,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: off (rndc) (stale-answer-ttl=1 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
grep '_default: off (rndc) (stale-answer-ttl=2 max-stale-ttl=3600)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -362,7 +380,7 @@ n=`expr $n + 1`
echo_i "check 'rndc serve-stale status' ($n)"
ret=0
$RNDCCMD 10.53.0.1 serve-stale status > rndc.out.test$n 2>&1 || ret=1
grep '_default: off (rndc) (stale-answer-ttl=2 max-stale-ttl=7200)' rndc.out.test$n > /dev/null || ret=1
grep '_default: off (rndc) (stale-answer-ttl=3 max-stale-ttl=7200)' rndc.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -408,7 +426,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*1.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -418,7 +436,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*1.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -428,7 +446,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*1.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -499,7 +517,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 data.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "data\.example\..*1.*IN.*TXT.*A text record with a 1 second ttl" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -509,7 +527,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 nodata.example TXT > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*1.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -519,7 +537,7 @@ ret=0
$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 0," dig.out.test$n > /dev/null || ret=1
grep "example.*1.*IN" dig.out.test$n > /dev/null || ret=1
grep "example\..*1.*IN.*SOA" dig.out.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`

View file

@ -108,6 +108,7 @@ struct dns_rdataset {
unsigned int magic; /* XXX ? */
dns_rdatasetmethods_t * methods;
ISC_LINK(dns_rdataset_t) link;
/*
* XXX do we need these, or should they be retrieved by methods?
* Leaning towards the latter, since they are not frequently required
@ -116,12 +117,19 @@ struct dns_rdataset {
dns_rdataclass_t rdclass;
dns_rdatatype_t type;
dns_ttl_t ttl;
/*
* Stale ttl is used to see how long this RRset can still be used
* to serve to clients, after the TTL has expired.
*/
dns_ttl_t stale_ttl;
dns_trust_t trust;
dns_rdatatype_t covers;
/*
* attributes
*/
unsigned int attributes;
/*%
* the counter provides the starting point in the "cyclic" order.
* The value UINT32_MAX has a special meaning of "picking up a
@ -129,11 +137,13 @@ struct dns_rdataset {
* increment the counter.
*/
uint32_t count;
/*
* This RRSIG RRset should be re-generated around this time.
* Only valid if DNS_RDATASETATTR_RESIGN is set in attributes.
*/
isc_stdtime_t resign;
/*@{*/
/*%
* These are for use by the rdataset implementation, and MUST NOT

View file

@ -81,6 +81,9 @@ struct dns_master_style {
*/
#define DNS_TOTEXT_LINEBREAK_MAXLEN 100
/*% Does the rdataset 'r' contain a stale answer? */
#define STALE(r) (((r)->attributes & DNS_RDATASETATTR_STALE) != 0)
/*%
* Context structure for a masterfile dump in progress.
*/
@ -1040,8 +1043,12 @@ dump_rdatasets_text(isc_mem_t *mctx, const dns_name_t *name,
/* Omit negative cache entries */
} else {
isc_result_t result;
if (rds->ttl < ctx->serve_stale_ttl)
fprintf(f, "; stale\n");
if (STALE(rds)) {
fprintf(f, "; stale (will be retained for "
"%u more seconds)\n",
(rds->stale_ttl -
ctx->serve_stale_ttl));
}
result = dump_rdataset(mctx, name, rds, ctx, buffer, f);
if (result != ISC_R_SUCCESS)
dumpresult = result;
@ -1509,13 +1516,14 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
dctx->do_date = dns_db_iscache(dctx->db);
if (dctx->do_date) {
/*
* Adjust the date backwards by the serve-stale TTL, if any.
* This is so the TTL will be loaded correctly when next started.
*/
(void)dns_db_getservestalettl(dctx->db,
&dctx->tctx.serve_stale_ttl);
dctx->now -= dctx->tctx.serve_stale_ttl;
/*
* Adjust the date backwards by the serve-stale TTL, if any.
* This is so the TTL will be loaded correctly when next
* started.
*/
(void)dns_db_getservestalettl(dctx->db,
&dctx->tctx.serve_stale_ttl);
dctx->now -= dctx->tctx.serve_stale_ttl;
}
if (dctx->format == dns_masterformat_text &&

View file

@ -2979,6 +2979,8 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
if (STALE(header)) {
rdataset->attributes |= DNS_RDATASETATTR_STALE;
rdataset->stale_ttl =
(rbtdb->serve_stale_ttl + header->rdh_ttl) - now;
rdataset->ttl = 0;
}
rdataset->private1 = rbtdb;

View file

@ -149,7 +149,7 @@ do { \
#define NOQNAME(r) (((r)->attributes & \
DNS_RDATASETATTR_NOQNAME) != 0)
/*% Does the rdataset 'r' contains a stale answer? */
/*% Does the rdataset 'r' contain a stale answer? */
#define STALE(r) (((r)->attributes & \
DNS_RDATASETATTR_STALE) != 0)