diff --git a/doc/Changelog b/doc/Changelog index 92ad04c04..c8f8cfa88 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,9 @@ +15 August 2008: Wouter + - DLV nsec code fixed for better detection of closest existing + enclosers from NSEC responses. + - DLV works, straight to the dlv repository, so not for production. + - Iana port update. + 14 August 2008: Wouter - synthesize DLV messages from the rrset cache, like done for DS. diff --git a/util/iana_ports.inc b/util/iana_ports.inc index 612cfd42e..6fc97f75e 100644 --- a/util/iana_ports.inc +++ b/util/iana_ports.inc @@ -661,6 +661,7 @@ 848, 860, 861, +862, 873, 886, 887, diff --git a/validator/val_nsec.c b/validator/val_nsec.c index 009aa814c..016b33a55 100644 --- a/validator/val_nsec.c +++ b/validator/val_nsec.c @@ -482,26 +482,26 @@ val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname, } /** - * Closest NONEMPTY encloser. - * Thus, no empty nonterminals are returned. - * @param qname: query name - * @param nsec: nsec record. - * @return the name (part of qname). + * Find shared topdomain that exists */ -static uint8_t* -nsec_closest_nonempty(uint8_t* qname, struct ub_packed_rrset_key* nsec) +static void +dlv_topdomain(struct ub_packed_rrset_key* nsec, uint8_t* qname, + uint8_t** nm, size_t* nm_len) { - uint8_t* next; - size_t nlen; - uint8_t* common1, *common2; - if(!nsec_get_next(nsec, &next, &nlen)) - return NULL; - /* shortest common with owner or next name */ - common1 = dname_get_shared_topdomain(qname, nsec->rk.dname); - common2 = dname_get_shared_topdomain(qname, next); - if(dname_count_labels(common1) < dname_count_labels(common2)) - return common1; - return common2; + /* make sure reply is part of nm */ + /* take shared topdomain with left of NSEC. */ + + /* because, if empty nonterminal, then right is subdomain of qname. + * and any shared topdomain would be empty nonterminals. + * + * If nxdomain, then the right is bigger, and could have an + * interesting shared topdomain, but if it does have one, it is + * an empty nonterminal. An empty nonterminal shared with the left + * one. */ + int n; + uint8_t* common = dname_get_shared_topdomain(qname, nsec->rk.dname); + n = dname_count_labels(*nm) - dname_count_labels(common); + dname_remove_labels(nm, nm_len, n); } int val_nsec_check_dlv(struct query_info* qinfo, @@ -525,14 +525,16 @@ int val_nsec_check_dlv(struct query_info* qinfo, rep->rrsets[i]->rk.dname, qinfo->qname); if(c == 0) { /* plain match */ + if(nsec_has_type(rep->rrsets[i], + LDNS_RR_TYPE_DLV)) + return 0; dname_remove_label(nm, nm_len); return 1; } else if(c < 0 && dname_strict_subdomain_c(next, qinfo->qname)) { /* ENT */ - *nm = nsec_closest_nonempty( - *nm, rep->rrsets[i]); - if(!*nm) return 0; + dlv_topdomain(rep->rrsets[i], qinfo->qname, + nm, nm_len); return 1; } } @@ -546,9 +548,8 @@ int val_nsec_check_dlv(struct query_info* qinfo, for(i=0; ins_numrrsets; i++) { if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) { - *nm = nsec_closest_nonempty( - *nm, rep->rrsets[i]); - if(!*nm) return 0; + dlv_topdomain(rep->rrsets[i], qinfo->qname, + nm, nm_len); return 1; } } diff --git a/validator/validator.c b/validator/validator.c index c05920be1..89547da9f 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1129,13 +1129,6 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, vq->ds_rrset = 0; vq->trust_anchor = anchors_lookup(qstate->env->anchors, lookup_name, lookup_len, vq->qchase.qclass); - if(vq->trust_anchor == NULL) { - /*response isn't under a trust anchor, so we cannot validate.*/ - vq->chase_reply->security = sec_status_indeterminate; - /* go to finished state to cache this result */ - vq->state = VAL_FINISHED_STATE; - return 1; - } /* Determine the signer/lookup name */ val_find_signer(subtype, &vq->qchase, vq->orig_msg->rep, @@ -1153,6 +1146,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, /* for NXDOMAIN it could be signed by a parent of the trust anchor */ if(subtype == VAL_CLASS_NAMEERROR && vq->signer_name && + vq->trust_anchor && dname_strict_subdomain_c(vq->trust_anchor->name, lookup_name)){ while(vq->trust_anchor && dname_strict_subdomain_c( vq->trust_anchor->name, lookup_name)) { @@ -1182,10 +1176,18 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, vq->key_entry = key_cache_obtain(ve->kcache, lookup_name, lookup_len, vq->qchase.qclass, qstate->region, *qstate->env->now); - + + /* there is no key(from DLV) and no trust anchor */ + if(vq->key_entry == NULL && vq->trust_anchor == NULL) { + /*response isn't under a trust anchor, so we cannot validate.*/ + vq->chase_reply->security = sec_status_indeterminate; + /* go to finished state to cache this result */ + vq->state = VAL_FINISHED_STATE; + return 1; + } /* if not key, or if keyentry is *above* the trustanchor, i.e. * the keyentry is based on another (higher) trustanchor */ - if(vq->key_entry == NULL || dname_strict_subdomain_c( + else if(vq->key_entry == NULL || dname_strict_subdomain_c( vq->trust_anchor->name, vq->key_entry->name)) { /* fire off a trust anchor priming query. */ verbose(VERB_DETAIL, "prime trust anchor"); @@ -1739,15 +1741,32 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, else if(vq->dlv_status==dlv_there_is_no_dlv) verbose(VERB_ALGO, "DLV woke up with status dlv_there_is_no_dlv"); else verbose(VERB_ALGO, "DLV woke up with status unknown"); - log_nametypeclass(VERB_ALGO, "next look", vq->dlv_lookup_name, - LDNS_RR_TYPE_DLV, vq->qchase.qclass); if(vq->dlv_status == dlv_error) { verbose(VERB_QUERY, "failed DLV lookup"); return val_error(qstate, id); } else if(vq->dlv_status == dlv_success) { + uint8_t* nm; + size_t nmlen; /* chain continues with DNSKEY, continue in FINDKEY */ vq->state = VAL_FINDKEY_STATE; + + /* strip off the DLV suffix from the name; could result in . */ + log_assert(dname_subdomain_c(vq->ds_rrset->rk.dname, + qstate->env->anchors->dlv_anchor->name)); + nmlen = vq->ds_rrset->rk.dname_len - + qstate->env->anchors->dlv_anchor->namelen + 1; + nm = regional_alloc_init(qstate->region, + vq->ds_rrset->rk.dname, nmlen); + if(!nm) { + log_err("Out of memory in DLVLook"); + return val_error(qstate, id); + } + nm[nmlen-1] = 0; + + vq->ds_rrset->rk.dname = nm; + vq->ds_rrset->rk.dname_len = nmlen; + if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, vq->qchase.qclass, BIT_CD)) { @@ -1779,8 +1798,8 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, return 1; } - if(!generate_request(qstate, id, vq->dlv_lookup_name, - vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, + if(!generate_request(qstate, id, vq->dlv_lookup_name, + vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, vq->qchase.qclass, 0)) { return val_error(qstate, id); }