diff --git a/doc/Changelog b/doc/Changelog index 63495ee94..01808e65d 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +21 August 2008: Wouter + - negative cache code linked into validator, for DLV use. + negative cache works for DLV. + 20 August 2008: Wouter - negative cache code, reviewed. diff --git a/validator/val_neg.c b/validator/val_neg.c index 85152a70b..29fd2d006 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -464,7 +464,7 @@ static struct val_neg_zone* neg_zone_chain( struct val_neg_zone* parent) { int i; - int tolabs = parent?parent->labs:-1; + int tolabs = parent?parent->labs:0; struct val_neg_zone* zone, *prev = NULL, *first = NULL; /* create the new subtree, i is labelcount of current creation */ @@ -612,7 +612,7 @@ static struct val_neg_data* neg_data_chain( uint8_t* nm, size_t nm_len, int labs, struct val_neg_data* parent) { int i; - int tolabs = parent?parent->labs:-1; + int tolabs = parent?parent->labs:0; struct val_neg_data* el, *first = NULL, *prev = NULL; /* create the new subtree, i is labelcount of current creation */ @@ -680,11 +680,11 @@ static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone, } walk = rbtree_next(&el->node); - while( walk ) { + while(walk && walk != RBTREE_NULL) { cur = (struct val_neg_data*)walk; /* sanity check: must be larger than start */ - if(dname_canon_lab_cmp(el->name, el->labs, - cur->name, cur->labs, &m) <= 0) { + if(dname_canon_lab_cmp(cur->name, cur->labs, + el->name, el->labs, &m) <= 0) { /* r == 0 skip original record. */ /* r < 0 too small! */ walk = rbtree_next(walk); @@ -738,6 +738,8 @@ static void neg_insert_data(struct val_neg_cache* neg, d = (struct packed_rrset_data*)nsec->entry.data; if(d->security != sec_status_secure) return; + log_nametypeclass(VERB_ALGO, "negcache rr", + nsec->rk.dname, LDNS_RR_TYPE_NSEC, ntohs(nsec->rk.rrset_class)); /* find closest enclosing parent data that (still) exists */ parent = neg_closest_data_parent(zone, nm, nm_len, labs); @@ -766,6 +768,7 @@ static void neg_insert_data(struct val_neg_cache* neg, /* mem use */ neg->use += sizeof(struct val_neg_data) + p->len; /* insert in tree */ + p->zone = zone; (void)rbtree_insert(&zone->tree, &p->node); /* last one needs proper parent pointer */ if(np == NULL) @@ -806,6 +809,9 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep) if(!soa) return; + log_nametypeclass(VERB_ALGO, "negcache insert for zone", + soa->rk.dname, LDNS_RR_TYPE_SOA, ntohs(soa->rk.rrset_class)); + /* ask for enough space to store all of it */ need = calc_data_need(rep) + calc_zone_need(soa); lock_basic_lock(&neg->lock); @@ -875,6 +881,9 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, uint8_t* wc; struct query_info qinfo; if(!neg) return 0; + + log_nametypeclass(VERB_ALGO, "negcache dlvlookup", qname, + LDNS_RR_TYPE_DLV, qclass); labs = dname_count_labels(qname); lock_basic_lock(&neg->lock); @@ -885,6 +894,8 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, lock_basic_unlock(&neg->lock); return 0; } + log_nametypeclass(VERB_ALGO, "negcache zone", zone->name, 0, + zone->dclass); /* lookup closest data record */ (void)neg_closest_data(zone, qname, len, labs, &data); @@ -894,6 +905,8 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, lock_basic_unlock(&neg->lock); return 0; } + log_nametypeclass(VERB_ALGO, "negcache rr", data->name, + LDNS_RR_TYPE_NSEC, zone->dclass); /* lookup rrset in rrset cache */ flags = 0; @@ -908,7 +921,7 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, return 0; } d = (struct packed_rrset_data*)nsec->entry.data; - if(!d || d->ttl > now) { + if(!d || now > d->ttl) { lock_rw_unlock(&nsec->entry.lock); /* delete data record if expired */ neg_delete_data(neg, data); @@ -921,6 +934,7 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, lock_basic_unlock(&neg->lock); return 0; } + verbose(VERB_ALGO, "negcache got secure rrset"); /* check NSEC security */ /* check if NSEC proves no DLV type exists */ @@ -933,6 +947,7 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, /* the NSEC is not a denial for the DLV */ lock_rw_unlock(&nsec->entry.lock); lock_basic_unlock(&neg->lock); + verbose(VERB_ALGO, "negcache not proven"); return 0; } /* so the NSEC was a NODATA proof, or NXDOMAIN proof. */ @@ -944,5 +959,6 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, /* if OK touch the LRU for neg_data element */ neg_lru_touch(neg, data); lock_basic_unlock(&neg->lock); - return 0; + verbose(VERB_ALGO, "negcache DLV denial proven"); + return 1; } diff --git a/validator/validator.c b/validator/validator.c index 89547da9f..0b4e7f878 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -47,6 +47,7 @@ #include "validator/val_utils.h" #include "validator/val_nsec.h" #include "validator/val_nsec3.h" +#include "validator/val_neg.h" #include "services/cache/dns.h" #include "util/data/dname.h" #include "util/module.h" @@ -120,6 +121,16 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env, log_err("validator: error in trustanchors config"); return 0; } + if(!val_env->neg_cache) + val_env->neg_cache = val_neg_create(); + if(!val_env->neg_cache) { + log_err("out of memory"); + return 0; + } + if(!val_neg_apply_cfg(val_env->neg_cache, cfg)) { + log_err("validator: error in negative cache config"); + return 0; + } val_env->date_override = cfg->val_date_override; c = cfg_count_numbers(cfg->val_nsec3_key_iterations); if(c < 1 || (c&1)) { @@ -164,6 +175,7 @@ val_deinit(struct module_env* env, int id) anchors_delete(env->anchors); env->anchors = NULL; key_cache_delete(val_env->kcache); + neg_cache_delete(val_env->neg_cache); free(val_env->nsec3_keysize); free(val_env->nsec3_maxiter); free(val_env); @@ -1575,12 +1587,11 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, /* If we can find the name in the aggressive negative cache, * give up; insecure is the answer */ - /* lookup, several places in the tree may qualify - * between insecure_at and the lookup_name - * Check proof thoroughly - * TODO - * return 1; - */ + if(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name, + vq->dlv_lookup_name_len, vq->qchase.qclass, + qstate->env->rrset_cache, *qstate->env->now)) { + return 1; + } /* perform a lookup for the DLV; with validation */ vq->state = VAL_DLVLOOKUP_STATE; @@ -1798,6 +1809,16 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, return 1; } + /* check negative cache before making new request */ + if(val_neg_dlvlookup(ve->neg_cache, vq->dlv_lookup_name, + vq->dlv_lookup_name_len, vq->qchase.qclass, + qstate->env->rrset_cache, *qstate->env->now)) { + vq->dlv_status = dlv_there_is_no_dlv; + /* continue with the insecure result we got */ + vq->state = VAL_FINISHED_STATE; + return 1; + } + if(!generate_request(qstate, id, vq->dlv_lookup_name, vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, vq->qchase.qclass, 0)) { @@ -2383,6 +2404,8 @@ process_dlv_response(struct module_qstate* qstate, struct val_qstate* vq, vq->dlv_status = dlv_success; return; } + /* store NSECs into negative cache */ + val_neg_addreply(ve->neg_cache, msg->rep); /* was the lookup a failure? * if we have to go up into the DLV for a higher DLV anchor @@ -2460,6 +2483,7 @@ val_get_mem(struct module_env* env, int id) if(!ve) return 0; return sizeof(*ve) + key_cache_get_mem(ve->kcache) + + val_neg_get_mem(ve->neg_cache) + anchors_get_mem(env->anchors) + sizeof(size_t)*2*ve->nsec3_keyiter_count; } diff --git a/validator/validator.h b/validator/validator.h index daf65c34f..28fbbc058 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -48,6 +48,7 @@ struct val_anchors; struct key_cache; struct key_entry_key; +struct val_neg_cache; /** * This is the TTL to use when a trust anchor fails to prime. A trust anchor @@ -63,6 +64,9 @@ struct val_env { * end up here after being primed. */ struct key_cache* kcache; + /** aggressive negative cache. index into NSECs in rrset cache. */ + struct val_neg_cache* neg_cache; + /** for debug testing a fixed validation date can be entered. * if 0, current time is used for rrsig validation */ int32_t date_override;