mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
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:
parent
5a62edfc26
commit
c9107bfb1a
6 changed files with 123 additions and 13 deletions
114
daemon/worker.c
114
daemon/worker.c
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
||||||
|
|
|
||||||
5
services/cache/dns.c
vendored
5
services/cache/dns.c
vendored
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3
services/cache/dns.h
vendored
3
services/cache/dns.h
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue