INSIST(result == ISC_R_SUCCESS);
stale_refresh_time = cfg_obj_asduration(obj);
+ result = dns_viewlist_find(&named_g_server->viewlist, view->name,
+ view->rdclass, &pview);
+ if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
/*
* Configure the view's cache.
*
}
}
} else if (strcmp(cachename, view->name) == 0) {
- result = dns_viewlist_find(&named_g_server->viewlist, cachename,
- view->rdclass, &pview);
- if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
- goto cleanup;
- }
if (pview != NULL) {
if (!cache_reusable(pview, view, zero_no_soattl)) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
dns_resolver_getqueryrttstats(pview->resolver,
&resqueryinrttstats,
&resqueryoutrttstats);
- dns_view_detach(&pview);
}
}
CHECK(dns_view_createresolver(view, resopts, tlsctx_client_cache,
dispatch4, dispatch6));
+ /*
+ * The deleg DB cache is preserved if reconfiguring/reloading the
+ * server.
+ */
+ if (pview != NULL) {
+ dns_delegdb_reuse(pview, view);
+ } else {
+ dns_delegdb_create(&view->deleg);
+ }
+
+ /*
+ * Totally arbitrary decision for now. This might need its own knob.
+ */
+ dns_delegdb_setsize(view->deleg, max_cache_size / 6);
+
+ /*
+ * The previous view isn't needed anymore.
+ */
+ if (pview != NULL) {
+ dns_view_detach(&pview);
+ }
+
if (resstats == NULL) {
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
}
#include <dns/adb.h>
#include <dns/cache.h>
#include <dns/db.h>
+#include <dns/deleg.h>
#include <dns/dispatch.h>
#include <dns/dns64.h>
#include <dns/dnstap.h>
return false;
}
+static void
+cache_delegglue(dns_delegset_t *delegset, dns_deleg_t *deleg, dns_ttl_t *ttl,
+ dns_rdataset_t *rdataset) {
+ if (rdataset->ttl < *ttl) {
+ *ttl = rdataset->ttl;
+ }
+
+ DNS_RDATASET_FOREACH(rdataset) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_in_a_t a;
+ isc_netaddr_t addr = { .family = AF_INET };
+
+ dns_rdataset_current(rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &a, NULL);
+ addr.type.in = a.in_addr;
+ dns_delegset_addaddr(delegset, deleg, &addr);
+ }
+}
+
+static void
+cache_delegglue6(dns_delegset_t *delegset, dns_deleg_t *deleg, dns_ttl_t *ttl,
+ dns_rdataset_t *rdataset) {
+ if (rdataset->ttl < *ttl) {
+ *ttl = rdataset->ttl;
+ }
+
+ DNS_RDATASET_FOREACH(rdataset) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_in_aaaa_t aaaa;
+ isc_netaddr_t addr = { .family = AF_INET6 };
+
+ dns_rdataset_current(rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &aaaa, NULL);
+ addr.type.in6 = aaaa.in6_addr;
+ dns_delegset_addaddr(delegset, deleg, &addr);
+ }
+}
+
+/*
+ * Cache the parent-side NS RRset in a delegation.
+ *
+ * Currently the resolver doesn't support DELEG, but when it does, this
+ * code will need to bail out if there is already a delegset from DELEG
+ * RRset in this zonecut. (See DELEG draft 5.1.3.)
+ *
+ * Maybe the simplest way to enforce it could be to pass a boolean flag
+ * `nooverride` to `dns_deleg_writeset()` so it simply detaches the
+ * `delegset` if there is already a `delegset` at this zonecut in the DB.
+ * And the flag would be true only from `cache_delegns()`.
+ */
+static isc_result_t
+cache_delegns(respctx_t *rctx) {
+ fetchctx_t *fctx = rctx->fctx;
+ dns_delegdb_t *delegdb = fctx->res->view->deleg;
+ dns_delegset_t *delegset = NULL;
+ dns_ttl_t ttl = rctx->ns_rdataset->ttl;
+ isc_result_t result;
+
+ FCTXTRACE("cache_delegns");
+
+ dns_delegset_allocset(delegdb, &delegset);
+
+ DNS_RDATASET_FOREACH(rctx->ns_rdataset) {
+ dns_rdataset_t *gluerdataset = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_ns_t ns;
+ dns_deleg_t *deleg = NULL;
+
+ /*
+ * We can't "group" all NS-based delegations into a single
+ * `dns_deleg_t` because some of them might have glues, some
+ * other might not, and a `dns_deleg_t` can't have both
+ * addresses and NS names. Let's assume this is a GLUE-based
+ * deleg first.
+ */
+ dns_delegset_allocdeleg(delegset, DNS_DELEGTYPE_NS_GLUES,
+ &deleg);
+
+ dns_rdataset_current(rctx->ns_rdataset, &rdata);
+ INSIST(rdata.type == dns_rdatatype_ns);
+ dns_rdata_tostruct(&rdata, &ns, NULL);
+
+ result = dns_message_findname(
+ rctx->query->rmessage, DNS_SECTION_ADDITIONAL, &ns.name,
+ dns_rdatatype_a, 0, NULL, &gluerdataset);
+ if (result == ISC_R_SUCCESS) {
+ cache_delegglue(delegset, deleg, &ttl, gluerdataset);
+ gluerdataset = NULL;
+ }
+
+ result = dns_message_findname(
+ rctx->query->rmessage, DNS_SECTION_ADDITIONAL, &ns.name,
+ dns_rdatatype_aaaa, 0, NULL, &gluerdataset);
+ if (result == ISC_R_SUCCESS) {
+ cache_delegglue6(delegset, deleg, &ttl, gluerdataset);
+ gluerdataset = NULL;
+ }
+
+ if (ISC_LIST_EMPTY(deleg->addresses)) {
+ /*
+ * There is actually no glues for this NSRRset, so this
+ * is actually a DNS_DELEGTYPE_NS_NAMES.
+ */
+ deleg->type = DNS_DELEGTYPE_NS_NAMES;
+ dns_delegset_addns(delegset, deleg, &ns.name);
+ }
+ }
+
+ result = dns_delegset_insert(delegdb, rctx->ns_name, ttl, delegset);
+ dns_delegset_detach(&delegset);
+
+ return result;
+}
+
static isc_result_t
check_section(void *arg, const dns_name_t *addname, dns_rdatatype_t type,
dns_rdataset_t *found, dns_section_t section) {
check_related, rctx, 0);
FCTX_ATTR_CLR(fctx, FCTX_ATTR_GLUING);
+ /*
+ * An NS-based delegation can be cached immediately (i.e. there is
+ * no DNSSEC validation).
+ */
+ cache_delegns(rctx);
+
/*
* NS rdatasets with 0 TTL cause problems.
* dns_view_findzonecut() will not find them when we