Commit a8783019 authored by Evan Hunt's avatar Evan Hunt

[master] servfail cache

3943.	[func]		SERVFAIL responses can now be cached for a
			limited time (configured by "servfail-ttl",
			default 10 seconds, limit 30). This can reduce
			the frequency of retries when an authoritative
			server is known to be failing, e.g., due to
			ongoing DNSSEC validation problems. [RT #21347]
parent bb70b45c
3943. [func] SERVFAIL responses can now be cached for a
limited time (configured by "servfail-ttl",
default 10 seconds, limit 30). This can reduce
the frequency of retries when an authoritative
server is known to be failing, e.g., due to
ongoing DNSSEC validation problems. [RT #21347]
3942. [bug] Wildcard responses from a optout range should be
marked as insecure. [RT #37072]
......
......@@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: client.c,v 1.286 2012/01/31 23:47:30 tbox Exp $ */
#include <config.h>
#include <isc/formatcheck.h>
......@@ -40,6 +38,7 @@
#include <isc/hmacsha.h>
#endif
#include <dns/badcache.h>
#include <dns/db.h>
#include <dns/dispatch.h>
#include <dns/events.h>
......@@ -1351,16 +1350,16 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
}
message->rcode = rcode;
/*
* FORMERR loop avoidance: If we sent a FORMERR message
* with the same ID to the same client less than two
* seconds ago, assume that we are in an infinite error
* packet dialog with a server for some protocol whose
* error responses look enough like DNS queries to
* elicit a FORMERR response. Drop a packet to break
* the loop.
*/
if (rcode == dns_rcode_formerr) {
/*
* FORMERR loop avoidance: If we sent a FORMERR message
* with the same ID to the same client less than two
* seconds ago, assume that we are in an infinite error
* packet dialog with a server for some protocol whose
* error responses look enough like DNS queries to
* elicit a FORMERR response. Drop a packet to break
* the loop.
*/
if (isc_sockaddr_equal(&client->peeraddr,
&client->formerrcache.addr) &&
message->id == client->formerrcache.id &&
......@@ -1376,6 +1375,27 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
client->formerrcache.addr = client->peeraddr;
client->formerrcache.time = client->requesttime;
client->formerrcache.id = message->id;
} else if (rcode == dns_rcode_servfail &&
client->view != NULL && client->view->fail_ttl != 0 &&
((client->attributes & NS_CLIENTATTR_NOSETFC) == 0))
{
/*
* SERVFAIL caching: store qname/qtype of failed queries
*/
isc_time_t expire;
isc_interval_t i;
isc_uint32_t flags = 0;
if ((message->flags & DNS_MESSAGEFLAG_CD) != 0)
flags = NS_FAILCACHE_CD;
isc_interval_set(&i, client->view->fail_ttl, 0);
result = isc_time_nowplusinterval(&expire, &i);
if (result == ISC_R_SUCCESS)
dns_badcache_add(client->view->failcache,
client->query.qname,
client->query.qtype,
ISC_TRUE, flags, &expire);
}
ns_client_send(client);
}
......@@ -2009,6 +2029,7 @@ client_request(isc_task_t *task, isc_event_t *event) {
isc_task_getcurrenttime(task, &client->requesttime);
client->now = client->requesttime;
isc_time_set(&client->tnow, client->now, 0);
if (result != ISC_R_SUCCESS) {
if (TCP_CLIENT(client)) {
......
......@@ -155,6 +155,7 @@ options {\n\
cleaning-interval 0; /* now meaningless */\n\
min-roots 2;\n\
lame-ttl 600;\n\
servfail-ttl 10;\n\
max-ncache-ttl 10800; /* 3 hours */\n\
max-cache-ttl 604800; /* 1 week */\n\
transfer-format many-answers;\n\
......
......@@ -131,6 +131,7 @@ struct ns_client {
ns_query_t query;
isc_stdtime_t requesttime;
isc_stdtime_t now;
isc_time_t tnow;
dns_name_t signername; /*%< [T]SIG key name */
dns_name_t * signer; /*%< NULL if not valid sig */
isc_boolean_t mortal; /*%< Die after handling request */
......@@ -195,6 +196,16 @@ typedef ISC_LIST(ns_client_t) client_list_t;
#define NS_CLIENTATTR_WANTOPT 0x2000 /*%< add opt to reply */
#define NS_CLIENTATTR_HAVEECS 0x4000 /*%< sent an ECS option */
#define NS_CLIENTATTR_NOSETFC 0x4000 /*%< don't set servfail cache */
/*
* Flag to use with the SERVFAIL cache to indicate
* that a query had the CD bit set.
*/
#define NS_FAILCACHE_CD 0x01
extern unsigned int ns_client_requests;
/***
......
......@@ -48,6 +48,7 @@ struct ns_query {
isc_boolean_t timerset;
dns_name_t * qname;
dns_name_t * origqname;
dns_rdatatype_t qtype;
unsigned int dboptions;
unsigned int fetchoptions;
dns_db_t * gluedb;
......@@ -88,7 +89,6 @@ struct ns_query {
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000
#define NS_QUERYATTR_RRL_CHECKED 0x10000
isc_result_t
ns_query_init(ns_client_t *client);
......
......@@ -29,6 +29,7 @@
#include <isc/util.h>
#include <dns/adb.h>
#include <dns/badcache.h>
#include <dns/byaddr.h>
#include <dns/cache.h>
#include <dns/db.h>
......@@ -152,6 +153,8 @@
#define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0)
#define SFCACHE_CDFLAG 0x1
typedef struct client_additionalctx {
ns_client_t *client;
dns_rdataset_t *rdataset;
......@@ -6159,6 +6162,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
isc_boolean_t associated;
dns_section_t section;
dns_ttl_t ttl;
isc_boolean_t failcache;
isc_uint32_t flags;
CTRACE(ISC_LOG_DEBUG(3), "query_find");
......@@ -6291,7 +6296,39 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
/*
* Not returning from recursion.
*/
*
* First, check for a recent match in the view's SERVFAIL cache.
* If we find one, and it was from a query with CD=1, *or*
* if the current query has CD=0, then we can just return
* SERVFAIL now.
*/
flags = 0;
failcache = dns_badcache_find(client->view->failcache,
client->query.qname, qtype,
&flags, &client->tnow);
if (failcache && (((flags & NS_FAILCACHE_CD) != 0) ||
((client->message->flags & DNS_MESSAGEFLAG_CD) == 0)))
{
if (isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(1))) {
char namebuf[DNS_NAME_FORMATSIZE];
char typename[DNS_RDATATYPE_FORMATSIZE];
dns_name_format(client->query.qname,
namebuf, sizeof(namebuf));
dns_rdatatype_format(qtype,
typename, sizeof(typename));
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(1),
"servfail cache hit %s/%s (%s)",
namebuf, typename,
((flags & NS_FAILCACHE_CD) != 0)
? "CD=1"
: "CD=0");
}
client->attributes |= NS_CLIENTATTR_NOSETFC;
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
/*
* If it's a SIG query, we'll iterate the node.
......@@ -8394,7 +8431,7 @@ ns_query_start(ns_client_t *client) {
*/
rdataset = ISC_LIST_HEAD(client->query.qname->list);
INSIST(rdataset != NULL);
qtype = rdataset->type;
client->query.qtype = qtype = rdataset->type;
dns_rdatatypestats_increment(ns_g_server->rcvquerystats, qtype);
if (dns_rdatatype_ismeta(qtype)) {
......
......@@ -64,6 +64,7 @@
#include <dns/acache.h>
#include <dns/adb.h>
#include <dns/badcache.h>
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/dispatch.h>
......@@ -2349,7 +2350,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
size_t max_cache_size;
size_t max_acache_size;
size_t max_adb_size;
isc_uint32_t lame_ttl;
isc_uint32_t lame_ttl, fail_ttl;
dns_tsig_keyring_t *ring = NULL;
dns_view_t *pview = NULL; /* Production view */
isc_mem_t *cmctx = NULL, *hmctx = NULL;
......@@ -3784,6 +3785,17 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
goto cleanup;
}
/*
* Set the servfail-ttl.
*/
obj = NULL;
result = ns_config_get(maps, "servfail-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
fail_ttl = cfg_obj_asuint32(obj);
if (fail_ttl > 300)
fail_ttl = 300;
dns_view_setfailttl(view, fail_ttl);
result = ISC_R_SUCCESS;
cleanup:
......@@ -7657,6 +7669,8 @@ dumpdone(void *arg, isc_result_t result) {
dns_adb_dump(dctx->view->view->adb, dctx->fp);
dns_resolver_printbadcache(dctx->view->view->resolver,
dctx->fp);
dns_badcache_print(dctx->view->view->failcache,
"SERVFAIL cache", dctx->fp);
dns_db_detach(&dctx->cache);
}
if (dctx->dumpzones) {
......
......@@ -540,9 +540,9 @@
<term><userinput>flushname</userinput> <replaceable>name</replaceable> <optional><replaceable>view</replaceable></optional> </term>
<listitem>
<para>
Flushes the given name from the server's DNS cache
and, if applicable, from the server's nameserver address
database or bad-server cache.
Flushes the given name from the view's DNS cache
and, if applicable, from the view's nameserver address
database, bad server cache and SERVFAIL cache.
</para>
</listitem>
</varlistentry>
......@@ -552,8 +552,8 @@
<listitem>
<para>
Flushes the given name, and all of its subdomains,
from the server's DNS cache, the address database,
and the bad server cache.
from the view's DNS cache, address database,
bad server cache, and SERVFAIL cache.
</para>
</listitem>
</varlistentry>
......
......@@ -70,9 +70,10 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
dname dns64 dnssec dsdigest dscp ecdsa emptyzones filter-aaaa
formerr forward geoip glue gost ixfr inline limits logfileconfig
lwresd masterfile masterformat metadata notify nslookup nsupdate
pending @PKCS11_TEST@ redirect resolver rndc rpz rrl rrchecker
rrsetorder rsabigexponent sit smartsign sortlist spf staticstub
statistics stub tkey tsig tsiggss unknown upforwd verify
pending @PKCS11_TEST@
redirect resolver rndc rpz rrl rrchecker rrsetorder rsabigexponent
sit sfcache smartsign sortlist spf staticstub statistics stub
tkey tsig tsiggss unknown upforwd verify
views wildcard xfer xferquota zero zonechecks"
# Use the CONFIG_SHELL detected by configure for tests
......
......@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: named.conf.post,v 1.2 2011/10/12 00:10:19 marka Exp $ */
// NS5
include "../../common/rndc.key";
......@@ -33,6 +31,7 @@ options {
recursion no;
notify yes;
notify-delay 0;
servfail-ttl 0;
};
zone "bits" {
......
......@@ -614,6 +614,7 @@ done
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
ret=0
n=`expr $n + 1`
echo "I:checking turning on of inline signing in a slave zone via reload ($n)"
$DIG $DIGOPTS @10.53.0.5 -p 5300 +dnssec bits SOA > dig.out.ns5.test$n
......
Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
The test setup for the SERVFAIL ncache tests has a secure root.
ns1 is the root server.
ns2 is an authoritative server for the various test domains.
ns5 is a caching-only server, configured with the an incorrect trusted
key for the root. It is used for testing failure cases.
#!/bin/sh
#
# Copyright (C) 2014 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.
rm -f */K*.key */K*.private */*.signed */*.db */dsset-*
rm -f */managed.conf */trusted.conf
rm -f random.data
rm -f */named.memstats
rm -f dig.*
rm -f sfcache.*
/*
* Copyright (C) 2014 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.
*/
// NS1
controls { /* empty */ };
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
notify yes;
dnssec-enable yes;
dnssec-validation yes;
};
zone "." {
type master;
file "root.db.signed";
};
include "trusted.conf";
; Copyright (C) 2014 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.
$TTL 300
. IN SOA gson.nominum.com. a.root.servers.nil. (
2000042100 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1
example. NS ns2.example.
ns2.example. A 10.53.0.2
#!/bin/sh -e
#
# Copyright (C) 2014 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.
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
RANDFILE=../random.data
zone=.
infile=root.db.in
zonefile=root.db
(cd ../ns2 && sh sign.sh )
cp ../ns2/dsset-example. .
keyname=`$KEYGEN -q -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone`
cat $infile $keyname.key > $zonefile
$SIGNER -P -g -r $RANDFILE -o $zone $zonefile > /dev/null
# Configure the resolving server with a trusted key.
cat $keyname.key | grep -v '^; ' | $PERL -n -e '
local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
local $key = join("", @rest);
print <<EOF
trusted-keys {
"$dn" $flags $proto $alg "$key";
};
EOF
' > trusted.conf
# ...or with a managed key.
cat $keyname.key | grep -v '^; ' | $PERL -n -e '
local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
local $key = join("", @rest);
print <<EOF
managed-keys {
"$dn" initial-key $flags $proto $alg "$key";
};
EOF
' > managed.conf
cp trusted.conf ../ns2/trusted.conf
; Copyright (C) 2014 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.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2000042407 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
NS ns3
ns2 A 10.53.0.2
ns3 A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
d A 10.0.0.4
; Used for testing ANY queries
foo TXT "testing"
foo A 10.0.1.0
bad-cname CNAME a
bad-dname DNAME @
; Used for testing CNAME queries
cname1 CNAME cname1-target
cname1-target TXT "testing cname"
cname2 CNAME cname2-target
cname2-target TXT "testing cname"
; Used for testing DNAME queries
dname1 DNAME dname1-target
foo.dname1-target TXT "testing dname"
dname2 DNAME dname2-target
foo.dname2-target TXT "testing dname"
; A secure subdomain
secure NS ns.secure
ns.secure A 10.53.0.3
; An insecure subdomain
insecure NS ns.insecure
ns.insecure A 10.53.0.3
; A secure subdomain we're going to inject bogus data into
bogus NS ns.bogus
ns.bogus A 10.53.0.3
; A dynamic secure subdomain
dynamic NS dynamic
dynamic A 10.53.0.3
; A insecure subdomain
mustbesecure NS ns.mustbesecure
ns.mustbesecure A 10.53.0.3
; A rfc2535 signed zone w/ CNAME
rfc2535 NS ns.rfc2535
ns.rfc2535 A 10.53.0.3
z A 10.0.0.26
keyless NS ns.keyless
ns.keyless A 10.53.0.3
nsec3 NS ns.nsec3
ns.nsec3 A 10.53.0.3
optout NS ns.optout
ns.optout A 10.53.0.3
nsec3-unknown NS ns.nsec3-unknown
ns.nsec3-unknown A 10.53.0.3
optout-unknown NS ns.optout-unknown
ns.optout-unknown A 10.53.0.3
multiple NS ns.multiple
ns.multiple A 10.53.0.3
*.wild A 10.0.0.27
rsasha256 NS ns.rsasha256
ns.rsasha256 A 10.53.0.3
rsasha512 NS ns.rsasha512
ns.rsasha512 A 10.53.0.3
kskonly NS ns.kskonly
ns.kskonly A 10.53.0.3
/*
* Copyright (C) 2014 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.
*/
// NS2
controls { /* empty */ };
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };