diff options
Diffstat (limited to 'validator/validator.c')
-rw-r--r-- | validator/validator.c | 142 |
1 files changed, 118 insertions, 24 deletions
diff --git a/validator/validator.c b/validator/validator.c index 81ba5fa17ba2..5f4a1eb4ebed 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -60,6 +60,7 @@ #include "util/fptr_wlist.h" #include "sldns/rrdef.h" #include "sldns/wire2str.h" +#include "sldns/str2wire.h" /* forward decl for cache response and normal super inform calls of a DS */ static void process_ds_response(struct module_qstate* qstate, @@ -112,8 +113,6 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env, { int c; val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl; - val_env->clean_additional = cfg->val_clean_additional; - val_env->permissive_mode = cfg->val_permissive_mode; if(!env->anchors) env->anchors = anchors_create(); if(!env->anchors) { @@ -170,7 +169,6 @@ val_init(struct module_env* env, int id) } env->modinfo[id] = (void*)val_env; env->need_to_validate = 1; - val_env->permissive_mode = 0; lock_basic_init(&val_env->bogus_lock); lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus, sizeof(val_env->num_rrset_bogus)); @@ -364,14 +362,17 @@ already_validated(struct dns_msg* ret_msg) * @param qtype: query type. * @param qclass: query class. * @param flags: additional flags, such as the CD bit (BIT_CD), or 0. + * @param newq: If the subquery is newly created, it is returned, + * otherwise NULL is returned + * @param detached: true if this qstate should not attach to the subquery * @return false on alloc failure. */ static int generate_request(struct module_qstate* qstate, int id, uint8_t* name, - size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags) + size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags, + struct module_qstate** newq, int detached) { struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id]; - struct module_qstate* newq; struct query_info ask; int valrec; ask.qname = name; @@ -380,22 +381,35 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, ask.qclass = qclass; ask.local_alias = NULL; log_query_info(VERB_ALGO, "generate request", &ask); - fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); /* enable valrec flag to avoid recursion to the same validation * routine, this lookup is simply a lookup. DLVs need validation */ if(qtype == LDNS_RR_TYPE_DLV) valrec = 0; else valrec = 1; - if(!(*qstate->env->attach_sub)(qstate, &ask, - (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){ - log_err("Could not generate request: out of memory"); - return 0; + if(detached) { + struct mesh_state* sub = NULL; + fptr_ok(fptr_whitelist_modenv_add_sub( + qstate->env->add_sub)); + if(!(*qstate->env->add_sub)(qstate, &ask, + (uint16_t)(BIT_RD|flags), 0, valrec, newq, &sub)){ + log_err("Could not generate request: out of memory"); + return 0; + } + } + else { + fptr_ok(fptr_whitelist_modenv_attach_sub( + qstate->env->attach_sub)); + if(!(*qstate->env->attach_sub)(qstate, &ask, + (uint16_t)(BIT_RD|flags), 0, valrec, newq)){ + log_err("Could not generate request: out of memory"); + return 0; + } } /* newq; validator does not need state created for that * query, and its a 'normal' for iterator as well */ - if(newq) { + if(*newq) { /* add our blacklist to the query blacklist */ - sock_list_merge(&newq->blacklist, newq->region, + sock_list_merge(&(*newq)->blacklist, (*newq)->region, vq->chain_blacklist); } qstate->ext_state[id] = module_wait_subquery; @@ -403,6 +417,66 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, } /** + * Generate, send and detach key tag signaling query. + * + * @param qstate: query state. + * @param id: module id. + * @param ta: trust anchor, locked. + * @return false on a processing error. + */ +static int +generate_keytag_query(struct module_qstate* qstate, int id, + struct trust_anchor* ta) +{ + /* 3 bytes for "_ta", 5 bytes per tag (4 bytes + "-") */ +#define MAX_LABEL_TAGS (LDNS_MAX_LABELLEN-3)/5 + size_t i, numtag; + uint16_t tags[MAX_LABEL_TAGS]; + char tagstr[LDNS_MAX_LABELLEN+1] = "_ta"; /* +1 for NULL byte */ + size_t tagstr_left = sizeof(tagstr) - strlen(tagstr); + char* tagstr_pos = tagstr + strlen(tagstr); + uint8_t dnamebuf[LDNS_MAX_DOMAINLEN+1]; /* +1 for label length byte */ + size_t dnamebuf_len = sizeof(dnamebuf); + uint8_t* keytagdname; + struct module_qstate* newq = NULL; + enum module_ext_state ext_state = qstate->ext_state[id]; + + numtag = anchor_list_keytags(ta, tags, MAX_LABEL_TAGS); + if(numtag == 0) + return 0; + + for(i=0; i<numtag; i++) { + /* Buffer can't overflow; numtag is limited to tags that fit in + * the buffer. */ + snprintf(tagstr_pos, tagstr_left, "-%04x", (unsigned)tags[i]); + tagstr_left -= strlen(tagstr_pos); + tagstr_pos += strlen(tagstr_pos); + } + + sldns_str2wire_dname_buf_origin(tagstr, dnamebuf, &dnamebuf_len, + ta->name, ta->namelen); + if(!(keytagdname = (uint8_t*)regional_alloc_init(qstate->region, + dnamebuf, dnamebuf_len))) { + log_err("could not generate key tag query: out of memory"); + return 0; + } + + log_nametypeclass(VERB_ALGO, "keytag query", keytagdname, + LDNS_RR_TYPE_NULL, ta->dclass); + if(!generate_request(qstate, id, keytagdname, dnamebuf_len, + LDNS_RR_TYPE_NULL, ta->dclass, 0, &newq, 1)) { + log_err("failed to generate key tag signaling request"); + return 0; + } + + /* Not interrested in subquery response. Restore the ext_state, + * that might be changed by generate_request() */ + qstate->ext_state[id] = ext_state; + + return 1; +} + +/** * Prime trust anchor for use. * Generate and dispatch a priming query for the given trust anchor. * The trust anchor can be DNSKEY or DS and does not have to be signed. @@ -417,8 +491,16 @@ static int prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq, int id, struct trust_anchor* toprime) { + struct module_qstate* newq = NULL; int ret = generate_request(qstate, id, toprime->name, toprime->namelen, - LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD); + LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD, &newq, 0); + + if(newq && qstate->env->cfg->trust_anchor_signaling && + !generate_keytag_query(qstate, id, toprime)) { + log_err("keytag signaling query failed"); + return 0; + } + if(!ret) { log_err("Could not prime trust anchor: out of memory"); return 0; @@ -534,9 +616,11 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, } } - /* attempt to validate the ADDITIONAL section rrsets */ - if(!ve->clean_additional) + /* If set, the validator should clean the additional section of + * secure messages. */ + if(!env->cfg->val_clean_additional) return 1; + /* attempt to validate the ADDITIONAL section rrsets */ for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets; i<chase_reply->rrset_count; i++) { s = chase_reply->rrsets[i]; @@ -1510,6 +1594,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) uint8_t* target_key_name, *current_key_name; size_t target_key_len; int strip_lab; + struct module_qstate* newq = NULL; log_query_info(VERB_ALGO, "validator: FindKey", &vq->qchase); /* We know that state.key_entry is not 0 or bad key -- if it were, @@ -1522,7 +1607,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) if(key_entry_isnull(vq->key_entry)) { 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)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1594,7 +1679,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) vq->key_entry->name) != 0) { 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)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1623,7 +1708,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) } if(!generate_request(qstate, id, target_key_name, target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass, - BIT_CD)) { + BIT_CD, &newq, 0)) { log_err("mem error generating DS request"); return val_error(qstate, id); } @@ -1633,7 +1718,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) /* Otherwise, it is time to query for the DNSKEY */ 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)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1847,6 +1932,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, { uint8_t* nm; size_t nm_len; + struct module_qstate* newq = NULL; /* there must be a DLV configured */ log_assert(qstate->env->anchors->dlv_anchor); /* this bool is true to avoid looping in the DLV checks */ @@ -1948,7 +2034,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, vq->state = VAL_DLVLOOKUP_STATE; if(!generate_request(qstate, id, vq->dlv_lookup_name, vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, - vq->qchase.qclass, 0)) { + vq->qchase.qclass, 0, &newq, 0)) { return val_error(qstate, id); } @@ -2042,7 +2128,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, * a different signer name). And drop additional rrsets * that are not secure (if clean-additional option is set) */ /* this may cause the msg to be marked bogus */ - val_check_nonsecure(ve, vq->orig_msg->rep); + val_check_nonsecure(qstate->env, vq->orig_msg->rep); if(vq->orig_msg->rep->security == sec_status_secure) { log_query_info(VERB_DETAIL, "validation success", &qstate->qinfo); @@ -2083,8 +2169,14 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, free(err); } } + /* + * If set, the validator will not make messages bogus, instead + * indeterminate is issued, so that no clients receive SERVFAIL. + * This allows an operator to run validation 'shadow' without + * hurting responses to clients. + */ /* If we are in permissive mode, bogus gets indeterminate */ - if(ve->permissive_mode) + if(qstate->env->cfg->val_permissive_mode) vq->orig_msg->rep->security = sec_status_indeterminate; } @@ -2128,6 +2220,7 @@ static int processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, struct val_env* ve, int id) { + struct module_qstate* newq = NULL; /* see if this we are ready to continue normal resolution */ /* we may need more DLV lookups */ if(vq->dlv_status==dlv_error) @@ -2176,7 +2269,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, 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)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -2218,7 +2311,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, if(!generate_request(qstate, id, vq->dlv_lookup_name, vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, - vq->qchase.qclass, 0)) { + vq->qchase.qclass, 0, &newq, 0)) { return val_error(qstate, id); } @@ -2857,6 +2950,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq, ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY, ta->dclass); } + if(ta->autr) { if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) { /* trust anchor revoked, restart with less anchors */ |