From: Mark Andrews Date: Sun, 12 Jan 2014 10:29:15 +0000 (+1100) Subject: 3703. [func] Prefetch about to expire records if they are queried X-Git-Tag: v9.10.0a2~108 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=fb756ba3047770957173ba546257ca43af7ba3e4;p=thirdparty%2Fbind9.git 3703. [func] Prefetch about to expire records if they are queried for, see prefetch option for details. [RT #35041] --- diff --git a/CHANGES b/CHANGES index 5014103180e..fccec231a63 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +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' diff --git a/bin/named/config.c b/bin/named/config.c index d3a2ed90435..8d4498c7707 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -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\ " diff --git a/bin/named/include/named/query.h b/bin/named/include/named/query.h index a14d5169c70..7843e8ffe60 100644 --- a/bin/named/include/named/query.h +++ b/bin/named/include/named/query.h @@ -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; diff --git a/bin/named/query.c b/bin/named/query.c index 47766917c2d..514c2ebbaac 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -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); diff --git a/bin/named/server.c b/bin/named/server.c index 0b427cd71b6..ac423fcd3e2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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); diff --git a/bin/tests/system/resolver/clean.sh b/bin/tests/system/resolver/clean.sh index 53171208642..5a0c8fcdd86 100644 --- a/bin/tests/system/resolver/clean.sh +++ b/bin/tests/system/resolver/clean.sh @@ -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.* diff --git a/bin/tests/system/resolver/ns4/tld1.db b/bin/tests/system/resolver/ns4/tld1.db index a2f55984d9b..3c28f42167d 100644 --- a/bin/tests/system/resolver/ns4/tld1.db +++ b/bin/tests/system/resolver/ns4/tld1.db @@ -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 diff --git a/bin/tests/system/resolver/ns4/tld2.db b/bin/tests/system/resolver/ns4/tld2.db index 6bd751438f3..dadacd43feb 100644 --- a/bin/tests/system/resolver/ns4/tld2.db +++ b/bin/tests/system/resolver/ns4/tld2.db @@ -24,3 +24,4 @@ $TTL 300 ) @ NS ns.tld. ns A 10.53.0.4 +fetch 10 TXT A short ttl diff --git a/bin/tests/system/resolver/ns5/named.conf b/bin/tests/system/resolver/ns5/named.conf index 374fa797fbc..71d233674de 100644 --- a/bin/tests/system/resolver/ns5/named.conf +++ b/bin/tests/system/resolver/ns5/named.conf @@ -16,7 +16,7 @@ /* $Id: named.conf,v 1.4 2011/03/13 23:47:36 tbox Exp $ */ -// NS4 +// NS5 controls { /* empty */ }; diff --git a/bin/tests/system/resolver/ns6/example.net.db.in b/bin/tests/system/resolver/ns6/example.net.db.in index 103cab4c887..0402ec9edfe 100644 --- a/bin/tests/system/resolver/ns6/example.net.db.in +++ b/bin/tests/system/resolver/ns6/example.net.db.in @@ -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 diff --git a/bin/tests/system/resolver/ns6/named.conf b/bin/tests/system/resolver/ns6/named.conf index bb10d8d667b..2075b1446c3 100644 --- a/bin/tests/system/resolver/ns6/named.conf +++ b/bin/tests/system/resolver/ns6/named.conf @@ -16,7 +16,7 @@ /* $Id: named.conf,v 1.4 2012/02/09 23:47:18 tbox Exp $ */ -// NS4 +// NS6 controls { /* empty */ }; diff --git a/bin/tests/system/resolver/ns7/named1.conf b/bin/tests/system/resolver/ns7/named1.conf index 103a40dfe9f..07784aaec73 100644 --- a/bin/tests/system/resolver/ns7/named1.conf +++ b/bin/tests/system/resolver/ns7/named1.conf @@ -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 { diff --git a/bin/tests/system/resolver/ns7/named2.conf b/bin/tests/system/resolver/ns7/named2.conf index ad7221fbaf1..149bf526dc5 100644 --- a/bin/tests/system/resolver/ns7/named2.conf +++ b/bin/tests/system/resolver/ns7/named2.conf @@ -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 { diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index 7f3e6c92fca..23e59d3759d 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -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 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 1bb4de8b77a..b1dd4169e5a 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -8736,6 +8736,21 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; + + + prefetch + + + 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. + + + diff --git a/doc/misc/options b/doc/misc/options index c034ad47695..fae4ed15ca6 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -139,9 +139,9 @@ options { fake-iquery ; // obsolete fetch-glue ; // obsolete files ; - filter-aaaa { ; ... }; // not configured - filter-aaaa-on-v4 ; // not configured - filter-aaaa-on-v6 ; // not configured + filter-aaaa { ; ... }; + filter-aaaa-on-v4 ; + filter-aaaa-on-v6 ; flush-zones-on-shutdown ; forward ( first | only ); forwarders [ port ] [ dscp ] { ( @@ -199,6 +199,7 @@ options { pid-file ( | none ); port ; preferred-glue ; + prefetch [ ]; provide-ixfr ; query-source ; query-source-v6 ; @@ -397,9 +398,9 @@ view { empty-server ; empty-zones-enable ; fetch-glue ; // obsolete - filter-aaaa { ; ... }; // not configured - filter-aaaa-on-v4 ; // not configured - filter-aaaa-on-v6 ; // not configured + filter-aaaa { ; ... }; + filter-aaaa-on-v4 ; + filter-aaaa-on-v6 ; forward ( first | only ); forwarders [ port ] [ dscp ] { ( | ) [ port ] [ dscp ]; ... }; @@ -446,6 +447,7 @@ view { notify-to-soa ; nsec3-test-zone ; // test only preferred-glue ; + prefetch [ ]; provide-ixfr ; query-source ; query-source-v6 ; diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 229083a1824..ab50a91e7bb 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -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 /*@}*/ /*% diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 31bcd15f142..a3ba5e3500c 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -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: diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 075fa8acb8a..2bc25a424fb 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -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 diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index b287869aef2..5f7f0e7dbf9 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 825fd427f07..3b0da11c0a6 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -330,8 +330,9 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t; #define RDATASET_ATTR_NXDOMAIN 0x0010 #define RDATASET_ATTR_RESIGN 0x0020 #define RDATASET_ATTR_STATCOUNT 0x0040 -#define RDATASET_ATTR_OPTOUT 0x0080 +#define RDATASET_ATTR_OPTOUT 0x0080 #define RDATASET_ATTR_NEGATIVE 0x0100 +#define RDATASET_ATTR_PREFETCH 0x0200 typedef struct acache_cbarg { dns_rdatasetadditional_t type; @@ -372,6 +373,8 @@ struct acachectl { (((header)->attributes & RDATASET_ATTR_OPTOUT) != 0) #define NEGATIVE(header) \ (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0) +#define PREFETCH(header) \ + (((header)->attributes & RDATASET_ATTR_PREFETCH) != 0) #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ @@ -2944,6 +2947,8 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; if (OPTOUT(header)) rdataset->attributes |= DNS_RDATASETATTR_OPTOUT; + if (PREFETCH(header)) + rdataset->attributes |= DNS_RDATASETATTR_PREFETCH; rdataset->private1 = rbtdb; rdataset->private2 = node; raw = (unsigned char *)header + sizeof(*header); @@ -6127,6 +6132,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, } } if (IS_CACHE(rbtdb) && header->rdh_ttl >= now && + (options & DNS_DBADD_PREFETCH) == 0 && (header->type == dns_rdatatype_a || header->type == dns_rdatatype_aaaa || header->type == dns_rdatatype_ds || @@ -6456,6 +6462,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } else { newheader->serial = 1; newheader->resign = 0; + if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0) + newheader->attributes |= RDATASET_ATTR_PREFETCH; if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) newheader->attributes |= RDATASET_ATTR_NEGATIVE; if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 028bc17be08..bf0ce47a89c 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -4382,8 +4382,11 @@ validated(isc_task_t *task, isc_event_t *event) { if (result != ISC_R_SUCCESS) goto noanswer_response; + unsigned options = 0; + if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) + options = DNS_DBADD_PREFETCH; result = dns_db_addrdataset(fctx->cache, node, NULL, now, - vevent->rdataset, 0, ardataset); + vevent->rdataset, options, ardataset); if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) goto noanswer_response; @@ -4793,6 +4796,12 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, if (rdataset->ttl > res->view->maxcachettl) rdataset->ttl = res->view->maxcachettl; + /* + * Mark the rdataset as being prefetch eligible. + */ + if (rdataset->ttl > fctx->res->view->prefetch_eligible) + rdataset->attributes |= DNS_RDATASETATTR_PREFETCH; + /* * Find the SIG for this rdataset, if we have it. */ @@ -4844,6 +4853,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, sigrdataset->ttl = rdataset->ttl; } + /* + * Mark the rdataset as being prefetch eligible. + */ + if (rdataset->ttl > fctx->res->view->prefetch_eligible) + rdataset->attributes |= DNS_RDATASETATTR_PREFETCH; + + /* * Cache this rdataset/sigrdataset pair as * pending data. Track whether it was additional @@ -4858,6 +4874,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, if (sigrdataset != NULL) sigrdataset->trust = trust; if (!need_validation || !ANSWER(rdataset)) { + options = 0; if (ANSWER(rdataset) && rdataset->type != dns_rdatatype_rrsig) { isc_result_t tresult; @@ -4874,10 +4891,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, ISC_R_SUCCESS); } } + if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) + options = DNS_DBADD_PREFETCH; addedrdataset = ardataset; result = dns_db_addrdataset(fctx->cache, node, NULL, now, rdataset, - 0, addedrdataset); + options, + addedrdataset); if (result == DNS_R_UNCHANGED) { result = ISC_R_SUCCESS; if (!need_validation && @@ -4911,7 +4931,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, addedrdataset = asigrdataset; result = dns_db_addrdataset(fctx->cache, node, NULL, now, - sigrdataset, 0, + sigrdataset, + options, addedrdataset); if (result == DNS_R_UNCHANGED) result = ISC_R_SUCCESS; @@ -4999,7 +5020,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, * over the existing cache contents. */ options = DNS_DBADD_FORCE; - } else + } else if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) + options = DNS_DBADD_PREFETCH; + else options = 0; if (ANSWER(rdataset) && diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 225cdf01371..dc979c6935e 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1402,6 +1402,43 @@ static cfg_type_t cfg_type_lookaside = { &cfg_rep_tuple, lookaside_fields }; +static isc_result_t +parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + UNUSED(type); + + CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); + if (pctx->token.type == isc_tokentype_number) { + CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret)); + } else { + CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); + } + cleanup: + return (result); +} + +static void +doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) { + UNUSED(type); + cfg_print_cstr(pctx, "[ ]"); +} + +static cfg_type_t cfg_type_optional_uint32 = { + "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32, + NULL, NULL }; + +static cfg_tuplefielddef_t prefetch_fields[] = { + { "trigger", &cfg_type_uint32, 0 }, + { "eligible", &cfg_type_optional_uint32, 0 }, + { NULL, NULL, 0 } +}; + +static cfg_type_t cfg_type_prefetch = { + "prefetch", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, prefetch_fields +}; /* * DNS64. */ @@ -1483,6 +1520,7 @@ view_clauses[] = { { "max-udp-size", &cfg_type_uint32, 0 }, { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, { "minimal-responses", &cfg_type_boolean, 0 }, + { "prefetch", &cfg_type_prefetch, 0 }, { "preferred-glue", &cfg_type_astring, 0 }, { "provide-ixfr", &cfg_type_boolean, 0 }, /* @@ -1537,32 +1575,6 @@ view_only_clauses[] = { /*% * Sig-validity-interval. */ -static isc_result_t -parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - UNUSED(type); - - CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER)); - if (pctx->token.type == isc_tokentype_number) { - CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret)); - } else { - CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); - } - cleanup: - return (result); -} - -static void -doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) { - UNUSED(type); - cfg_print_cstr(pctx, "[ ]"); -} - -static cfg_type_t cfg_type_optional_uint32 = { - "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32, - NULL, NULL }; static cfg_tuplefielddef_t validityinterval_fields[] = { { "validity", &cfg_type_uint32, 0 },