validate_nameerror_response(struct module_env* env, struct val_env* ve,
	struct query_info* qchase, struct reply_info* chase_reply,
	struct key_entry_key* kkey, int* rcode)
{
	int has_valid_nsec = 0;
	int has_valid_wnsec = 0;
	int nsec3s_seen = 0;
	struct ub_packed_rrset_key* s; 
	size_t i;
	uint8_t* ce;
	int ce_labs = 0;
	int prev_ce_labs = 0;

	for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
		chase_reply->ns_numrrsets; i++) {
		s = chase_reply->rrsets[i];
		if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
			if(val_nsec_proves_name_error(s, qchase->qname))
				has_valid_nsec = 1;
			ce = nsec_closest_encloser(qchase->qname, s);            
			ce_labs = dname_count_labels(ce);                        
			/* Use longest closest encloser to prove wildcard. */
			if(ce_labs > prev_ce_labs ||                             
			       (ce_labs == prev_ce_labs &&                      
				       has_valid_wnsec == 0)) {                 
			       if(val_nsec_proves_no_wc(s, qchase->qname,       
				       qchase->qname_len))                      
				       has_valid_wnsec = 1;                     
			       else                                             
				       has_valid_wnsec = 0;                     
			}                                                        
			prev_ce_labs = ce_labs; 
			if(val_nsec_proves_insecuredelegation(s, qchase)) {
				verbose(VERB_ALGO, "delegation is insecure");
				chase_reply->security = sec_status_insecure;
				return;
			}
		} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3)
			nsec3s_seen = 1;
	}

	if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) {
		/* use NSEC3 proof, both answer and auth rrsets, in case
		 * NSEC3s end up in the answer (due to qtype=NSEC3 or so) */
		chase_reply->security = nsec3_prove_nameerror(env, ve,
			chase_reply->rrsets, chase_reply->an_numrrsets+
			chase_reply->ns_numrrsets, qchase, kkey);
		if(chase_reply->security != sec_status_secure) {
			verbose(VERB_QUERY, "NameError response failed nsec, "
				"nsec3 proof was %s", sec_status_to_string(
				chase_reply->security));
			return;
		}
		has_valid_nsec = 1;
		has_valid_wnsec = 1;
	}

	/* If the message fails to prove either condition, it is bogus. */
	if(!has_valid_nsec) {
		verbose(VERB_QUERY, "NameError response has failed to prove: "
		          "qname does not exist");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		/* Be lenient with RCODE in NSEC NameError responses */
		validate_nodata_response(env, ve, qchase, chase_reply, kkey);
		if (chase_reply->security == sec_status_secure)
			*rcode = LDNS_RCODE_NOERROR;
		return;
	}

	if(!has_valid_wnsec) {
		verbose(VERB_QUERY, "NameError response has failed to prove: "
		          "covering wildcard does not exist");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		/* Be lenient with RCODE in NSEC NameError responses */
		validate_nodata_response(env, ve, qchase, chase_reply, kkey);
		if (chase_reply->security == sec_status_secure)
			*rcode = LDNS_RCODE_NOERROR;
		return;
	}

	/* Otherwise, we consider the message secure. */
	verbose(VERB_ALGO, "successfully validated NAME ERROR response.");
	chase_reply->security = sec_status_secure;
}
validate_nameerror_response(struct module_env* env, struct val_env* ve,
	struct query_info* qchase, struct reply_info* chase_reply,
	struct key_entry_key* kkey, int* rcode)
{
	int has_valid_nsec = 0;
	int has_valid_wnsec = 0;
	int nsec3s_seen = 0;
	struct ub_packed_rrset_key* s; 
	size_t i;
	uint8_t* ce;
	int ce_labs = 0;
	int prev_ce_labs = 0;

	for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
		chase_reply->ns_numrrsets; i++) {
		s = chase_reply->rrsets[i];
		if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
			if(val_nsec_proves_name_error(s, qchase->qname))
				has_valid_nsec = 1;
			ce = nsec_closest_encloser(qchase->qname, s);            
			ce_labs = dname_count_labels(ce);                        
			 
			if(ce_labs > prev_ce_labs ||                             
			       (ce_labs == prev_ce_labs &&                      
				       has_valid_wnsec == 0)) {                 
			       if(val_nsec_proves_no_wc(s, qchase->qname,       
				       qchase->qname_len))                      
				       has_valid_wnsec = 1;                     
			       else                                             
				       has_valid_wnsec = 0;                     
			}                                                        
			prev_ce_labs = ce_labs; 
			if(val_nsec_proves_insecuredelegation(s, qchase)) {
				verbose(VERB_ALGO, "delegation is insecure");
				chase_reply->security = sec_status_insecure;
				return;
			}
		} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3)
			nsec3s_seen = 1;
	}

	if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) {
		 
		chase_reply->security = nsec3_prove_nameerror(env, ve,
			chase_reply->rrsets, chase_reply->an_numrrsets+
			chase_reply->ns_numrrsets, qchase, kkey);
		if(chase_reply->security != sec_status_secure) {
			verbose(VERB_QUERY, "NameError response failed nsec, "
				"nsec3 proof was %s", sec_status_to_string(
				chase_reply->security));
			return;
		}
		has_valid_nsec = 1;
		has_valid_wnsec = 1;
	}

	 
	if(!has_valid_nsec) {
		verbose(VERB_QUERY, "NameError response has failed to prove: "
		          "qname does not exist");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		 
		validate_nodata_response(env, ve, qchase, chase_reply, kkey);
		if (chase_reply->security == sec_status_secure)
			*rcode = LDNS_RCODE_NOERROR;
		return;
	}

	if(!has_valid_wnsec) {
		verbose(VERB_QUERY, "NameError response has failed to prove: "
		          "covering wildcard does not exist");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		 
		validate_nodata_response(env, ve, qchase, chase_reply, kkey);
		if (chase_reply->security == sec_status_secure)
			*rcode = LDNS_RCODE_NOERROR;
		return;
	}

	 
	verbose(VERB_ALGO, "successfully validated NAME ERROR response.");
	chase_reply->security = sec_status_secure;
}