Commit fb756ba3 authored by Mark Andrews's avatar Mark Andrews
Browse files

3703. [func] Prefetch about to expire records if they are queried

                        for, see prefetch option for details. [RT #35041]
parent dc1cfff9
3703. [func] Prefetch about to expire records if they are queried
for, see prefetch option for details. [RT #35041]
3702. [func] 'dnssec-coverage -l' option specifies a length
of time to check for coverage; events further into
the future are ignored. 'dnssec-coverage -z'
......
......@@ -80,6 +80,7 @@ options {\n\
# pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
port 53;\n\
prefetch 2 9;\n\
recursing-file \"named.recursing\";\n\
secroots-file \"named.secroots\";\n\
"
......
......@@ -57,6 +57,7 @@ struct ns_query {
isc_boolean_t isreferral;
isc_mutex_t fetchlock;
dns_fetch_t * fetch;
dns_fetch_t * prefetch;
dns_rpz_st_t * rpz_st;
isc_bufferlist_t namebufs;
ISC_LIST(ns_dbversion_t) activeversions;
......
......@@ -615,6 +615,7 @@ ns_query_init(ns_client_t *client) {
if (result != ISC_R_SUCCESS)
return (result);
client->query.fetch = NULL;
client->query.prefetch = NULL;
client->query.authdb = NULL;
client->query.authzone = NULL;
client->query.authdbset = ISC_FALSE;
......@@ -3786,6 +3787,79 @@ query_resume(isc_task_t *task, isc_event_t *event) {
dns_resolver_destroyfetch(&fetch);
}
static void
prefetch_done(isc_task_t *task, isc_event_t *event) {
dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
ns_client_t *client;
UNUSED(task);
REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
client = devent->ev_arg;
REQUIRE(NS_CLIENT_VALID(client));
REQUIRE(task == client->task);
LOCK(&client->query.fetchlock);
if (client->query.prefetch != NULL) {
INSIST(devent->fetch == client->query.prefetch);
client->query.prefetch = NULL;
}
UNLOCK(&client->query.fetchlock);
if (devent->fetch != NULL)
dns_resolver_destroyfetch(&devent->fetch);
if (devent->node != NULL)
dns_db_detachnode(devent->db, &devent->node);
if (devent->db != NULL)
dns_db_detach(&devent->db);
query_putrdataset(client, &devent->rdataset);
isc_event_free(&event);
ns_client_detach(&client);
}
static void
query_prefetch(ns_client_t *client, dns_name_t *qname,
dns_rdataset_t *rdataset)
{
isc_result_t result;
isc_sockaddr_t *peeraddr;
dns_rdataset_t *tmprdataset;
ns_client_t *dummy = NULL;
if (client->view->prefetch_trigger == 0U ||
rdataset->ttl > client->view->prefetch_trigger ||
(rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
return;
if (client->recursionquota == NULL) {
result = isc_quota_attach(&ns_g_server->recursionquota,
&client->recursionquota);
if (result != ISC_R_SUCCESS)
return;
}
if (client->query.prefetch != NULL)
return;
tmprdataset = query_newrdataset(client);
if (tmprdataset == NULL)
return;
if ((client->attributes & NS_CLIENTATTR_TCP) == 0)
peeraddr = &client->peeraddr;
else
peeraddr = NULL;
ns_client_attach(client, &dummy);
unsigned options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
result = dns_resolver_createfetch2(client->view->resolver,
qname, rdataset->type, NULL, NULL,
NULL, peeraddr, client->message->id,
options, client->task,
prefetch_done, client, tmprdataset,
NULL, &client->query.prefetch);
if (result != ISC_R_SUCCESS) {
query_putrdataset(client, &tmprdataset);
ns_client_detach(&dummy);
}
}
static isc_result_t
query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
dns_name_t *qdomain, dns_rdataset_t *nameservers,
......@@ -7271,6 +7345,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
noqname = rdataset;
else
noqname = NULL;
if (!is_zone && RECURSIONOK(client))
query_prefetch(client, fname, rdataset);
query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
DNS_SECTION_ANSWER);
if (noqname != NULL)
......@@ -7343,6 +7419,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
NULL);
need_wildcardproof = ISC_TRUE;
}
if (!is_zone && RECURSIONOK(client))
query_prefetch(client, fname, rdataset);
query_addrrset(client, &fname, &rdataset, sigrdatasetp, dbuf,
DNS_SECTION_ANSWER);
/*
......@@ -7547,6 +7625,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (rpz_st != NULL)
rdataset->ttl = ISC_MIN(rdataset->ttl,
rpz_st->m.ttl);
if (!is_zone && RECURSIONOK(client))
query_prefetch(client, fname, rdataset);
query_addrrset(client,
fname != NULL ? &fname : &tname,
&rdataset, NULL,
......@@ -7801,9 +7881,12 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
query_filter64(client, &fname, rdataset, dbuf,
DNS_SECTION_ANSWER);
query_putrdataset(client, &rdataset);
} else
} else {
if (!is_zone && RECURSIONOK(client))
query_prefetch(client, fname, rdataset);
query_addrrset(client, &fname, &rdataset,
sigrdatasetp, dbuf, DNS_SECTION_ANSWER);
}
if (noqname != NULL)
query_addnoqnameproof(client, noqname);
......
......@@ -3401,6 +3401,33 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
CHECK(configure_view_acl(vconfig, config, "filter-aaaa", NULL,
actx, ns_g_mctx, &view->aaaa_acl));
#endif
obj = NULL;
result = ns_config_get(maps, "prefetch", &obj);
if (result == ISC_R_SUCCESS) {
const cfg_obj_t *trigger, *eligible;
trigger = cfg_tuple_get(obj, "trigger");
view->prefetch_trigger = cfg_obj_asuint32(trigger);
if (view->prefetch_trigger > 10)
view->prefetch_trigger = 10;
eligible = cfg_tuple_get(obj, "eligible");
if (cfg_obj_isvoid(eligible)) {
int i;
for (i = 1; maps[i] != NULL; i++) {
obj = NULL;
result = ns_config_get(&maps[i],
"prefetch", &obj);
INSIST(result == ISC_R_SUCCESS);
eligible = cfg_tuple_get(obj, "eligible");
if (cfg_obj_isuint32(eligible))
break;
}
INSIST(cfg_obj_isuint32(eligible));
}
view->prefetch_eligible = cfg_obj_asuint32(eligible);
if (view->prefetch_eligible < view->prefetch_trigger + 6)
view->prefetch_eligible = view->prefetch_trigger + 6;
}
obj = NULL;
result = ns_config_get(maps, "dnssec-enable", &obj);
......
......@@ -20,7 +20,9 @@
# Clean up after resolver tests.
#
rm -f */named.memstats
rm -f dig.out dig.*.out.*
rm -f */*.jdb
rm -f dig.out dig.out.*
rm -f dig.*.out.*
rm -f dig.*.foo.*
rm -f dig.*.bar.*
rm -f dig.*.prime.*
......
......@@ -27,3 +27,4 @@ ns A 10.53.0.4
$TTL 5
to-be-removed NS ns.to-be-removed
ns.to-be-removed A 10.53.0.6
fetch 10 TXT A short ttl
......@@ -24,3 +24,4 @@ $TTL 300
)
@ NS ns.tld.
ns A 10.53.0.4
fetch 10 TXT A short ttl
......@@ -16,7 +16,7 @@
/* $Id: named.conf,v 1.4 2011/03/13 23:47:36 tbox Exp $ */
// NS4
// NS5
controls { /* empty */ };
......
......@@ -20,3 +20,4 @@ $TTL 600
@ IN MX 0 mail
ns IN A 10.53.0.6
mail IN A 10.53.0.6
fetch 10 IN TXT A short ttl
......@@ -16,7 +16,7 @@
/* $Id: named.conf,v 1.4 2012/02/09 23:47:18 tbox Exp $ */
// NS4
// NS6
controls { /* empty */ };
......
......@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
// NS4
// NS7
controls { /* empty */ };
......@@ -29,6 +29,7 @@ options {
recursion yes;
empty-zones-enable yes;
disable-empty-zone 20.172.in-addr.arpa;
prefetch 0;
};
key rndc_key {
......
......@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
// NS4
// NS7
controls { /* empty */ };
......@@ -29,6 +29,7 @@ options {
recursion yes;
empty-zones-enable yes;
disable-empty-zone 20.172.in-addr.arpa;
prefetch 0;
};
key rndc_key {
......
......@@ -403,7 +403,6 @@ grep "not subdomain of zone" ns1/named.run > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
#HERE <<<
cp ns7/named2.conf ns7/named.conf
$RNDC -c ../common/rndc.conf -s 10.53.0.7 -p 9953 reconfig 2>&1 | sed 's/^/I:ns7 /'
......@@ -415,7 +414,49 @@ grep "status: NOERROR" dig.ns7.out.${n} > /dev/null || ret=1
grep "ANSWER: 1" dig.ns7.out.${n} > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
#HERE >>>
n=`expr $n + 1`
echo "I:check prefetch (${n})"
ret=0
$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.1.${n} || ret=1
ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 2 }' dig.out.1.${n}`
# sleep so we are in prefetch range
sleep ${ttl1:-0}
# trigger prefetch
$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.2.${n} || ret=1
ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
sleep 1
# check that prefetch occured
$DIG @10.53.0.5 -p 5300 fetch.tld txt > dig.out.3.${n} || ret=1
ttl=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.3.${n}`
test ${ttl:-0} -gt ${ttl2:-1} || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo "I:check prefetch disabled (${n})"
ret=0
$DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.1.${n} || ret=1
ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 1 }' dig.out.1.${n}`
# sleep so we are in expire range
sleep ${ttl1:-0}
# look for zero ttl, allow for one miss at getting zero ttl
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
do
$DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.2.${n} || ret=1
ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
test ${ttl2:-1} -eq 0 && break
sleep 1
done
test ${ttl2:-1} -eq 0 || ret=1
# delay so that any prefetched record will have a lower ttl than expected
sleep 3
# check that prefetch has not occured
$DIG @10.53.0.7 -p 5300 fetch.example.net txt > dig.out.3.${n} || ret=1
ttl=`awk '/"A" "short" "ttl"/ { print $2 - 1 }' dig.out.3.${n}`
test ${ttl:-0} -eq ${ttl1:-1} || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:exit status: $status"
exit $status
......@@ -8736,6 +8736,21 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>prefetch</command></term>
<listitem>
<para>
Specifies the trigger ttl value (range [1..10])
at which prefetch of the current query will be
made and optionally the minimum ttl value that will be
accepted for the records to be candidates for
prefetching. The defaults are 2 and 9 respectively.
Setting a trigger ttl value of 0 will disable
prefetching. A minimum delta of 6 is enforced.
</para>
</listitem>
</varlistentry>
</variablelist>
 
</sect3>
......
......@@ -139,9 +139,9 @@ options {
fake-iquery <boolean>; // obsolete
fetch-glue <boolean>; // obsolete
files <size>;
filter-aaaa { <address_match_element>; ... }; // not configured
filter-aaaa-on-v4 <filter_aaaa>; // not configured
filter-aaaa-on-v6 <filter_aaaa>; // not configured
filter-aaaa { <address_match_element>; ... };
filter-aaaa-on-v4 <filter_aaaa>;
filter-aaaa-on-v6 <filter_aaaa>;
flush-zones-on-shutdown <boolean>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
......@@ -199,6 +199,7 @@ options {
pid-file ( <quoted_string> | none );
port <integer>;
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
query-source <querysource4>;
query-source-v6 <querysource6>;
......@@ -397,9 +398,9 @@ view <string> <optional_class> {
empty-server <string>;
empty-zones-enable <boolean>;
fetch-glue <boolean>; // obsolete
filter-aaaa { <address_match_element>; ... }; // not configured
filter-aaaa-on-v4 <filter_aaaa>; // not configured
filter-aaaa-on-v6 <filter_aaaa>; // not configured
filter-aaaa { <address_match_element>; ... };
filter-aaaa-on-v4 <filter_aaaa>;
filter-aaaa-on-v6 <filter_aaaa>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
| <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
......@@ -446,6 +447,7 @@ view <string> <optional_class> {
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
query-source <querysource4>;
query-source-v6 <querysource6>;
......
......@@ -252,6 +252,7 @@ struct dns_db {
#define DNS_DBADD_FORCE 0x02
#define DNS_DBADD_EXACT 0x04
#define DNS_DBADD_EXACTTTL 0x08
#define DNS_DBADD_PREFETCH 0x10
/*@}*/
/*%
......
......@@ -205,6 +205,7 @@ struct dns_rdataset {
#define DNS_RDATASETATTR_CLOSEST 0x00080000
#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */
#define DNS_RDATASETATTR_NEGATIVE 0x00200000
#define DNS_RDATASETATTR_PREFETCH 0x00400000
/*%
* _OMITDNSSEC:
......
......@@ -87,15 +87,16 @@ typedef struct dns_fetchevent {
/*
* Options that modify how a 'fetch' is done.
*/
#define DNS_FETCHOPT_TCP 0x01 /*%< Use TCP. */
#define DNS_FETCHOPT_UNSHARED 0x02 /*%< See below. */
#define DNS_FETCHOPT_RECURSIVE 0x04 /*%< Set RD? */
#define DNS_FETCHOPT_NOEDNS0 0x08 /*%< Do not use EDNS. */
#define DNS_FETCHOPT_FORWARDONLY 0x10 /*%< Only use forwarders. */
#define DNS_FETCHOPT_NOVALIDATE 0x20 /*%< Disable validation. */
#define DNS_FETCHOPT_EDNS512 0x40 /*%< Advertise a 512 byte
#define DNS_FETCHOPT_TCP 0x001 /*%< Use TCP. */
#define DNS_FETCHOPT_UNSHARED 0x002 /*%< See below. */
#define DNS_FETCHOPT_RECURSIVE 0x004 /*%< Set RD? */
#define DNS_FETCHOPT_NOEDNS0 0x008 /*%< Do not use EDNS. */
#define DNS_FETCHOPT_FORWARDONLY 0x010 /*%< Only use forwarders. */
#define DNS_FETCHOPT_NOVALIDATE 0x020 /*%< Disable validation. */
#define DNS_FETCHOPT_EDNS512 0x040 /*%< Advertise a 512 byte
UDP buffer. */
#define DNS_FETCHOPT_WANTNSID 0x80 /*%< Request NSID */
#define DNS_FETCHOPT_WANTNSID 0x080 /*%< Request NSID */
#define DNS_FETCHOPT_PREFETCH 0x100 /*%< Request NSID */
#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000
#define DNS_FETCHOPT_EDNSVERSIONMASK 0xff000000
......
......@@ -149,6 +149,8 @@ struct dns_view {
isc_boolean_t requestnsid;
dns_ttl_t maxcachettl;
dns_ttl_t maxncachettl;
dns_ttl_t prefetch_trigger;
dns_ttl_t prefetch_eligible;
in_port_t dstport;
dns_aclenv_t aclenv;
dns_rdatatype_t preferred_glue;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment