From 77b9650eb11e407b68e48bcd3ea76d066bdf5274 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Wed, 3 Nov 1999 03:19:17 +0000 Subject: [PATCH] Improve response caching logic. First try at handling type 3 negative replies. --- lib/dns/resolver.c | 117 ++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 44 deletions(-) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 3259284983..7300df1a8a 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -151,6 +151,8 @@ struct fetchctx { #define FCTX_ATTR_GLUING 0x02 #define FCTX_ATTR_ADDRWAIT 0x04 #define FCTX_ATTR_SHUTTINGDOWN 0x08 +#define FCTX_ATTR_WANTCACHE 0x10 +#define FCTX_ATTR_WANTNCACHE 0x20 #define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \ 0) @@ -160,6 +162,8 @@ struct fetchctx { 0) #define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \ != 0) +#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0) +#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) struct dns_fetch { unsigned int magic; @@ -1398,6 +1402,10 @@ cache_message(fetchctx_t *fctx, isc_stdtime_t now) { dns_section_t section; dns_name_t *name; + FCTXTRACE("cache_message"); + + fctx->attributes &= ~FCTX_ATTR_WANTCACHE; + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); for (section = DNS_SECTION_ANSWER; @@ -1440,6 +1448,10 @@ ncache_message(fetchctx_t *fctx, dns_rdatatype_t covers, isc_stdtime_t now) { dns_fetchevent_t *event; void *data; + FCTXTRACE("ncache_message"); + + fctx->attributes &= ~FCTX_ATTR_WANTNCACHE; + res = fctx->res; need_validation = ISC_FALSE; eresult = ISC_R_SUCCESS; @@ -1503,6 +1515,7 @@ ncache_message(fetchctx_t *fctx, dns_rdatatype_t covers, isc_stdtime_t now) { eresult = DNS_R_NCACHENXDOMAIN; else eresult = DNS_R_NCACHENXRRSET; + result = ISC_R_SUCCESS; } else { /* * Either we don't care about the nature of the @@ -1691,10 +1704,12 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) { isc_result_t result; dns_message_t *message; dns_name_t *name, *qname, *ns_name, *soa_name; - dns_rdataset_t *rdataset; + dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t done, aa, negative_response; dns_rdatatype_t type; + FCTXTRACE("noanswer_response"); + message = fctx->rmessage; /* @@ -1721,14 +1736,25 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) { /* * We have to figure out if this is a negative response, or a - * referral. We start by examining the rcode. + * referral. + */ + + /* + * Sometimes we can tell if its a negative response by looking at + * the message header. */ negative_response = ISC_FALSE; - if (message->rcode == dns_rcode_nxdomain) + if (message->rcode == dns_rcode_nxdomain || + (message->counts[DNS_SECTION_ANSWER] == 0 && + message->counts[DNS_SECTION_AUTHORITY] == 0)) negative_response = ISC_TRUE; + /* + * Process the authority section. + */ done = ISC_FALSE; ns_name = NULL; + ns_rdataset = NULL; soa_name = NULL; result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (!done && result == ISC_R_SUCCESS) { @@ -1755,18 +1781,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) { rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = dns_trust_glue; - /* - * Mark any additional data related - * to this rdataset. - */ - fctx->attributes |= - FCTX_ATTR_GLUING; - (void)dns_rdataset_additionaldata( - rdataset, - check_related, - fctx); - fctx->attributes &= - ~FCTX_ATTR_GLUING; + ns_rdataset = rdataset; } else if (rdataset->type == dns_rdatatype_soa || rdataset->type == @@ -1837,25 +1852,21 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) { ns_name->attributes &= ~DNS_NAMEATTR_CACHE; } - /* - * A negative response without an SOA isn't useful. - */ - if (negative_response && soa_name == NULL) { - if (oqname != NULL) { - /* - * But again, we don't care if we've got an answer - * already. - */ - return (ISC_R_SUCCESS); - } else - return (DNS_R_FORMERR); - } - /* * Do we have a referral? (We only want to follow a referral if * we're not following a chain.) */ if (!negative_response && ns_name != NULL && oqname == NULL) { + /* + * Mark any additional data related to this rdataset. + * It's important that we do this before we change the + * query domain. + */ + INSIST(ns_rdataset != NULL); + fctx->attributes |= FCTX_ATTR_GLUING; + (void)dns_rdataset_additionaldata(ns_rdataset, check_related, + fctx); + fctx->attributes &= ~FCTX_ATTR_GLUING; /* * Set the current query domain to the referral name. */ @@ -1866,9 +1877,13 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname) { result = dns_name_dup(ns_name, fctx->res->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) return (result); + fctx->attributes |= FCTX_ATTR_WANTCACHE; return (DNS_R_DELEGATION); } + if (negative_response) + fctx->attributes |= FCTX_ATTR_WANTNCACHE; + return (ISC_R_SUCCESS); } @@ -1884,6 +1899,8 @@ answer_response(fetchctx_t *fctx) { dns_rdatatype_t type; dns_fixedname_t dname; + FCTXTRACE("answer_response"); + message = fctx->rmessage; /* @@ -2136,6 +2153,11 @@ answer_response(fetchctx_t *fctx) { if (!have_answer) return (DNS_R_FORMERR); + /* + * This response is now potentially cacheable. + */ + fctx->attributes |= FCTX_ATTR_WANTCACHE; + /* * Did chaining end before we got the final answer? */ @@ -2338,20 +2360,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ get_nameservers = ISC_TRUE; keep_trying = ISC_TRUE; - } else if (result == ISC_R_SUCCESS) { - if (message->rcode == dns_rcode_nxdomain) - covers = dns_rdatatype_any; - else - covers = fctx->type; - /* - * Cache any negative cache entries in the message. - * This may also cause work to be queued to the - * DNSSEC validator. - */ - result = ncache_message(fctx, covers, now); - if (result != ISC_R_SUCCESS) - goto done; - } else { + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS) { /* * Something has gone wrong. */ @@ -2378,7 +2388,26 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Cache the cacheable parts of the message. This may also cause * work to be queued to the DNSSEC validator. */ - result = cache_message(fctx, now); + if (WANTCACHE(fctx)) { + result = cache_message(fctx, now); + if (result != ISC_R_SUCCESS) + goto done; + } + + /* + * Ncache the negatively cacheable parts of the message. This may + * also cause work to be queued to the DNSSEC validator. + */ + if (WANTNCACHE(fctx)) { + if (message->rcode == dns_rcode_nxdomain) + covers = dns_rdatatype_any; + else + covers = fctx->type; + /* + * Cache any negative cache entries in the message. + */ + result = ncache_message(fctx, covers, now); + } done: /*