Description: enable aggressive nsec use for nxdomain URL: http://member.wide.ad.jp/~fujiwara/files/unbound.diff Author: Fujiwara --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ Index: unbound-1.6.1~rc3/validator/val_neg.c =================================================================== --- unbound-1.6.1~rc3.orig/validator/val_neg.c +++ unbound-1.6.1~rc3/validator/val_neg.c @@ -927,6 +927,107 @@ static int neg_closest_data(struct val_n } } +struct packed_rrset_data* val_neg_lookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, + uint16_t qtype, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now) +{ + /* lookup closest zone */ + struct val_neg_zone* zone; + struct val_neg_data* data; + int labs; + struct ub_packed_rrset_key* nsec; + struct packed_rrset_data* d; + uint32_t flags; + uint8_t* wc; + struct query_info qinfo; + if(!neg) return NULL; + + log_nametypeclass(VERB_ALGO, "negcache lookup", qname, + qtype, qclass); + + labs = dname_count_labels(qname); + lock_basic_lock(&neg->lock); + zone = neg_closest_zone_parent(neg, qname, len, labs, qclass); + while(zone && !zone->in_use) + zone = zone->parent; + if(!zone) { + lock_basic_unlock(&neg->lock); + return NULL; + } + log_nametypeclass(VERB_ALGO, "negcache zone", zone->name, 0, + zone->dclass); + + /* DLV is defined to use NSEC only */ + if(zone->nsec3_hash) { + lock_basic_unlock(&neg->lock); + return NULL; + } + + /* lookup closest data record */ + (void)neg_closest_data(zone, qname, len, labs, &data); + while(data && !data->in_use) + data = data->parent; + if(!data) { + lock_basic_unlock(&neg->lock); + return NULL; + } + log_nametypeclass(VERB_ALGO, "negcache rr", data->name, + LDNS_RR_TYPE_NSEC, zone->dclass); + + /* lookup rrset in rrset cache */ + flags = 0; + if(query_dname_compare(data->name, zone->name) == 0) + flags = PACKED_RRSET_NSEC_AT_APEX; + nsec = rrset_cache_lookup(rrset_cache, data->name, data->len, + LDNS_RR_TYPE_NSEC, zone->dclass, flags, now, 0); + + /* check if secure and TTL ok */ + if(!nsec) { + lock_basic_unlock(&neg->lock); + return NULL; + } + d = (struct packed_rrset_data*)nsec->entry.data; + if(!d || now > d->ttl) { + lock_rw_unlock(&nsec->entry.lock); + /* delete data record if expired */ + neg_delete_data(neg, data); + lock_basic_unlock(&neg->lock); + return NULL; + } + if(d->security != sec_status_secure) { + lock_rw_unlock(&nsec->entry.lock); + neg_delete_data(neg, data); + lock_basic_unlock(&neg->lock); + return NULL; + } + verbose(VERB_ALGO, "negcache got secure rrset"); + + /* check NSEC security */ + /* check if NSEC proves no DLV type exists */ + /* check if NSEC proves NXDOMAIN for qname */ + qinfo.qname = qname; + qinfo.qtype = qtype; + qinfo.qclass = qclass; + if(!nsec_proves_nodata(nsec, &qinfo, &wc) && + !val_nsec_proves_name_error(nsec, qname)) { + /* 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 NULL; + } + /* so the NSEC was a NODATA proof, or NXDOMAIN proof. */ + + /* no need to check for wildcard NSEC; no wildcards in DLV repos */ + /* no need to lookup SOA record for client; no response message */ + + lock_rw_unlock(&nsec->entry.lock); + /* if OK touch the LRU for neg_data element */ + neg_lru_touch(neg, data); + lock_basic_unlock(&neg->lock); + verbose(VERB_ALGO, "negcache denial proven"); + return nsec; +} + int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now) { Index: unbound-1.6.1~rc3/validator/val_neg.h =================================================================== --- unbound-1.6.1~rc3.orig/validator/val_neg.h +++ unbound-1.6.1~rc3/validator/val_neg.h @@ -231,6 +231,8 @@ void val_neg_addreferral(struct val_neg_ */ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now); +struct packed_rrset_data* val_neg_lookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, + uint16_t qtype, uint16_t qclass, struct rrset_cache* rrset_cache, time_t now); /** * For the given query, try to get a reply out of the negative cache. Index: unbound-1.6.1~rc3/validator/validator.c =================================================================== --- unbound-1.6.1~rc3.orig/validator/validator.c +++ unbound-1.6.1~rc3/validator/validator.c @@ -919,6 +919,9 @@ validate_nameerror_response(struct modul /* Otherwise, we consider the message secure. */ verbose(VERB_ALGO, "successfully validated NAME ERROR response."); chase_reply->security = sec_status_secure; + + /* store NSECs into negative cache */ + val_neg_addreply(ve->neg_cache, chase_reply); } /** @@ -2271,6 +2274,8 @@ val_operate(struct module_qstate* qstate { struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id]; + struct packed_rrset_data* nsec; + verbose(VERB_QUERY, "validator[module %d] operate: extstate:%s " "event:%s", id, strextstate(qstate->ext_state[id]), strmodulevent(event)); @@ -2283,6 +2288,19 @@ val_operate(struct module_qstate* qstate if(event == module_event_new || (event == module_event_pass && vq == NULL)) { + nsec = val_neg_lookup(ve->neg_cache, qstate->qinfo.qname, + qstate->qinfo.qname_len, qstate->qinfo.qtype, + qstate->qinfo.qclass, + qstate->env->rrset_cache, *qstate->env->now); + + /* Aggressive NSEC caching */ + if (nsec != NULL) { + qstate->return_rcode = LDNS_RCODE_NXDOMAIN; + qstate->return_msg = NULL; + qstate->ext_state[id] = module_finished; + return; + } + /* pass request to next module, to get it */ verbose(VERB_ALGO, "validator: pass to next module"); qstate->ext_state[id] = module_wait_module;