nxdomain validation.

git-svn-id: file:///svn/unbound/trunk@534 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-08-20 14:27:11 +00:00
parent 5605f8d003
commit 0f9ae7acd8
4 changed files with 131 additions and 16 deletions

View file

@ -1,7 +1,7 @@
18 August 2007: Wouter
- process DNSKEY response in FINDKEY state.
- validate and positive validation, positive wildcard NSEC validation.
- nodata validation.
- nodata validation, nxdomain validation.
17 August 2007: Wouter
- work on DS2KE routine.

View file

@ -330,19 +330,21 @@ val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname)
return 0;
}
/* see if this nsec is the only nsec */
if(query_dname_compare(owner, next) == 0) {
/* only zone.name NSEC zone.name, disproves everything else */
return 1;
}
/* see if this nsec is the last nsec */
if(dname_canonical_compare(owner, next) > 0) {
/* this is the last nsec, ....(bigger) NSEC zonename(smaller) */
/* the names after the last (owner) name do not exist */
if(dname_canonical_compare(owner, qname) < 0)
/* this nsec is the only nsec */
/* zone.name NSEC zone.name, disproves everything else */
/* but only for subdomains of that zone */
if(dname_strict_subdomain_c(qname, next))
return 1;
}
else if(dname_canonical_compare(owner, next) > 0) {
/* this is the last nsec, ....(bigger) NSEC zonename(smaller) */
/* the names after the last (owner) name do not exist
* there are no names before the zone name in the zone
* but the qname must be a subdomain of the zone name(next). */
if(dname_canonical_compare(owner, qname) < 0 &&
dname_strict_subdomain_c(qname, next))
return 1;
/* there are no names before the zone name in the zone */
/* if(dname_canonical_compare(qname, next) < 0) return 1; */
} else {
/* regular NSEC, (smaller) NSEC (larger) */
if(dname_canonical_compare(owner, qname) < 0 &&
@ -387,3 +389,38 @@ int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
}
return 1;
}
int
val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
size_t qnamelen)
{
/* Determine if a NSEC record proves the non-existence of a
* wildcard that could have produced qname. */
int labs;
int i;
uint8_t* ce = nsec_closest_encloser(qname, nsec);
uint8_t* strip;
size_t striplen;
uint8_t buf[LDNS_MAX_DOMAINLEN+3];
if(!ce)
return 0;
/* we can subtract the closest encloser count - since that is the
* largest shared topdomain with owner and next NSEC name,
* because the NSEC is no proof for names shorter than the owner
* and next names. */
labs = dname_count_labels(qname) - dname_count_labels(ce);
for(i=labs; i>0; i--) {
/* i is number of labels to strip off qname, prepend * wild */
strip = qname;
striplen = qnamelen;
dname_remove_labels(&strip, &striplen, i);
buf[0] = 1;
buf[1] = (uint8_t)'*';
memmove(buf+2, strip, striplen);
if(val_nsec_proves_name_error(nsec, buf)) {
return 1;
}
}
return 0;
}

View file

@ -123,4 +123,15 @@ int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
uint8_t* nsec_closest_encloser(uint8_t* qname,
struct ub_packed_rrset_key* nsec);
/**
* Determine if the given NSEC proves that a wildcard match does not exist.
*
* @param nsec: the nsec RRset.
* @param qname: the name queried for.
* @param qnamelen: length of qname.
* @return true if proven.
*/
int val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
size_t qnamelen);
#endif /* VALIDATOR_VAL_NSEC_H */

View file

@ -451,9 +451,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
if(val_nsec_proves_name_error(s, qchase->qname)) {
ce = nsec_closest_encloser(qchase->qname, s);
}
}
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
nsec3s_seen = 1;
}
}
@ -491,12 +489,81 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
chase_reply->security = sec_status_secure;
}
/** validate NAME ERROR (nxdomain) response */
/**
* Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
* Rcode. This consists of verifying the authority section rrsets and making
* certain that the authority section NSEC proves that the qname doesn't
* exist and the covering wildcard also doesn't exist..
*
* Note that by the time this method is called, the process of finding the
* trusted DNSKEY rrset that signs this response must already have been
* completed.
*
* @param env: module env for verify.
* @param ve: validator env for verify.
* @param qchase: query that was made.
* @param chase_reply: answer to that query to validate.
* @param key_entry: the key entry, which is trusted, and which matches
* the signer of the answer. The key entry isgood().
*/
static void
validate_nameerror_response(struct module_env* env, struct val_env* ve,
struct query_info* qchase, struct reply_info* chase_reply,
struct key_entry_key* key_entry)
{
/* FIXME: should we check to see if there is anything in the answer
* section? if so, what should the result be? */
int has_valid_nsec = 0;
int has_valid_wnsec = 0;
int nsec3s_seen = 0;
struct ub_packed_rrset_key* s;
enum sec_status sec;
size_t i;
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
chase_reply->ns_numrrsets; i++) {
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry);
if(sec != sec_status_secure) {
log_nametypeclass(VERB_ALGO, "NameError response has "
"failed AUTHORITY rrset: ", s->rk.dname,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
return;
}
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
if(val_nsec_proves_name_error(s, qchase->qname))
has_valid_nsec = 1;
if(val_nsec_proves_no_wc(s, qchase->qname,
qchase->qname_len))
has_valid_wnsec = 1;
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3)
nsec3s_seen = 1;
}
if(!has_valid_nsec || !has_valid_wnsec) {
/* TODO: use NSEC3 proof */
}
/* If the message fails to prove either condition, it is bogus. */
if(!has_valid_nsec) {
verbose(VERB_ALGO, "NameError response has failed to prove: "
"qname does not exist");
chase_reply->security = sec_status_bogus;
return;
}
if(!has_valid_wnsec) {
verbose(VERB_ALGO, "NameError response has failed to prove: "
"covering wildcard does not exist");
chase_reply->security = sec_status_bogus;
return;
}
/* Otherwise, we consider the message secure. */
verbose(VERB_ALGO, "successfully validated NAME ERROR response.");
chase_reply->security = sec_status_secure;
}
/** validate positive ANY response */