answer non-recursive straight from cache, if possible.

git-svn-id: file:///svn/unbound/trunk@548 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-08-27 09:53:16 +00:00
parent 5a62edfc26
commit c9107bfb1a
6 changed files with 123 additions and 13 deletions

View file

@ -55,6 +55,7 @@
#include "services/outbound_list.h" #include "services/outbound_list.h"
#include "services/cache/rrset.h" #include "services/cache/rrset.h"
#include "services/cache/infra.h" #include "services/cache/infra.h"
#include "services/cache/dns.h"
#include "services/mesh.h" #include "services/mesh.h"
#include "util/data/msgparse.h" #include "util/data/msgparse.h"
#include "util/data/msgencode.h" #include "util/data/msgencode.h"
@ -302,6 +303,96 @@ worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
return 0; return 0;
} }
/** check if a delegation is secure */
static enum sec_status
check_delegation_secure(struct reply_info *rep)
{
/* return smallest security status */
size_t i;
enum sec_status sec = sec_status_secure;
enum sec_status s;
for(i=0; i<rep->rrset_count; i++) {
s = ((struct packed_rrset_data*)rep->rrsets[i])->security;
if(s < sec)
sec = s;
}
return sec;
}
/** answer nonrecursive query from the cache */
static int
answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
uint16_t id, uint16_t flags, struct comm_reply* repinfo,
struct edns_data* edns)
{
/* for a nonrecursive query return either:
* o an error (servfail; we try to avoid this)
* o a delegation (closest we have; this routine tries that)
* o the answer (checked by answer_from_cache)
*
* So, grab a delegation from the rrset cache.
* Then check if it needs validation, if so, this routine fails,
* so that iterator can prime and validator can verify rrsets.
*/
uint16_t udpsize = edns->udp_size;
int secure = 0;
uint32_t timenow = (uint32_t)time(0);
int must_validate = !(flags&BIT_CD) && worker->env.need_to_validate;
struct dns_msg *msg = NULL;
struct delegpt *dp;
dp = dns_cache_find_delegation(&worker->env, qinfo->qname,
qinfo->qname_len, qinfo->qtype, qinfo->qclass,
worker->scratchpad, &msg, timenow);
if(!dp) { /* no delegation, need to reprime */
region_free_all(worker->scratchpad);
return 0;
}
if(must_validate) {
switch(check_delegation_secure(msg->rep)) {
case sec_status_unchecked:
/* some rrsets have not been verified yet, go and
* let validator do that */
region_free_all(worker->scratchpad);
return 0;
case sec_status_bogus:
/* some rrsets are bogus, reply servfail */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
region_free_all(worker->scratchpad);
return 1;
case sec_status_secure:
/* all rrsets are secure */
secure = 1;
break;
case sec_status_indeterminate:
case sec_status_insecure:
default:
/* not secure */
secure = 0;
break;
}
}
/* return this delegation from the cache */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
msg->rep->flags |= BIT_QR|BIT_RA;
if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
}
region_free_all(worker->scratchpad);
return 1;
}
/** check cname chain in cache reply */ /** check cname chain in cache reply */
static int static int
check_cache_chain(struct reply_info* rep) { check_cache_chain(struct reply_info* rep) {
@ -358,10 +449,6 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
*/ */
return 0; return 0;
} }
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
return 0; return 0;
/* locked and ids and ttls are OK. */ /* locked and ids and ttls are OK. */
@ -382,6 +469,10 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
/* check security status of the cached answer */ /* check security status of the cached answer */
if( rep->security == sec_status_bogus && must_validate) { if( rep->security == sec_status_bogus && must_validate) {
/* BAD cached */ /* BAD cached */
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&mrentry->key, id, flags, edns); &mrentry->key, id, flags, edns);
rrset_array_unlock_touch(worker->env.rrset_cache, rrset_array_unlock_touch(worker->env.rrset_cache,
@ -405,6 +496,10 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
} }
} else secure = 0; } else secure = 0;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags, if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad, repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
@ -589,7 +684,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
edns.udp_size = 65535; /* max size for TCP replies */ edns.udp_size = 65535; /* max size for TCP replies */
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
&edns, c->buffer)) { &edns, c->buffer)) {
verbose(VERB_ALGO, "class CH reply");
return 1; return 1;
} }
h = query_info_hash(&qinfo); h = query_info_hash(&qinfo);
@ -605,6 +699,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_DETAIL, "answer from the cache -- data has timed out"); verbose(VERB_DETAIL, "answer from the cache -- data has timed out");
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
} }
if(!LDNS_RD_WIRE(ldns_buffer_begin(c->buffer))) {
if(answer_norec_from_cache(worker, &qinfo,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
return 1;
}
verbose(VERB_DETAIL, "answer norec from cache -- "
"need to validate or not primed");
}
ldns_buffer_rewind(c->buffer); ldns_buffer_rewind(c->buffer);
server_stats_querymiss(&worker->stats, worker); server_stats_querymiss(&worker->stats, worker);

View file

@ -1,3 +1,7 @@
27 August 2007: Wouter
- do not garble the edns if a cache answer fails.
- answer norecursive from cache if possible.
24 August 2007: Wouter 24 August 2007: Wouter
- message is bogus if unsecure authority rrsets are present. - message is bogus if unsecure authority rrsets are present.
- val-clean-additional option, so you can turn it off. - val-clean-additional option, so you can turn it off.

View file

@ -652,7 +652,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
* to be primed for the qclass. */ * to be primed for the qclass. */
iq->dp = dns_cache_find_delegation(qstate->env, delname, delnamelen, iq->dp = dns_cache_find_delegation(qstate->env, delname, delnamelen,
iq->qchase.qtype, iq->qchase.qclass, qstate->region, iq->qchase.qtype, iq->qchase.qclass, qstate->region,
&iq->deleg_msg); &iq->deleg_msg, (uint32_t)time(NULL));
/* If the cache has returned nothing, then we have a root priming /* If the cache has returned nothing, then we have a root priming
* situation. */ * situation. */
@ -668,6 +668,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
* of priming. */ * of priming. */
return 0; return 0;
} }
if(verbosity >= VERB_ALGO) {
log_info("dns_cache_find_delegation returns delegpt");
delegpt_log(iq->dp);
}
/* Reset the RD flag. If this is a query restart, then the RD /* Reset the RD flag. If this is a query restart, then the RD
* will have been turned off. */ * will have been turned off. */

View file

@ -316,13 +316,12 @@ create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct delegpt* struct delegpt*
dns_cache_find_delegation(struct module_env* env, uint8_t* qname, dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
size_t qnamelen, uint16_t qtype, uint16_t qclass, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct region* region, struct dns_msg** msg) struct region* region, struct dns_msg** msg, uint32_t now)
{ {
/* try to find closest NS rrset */ /* try to find closest NS rrset */
struct ub_packed_rrset_key* nskey; struct ub_packed_rrset_key* nskey;
struct packed_rrset_data* nsdata; struct packed_rrset_data* nsdata;
struct delegpt* dp; struct delegpt* dp;
uint32_t now = (uint32_t)time(NULL);
nskey = find_closest_of_type(env, qname, qnamelen, qclass, now, nskey = find_closest_of_type(env, qname, qnamelen, qclass, now,
LDNS_RR_TYPE_NS); LDNS_RR_TYPE_NS);
@ -355,8 +354,6 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
/* find and add A entries */ /* find and add A entries */
if(!find_add_addrs(env, qclass, region, dp, now, msg)) if(!find_add_addrs(env, qclass, region, dp, now, msg))
log_err("find_delegation: addrs out of memory"); log_err("find_delegation: addrs out of memory");
log_info("dns_cache_find_delegation returns delegpt");
delegpt_log(dp);
return dp; return dp;
} }

View file

@ -102,11 +102,12 @@ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
* @param region: where to allocate result delegation. * @param region: where to allocate result delegation.
* @param msg: if not NULL, delegation message is returned here, synthesized * @param msg: if not NULL, delegation message is returned here, synthesized
* from the cache. * from the cache.
* @param timenow: the time now, for checking if TTL on cache entries is OK.
* @return new delegation or NULL on error or if not found in cache. * @return new delegation or NULL on error or if not found in cache.
*/ */
struct delegpt* dns_cache_find_delegation(struct module_env* env, struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct region* region, struct dns_msg** msg); struct region* region, struct dns_msg** msg, uint32_t timenow);
/** /**
* Find cached message * Find cached message

View file

@ -712,8 +712,8 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
int attach_edns = 1; int attach_edns = 1;
if(!cached) { if(!cached) {
/* original flags, copy RD bit from query. */ /* original flags, copy RD and CD bits from query. */
flags = rep->flags | (qflags & BIT_RD); flags = rep->flags | (qflags & (BIT_RD|BIT_CD));
} else { } else {
/* remove AA bit, copy RD and CD bits from query. */ /* remove AA bit, copy RD and CD bits from query. */
flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));