2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

rename and refactor cache_name() and related functions

- renamed cache_message() to rctx_cachemessage()
- renamed cache_name() to rctx_cachename()
- merged ncache_message() into rctx_ncache()
- split out a new function, rctx_cacherdataset(), which is
  called by rctx_cachename() in a loop to process each of
  the rdatasets associated with the name.
This commit is contained in:
Evan Hunt
2025-03-01 20:04:18 -08:00
committed by Ondřej Surý
parent 83980d76b2
commit ed56a91d7d

View File

@@ -842,6 +842,9 @@ typedef struct respctx {
* response */ * response */
dns_rdataset_t *opt; /* OPT rdataset */ dns_rdataset_t *opt; /* OPT rdataset */
dns_rdataset_t *vrdataset;
dns_rdataset_t *vsigrdataset;
} respctx_t; } respctx_t;
static void static void
@@ -958,7 +961,7 @@ set_stats(dns_resolver_t *res, isc_statscounter_t counter, uint64_t val) {
} }
} }
static isc_result_t static void
valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo, valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset) { dns_rdataset_t *sigrdataset) {
@@ -985,8 +988,6 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
if (!ISC_LIST_EMPTY(fctx->validators)) { if (!ISC_LIST_EMPTY(fctx->validators)) {
valoptions |= DNS_VALIDATOR_DEFER; valoptions |= DNS_VALIDATOR_DEFER;
} else {
valoptions &= ~DNS_VALIDATOR_DEFER;
} }
result = dns_validator_create( result = dns_validator_create(
@@ -996,7 +997,6 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(result == ISC_R_SUCCESS);
inc_stats(fctx->res, dns_resstatscounter_val); inc_stats(fctx->res, dns_resstatscounter_val);
ISC_LIST_APPEND(fctx->validators, validator, link); ISC_LIST_APPEND(fctx->validators, validator, link);
return ISC_R_SUCCESS;
} }
static void static void
@@ -2248,8 +2248,8 @@ compute_cc(const resquery_t *query, uint8_t *cookie, const size_t len) {
} }
static bool static bool
issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, issecuredomain(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type,
isc_stdtime_t now, bool checknta, bool *ntap) { isc_stdtime_t now, bool *ntap) {
dns_name_t suffix; dns_name_t suffix;
unsigned int labels; unsigned int labels;
@@ -2266,7 +2266,8 @@ issecuredomain(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
name = &suffix; name = &suffix;
} }
return dns_view_issecuredomain(view, name, now, checknta, ntap); return dns_view_issecuredomain(fctx->res->view, name, now,
CHECKNTA(fctx), ntap);
} }
static isc_result_t static isc_result_t
@@ -5184,7 +5185,7 @@ validated(void *arg) {
dns_adbaddrinfo_t *addrinfo = NULL; dns_adbaddrinfo_t *addrinfo = NULL;
dns_dbnode_t *node = NULL; dns_dbnode_t *node = NULL;
dns_dbnode_t *nsnode = NULL; dns_dbnode_t *nsnode = NULL;
dns_fetchresponse_t *hresp = NULL; dns_fetchresponse_t *resp = NULL;
dns_rdataset_t *ardataset = NULL; dns_rdataset_t *ardataset = NULL;
dns_rdataset_t *asigrdataset = NULL; dns_rdataset_t *asigrdataset = NULL;
dns_resolver_t *res = NULL; dns_resolver_t *res = NULL;
@@ -5196,7 +5197,7 @@ validated(void *arg) {
isc_result_t eresult = ISC_R_SUCCESS; isc_result_t eresult = ISC_R_SUCCESS;
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
isc_stdtime_t now; isc_stdtime_t now;
unsigned int options; unsigned int options = 0;
dns_fixedname_t fwild; dns_fixedname_t fwild;
dns_name_t *wild = NULL; dns_name_t *wild = NULL;
dns_message_t *message = NULL; dns_message_t *message = NULL;
@@ -5276,8 +5277,8 @@ validated(void *arg) {
* started by a query with cd set) * started by a query with cd set)
*/ */
hresp = ISC_LIST_HEAD(fctx->resps); resp = ISC_LIST_HEAD(fctx->resps);
if (hresp != NULL) { if (resp != NULL) {
if (!negative && !chaining && dns_rdatatype_ismulti(fctx->type)) if (!negative && !chaining && dns_rdatatype_ismulti(fctx->type))
{ {
/* /*
@@ -5285,8 +5286,8 @@ validated(void *arg) {
* will iterate the node. * will iterate the node.
*/ */
} else { } else {
ardataset = hresp->rdataset; ardataset = resp->rdataset;
asigrdataset = hresp->sigrdataset; asigrdataset = resp->sigrdataset;
} }
} }
@@ -5406,21 +5407,18 @@ validated(void *arg) {
goto noanswer_response; goto noanswer_response;
} }
options = 0;
if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) { if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) {
options = DNS_DBADD_PREFETCH; options = DNS_DBADD_PREFETCH;
} }
result = dns_db_addrdataset(fctx->cache, node, NULL, now, val->rdataset, result = dns_db_addrdataset(fctx->cache, node, NULL, now, val->rdataset,
options, ardataset); options, ardataset);
if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) { if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) {
goto noanswer_response; goto noanswer_response;
} }
if (ardataset != NULL && NEGATIVE(ardataset)) { if (ardataset != NULL && NEGATIVE(ardataset)) {
if (NXDOMAIN(ardataset)) { eresult = NXDOMAIN(ardataset) ? DNS_R_NCACHENXDOMAIN
eresult = DNS_R_NCACHENXDOMAIN; : DNS_R_NCACHENXRRSET;
} else {
eresult = DNS_R_NCACHENXRRSET;
}
} else if (val->sigrdataset != NULL) { } else if (val->sigrdataset != NULL) {
result = dns_db_addrdataset(fctx->cache, node, NULL, now, result = dns_db_addrdataset(fctx->cache, node, NULL, now,
val->sigrdataset, options, val->sigrdataset, options,
@@ -5446,10 +5444,10 @@ validated(void *arg) {
if (!ISC_LIST_EMPTY(fctx->validators)) { if (!ISC_LIST_EMPTY(fctx->validators)) {
INSIST(!negative); INSIST(!negative);
INSIST(dns_rdatatype_ismulti(fctx->type)); INSIST(dns_rdatatype_ismulti(fctx->type));
/* /*
* Don't send a response yet - we have * Don't send a response yet - we have more rdatasets
* more rdatasets that still need to * that still need to be validated.
* be validated.
*/ */
dns_db_detachnode(fctx->cache, &node); dns_db_detachnode(fctx->cache, &node);
UNLOCK(&fctx->lock); UNLOCK(&fctx->lock);
@@ -5576,6 +5574,10 @@ answer_response:
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
if (HAVE_ANSWER(fctx) || resp == NULL) {
goto noanswer_response;
}
/* /*
* Respond with an answer, positive or negative, * Respond with an answer, positive or negative,
* as opposed to an error. 'node' must be non-NULL. * as opposed to an error. 'node' must be non-NULL.
@@ -5583,19 +5585,15 @@ answer_response:
FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER);
if (hresp != NULL) { INSIST(resp->rdataset != NULL);
/* if (dns_rdataset_isassociated(resp->rdataset)) {
* Negative results must be indicated in val->result. if (NEGATIVE(resp->rdataset)) {
*/
INSIST(hresp->rdataset != NULL);
if (dns_rdataset_isassociated(hresp->rdataset)) {
if (NEGATIVE(hresp->rdataset)) {
INSIST(eresult == DNS_R_NCACHENXDOMAIN || INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
eresult == DNS_R_NCACHENXRRSET); eresult == DNS_R_NCACHENXRRSET);
} else if (eresult == ISC_R_SUCCESS && } else if (eresult == ISC_R_SUCCESS &&
hresp->rdataset->type != fctx->type) resp->rdataset->type != fctx->type)
{ {
switch (hresp->rdataset->type) { switch (resp->rdataset->type) {
case dns_rdatatype_cname: case dns_rdatatype_cname:
eresult = DNS_R_CNAME; eresult = DNS_R_CNAME;
break; break;
@@ -5608,12 +5606,11 @@ answer_response:
} }
} }
hresp->result = eresult; resp->result = eresult;
dns_name_copy(val->name, hresp->foundname); dns_name_copy(val->name, resp->foundname);
dns_db_attach(fctx->cache, &hresp->db); dns_db_attach(fctx->cache, &resp->db);
dns_db_transfernode(fctx->cache, &node, &hresp->node); dns_db_transfernode(fctx->cache, &node, &resp->node);
clone_results(fctx); clone_results(fctx);
}
noanswer_response: noanswer_response:
if (node != NULL) { if (node != NULL) {
@@ -5847,19 +5844,203 @@ fixttls(dns_view_t *view, dns_rdataset_t *rdataset,
} }
static isc_result_t static isc_result_t
cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message, rctx_cacherdataset(respctx_t *rctx, dns_message_t *message, dns_name_t *name,
dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) { dns_dbnode_t *node, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset, bool secure_domain,
bool need_validation) {
isc_result_t result;
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
dns_rdataset_t *ardataset = NULL, *asigset = NULL;
dns_fetchresponse_t *resp = ISC_LIST_HEAD(fctx->resps);
unsigned int options = 0;
if (secure_domain && rdataset->trust != dns_trust_glue) {
/*
* RRSIGs are validated as part of validating
* the type they cover.
*/
if (rdataset->type == dns_rdatatype_rrsig) {
return ISC_R_SUCCESS;
}
/*
* Ignore unrelated non-answer rdatasets that are
* missing signatures.
*/
if (sigrdataset == NULL && need_validation && !ANSWER(rdataset))
{
return ISC_R_SUCCESS;
}
/*
* Mark this rdataset/sigrdataset pair as pending data.
* Track whether it was additional or not.
*/
if (rdataset->trust == dns_trust_additional) {
rdataset->trust = dns_trust_pending_additional;
} else {
rdataset->trust = dns_trust_pending_answer;
}
if (sigrdataset != NULL) {
sigrdataset->trust = rdataset->trust;
}
if (ANSWER(rdataset) && need_validation) {
if (!dns_rdatatype_ismulti(fctx->type)) {
/*
* This is The Answer. We will validate
* it, but first we cache the rest of the
* response - it may contain useful keys.
*/
INSIST(rctx->vrdataset == NULL &&
rctx->vsigrdataset == NULL);
rctx->vrdataset = rdataset;
rctx->vsigrdataset = sigrdataset;
} else {
/*
* This is one of (potentially) multiple
* answers to an ANY query. To keep things
* simple, we just start the validator
* right away rather than caching first and
* having to remember which rdatasets
* needed validation.
*/
valcreate(fctx, message, query->addrinfo, name,
rdataset->type, rdataset,
sigrdataset);
}
} else {
if (ANSWER(rdataset)) {
/*
* We're not validating, but the client might
* be, so look for the NOQNAME proof.
*/
findnoqname(fctx, message, name, rdataset);
/*
* If this was not an ANY/RRSIG/SIG query,
* or if it was but we got a CNAME/DNAME,
* then we need to set up rdatasets to
* send back to the caller.
*/
if (!dns_rdatatype_ismulti(fctx->type) ||
CHAINING(rdataset))
{
ardataset = resp->rdataset;
asigset = resp->sigrdataset;
}
}
if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) {
options = DNS_DBADD_PREFETCH;
}
if ((fctx->options & DNS_FETCHOPT_NOCACHED) != 0) {
options |= DNS_DBADD_FORCE;
}
result = dns_db_addrdataset(fctx->cache, node, NULL,
rctx->now, rdataset,
options, ardataset);
if (result != DNS_R_UNCHANGED &&
result != ISC_R_SUCCESS)
{
return result;
}
if (sigrdataset == NULL) {
return ISC_R_SUCCESS;
}
if (result == DNS_R_UNCHANGED && !need_validation &&
ardataset != NULL &&
!dns_rdataset_equals(rdataset, ardataset))
{
/*
* The cache wasn't updated because
* something was already there. If the data
* was the same as what we were trying to
* add, then sigrdataset might still be
* useful, and we should carry on caching
* it. Otherwise, move on.
*/
return ISC_R_SUCCESS;
}
result = dns_db_addrdataset(fctx->cache, node, NULL,
rctx->now, sigrdataset,
options, asigset);
if (result != DNS_R_UNCHANGED &&
result != ISC_R_SUCCESS)
{
return result;
}
}
return ISC_R_SUCCESS;
}
/*
* We're not in a secure domain, or this is glue,
* so we can cache right away.
*
* If this wasn't an ANY/RRSIG/SIG query then send
* an answer back to the caller.
*/
dns_rdataset_t *added = NULL; dns_rdataset_t *added = NULL;
dns_rdataset_t *sigrdataset = NULL; if (!dns_rdatatype_ismulti(fctx->type)) {
dns_rdataset_t *ardataset = NULL, *asigrdataset = NULL; if (ANSWER(rdataset)) {
dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; added = resp->rdataset;
dns_dbnode_t *node = NULL; } else if (ANSWERSIG(rdataset)) {
added = resp->sigrdataset;
}
}
if (rdataset->trust == dns_trust_glue &&
dns_rdataset_matchestype(rdataset, dns_rdatatype_ns))
{
/*
* If the trust level is glue, then we are adding data from
* a referral we got while executing the search algorithm.
* New referral data always takes precedence over the
* existing cache contents.
*/
options = DNS_DBADD_FORCE;
} else if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0) {
options = DNS_DBADD_PREFETCH;
}
/*
* Look for the NOQNAME proof.
*/
if (ANSWER(rdataset)) {
findnoqname(fctx, message, name, rdataset);
}
/*
* Now we can add the rdataset.
*/
result = dns_db_addrdataset(fctx->cache, node, NULL, rctx->now,
rdataset, options, added);
if (result == DNS_R_UNCHANGED) {
result = ISC_R_SUCCESS;
}
return result;
}
static isc_result_t
rctx_cachename(respctx_t *rctx, dns_message_t *message, dns_name_t *name) {
isc_result_t result;
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
dns_resolver_t *res = fctx->res; dns_resolver_t *res = fctx->res;
bool have_answer = false; dns_rdataset_t *sigrdataset = NULL;
isc_result_t result, eresult = ISC_R_SUCCESS; dns_dbnode_t *node = NULL;
dns_fetchresponse_t *resp = NULL; dns_fetchresponse_t *resp = NULL;
FCTXTRACE("cache_name"); FCTXTRACE("rctx_cachename");
/* /*
* The appropriate bucket lock must be held. * The appropriate bucket lock must be held.
@@ -5868,33 +6049,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
/* /*
* Is DNSSEC validation required for this name? * Is DNSSEC validation required for this name?
*/ */
bool checknta = ((fctx->options & DNS_FETCHOPT_NONTA) == 0); bool secure_domain = issecuredomain(fctx, name, fctx->type, rctx->now,
bool secure_domain = issecuredomain(res->view, name, fctx->type, now, NULL);
checknta, NULL);
bool need_validation = secure_domain && bool need_validation = secure_domain &&
((fctx->options & DNS_FETCHOPT_NOVALIDATE) == 0); ((fctx->options & DNS_FETCHOPT_NOVALIDATE) == 0);
if (name->attributes.answer && !need_validation) {
have_answer = true;
resp = ISC_LIST_HEAD(fctx->resps);
if (resp != NULL) {
/*
* If this is an ANY, SIG or RRSIG query, we're
* not going to return any rdatasets, unless we
* encountered a CNAME or DNAME as "the answer".
* In this case, we're going to return
* DNS_R_CNAME or DNS_R_DNAME and we must set up
* the rdatasets.
*/
if (!dns_rdatatype_ismulti(fctx->type) ||
name->attributes.chaining)
{
ardataset = resp->rdataset;
asigrdataset = resp->sigrdataset;
}
}
}
/* /*
* Find or create the cache node. * Find or create the cache node.
*/ */
@@ -5906,10 +6065,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
/* /*
* Cache or validate each cacheable rdataset. * Cache or validate each cacheable rdataset.
*/ */
bool fail = ((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0); bool fail = ((res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
ISC_LIST_FOREACH (name->list, rdataset, link) { ISC_LIST_FOREACH (name->list, rdataset, link) {
unsigned int options = 0;
result = check_cacheable(name, rdataset, fail); result = check_cacheable(name, rdataset, fail);
if (result == DNS_R_CONTINUE) { if (result == DNS_R_CONTINUE) {
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
@@ -5934,288 +6091,50 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
*/ */
fixttls(res->view, rdataset, sigrdataset); fixttls(res->view, rdataset, sigrdataset);
/* /* Try to cache the rdataset */
* If this RRset is in a secure domain, is in bailiwick, result = rctx_cacherdataset(rctx, message, name, node, rdataset,
* and is not glue, attempt DNSSEC validation. sigrdataset, secure_domain,
* need_validation);
* We do not attempt to validate glue or out-of-bailiwick
* data - even though there might be some performance
* benefit to doing so - because it makes it simpler and
* safer to ensure that records from a secure domain are
* only cached if validated within the context of a query
* to the domain that owns them.
*/
if (secure_domain && rdataset->trust != dns_trust_glue) {
/*
* RRSIGs are validated as part of validating
* the type they cover.
*/
if (rdataset->type == dns_rdatatype_rrsig) {
continue;
}
/*
* Ignore unrelated non-answer rdatasets that are
* missing signatures.
*/
if (sigrdataset == NULL && need_validation &&
!ANSWER(rdataset))
{
continue;
}
/*
* Normalize the rdataset and sigrdataset TTLs.
*/
if (sigrdataset != NULL) {
rdataset->ttl = ISC_MIN(rdataset->ttl,
sigrdataset->ttl);
sigrdataset->ttl = rdataset->ttl;
}
/*
* Mark the rdataset as being prefetch eligible.
*/
if (rdataset->ttl >= fctx->res->view->prefetch_eligible)
{
rdataset->attributes.prefetch = true;
}
/*
* Cache this rdataset/sigrdataset pair as
* pending data. Track whether it was
* additional or not. If this was a priming
* query, additional should be cached as glue.
*/
if (rdataset->trust == dns_trust_additional) {
rdataset->trust = dns_trust_pending_additional;
} else {
rdataset->trust = dns_trust_pending_answer;
}
if (sigrdataset != NULL) {
sigrdataset->trust = rdataset->trust;
}
if (ANSWER(rdataset) && need_validation) {
if (!dns_rdatatype_ismulti(fctx->type)) {
/*
* This is The Answer. We will
* validate it, but first we
* cache the rest of the
* response - it may contain
* useful keys.
*/
INSIST(valrdataset == NULL &&
valsigrdataset == NULL);
valrdataset = rdataset;
valsigrdataset = sigrdataset;
} else {
/*
* This is one of (potentially)
* multiple answers to an ANY
* or SIG query. To keep things
* simple, we just start the
* validator right away rather
* than caching first and
* having to remember which
* rdatasets needed validation.
*/
result = valcreate(
fctx, message, addrinfo, name,
rdataset->type, rdataset,
sigrdataset);
}
} else {
if (ANSWER(rdataset)) {
findnoqname(fctx, message, name,
rdataset);
}
if ((fctx->options & DNS_FETCHOPT_PREFETCH) !=
0)
{
options = DNS_DBADD_PREFETCH;
}
if ((fctx->options & DNS_FETCHOPT_NOCACHED) !=
0)
{
options |= DNS_DBADD_FORCE;
}
added = ardataset;
result = dns_db_addrdataset(fctx->cache, node,
NULL, now, rdataset,
options, added);
if (result == DNS_R_UNCHANGED) {
result = ISC_R_SUCCESS;
if (!need_validation && added != NULL &&
NEGATIVE(added))
{
/*
* The answer in the
* cache is better than
* the answer we found.
* If it's a negative
* cache entry, we
* must set eresult
* appropriately.
*/
if (NXDOMAIN(added)) {
eresult =
DNS_R_NCACHENXDOMAIN;
} else {
eresult =
DNS_R_NCACHENXRRSET;
}
continue;
} else if (!need_validation &&
added != NULL &&
sigrdataset != NULL &&
!dns_rdataset_equals(
rdataset, added))
{
/*
* The cache wasn't updated
* because something was
* already there. If the
* data was the same as what
* we were trying to add,
* then sigrdataset might
* still be useful, and we
* should carry on caching
* it. Otherwise, move on.
*/
continue;
}
}
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
break; goto cleanup;
}
if (sigrdataset != NULL) {
added = asigrdataset;
result = dns_db_addrdataset(
fctx->cache, node, NULL, now,
sigrdataset, options, added);
if (result == DNS_R_UNCHANGED) {
result = ISC_R_SUCCESS;
}
if (result != ISC_R_SUCCESS) {
break;
}
} else if (!ANSWER(rdataset)) {
continue;
}
if (CHAINING(rdataset)) {
if (rdataset->type ==
dns_rdatatype_cname)
{
eresult = DNS_R_CNAME;
} else {
INSIST(rdataset->type ==
dns_rdatatype_dname);
eresult = DNS_R_DNAME;
}
}
}
} else {
/*
* It's OK to cache this rdataset now.
*/
if (ANSWER(rdataset)) {
added = ardataset;
} else if (ANSWERSIG(rdataset)) {
added = asigrdataset;
} else {
added = NULL;
}
if (rdataset->trust == dns_trust_glue &&
dns_rdataset_matchestype(rdataset,
dns_rdatatype_ns))
{
/*
* If the trust level is
* 'dns_trust_glue' then we are adding
* data from a referral we got while
* executing the search algorithm. New
* referral data always takes precedence
* over the existing cache contents.
*/
options = DNS_DBADD_FORCE;
} else if ((fctx->options & DNS_FETCHOPT_PREFETCH) != 0)
{
options = DNS_DBADD_PREFETCH;
}
if (ANSWER(rdataset)) {
findnoqname(fctx, message, name, rdataset);
}
/*
* Now we can add the rdataset.
*/
result = dns_db_addrdataset(fctx->cache, node, NULL,
now, rdataset, options,
added);
if (result == DNS_R_UNCHANGED) {
if (ANSWER(rdataset) && added != NULL &&
NEGATIVE(added))
{
/*
* The answer in the cache is
* better than the answer we
* found, and is a negative
* cache entry, so we must set
* eresult appropriately.
*/
if (NXDOMAIN(added)) {
eresult = DNS_R_NCACHENXDOMAIN;
} else {
eresult = DNS_R_NCACHENXRRSET;
}
}
result = ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {
break;
}
} }
} }
if (valrdataset != NULL) { if (rctx->vrdataset != NULL) {
dns_rdatatype_t vtype = fctx->type; dns_rdatatype_t vtype = fctx->type;
if (CHAINING(valrdataset)) { if (CHAINING(rctx->vrdataset)) {
if (valrdataset->type == dns_rdatatype_cname) { vtype = rctx->vrdataset->type;
vtype = dns_rdatatype_cname; INSIST(dns_rdatatype_isalias(vtype));
} else {
vtype = dns_rdatatype_dname;
}
} }
result = valcreate(fctx, message, addrinfo, name, vtype, valcreate(fctx, message, query->addrinfo, name, vtype,
valrdataset, valsigrdataset); rctx->vrdataset, rctx->vsigrdataset);
rctx->vrdataset = NULL;
rctx->vsigrdataset = NULL;
} }
if (result == ISC_R_SUCCESS && have_answer) { if (result == ISC_R_SUCCESS && name->attributes.answer &&
FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); !need_validation && !HAVE_ANSWER(fctx))
{
resp = ISC_LIST_HEAD(fctx->resps);
if (resp != NULL) { if (resp != NULL) {
/* /*
* Negative results must be indicated in * Negative results must be indicated in
* resp->result. * resp->result.
*/ */
resp->result = ISC_R_SUCCESS;
if (dns_rdataset_isassociated(resp->rdataset)) { if (dns_rdataset_isassociated(resp->rdataset)) {
if (NEGATIVE(resp->rdataset)) { if (NXDOMAIN(resp->rdataset)) {
INSIST(eresult == resp->result = DNS_R_NCACHENXDOMAIN;
DNS_R_NCACHENXDOMAIN || } else if (NEGATIVE(resp->rdataset)) {
eresult == DNS_R_NCACHENXRRSET); resp->result = DNS_R_NCACHENXRRSET;
} else if (eresult == ISC_R_SUCCESS && } else if (resp->rdataset->type != fctx->type) {
resp->rdataset->type != fctx->type)
{
switch (resp->rdataset->type) { switch (resp->rdataset->type) {
case dns_rdatatype_cname: case dns_rdatatype_cname:
eresult = DNS_R_CNAME; resp->result = DNS_R_CNAME;
break; break;
case dns_rdatatype_dname: case dns_rdatatype_dname:
eresult = DNS_R_DNAME; resp->result = DNS_R_DNAME;
break; break;
default: default:
break; break;
@@ -6223,12 +6142,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
} }
} }
resp->result = eresult;
dns_name_copy(name, resp->foundname); dns_name_copy(name, resp->foundname);
dns_db_attach(fctx->cache, &resp->db); dns_db_attach(fctx->cache, &resp->db);
dns_db_transfernode(fctx->cache, &node, &resp->node); dns_db_transfernode(fctx->cache, &node, &resp->node);
clone_results(fctx); clone_results(fctx);
} }
FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER);
} }
cleanup: cleanup:
@@ -6240,22 +6160,24 @@ cleanup:
} }
static isc_result_t static isc_result_t
cache_message(fetchctx_t *fctx, dns_message_t *message, rctx_cachemessage(respctx_t *rctx) {
dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) { isc_result_t result;
FCTXTRACE("cache_message"); fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
dns_message_t *message = query->rmessage;
FCTXTRACE("rctx_cachemessage");
FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTCACHE); FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTCACHE);
LOCK(&fctx->lock); LOCK(&fctx->lock);
isc_result_t result = ISC_R_SUCCESS;
for (dns_section_t section = DNS_SECTION_ANSWER; for (dns_section_t section = DNS_SECTION_ANSWER;
section <= DNS_SECTION_ADDITIONAL; section++) section <= DNS_SECTION_ADDITIONAL; section++)
{ {
MSG_SECTION_FOREACH (message, section, name) { MSG_SECTION_FOREACH (message, section, name) {
if (name->attributes.cache) { if (name->attributes.cache) {
result = cache_name(fctx, name, message, result = rctx_cachename(rctx, message, name);
addrinfo, now);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
goto cleanup; goto cleanup;
} }
@@ -6358,17 +6280,28 @@ negcache(dns_message_t *message, fetchctx_t *fctx, const dns_name_t *name,
return result; return result;
} }
static isc_result_t /*
ncache_message(fetchctx_t *fctx, dns_message_t *message, * rctx_ncache():
dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) { * Cache the negatively cacheable parts of the message. This may
isc_result_t result, eresult = ISC_R_SUCCESS; * also cause work to be queued to the DNSSEC validator.
*/
static void
rctx_ncache(respctx_t *rctx) {
isc_result_t result = ISC_R_SUCCESS;
isc_result_t eresult = ISC_R_SUCCESS;
fetchctx_t *fctx = rctx->fctx;
dns_name_t *name = fctx->name; dns_name_t *name = fctx->name;
dns_resolver_t *res = fctx->res; dns_message_t *message = rctx->query->rmessage;
dns_adbaddrinfo_t *addrinfo = rctx->query->addrinfo;
dns_dbnode_t *node = NULL; dns_dbnode_t *node = NULL;
dns_fetchresponse_t *resp = NULL; dns_fetchresponse_t *resp = NULL;
dns_rdataset_t *added = NULL; dns_rdataset_t *added = NULL;
FCTXTRACE("ncache_message"); FCTXTRACE("rctx_ncache");
if (!WANTNCACHE(fctx)) {
goto done;
}
FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTNCACHE); FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTNCACHE);
@@ -6381,15 +6314,16 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message,
/* /*
* Is DNSSEC validation required for this name? * Is DNSSEC validation required for this name?
*/ */
bool checknta = ((fctx->options & DNS_FETCHOPT_NONTA) == 0); bool secure_domain = issecuredomain(fctx, name, fctx->type, rctx->now,
bool secure_domain = issecuredomain(res->view, name, fctx->type, now, NULL);
checknta, NULL);
bool need_validation = secure_domain && bool need_validation = secure_domain &&
((fctx->options & DNS_FETCHOPT_NOVALIDATE) == 0); ((fctx->options & DNS_FETCHOPT_NOVALIDATE) == 0);
if (secure_domain) { if (secure_domain) {
/* /*
* Mark all rdatasets as pending. * Mark all rdatasets as pending. (We do this for
* any domain under a trust anchor, regardless
* of whether we're actually validating.)
*/ */
MSG_SECTION_FOREACH (message, DNS_SECTION_AUTHORITY, tname) { MSG_SECTION_FOREACH (message, DNS_SECTION_AUTHORITY, tname) {
ISC_LIST_FOREACH (tname->list, trdataset, link) { ISC_LIST_FOREACH (tname->list, trdataset, link) {
@@ -6400,37 +6334,31 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message,
if (need_validation) { if (need_validation) {
/* /*
* Do negative response validation. * Start the validator for the negative response. It
* will call validated() on completion; the caching of
* negative answers will be done then.
*/ */
result = valcreate(fctx, message, addrinfo, name, fctx->type, valcreate(fctx, message, addrinfo, name, fctx->type, NULL,
NULL, NULL); NULL);
/* goto done;
* If validation is necessary, return now. Otherwise
* continue to process the message, letting the
* validation complete in its own good time.
*/
return result;
} }
/*
* Cache the negative answer, and copy it into the fetch response.
*/
LOCK(&fctx->lock); LOCK(&fctx->lock);
if (!HAVE_ANSWER(fctx)) {
resp = ISC_LIST_HEAD(fctx->resps); resp = ISC_LIST_HEAD(fctx->resps);
if (resp != NULL) { if (!HAVE_ANSWER(fctx) && resp != NULL) {
added = resp->rdataset; added = resp->rdataset;
} }
}
result = negcache(message, fctx, name, now, false, false, added, &node, result = negcache(message, fctx, name, rctx->now, false, false, added,
&eresult); &node, &eresult);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS || HAVE_ANSWER(fctx)) {
goto unlock; goto unlock;
} }
if (!HAVE_ANSWER(fctx)) {
FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER); FCTX_ATTR_SET(fctx, FCTX_ATTR_HAVEANSWER);
}
if (resp != NULL) { if (resp != NULL) {
resp->result = eresult; resp->result = eresult;
dns_name_copy(name, resp->foundname); dns_name_copy(name, resp->foundname);
@@ -6446,7 +6374,10 @@ unlock:
dns_db_detachnode(fctx->cache, &node); dns_db_detachnode(fctx->cache, &node);
} }
return result; done:
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("rctx_ncache complete", result);
}
} }
static void static void
@@ -6465,6 +6396,7 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset, bool external,
} else { } else {
rdataset->trust = dns_trust_additional; rdataset->trust = dns_trust_additional;
} }
/* /*
* Avoid infinite loops by only marking new rdatasets. * Avoid infinite loops by only marking new rdatasets.
*/ */
@@ -7696,10 +7628,9 @@ resquery_response_continue(void *arg, isc_result_t result) {
*/ */
if (WANTCACHE(fctx)) { if (WANTCACHE(fctx)) {
isc_result_t tresult; isc_result_t tresult;
tresult = cache_message(fctx, query->rmessage, query->addrinfo, tresult = rctx_cachemessage(rctx);
rctx->now);
if (tresult != ISC_R_SUCCESS) { if (tresult != ISC_R_SUCCESS) {
FCTXTRACE3("cache_message complete", tresult); FCTXTRACE3("rctx_cachemessage complete", tresult);
rctx_done(rctx, tresult); rctx_done(rctx, tresult);
goto cleanup; goto cleanup;
} }
@@ -7794,6 +7725,9 @@ rctx_answer_init(respctx_t *rctx) {
rctx->soa_name = NULL; rctx->soa_name = NULL;
rctx->ds_name = NULL; rctx->ds_name = NULL;
rctx->found_name = NULL; rctx->found_name = NULL;
rctx->vrdataset = NULL;
rctx->vsigrdataset = NULL;
} }
/* /*
@@ -8882,30 +8816,6 @@ rctx_authority_negative(respctx_t *rctx) {
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
/*
* rctx_ncache():
* Cache the negatively cacheable parts of the message. This may
* also cause work to be queued to the DNSSEC validator.
*/
static void
rctx_ncache(respctx_t *rctx) {
isc_result_t result;
fetchctx_t *fctx = rctx->fctx;
if (!WANTNCACHE(fctx)) {
return;
}
/*
* Cache any negative cache entries in the message.
*/
result = ncache_message(fctx, rctx->query->rmessage,
rctx->query->addrinfo, rctx->now);
if (result != ISC_R_SUCCESS) {
FCTXTRACE3("ncache_message complete", result);
}
}
/* /*
* rctx_authority_dnssec(): * rctx_authority_dnssec():
* *
@@ -8929,7 +8839,6 @@ rctx_authority_dnssec(respctx_t *rctx) {
} }
ISC_LIST_FOREACH (name->list, rdataset, link) { ISC_LIST_FOREACH (name->list, rdataset, link) {
bool checknta = true;
bool secure_domain = false; bool secure_domain = false;
dns_rdatatype_t type = rdataset->type; dns_rdatatype_t type = rdataset->type;
@@ -8993,12 +8902,9 @@ rctx_authority_dnssec(respctx_t *rctx) {
name->attributes.cache = true; name->attributes.cache = true;
rdataset->attributes.cache = true; rdataset->attributes.cache = true;
if ((fctx->options & DNS_FETCHOPT_NONTA) != 0) { secure_domain = issecuredomain(fctx, name,
checknta = false; dns_rdatatype_ds,
} fctx->now, NULL);
secure_domain = issecuredomain(
fctx->res->view, name, dns_rdatatype_ds,
fctx->now, checknta, NULL);
if (secure_domain) { if (secure_domain) {
rdataset->trust = rdataset->trust =
dns_trust_pending_answer; dns_trust_pending_answer;