aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/validator/validator.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/validator/validator.c')
-rw-r--r--contrib/unbound/validator/validator.c339
1 files changed, 246 insertions, 93 deletions
diff --git a/contrib/unbound/validator/validator.c b/contrib/unbound/validator/validator.c
index aa71df9cbf58..a0550b484eae 100644
--- a/contrib/unbound/validator/validator.c
+++ b/contrib/unbound/validator/validator.c
@@ -72,7 +72,8 @@
/* forward decl for cache response and normal super inform calls of a DS */
static void process_ds_response(struct module_qstate* qstate,
struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
- struct query_info* qinfo, struct sock_list* origin, int* suspend);
+ struct query_info* qinfo, struct sock_list* origin, int* suspend,
+ struct module_qstate* sub_qstate);
/* Updates the suplied EDE (RFC8914) code selectively so we don't lose
@@ -90,50 +91,98 @@ update_reason_bogus(struct reply_info* rep, sldns_ede_code reason_bogus)
/** fill up nsec3 key iterations config entry */
static int
-fill_nsec3_iter(struct val_env* ve, char* s, int c)
+fill_nsec3_iter(size_t** keysize, size_t** maxiter, char* s, int c)
{
char* e;
int i;
- free(ve->nsec3_keysize);
- free(ve->nsec3_maxiter);
- ve->nsec3_keysize = (size_t*)calloc(sizeof(size_t), (size_t)c);
- ve->nsec3_maxiter = (size_t*)calloc(sizeof(size_t), (size_t)c);
- if(!ve->nsec3_keysize || !ve->nsec3_maxiter) {
+ *keysize = (size_t*)calloc((size_t)c, sizeof(size_t));
+ *maxiter = (size_t*)calloc((size_t)c, sizeof(size_t));
+ if(!*keysize || !*maxiter) {
+ free(*keysize);
+ *keysize = NULL;
+ free(*maxiter);
+ *maxiter = NULL;
log_err("out of memory");
return 0;
}
for(i=0; i<c; i++) {
- ve->nsec3_keysize[i] = (size_t)strtol(s, &e, 10);
+ (*keysize)[i] = (size_t)strtol(s, &e, 10);
if(s == e) {
log_err("cannot parse: %s", s);
+ free(*keysize);
+ *keysize = NULL;
+ free(*maxiter);
+ *maxiter = NULL;
return 0;
}
s = e;
- ve->nsec3_maxiter[i] = (size_t)strtol(s, &e, 10);
+ (*maxiter)[i] = (size_t)strtol(s, &e, 10);
if(s == e) {
log_err("cannot parse: %s", s);
+ free(*keysize);
+ *keysize = NULL;
+ free(*maxiter);
+ *maxiter = NULL;
return 0;
}
s = e;
- if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) {
+ if(i>0 && (*keysize)[i-1] >= (*keysize)[i]) {
log_err("nsec3 key iterations not ascending: %d %d",
- (int)ve->nsec3_keysize[i-1],
- (int)ve->nsec3_keysize[i]);
+ (int)(*keysize)[i-1], (int)(*keysize)[i]);
+ free(*keysize);
+ *keysize = NULL;
+ free(*maxiter);
+ *maxiter = NULL;
return 0;
}
verbose(VERB_ALGO, "validator nsec3cfg keysz %d mxiter %d",
- (int)ve->nsec3_keysize[i], (int)ve->nsec3_maxiter[i]);
+ (int)(*keysize)[i], (int)(*maxiter)[i]);
}
return 1;
}
+int
+val_env_parse_key_iter(char* val_nsec3_key_iterations, size_t** keysize,
+ size_t** maxiter, int* keyiter_count)
+{
+ int c;
+ c = cfg_count_numbers(val_nsec3_key_iterations);
+ if(c < 1 || (c&1)) {
+ log_err("validator: unparsable or odd nsec3 key "
+ "iterations: %s", val_nsec3_key_iterations);
+ return 0;
+ }
+ *keyiter_count = c/2;
+ if(!fill_nsec3_iter(keysize, maxiter, val_nsec3_key_iterations, c/2)) {
+ log_err("validator: cannot apply nsec3 key iterations");
+ return 0;
+ }
+ return 1;
+}
+
+void
+val_env_apply_cfg(struct val_env* val_env, struct config_file* cfg,
+ size_t* keysize, size_t* maxiter, int keyiter_count)
+{
+ free(val_env->nsec3_keysize);
+ free(val_env->nsec3_maxiter);
+ val_env->nsec3_keysize = keysize;
+ val_env->nsec3_maxiter = maxiter;
+ val_env->nsec3_keyiter_count = keyiter_count;
+ val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
+ val_env->date_override = cfg->val_date_override;
+ val_env->skew_min = cfg->val_sig_skew_min;
+ val_env->skew_max = cfg->val_sig_skew_max;
+ val_env->max_restart = cfg->val_max_restart;
+}
+
/** apply config settings to validator */
static int
val_apply_cfg(struct module_env* env, struct val_env* val_env,
struct config_file* cfg)
{
- int c;
- val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl;
+ size_t* keysize=NULL, *maxiter=NULL;
+ int keyiter_count = 0;
if(!env->anchors)
env->anchors = anchors_create();
if(!env->anchors) {
@@ -153,21 +202,11 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
log_err("validator: error in trustanchors config");
return 0;
}
- val_env->date_override = cfg->val_date_override;
- val_env->skew_min = cfg->val_sig_skew_min;
- val_env->skew_max = cfg->val_sig_skew_max;
- val_env->max_restart = cfg->val_max_restart;
- c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
- if(c < 1 || (c&1)) {
- log_err("validator: unparsable or odd nsec3 key "
- "iterations: %s", cfg->val_nsec3_key_iterations);
- return 0;
- }
- val_env->nsec3_keyiter_count = c/2;
- if(!fill_nsec3_iter(val_env, cfg->val_nsec3_key_iterations, c/2)) {
- log_err("validator: cannot apply nsec3 key iterations");
+ if(!val_env_parse_key_iter(cfg->val_nsec3_key_iterations,
+ &keysize, &maxiter, &keyiter_count)) {
return 0;
}
+ val_env_apply_cfg(val_env, cfg, keysize, maxiter, keyiter_count);
if (env->neg_cache)
val_env->neg_cache = env->neg_cache;
if(!val_env->neg_cache)
@@ -209,7 +248,7 @@ val_init(struct module_env* env, int id)
struct trust_anchor* anchor = anchors_find_any_noninsecure(
env->anchors);
if(anchor) {
- char b[LDNS_MAX_DOMAINLEN+2];
+ char b[LDNS_MAX_DOMAINLEN];
dname_str(anchor->name, b);
log_warn("validator: disable-edns-do is enabled, but there is a trust anchor for '%s'. Since DNSSEC could not work, the disable-edns-do setting is turned off. Continuing without it.", b);
lock_basic_unlock(&anchor->lock);
@@ -273,11 +312,17 @@ val_new_getmsg(struct module_qstate* qstate, struct val_qstate* vq)
return NULL;
if(vq->orig_msg->rep->rrset_count > RR_COUNT_MAX)
return NULL; /* protect against integer overflow */
- vq->chase_reply->rrsets = regional_alloc_init(qstate->region,
- vq->orig_msg->rep->rrsets, sizeof(struct ub_packed_rrset_key*)
- * vq->orig_msg->rep->rrset_count);
+ /* Over allocate (+an_numrrsets) in case we need to put extra DNAME
+ * records for unsigned CNAME repetitions */
+ vq->chase_reply->rrsets = regional_alloc(qstate->region,
+ sizeof(struct ub_packed_rrset_key*) *
+ (vq->orig_msg->rep->rrset_count
+ + vq->orig_msg->rep->an_numrrsets));
if(!vq->chase_reply->rrsets)
return NULL;
+ memmove(vq->chase_reply->rrsets, vq->orig_msg->rep->rrsets,
+ sizeof(struct ub_packed_rrset_key*) *
+ vq->orig_msg->rep->rrset_count);
vq->rrset_skip = 0;
return vq;
}
@@ -621,7 +666,6 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
* @param vq: validator query state.
* @param env: module env for verify.
* @param ve: validator env for verify.
- * @param qchase: query that was made.
* @param chase_reply: answer to validate.
* @param key_entry: the key entry, which is trusted, and which matches
* the signer of the answer. The key entry isgood().
@@ -632,7 +676,7 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
*/
static int
validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
- struct module_env* env, struct val_env* ve, struct query_info* qchase,
+ struct module_env* env, struct val_env* ve,
struct reply_info* chase_reply, struct key_entry_key* key_entry,
int* suspend)
{
@@ -640,7 +684,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
size_t i, slen;
struct ub_packed_rrset_key* s;
enum sec_status sec;
- int dname_seen = 0, num_verifies = 0, verified, have_state = 0;
+ int num_verifies = 0, verified, have_state = 0;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
*suspend = 0;
@@ -658,9 +703,13 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
/* Skip the CNAME following a (validated) DNAME.
* Because of the normalization routines in the iterator,
* there will always be an unsigned CNAME following a DNAME
- * (unless qtype=DNAME). */
- if(dname_seen && ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) {
- dname_seen = 0;
+ * (unless qtype=DNAME in the answer part). */
+ if(i>0 && ntohs(chase_reply->rrsets[i-1]->rk.type) ==
+ LDNS_RR_TYPE_DNAME &&
+ ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
+ ((struct packed_rrset_data*)chase_reply->rrsets[i-1]->entry.data)->security == sec_status_secure &&
+ dname_strict_subdomain_c(s->rk.dname, chase_reply->rrsets[i-1]->rk.dname)
+ ) {
/* CNAME was synthesized by our own iterator */
/* since the DNAME verified, mark the CNAME as secure */
((struct packed_rrset_data*)s->entry.data)->security =
@@ -672,7 +721,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
/* Verify the answer rrset */
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
- &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
+ &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified,
+ reasonbuf, sizeof(reasonbuf));
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
@@ -691,12 +741,6 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
return 0;
}
- /* Notice a DNAME that should be followed by an unsigned
- * CNAME. */
- if(qchase->qtype != LDNS_RR_TYPE_DNAME &&
- ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) {
- dname_seen = 1;
- }
num_verifies += verified;
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
i+1 < (env->cfg->val_clean_additional?
@@ -723,7 +767,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
- &verified);
+ &verified, reasonbuf, sizeof(reasonbuf));
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
@@ -769,7 +813,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry,
&reason, NULL, LDNS_SECTION_ADDITIONAL, qstate,
- &verified);
+ &verified, reasonbuf, sizeof(reasonbuf));
/* the additional section can fail to be secure,
* it is optional, check signature in case we need
* to clean the additional section later. */
@@ -2063,7 +2107,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
verbose(VERB_ALGO, "Process suspended sub DS response");
msg = vq->sub_ds_msg;
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
- msg, &msg->qinfo, NULL, &suspend);
+ msg, &msg->qinfo, NULL, &suspend, NULL);
if(suspend) {
/* we'll come back here later to continue */
if(!validate_suspend_setup_timer(qstate, vq,
@@ -2079,7 +2123,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
vq->key_entry->name)) ) {
verbose(VERB_ALGO, "Process cached DS response");
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
- msg, &msg->qinfo, NULL, &suspend);
+ msg, &msg->qinfo, NULL, &suspend, NULL);
if(suspend) {
/* we'll come back here later to continue */
if(!validate_suspend_setup_timer(qstate, vq,
@@ -2186,7 +2230,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
/* check signatures in the message;
* answer and authority must be valid, additional is only checked. */
- if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase,
+ if(!validate_msg_signatures(qstate, vq, qstate->env, ve,
vq->chase_reply, vq->key_entry, &suspend)) {
if(suspend) {
if(!validate_suspend_setup_timer(qstate, vq,
@@ -2429,6 +2473,8 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
/* if the result is bogus - set message ttl to bogus ttl to avoid
* endless bogus revalidation */
if(vq->orig_msg->rep->security == sec_status_bogus) {
+ struct msgreply_entry* e;
+
/* see if we can try again to fetch data */
if(vq->restart_count < ve->max_restart) {
verbose(VERB_ALGO, "validation failed, "
@@ -2443,10 +2489,51 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
return 0;
}
+ if(qstate->env->cfg->serve_expired &&
+ (e=msg_cache_lookup(qstate->env, qstate->qinfo.qname,
+ qstate->qinfo.qname_len, qstate->qinfo.qtype,
+ qstate->qinfo.qclass, qstate->query_flags,
+ 0 /*now; allow expired*/,
+ 1 /*wr; we may update the data*/))) {
+ struct reply_info* rep = (struct reply_info*)e->entry.data;
+ if(rep && rep->security > sec_status_bogus &&
+ (!qstate->env->cfg->serve_expired_ttl ||
+ qstate->env->cfg->serve_expired_ttl_reset ||
+ *qstate->env->now <= rep->serve_expired_ttl)) {
+ verbose(VERB_ALGO, "validation failed but "
+ "previously cached valid response "
+ "exists; set serve-expired-norec-ttl "
+ "for response in cache");
+ rep->serve_expired_norec_ttl = NORR_TTL +
+ *qstate->env->now;
+ if(qstate->env->cfg->serve_expired_ttl_reset &&
+ *qstate->env->now + qstate->env->cfg->serve_expired_ttl
+ > rep->serve_expired_ttl) {
+ verbose(VERB_ALGO, "reset serve-expired-ttl for "
+ "valid response in cache");
+ rep->serve_expired_ttl = *qstate->env->now +
+ qstate->env->cfg->serve_expired_ttl;
+ }
+ /* Return an error response.
+ * If serve-expired-client-timeout is enabled,
+ * the client-timeout logic will try to find an
+ * (expired) answer in the cache as last
+ * resort. If it is not enabled, expired
+ * answers are already used before the mesh
+ * activation. */
+ qstate->return_rcode = LDNS_RCODE_SERVFAIL;
+ qstate->return_msg = NULL;
+ qstate->ext_state[id] = module_finished;
+ lock_rw_unlock(&e->entry.lock);
+ return 0;
+ }
+ lock_rw_unlock(&e->entry.lock);
+ }
+
vq->orig_msg->rep->ttl = ve->bogus_ttl;
vq->orig_msg->rep->prefetch_ttl =
PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl);
- vq->orig_msg->rep->serve_expired_ttl =
+ vq->orig_msg->rep->serve_expired_ttl =
vq->orig_msg->rep->ttl + qstate->env->cfg->serve_expired_ttl;
if((qstate->env->cfg->val_log_level >= 1 ||
qstate->env->cfg->log_servfail) &&
@@ -2456,19 +2543,12 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
log_query_info(NO_VERBOSE, "validation failure",
&qstate->qinfo);
else {
- char* err_str = errinf_to_str_bogus(qstate);
+ char* err_str = errinf_to_str_bogus(qstate,
+ qstate->region);
if(err_str) {
- size_t err_str_len = strlen(err_str);
log_info("%s", err_str);
- /* allocate space and store the error
- * string */
- vq->orig_msg->rep->reason_bogus_str = regional_alloc(
- qstate->region,
- sizeof(char) * (err_str_len+1));
- memcpy(vq->orig_msg->rep->reason_bogus_str,
- err_str, err_str_len+1);
+ vq->orig_msg->rep->reason_bogus_str = err_str;
}
- free(err_str);
}
}
/*
@@ -2519,8 +2599,9 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
* to check if from parentNS */
if(!qstate->no_cache_store) {
if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL,
- qstate->query_flags, qstate->qstarttime)) {
+ vq->orig_msg->rep, 0, qstate->prefetch_leeway,
+ 0, qstate->region, qstate->query_flags,
+ qstate->qstarttime, qstate->is_valrec)) {
log_err("out of memory caching validator results");
}
}
@@ -2528,8 +2609,9 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
/* for a referral, store the verified RRsets */
/* and this does not get prefetched, so no leeway */
if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 1, 0, 0, NULL,
- qstate->query_flags, qstate->qstarttime)) {
+ vq->orig_msg->rep, 1, 0, 0, qstate->region,
+ qstate->query_flags, qstate->qstarttime,
+ qstate->is_valrec)) {
log_err("out of memory caching validator results");
}
}
@@ -2618,6 +2700,14 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
qstate->ext_state[id] = module_finished;
return;
}
+ if(qstate->rpz_applied) {
+ verbose(VERB_ALGO, "rpz applied, mark it as insecure");
+ if(qstate->return_msg)
+ qstate->return_msg->rep->security =
+ sec_status_insecure;
+ qstate->ext_state[id] = module_finished;
+ return;
+ }
/* qclass ANY should have validation result from spawned
* queries. If we get here, it is bogus or an internal error */
if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
@@ -2668,6 +2758,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
* @param ta: trust anchor.
* @param qstate: qstate that needs key.
* @param id: module id.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
* @return new key entry or NULL on allocation failure.
* The key entry will either contain a validated DNSKEY rrset, or
* represent a Null key (query failed, but validation did not), or a
@@ -2675,31 +2767,38 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
*/
static struct key_entry_key*
primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
- struct trust_anchor* ta, struct module_qstate* qstate, int id)
+ struct trust_anchor* ta, struct module_qstate* qstate, int id,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
int downprot = qstate->env->cfg->harden_algo_downgrade;
if(!dnskey_rrset) {
+ char* err = errinf_to_str_misc(sub_qstate);
+ char rstr[1024];
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
"could not fetch DNSKEY rrset",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
reason_bogus = LDNS_EDE_DNSKEY_MISSING;
- reason = "no DNSKEY rrset";
+ if(!err) {
+ snprintf(rstr, sizeof(rstr), "no DNSKEY rrset");
+ } else {
+ snprintf(rstr, sizeof(rstr), "no DNSKEY rrset "
+ "[%s]", err);
+ }
if(qstate->env->cfg->harden_dnssec_stripped) {
- errinf_ede(qstate, reason, reason_bogus);
+ errinf_ede(qstate, rstr, reason_bogus);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
- reason_bogus, reason,
- *qstate->env->now);
+ reason_bogus, rstr, *qstate->env->now);
} else kkey = key_entry_create_null(qstate->region, ta->name,
ta->namelen, ta->dclass, NULL_KEY_TTL,
- reason_bogus, reason,
- *qstate->env->now);
+ reason_bogus, rstr, *qstate->env->now);
if(!kkey) {
log_err("out of memory: allocate fail prime key");
return NULL;
@@ -2709,7 +2808,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
/* attempt to verify with trust anchor DS and DNSKEY */
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
- &reason, &reason_bogus, qstate);
+ &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf));
if(!kkey) {
log_err("out of memory: verifying prime TA");
return NULL;
@@ -2764,6 +2863,9 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
* DS response indicated an end to secure space, is_good if the DS
* validated. It returns ke=NULL if the DS response indicated that the
* request wasn't a delegation point.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
+ * Can be NULL.
* @return
* 0 on success,
* 1 on servfail error (malloc failure),
@@ -2772,9 +2874,10 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
static int
ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct key_entry_key** ke)
+ struct key_entry_key** ke, struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
enum val_classification subtype;
@@ -2787,6 +2890,14 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
verbose(VERB_DETAIL, "DS response was error, thus bogus");
errinf(qstate, rc);
reason = "no DS";
+ if(sub_qstate) {
+ char* err = errinf_to_str_misc(sub_qstate);
+ if(err) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "[%s]", err);
+ errinf(qstate, buf);
+ }
+ }
reason_bogus = LDNS_EDE_NETWORK_ERROR;
errinf_ede(qstate, reason, reason_bogus);
goto return_bogus;
@@ -2809,7 +2920,9 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
- vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
+ vq->key_entry, &reason, &reason_bogus,
+ LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
+ sizeof(reasonbuf));
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
@@ -2859,7 +2972,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
/* Try to prove absence of the DS with NSEC */
sec = val_nsec_prove_nodata_dsreply(
qstate->env, ve, qinfo, msg->rep, vq->key_entry,
- &proof_ttl, &reason, &reason_bogus, qstate);
+ &proof_ttl, &reason, &reason_bogus, qstate,
+ reasonbuf, sizeof(reasonbuf));
switch(sec) {
case sec_status_secure:
verbose(VERB_DETAIL, "NSEC RRset for the "
@@ -2896,7 +3010,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
sec = nsec3_prove_nods(qstate->env, ve,
msg->rep->rrsets + msg->rep->an_numrrsets,
msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
- &reason_bogus, qstate, &vq->nsec3_cache_table);
+ &reason_bogus, qstate, &vq->nsec3_cache_table,
+ reasonbuf, sizeof(reasonbuf));
switch(sec) {
case sec_status_insecure:
/* case insecure also continues to unsigned
@@ -2963,7 +3078,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
}
sec = val_verify_rrset_entry(qstate->env, ve, cname,
vq->key_entry, &reason, &reason_bogus,
- LDNS_SECTION_ANSWER, qstate, &verified);
+ LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
+ sizeof(reasonbuf));
if(sec == sec_status_secure) {
verbose(VERB_ALGO, "CNAME validated, "
"proof that DS does not exist");
@@ -3012,11 +3128,15 @@ return_bogus:
* @param origin: the origin of msg.
* @param suspend: returned true if the task takes too long and needs to
* suspend to continue the effort later.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
+ * Can be NULL.
*/
static void
process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin, int* suspend)
+ struct sock_list* origin, int* suspend,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* dske = NULL;
@@ -3024,7 +3144,16 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
int ret;
*suspend = 0;
vq->empty_DS_name = NULL;
- ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske);
+ if(sub_qstate && sub_qstate->rpz_applied) {
+ verbose(VERB_ALGO, "rpz was applied to the DS lookup, "
+ "make it insecure");
+ vq->key_entry = NULL;
+ vq->state = VAL_FINISHED_STATE;
+ vq->chase_reply->security = sec_status_insecure;
+ return;
+ }
+ ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske,
+ sub_qstate);
if(ret != 0) {
switch(ret) {
case 1:
@@ -3100,23 +3229,37 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
* @param msg: result message (if rcode is OK).
* @param qinfo: from the sub query state, query info.
* @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
*/
static void
process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin)
+ struct sock_list* origin, struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* old = vq->key_entry;
struct ub_packed_rrset_key* dnskey = NULL;
int downprot;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
+ if(sub_qstate && sub_qstate->rpz_applied) {
+ verbose(VERB_ALGO, "rpz was applied to the DNSKEY lookup, "
+ "make it insecure");
+ vq->key_entry = NULL;
+ vq->state = VAL_FINISHED_STATE;
+ vq->chase_reply->security = sec_status_insecure;
+ return;
+ }
+
if(rcode == LDNS_RCODE_NOERROR)
dnskey = reply_find_answer_rrset(qinfo, msg->rep);
if(dnskey == NULL) {
+ char* err;
+ char rstr[1024];
/* bad response */
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
@@ -3128,17 +3271,22 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
vq->restart_count++;
return;
}
- reason = "No DNSKEY record";
+ err = errinf_to_str_misc(sub_qstate);
+ if(!err) {
+ snprintf(rstr, sizeof(rstr), "No DNSKEY record");
+ } else {
+ snprintf(rstr, sizeof(rstr), "No DNSKEY record "
+ "[%s]", err);
+ }
reason_bogus = LDNS_EDE_DNSKEY_MISSING;
vq->key_entry = key_entry_create_bad(qstate->region,
qinfo->qname, qinfo->qname_len, qinfo->qclass,
- BOGUS_KEY_TTL, reason_bogus, reason,
- *qstate->env->now);
+ BOGUS_KEY_TTL, reason_bogus, rstr, *qstate->env->now);
if(!vq->key_entry) {
log_err("alloc failure in missing dnskey response");
/* key_entry is NULL for failure in Validate */
}
- errinf_ede(qstate, reason, reason_bogus);
+ errinf_ede(qstate, rstr, reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
vq->state = VAL_VALIDATE_STATE;
@@ -3152,7 +3300,8 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
}
downprot = qstate->env->cfg->harden_algo_downgrade;
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
- ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate);
+ ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus,
+ qstate, reasonbuf, sizeof(reasonbuf));
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
@@ -3202,10 +3351,13 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
* @param rcode: rcode result value.
* @param msg: result message (if rcode is OK).
* @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
*/
static void
process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct sock_list* origin)
+ int id, int rcode, struct dns_msg* msg, struct sock_list* origin,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct ub_packed_rrset_key* dnskey_rrset = NULL;
@@ -3237,7 +3389,8 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
return;
}
}
- vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id);
+ vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id,
+ sub_qstate);
lock_basic_unlock(&ta->lock);
if(vq->key_entry) {
if(key_entry_isbad(vq->key_entry)
@@ -3288,14 +3441,14 @@ val_inform_super(struct module_qstate* qstate, int id,
if(vq->wait_prime_ta) {
vq->wait_prime_ta = 0;
process_prime_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, qstate->reply_origin);
+ qstate->return_msg, qstate->reply_origin, qstate);
return;
}
if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
int suspend;
process_ds_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin, &suspend);
+ qstate->reply_origin, &suspend, qstate);
/* If NSEC3 was needed during validation, NULL the NSEC3 cache;
* it will be re-initiated if needed later on.
* Validation (and the cache table) are happening/allocated in
@@ -3316,7 +3469,7 @@ val_inform_super(struct module_qstate* qstate, int id,
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
process_dnskey_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin);
+ qstate->reply_origin, qstate);
return;
}
log_err("internal error in validator: no inform_supers possible");
@@ -3354,8 +3507,8 @@ val_get_mem(struct module_env* env, int id)
*/
static struct module_func_block val_block = {
"validator",
- &val_init, &val_deinit, &val_operate, &val_inform_super, &val_clear,
- &val_get_mem
+ NULL, NULL, &val_init, &val_deinit, &val_operate, &val_inform_super,
+ &val_clear, &val_get_mem
};
struct module_func_block*