if(!go_on)
return 1; /* skip this one, not all references satisfied */
- if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) {
+ if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
log_warn("error out of memory");
return 0;
}
k.qname_len = nmlen;
k.qtype = t;
k.qclass = c;
- h = query_info_hash(&k);
+ h = query_info_hash(&k, 0);
slabhash_remove(worker->env.msg_cache, h, &k);
+ if(t == LDNS_RR_TYPE_AAAA) {
+ /* for AAAA also flush dns64 bit_cd packet */
+ h = query_info_hash(&k, BIT_CD);
+ slabhash_remove(worker->env.msg_cache, h, &k);
+ }
}
/** flush a type */
&repinfo->addr, repinfo->addrlen);
goto send_reply;
}
- h = query_info_hash(&qinfo);
+ h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
if(answer_from_cache(worker, &qinfo,
/* Create the new sub-query. */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
- if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
+ if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0,
&subq))
return module_error;
if (subq) {
/* Start the sub-query. */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
- &subq))
+ 0, &subq))
{
verbose(VERB_ALGO, "dns64: sub-query creation failed");
return module_error;
*
* - An internal query.
* - A query for a record type other than AAAA.
+ * - CD FLAG was set on querier
* - An AAAA query for which an error was returned.
* - A successful AAAA query with an answer.
*/
if ( (enum dns64_qstate)qstate->minfo[id] == DNS64_INTERNAL_QUERY
|| qstate->qinfo.qtype != LDNS_RR_TYPE_AAAA
+ || (qstate->query_flags & BIT_CD)
|| qstate->return_rcode != LDNS_RCODE_NOERROR
|| (qstate->return_msg &&
qstate->return_msg->rep &&
/* Store the generated response in cache. */
if (!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
- 0, 0, 0, NULL))
+ 0, 0, 0, NULL, super->query_flags))
log_err("out of memory");
}
+18 November 2014: Wouter
+ - Fix that CD flag disables DNS64 processing, returning the DNSSEC
+ signed AAAA denial.
+
17 November 2014: Wouter
- Fix #627: SSL_CTX_load_verify_locations return code not properly
checked.
void
iter_dns_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
- struct regional* region)
+ struct regional* region, uint16_t flags)
{
if(!dns_cache_store(env, msgqinf, msgrep, is_referral, leeway,
- pside, region))
+ pside, region, flags))
log_err("out of memory: cannot store data in cache");
}
fptr_ok(fptr_whitelist_modenv_detect_cycle(
qstate->env->detect_cycle));
return (*qstate->env->detect_cycle)(qstate, &qinf,
- (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming);
+ (uint16_t)(BIT_RD|BIT_CD), qstate->is_priming,
+ qstate->is_valrec);
}
void
* @param pside: true if dp is parentside, thus message is 'fresh' and NS
* can be prefetch-updates.
* @param region: to copy modified (cache is better) rrs back to.
+ * @param flags: with BIT_CD for dns64 AAAA translated queries.
* @return void, because we are not interested in alloc errors,
* the iterator and validator can operate on the results in their
* scratch space (the qstate.region) and are not dependent on the cache.
*/
void iter_dns_store(struct module_env* env, struct query_info* qinf,
struct reply_info* rep, int is_referral, time_t leeway, int pside,
- struct regional* region);
+ struct regional* region, uint16_t flags);
/**
* Select randomly with n/m probability.
verbose(VERB_ALGO, "error response for prefetch in cache");
/* attempt to adjust the cache entry prefetch */
if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo,
- NORR_TTL))
+ NORR_TTL, qstate->query_flags))
return error_response(qstate, id, rcode);
/* if that fails (not in cache), fall through to store err */
}
/* do not waste time trying to validate this servfail */
err.security = sec_status_indeterminate;
verbose(VERB_ALGO, "store error response in message cache");
- iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL);
+ iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL,
+ qstate->query_flags);
return error_response(qstate, id, rcode);
}
/* attach subquery, lookup existing or make a new one */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
- if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, &subq)) {
+ if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, 0,
+ &subq)) {
return 0;
}
*subq_ret = subq;
} else {
msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
iq->qchase.qname_len, iq->qchase.qtype,
- iq->qchase.qclass, qstate->region, qstate->env->scratch);
+ iq->qchase.qclass, qstate->query_flags,
+ qstate->region, qstate->env->scratch);
if(!msg && qstate->env->neg_cache) {
/* lookup in negative cache; may result in
* NOERROR/NODATA or NXDOMAIN answers that need validation */
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
- qstate->region);
+ qstate->region, qstate->query_flags);
/* close down outstanding requests to be discarded */
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
/* Store the referral under the current query */
/* no prefetch-leeway, since its not the answer */
iter_dns_store(qstate->env, &iq->response->qinfo,
- iq->response->rep, 1, 0, 0, NULL);
+ iq->response->rep, 1, 0, 0, NULL, 0);
if(iq->store_parent_NS)
iter_store_parentside_NS(qstate->env,
iq->response->rep);
/* prefetchleeway applied because this updates answer parts */
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1, qstate->prefetch_leeway,
- iq->dp&&iq->dp->has_parent_side_NS, NULL);
+ iq->dp&&iq->dp->has_parent_side_NS, NULL,
+ qstate->query_flags);
/* set the current request's qname to the new value. */
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
}
/**
- * Return priming query results to interestes super querystates.
+ * Return priming query results to interested super querystates.
*
* Sets the delegation point and delegation message (not nonRD queries).
* This is a callback from walk_supers.
iter_dns_store(qstate->env, &qstate->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
- qstate->region);
+ qstate->region, qstate->query_flags);
}
}
qstate->return_rcode = LDNS_RCODE_NOERROR;
}
return dns_cache_store(qstate->env, qinfo, msgrep, is_referral,
- qstate->prefetch_leeway, 0, NULL);
+ qstate->prefetch_leeway, 0, NULL, qstate->query_flags);
}
/* Invalidate the message associated with query_info stored in message cache */
struct reply_info *r;
size_t i, j;
- h = query_info_hash(qinfo);
+ h = query_info_hash(qinfo, qstate->query_flags);
if ((e=slabhash_lookup(qstate->env->msg_cache, h, qinfo, 0)))
{
r = (struct reply_info*)(e->data);
/** lookup message in message cache */
static struct msgreply_entry*
msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen,
- uint16_t qtype, uint16_t qclass, time_t now, int wr)
+ uint16_t qtype, uint16_t qclass, uint16_t flags, time_t now, int wr)
{
struct lruhash_entry* e;
struct query_info k;
k.qname_len = qnamelen;
k.qtype = qtype;
k.qclass = qclass;
- h = query_info_hash(&k);
+ h = query_info_hash(&k, flags);
e = slabhash_lookup(env->msg_cache, h, &k, wr);
if(!e) return NULL;
addr_to_additional(akey, region, *msg, now);
lock_rw_unlock(&akey->entry.lock);
} else {
+ /* BIT_CD on false because delegpt lookup does
+ * not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
- LDNS_RR_TYPE_A, qclass, now, 0);
+ LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
addr_to_additional(akey, region, *msg, now);
lock_rw_unlock(&akey->entry.lock);
} else {
+ /* BIT_CD on false because delegpt lookup does
+ * not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
- LDNS_RR_TYPE_AAAA, qclass, now, 0);
+ LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
ns->name, LDNS_RR_TYPE_A, qclass);
lock_rw_unlock(&akey->entry.lock);
} else {
+ /* BIT_CD on false because delegpt lookup does
+ * not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
- LDNS_RR_TYPE_A, qclass, now, 0);
+ LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
ns->name, LDNS_RR_TYPE_AAAA, qclass);
lock_rw_unlock(&akey->entry.lock);
} else {
+ /* BIT_CD on false because delegpt lookup does
+ * not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
- LDNS_RR_TYPE_AAAA, qclass, now, 0);
+ LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
struct dns_msg*
dns_cache_lookup(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
- struct regional* region, struct regional* scratch)
+ uint16_t flags, struct regional* region, struct regional* scratch)
{
struct lruhash_entry* e;
struct query_info k;
k.qname_len = qnamelen;
k.qtype = qtype;
k.qclass = qclass;
- h = query_info_hash(&k);
+ h = query_info_hash(&k, flags);
e = slabhash_lookup(env->msg_cache, h, &k, 0);
if(e) {
struct msgreply_entry* key = (struct msgreply_entry*)e->key;
if(env->cfg->harden_below_nxdomain)
while(!dname_is_root(k.qname)) {
dname_remove_label(&k.qname, &k.qname_len);
- h = query_info_hash(&k);
+ h = query_info_hash(&k, flags);
e = slabhash_lookup(env->msg_cache, h, &k, 0);
if(e) {
struct reply_info* data = (struct reply_info*)e->data;
int
dns_cache_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
- struct regional* region)
+ struct regional* region, uint16_t flags)
{
struct reply_info* rep = NULL;
/* alloc, malloc properly (not in region, like msg is) */
* Not AA from cache. Not CD in cache (depends on client bit). */
rep->flags |= (BIT_RA | BIT_QR);
rep->flags &= ~(BIT_AA | BIT_CD);
- h = query_info_hash(&qinf);
+ h = query_info_hash(&qinf, flags);
dns_cache_store_msg(env, &qinf, h, rep, leeway, pside, msgrep,
region);
/* qname is used inside query_info_entrysetup, and set to
int
dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo,
- time_t adjust)
+ time_t adjust, uint16_t flags)
{
struct msgreply_entry* msg;
msg = msg_cache_lookup(env, qinfo->qname, qinfo->qname_len,
- qinfo->qtype, qinfo->qclass, *env->now, 1);
+ qinfo->qtype, qinfo->qclass, flags, *env->now, 1);
if(msg) {
struct reply_info* rep = (struct reply_info*)msg->entry.data;
if(rep) {
* can be updated to full TTL even in prefetch situations.
* @param region: region to allocate better entries from cache into.
* (used when is_referral is false).
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
* @return 0 on alloc error (out of memory).
*/
int dns_cache_store(struct module_env* env, struct query_info* qinf,
struct reply_info* rep, int is_referral, time_t leeway, int pside,
- struct regional* region);
+ struct regional* region, uint16_t flags);
/**
* Store message in the cache. Stores in message cache and rrset cache.
* @param qnamelen: length of qname.
* @param qtype: query type.
* @param qclass: query class.
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
* @param region: where to allocate result.
* @param scratch: where to allocate temporary data.
* @return new response message (alloced in region, rrsets do not have IDs).
*/
struct dns_msg* dns_cache_lookup(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
- struct regional* region, struct regional* scratch);
+ uint16_t flags, struct regional* region, struct regional* scratch);
/**
* find and add A and AAAA records for missing nameservers in delegpt
* @param env: module environment with caches and time.
* @param qinfo: query info for the query that needs adjustment.
* @param adjust: time in seconds to add to the prefetch_leeway.
+ * @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
* @return false if not in cache. true if added.
*/
int dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo,
- time_t adjust);
+ time_t adjust, uint16_t flags);
#endif /* SERVICES_CACHE_DNS_H */
if(!a->s.is_priming && b->s.is_priming)
return 1;
+ if(a->s.is_valrec && !b->s.is_valrec)
+ return -1;
+ if(!a->s.is_valrec && b->s.is_valrec)
+ return 1;
+
if((a->s.query_flags&BIT_RD) && !(b->s.query_flags&BIT_RD))
return -1;
if(!(a->s.query_flags&BIT_RD) && (b->s.query_flags&BIT_RD))
uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
uint16_t qid)
{
- /* do not use CD flag from user for mesh state, we want the CD-query
- * to receive validation anyway, to protect out cache contents and
- * avoid bad-data in this cache that a downstream validator cannot
- * remove from this cache */
- struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+ struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
#ifdef UNBOUND_DEBUG
struct rbnode_t* n;
#endif
- s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+ s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
uint16_t qid, mesh_cb_func_t cb, void* cb_arg)
{
- struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+ struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
#ifdef UNBOUND_DEBUG
struct rbnode_t* n;
#endif
- s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+ s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
if(!s) {
return 0;
}
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway)
{
- struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
+ struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0, 0);
#ifdef UNBOUND_DEBUG
struct rbnode_t* n;
#endif
mesh->stats_dropped ++;
return;
}
- s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
+ s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0, 0);
if(!s) {
log_err("prefetch mesh_state_create: out of memory");
return;
struct mesh_state*
mesh_state_create(struct module_env* env, struct query_info* qinfo,
- uint16_t qflags, int prime)
+ uint16_t qflags, int prime, int valrec)
{
struct regional* region = alloc_reg_obtain(env->alloc);
struct mesh_state* mstate;
/* remove all weird bits from qflags */
mstate->s.query_flags = (qflags & (BIT_RD|BIT_CD));
mstate->s.is_priming = prime;
+ mstate->s.is_valrec = valrec;
mstate->s.reply = NULL;
mstate->s.region = region;
mstate->s.curmod = 0;
}
int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t qflags, int prime, struct module_qstate** newq)
+ uint16_t qflags, int prime, int valrec, struct module_qstate** newq)
{
/* find it, if not, create it */
struct mesh_area* mesh = qstate->env->mesh;
- struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime);
+ struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime,
+ valrec);
int was_detached;
+ log_info("mesh attach sub: myvalrec is %d", qstate->is_valrec);
if(mesh_detect_cycle_found(qstate, sub)) {
verbose(VERB_ALGO, "attach failed, cycle detected");
return 0;
struct rbnode_t* n;
#endif
/* create a new one */
- sub = mesh_state_create(qstate->env, qinfo, qflags, prime);
+ sub = mesh_state_create(qstate->env, qinfo, qflags, prime,
+ valrec);
if(!sub) {
log_err("mesh_attach_sub: out of memory");
return 0;
}
struct mesh_state* mesh_area_find(struct mesh_area* mesh,
- struct query_info* qinfo, uint16_t qflags, int prime)
+ struct query_info* qinfo, uint16_t qflags, int prime, int valrec)
{
struct mesh_state key;
struct mesh_state* result;
key.node.key = &key;
key.s.is_priming = prime;
+ key.s.is_valrec = valrec;
key.s.qinfo = *qinfo;
key.s.query_flags = qflags;
struct mesh_state* m;
int num = 0;
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
- snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s%s",
+ snprintf(buf, sizeof(buf), "%d%s%s%s%s%s%s mod%d %s%s",
num++, (m->s.is_priming)?"p":"", /* prime */
+ (m->s.is_valrec)?"v":"", /* prime */
(m->s.query_flags&BIT_RD)?"RD":"",
(m->s.query_flags&BIT_CD)?"CD":"",
(m->super_set.count==0)?"d":"", /* detached */
int
mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t flags, int prime)
+ uint16_t flags, int prime, int valrec)
{
struct mesh_area* mesh = qstate->env->mesh;
- struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, flags, prime);
+ struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, flags, prime,
+ valrec);
return mesh_detect_cycle_found(qstate, dep_m);
}
* @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD / CD flag or not).
* @param prime: if it is a (stub) priming query.
+ * @param valrec: if it is a validation recursion query (lookup of key, DS).
* @param newq: If the new subquery needs initialisation, it is returned,
* otherwise NULL is returned.
* @return: false on error, true if success (and init may be needed).
*/
int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t qflags, int prime, struct module_qstate** newq);
+ uint16_t qflags, int prime, int valrec, struct module_qstate** newq);
/**
* Query state is done, send messages to reply entries.
* @param qinfo: query info that the mesh is for.
* @param qflags: flags for query (RD / CD flag).
* @param prime: if true, it is a priming query, set is_priming on mesh state.
+ * @param valrec: if true, it is a validation recursion query, and sets
+ * is_valrec on the mesh state.
* @return: new mesh state or NULL on allocation error.
*/
struct mesh_state* mesh_state_create(struct module_env* env,
- struct query_info* qinfo, uint16_t qflags, int prime);
+ struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
/**
* Cleanup a mesh state and its query state. Does not do rbtree or
* @param qinfo: what query
* @param qflags: if RD / CD bit is set or not.
* @param prime: if it is a priming query.
+ * @param valrec: if it is a validation-recursion query.
* @return: mesh state or NULL if not found.
*/
struct mesh_state* mesh_area_find(struct mesh_area* mesh,
- struct query_info* qinfo, uint16_t qflags, int prime);
+ struct query_info* qinfo, uint16_t qflags, int prime, int valrec);
/**
* Setup attachment super/sub relation between super and sub mesh state.
* @param qinfo: query info for dependency.
* @param flags: query flags of dependency.
* @param prime: if dependency is a priming query or not.
+ * @param valrec: if it is a validation recursion query (lookup of key, DS).
* @return true if the name,type,class exists and the given qstate mesh exists
* as a dependency of that name. Thus if qstate becomes dependent on
* name,type,class then a cycle is created, this is return value 1.
* Too large to search is value 2 (also true).
*/
int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t flags, int prime);
+ uint16_t flags, int prime, int valrec);
/** compare two mesh_states */
int mesh_state_compare(const void* ap, const void* bp);
}
hashvalue_t
-query_info_hash(struct query_info *q)
+query_info_hash(struct query_info *q, uint16_t flags)
{
hashvalue_t h = 0xab;
h = hashlittle(&q->qtype, sizeof(q->qtype), h);
+ if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
+ h++;
h = hashlittle(&q->qclass, sizeof(q->qclass), h);
h = dname_query_hash(q->qname, h);
return h;
/** delete reply_info data structure */
void reply_info_delete(void* d, void* arg);
-/** calculate hash value of query_info, lowercases the qname */
-hashvalue_t query_info_hash(struct query_info *q);
+/** calculate hash value of query_info, lowercases the qname,
+ * uses CD flag for AAAA qtype */
+hashvalue_t query_info_hash(struct query_info *q, uint16_t flags);
/**
* Setup query info entry
int
fptr_whitelist_modenv_attach_sub(int (*fptr)(
struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t qflags, int prime, struct module_qstate** newq))
+ uint16_t qflags, int prime, int valrec, struct module_qstate** newq))
{
if(fptr == &mesh_attach_sub) return 1;
return 0;
int
fptr_whitelist_modenv_detect_cycle(int (*fptr)(
struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t flags, int prime))
+ uint16_t flags, int prime, int valrec))
{
if(fptr == &mesh_detect_cycle) return 1;
return 0;
*/
int fptr_whitelist_modenv_attach_sub(int (*fptr)(
struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t qflags, int prime, struct module_qstate** newq));
+ uint16_t qflags, int prime, int valrec, struct module_qstate** newq));
/**
* Check function pointer whitelist for module_env kill_sub callback values.
*/
int fptr_whitelist_modenv_detect_cycle(int (*fptr)(
struct module_qstate* qstate, struct query_info* qinfo,
- uint16_t flags, int prime));
+ uint16_t flags, int prime, int valrec));
/**
* Check function pointer whitelist for module init call values.
* @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD, CD flag or not).
* @param prime: if it is a (stub) priming query.
+ * @param valrec: validation lookup recursion, does not need validation
* @param newq: If the new subquery needs initialisation, it is
* returned, otherwise NULL is returned.
* @return: false on error, true if success (and init may be needed).
*/
int (*attach_sub)(struct module_qstate* qstate,
struct query_info* qinfo, uint16_t qflags, int prime,
- struct module_qstate** newq);
+ int valrec, struct module_qstate** newq);
/**
* Kill newly attached sub. If attach_sub returns newq for
* @param qinfo: query info for dependency.
* @param flags: query flags of dependency, RD/CD flags.
* @param prime: if dependency is a priming query or not.
+ * @param valrec: validation lookup recursion, does not need validation
* @return true if the name,type,class exists and the given
* qstate mesh exists as a dependency of that name. Thus
* if qstate becomes dependent on name,type,class then a
* cycle is created.
*/
int (*detect_cycle)(struct module_qstate* qstate,
- struct query_info* qinfo, uint16_t flags, int prime);
+ struct query_info* qinfo, uint16_t flags, int prime,
+ int valrec);
/** region for temporary usage. May be cleared after operate() call. */
struct regional* scratch;
uint16_t query_flags;
/** if this is a (stub or root) priming query (with hints) */
int is_priming;
+ /** if this is a validation recursion query that does not get
+ * validation itself */
+ int is_valrec;
/** comm_reply contains server replies */
struct comm_reply* reply;
verbose(VERB_ALGO, "not validating response due to CD bit");
return 0;
}
+ if(qstate->is_valrec) {
+ verbose(VERB_ALGO, "not validating response, is valrec"
+ "(validation recursion lookup)");
+ return 0;
+ }
if(ret_rc != LDNS_RCODE_NOERROR || !ret_msg)
rcode = ret_rc;
struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
struct module_qstate* newq;
struct query_info ask;
+ int valrec;
ask.qname = name;
ask.qname_len = namelen;
ask.qtype = qtype;
ask.qclass = qclass;
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, &newq)){
+ (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){
log_err("Could not generate request: out of memory");
return 0;
}
/* if secure, this will override cache anyway, no need
* to check if from parentNS */
if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
- vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL)) {
+ vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL,
+ qstate->query_flags)) {
log_err("out of memory caching validator results");
}
} else {
/* 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)) {
+ vq->orig_msg->rep, 1, 0, 0, NULL,
+ qstate->query_flags)) {
log_err("out of memory caching validator results");
}
}