aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/iterator/iterator.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/iterator/iterator.c')
-rw-r--r--external/unbound/iterator/iterator.c364
1 files changed, 246 insertions, 118 deletions
diff --git a/external/unbound/iterator/iterator.c b/external/unbound/iterator/iterator.c
index b1bf902d5..43b3d30c3 100644
--- a/external/unbound/iterator/iterator.c
+++ b/external/unbound/iterator/iterator.c
@@ -82,27 +82,13 @@ iter_init(struct module_env* env, int id)
log_err("iterator: could not apply configuration settings.");
return 0;
}
- if(env->cfg->qname_minimisation) {
- uint8_t dname[LDNS_MAX_DOMAINLEN+1];
- size_t len = sizeof(dname);
- if(sldns_str2wire_dname_buf("ip6.arpa.", dname, &len) != 0) {
- log_err("ip6.arpa. parse error");
- return 0;
- }
- iter_env->ip6arpa_dname = (uint8_t*)malloc(len);
- if(!iter_env->ip6arpa_dname) {
- log_err("malloc failure");
- return 0;
- }
- memcpy(iter_env->ip6arpa_dname, dname, len);
- }
return 1;
}
/** delete caps_whitelist element */
static void
-caps_free(struct rbnode_t* n, void* ATTR_UNUSED(d))
+caps_free(struct rbnode_type* n, void* ATTR_UNUSED(d))
{
if(n) {
free(((struct name_tree_node*)n)->name);
@@ -117,7 +103,6 @@ iter_deinit(struct module_env* env, int id)
if(!env || !env->modinfo[id])
return;
iter_env = (struct iter_env*)env->modinfo[id];
- free(iter_env->ip6arpa_dname);
free(iter_env->target_fetch_policy);
priv_delete(iter_env->priv);
donotq_delete(iter_env->donotq);
@@ -162,6 +147,8 @@ iter_new(struct module_qstate* qstate, int id)
/* Start with the (current) qname. */
iq->qchase = qstate->qinfo;
outbound_list_init(&iq->outlist);
+ iq->minimise_count = 0;
+ iq->minimise_timeout_count = 0;
if (qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
else
@@ -229,6 +216,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) {
/* mark address as failed. */
struct delegpt_ns* dpns = NULL;
+ super_iq->num_target_queries--;
if(super_iq->dp)
dpns = delegpt_find_ns(super_iq->dp,
qstate->qinfo.qname, qstate->qinfo.qname_len);
@@ -242,13 +230,11 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
return;
} else {
/* see if the failure did get (parent-lame) info */
- if(!cache_fill_missing(super->env,
- super_iq->qchase.qclass, super->region,
- super_iq->dp))
+ if(!cache_fill_missing(super->env, super_iq->qchase.qclass,
+ super->region, super_iq->dp))
log_err("out of memory adding missing");
}
dpns->resolved = 1; /* mark as failed */
- super_iq->num_target_queries--;
}
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
/* prime failed to get delegation */
@@ -291,27 +277,29 @@ error_response(struct module_qstate* qstate, int id, int rcode)
static int
error_response_cache(struct module_qstate* qstate, int id, int rcode)
{
- /* store in cache */
- struct reply_info err;
- if(qstate->prefetch_leeway > NORR_TTL) {
- 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, qstate->query_flags))
- return error_response(qstate, id, rcode);
- /* if that fails (not in cache), fall through to store err */
- }
- memset(&err, 0, sizeof(err));
- err.flags = (uint16_t)(BIT_QR | BIT_RA);
- FLAGS_SET_RCODE(err.flags, rcode);
- err.qdcount = 1;
- err.ttl = NORR_TTL;
- err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl);
- /* 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,
- qstate->query_flags);
+ if(!qstate->no_cache_store) {
+ /* store in cache */
+ struct reply_info err;
+ if(qstate->prefetch_leeway > NORR_TTL) {
+ 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, qstate->query_flags))
+ return error_response(qstate, id, rcode);
+ /* if that fails (not in cache), fall through to store err */
+ }
+ memset(&err, 0, sizeof(err));
+ err.flags = (uint16_t)(BIT_QR | BIT_RA);
+ FLAGS_SET_RCODE(err.flags, rcode);
+ err.qdcount = 1;
+ err.ttl = NORR_TTL;
+ err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl);
+ /* 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,
+ qstate->query_flags);
+ }
return error_response(qstate, id, rcode);
}
@@ -385,6 +373,29 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
}
/**
+ * Find rrset in ANSWER prepend list.
+ * to avoid duplicate DNAMEs when a DNAME is traversed twice.
+ * @param iq: iterator query state.
+ * @param rrset: rrset to add.
+ * @return false if not found
+ */
+static int
+iter_find_rrset_in_prepend_answer(struct iter_qstate* iq,
+ struct ub_packed_rrset_key* rrset)
+{
+ struct iter_prep_list* p = iq->an_prepend_list;
+ while(p) {
+ if(ub_rrset_compare(p->rrset, rrset) == 0 &&
+ rrsetdata_equal((struct packed_rrset_data*)p->rrset
+ ->entry.data, (struct packed_rrset_data*)rrset
+ ->entry.data))
+ return 1;
+ p = p->next;
+ }
+ return 0;
+}
+
+/**
* Add rrset to ANSWER prepend list
* @param qstate: query state.
* @param iq: iterator query state.
@@ -466,14 +477,16 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
* by this DNAME following, so we don't process the DNAME
* directly. */
if(ntohs(r->rk.type) == LDNS_RR_TYPE_DNAME &&
- dname_strict_subdomain_c(*mname, r->rk.dname)) {
+ dname_strict_subdomain_c(*mname, r->rk.dname) &&
+ !iter_find_rrset_in_prepend_answer(iq, r)) {
if(!iter_add_prepend_answer(qstate, iq, r))
return 0;
continue;
}
if(ntohs(r->rk.type) == LDNS_RR_TYPE_CNAME &&
- query_dname_compare(*mname, r->rk.dname) == 0) {
+ query_dname_compare(*mname, r->rk.dname) == 0 &&
+ !iter_find_rrset_in_prepend_answer(iq, r)) {
/* Add this relevant CNAME rrset to the prepend list.*/
if(!iter_add_prepend_answer(qstate, iq, r))
return 0;
@@ -564,6 +577,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
qinf.qname_len = qnamelen;
qinf.qtype = qtype;
qinf.qclass = qclass;
+ qinf.local_alias = NULL;
/* RD should be set only when sending the query back through the INIT
* state. */
@@ -981,7 +995,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
{
uint8_t* delname;
size_t delnamelen;
- struct dns_msg* msg;
+ struct dns_msg* msg = NULL;
log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
/* check effort */
@@ -1021,13 +1035,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
* getting older results from cache is a bad idea, no cache */
verbose(VERB_ALGO, "cache blacklisted, going to the network");
msg = NULL;
- } else {
+ } else if(!qstate->no_cache_lookup) {
msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
iq->qchase.qname_len, iq->qchase.qtype,
iq->qchase.qclass, qstate->query_flags,
qstate->region, qstate->env->scratch);
if(!msg && qstate->env->neg_cache) {
- /* lookup in negative cache; may result in
+ /* lookup in negative cache; may result in
* NOERROR/NODATA or NXDOMAIN answers that need validation */
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
qstate->region, qstate->env->rrset_cache,
@@ -1337,7 +1351,7 @@ processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq,
/* If the RD flag wasn't set, then we just finish with the
* cached referral as the response. */
- if(!(qstate->query_flags & BIT_RD)) {
+ if(!(qstate->query_flags & BIT_RD) && iq->deleg_msg) {
iq->response = iq->deleg_msg;
if(verbosity >= VERB_ALGO && iq->response)
log_dns_msg("no RD requested, using delegation msg",
@@ -1713,10 +1727,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
/* if this was a parent-side glue query itself, then store that
* failure in cache. */
- if(iq->query_for_pside_glue && !iq->pside_glue)
- iter_store_parentside_neg(qstate->env, &qstate->qinfo,
- iq->deleg_msg?iq->deleg_msg->rep:
- (iq->response?iq->response->rep:NULL));
+ if(!qstate->no_cache_store && iq->query_for_pside_glue
+ && !iq->pside_glue)
+ iter_store_parentside_neg(qstate->env, &qstate->qinfo,
+ iq->deleg_msg?iq->deleg_msg->rep:
+ (iq->response?iq->response->rep:NULL));
verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL");
/* fail -- no more targets, no more hope of targets, no hope
@@ -2009,9 +2024,10 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
}
if(iq->minimisation_state == INIT_MINIMISE_STATE) {
- /* (Re)set qinfo_out to (new) delegation point, except
- * when qinfo_out is already a subdomain of dp. This happens
- * when resolving ip6.arpa dnames. */
+ /* (Re)set qinfo_out to (new) delegation point, except when
+ * qinfo_out is already a subdomain of dp. This happens when
+ * increasing by more than one label at once (QNAMEs with more
+ * than MAX_MINIMISE_COUNT labels). */
if(!(iq->qinfo_out.qname_len
&& dname_subdomain_c(iq->qchase.qname,
iq->qinfo_out.qname)
@@ -2019,30 +2035,53 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dp->name))) {
iq->qinfo_out.qname = iq->dp->name;
iq->qinfo_out.qname_len = iq->dp->namelen;
- iq->qinfo_out.qtype = LDNS_RR_TYPE_NS;
+ iq->qinfo_out.qtype = LDNS_RR_TYPE_A;
iq->qinfo_out.qclass = iq->qchase.qclass;
+ iq->qinfo_out.local_alias = NULL;
+ iq->minimise_count = 0;
}
iq->minimisation_state = MINIMISE_STATE;
}
if(iq->minimisation_state == MINIMISE_STATE) {
- int labdiff = dname_count_labels(iq->qchase.qname) -
+ int qchaselabs = dname_count_labels(iq->qchase.qname);
+ int labdiff = qchaselabs -
dname_count_labels(iq->qinfo_out.qname);
iq->qinfo_out.qname = iq->qchase.qname;
iq->qinfo_out.qname_len = iq->qchase.qname_len;
+ iq->minimise_count++;
+ iq->minimise_timeout_count = 0;
- /* Special treatment for ip6.arpa lookups.
- * Reverse IPv6 dname has 34 labels, increment the IP part
- * (usually first 32 labels) by 8 labels (7 more than the
- * default 1 label increment). */
- if(labdiff <= 32 &&
- dname_subdomain_c(iq->qchase.qname, ie->ip6arpa_dname)) {
- labdiff -= 7;
- /* Small chance of zone cut after first label. Stop
- * minimising */
- if(labdiff <= 1)
- labdiff = 0;
+ iter_dec_attempts(iq->dp, 1);
+
+ /* Limit number of iterations for QNAMEs with more
+ * than MAX_MINIMISE_COUNT labels. Send first MINIMISE_ONE_LAB
+ * labels of QNAME always individually.
+ */
+ if(qchaselabs > MAX_MINIMISE_COUNT && labdiff > 1 &&
+ iq->minimise_count > MINIMISE_ONE_LAB) {
+ if(iq->minimise_count < MAX_MINIMISE_COUNT) {
+ int multilabs = qchaselabs - 1 -
+ MINIMISE_ONE_LAB;
+ int extralabs = multilabs /
+ MINIMISE_MULTIPLE_LABS;
+
+ if (MAX_MINIMISE_COUNT - iq->minimise_count >=
+ multilabs % MINIMISE_MULTIPLE_LABS)
+ /* Default behaviour is to add 1 label
+ * every iteration. Therefore, decrement
+ * the extralabs by 1 */
+ extralabs--;
+ if (extralabs < labdiff)
+ labdiff -= extralabs;
+ else
+ labdiff = 1;
+ }
+ /* Last minimised iteration, send all labels with
+ * QTYPE=NS */
+ else
+ labdiff = 1;
}
if(labdiff > 1) {
@@ -2051,11 +2090,12 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
&iq->qinfo_out.qname_len,
labdiff-1);
}
- if(labdiff < 1 ||
- (labdiff < 2 && iq->qchase.qtype == LDNS_RR_TYPE_DS))
+ if(labdiff < 1 || (labdiff < 2
+ && (iq->qchase.qtype == LDNS_RR_TYPE_DS
+ || iq->qchase.qtype == LDNS_RR_TYPE_A)))
/* Stop minimising this query, resolve "as usual" */
iq->minimisation_state = DONOT_MINIMISE_STATE;
- else {
+ else if(!qstate->no_cache_lookup) {
struct dns_msg* msg = dns_cache_lookup(qstate->env,
iq->qinfo_out.qname, iq->qinfo_out.qname_len,
iq->qinfo_out.qtype, iq->qinfo_out.qclass,
@@ -2068,12 +2108,18 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
* cached as NOERROR/NODATA */
return 1;
}
-
}
- if(iq->minimisation_state == SKIP_MINIMISE_STATE)
- /* Do not increment qname, continue incrementing next
- * iteration */
- iq->minimisation_state = MINIMISE_STATE;
+ if(iq->minimisation_state == SKIP_MINIMISE_STATE) {
+ iq->minimise_timeout_count++;
+ if(iq->minimise_timeout_count < MAX_MINIMISE_TIMEOUT_COUNT)
+ /* Do not increment qname, continue incrementing next
+ * iteration */
+ iq->minimisation_state = MINIMISE_STATE;
+ else if(!qstate->env->cfg->qname_minimisation_strict)
+ /* Too many time-outs detected for this QNAME and QTYPE.
+ * We give up, disable QNAME minimisation. */
+ iq->minimisation_state = DONOT_MINIMISE_STATE;
+ }
if(iq->minimisation_state == DONOT_MINIMISE_STATE)
iq->qinfo_out = iq->qchase;
@@ -2087,13 +2133,18 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dnssec_lame_query?" but lame_query anyway": "");
}
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
- outq = (*qstate->env->send_query)(
- iq->qinfo_out.qname, iq->qinfo_out.qname_len,
- iq->qinfo_out.qtype, iq->qinfo_out.qclass,
- iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD,
+ outq = (*qstate->env->send_query)(&iq->qinfo_out,
+ iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
+ /* unset CD if to forwarder(RD set) and not dnssec retry
+ * (blacklist nonempty) and no trust-anchors are configured
+ * above the qname or on the first attempt when dnssec is on */
+ EDNS_DO| ((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&&
+ !qstate->blacklist&&(!iter_indicates_dnssec_fwd(qstate->env,
+ &iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
- ie, iq), &target->addr, target->addrlen, iq->dp->name,
- iq->dp->namelen, qstate);
+ ie, iq), &target->addr, target->addrlen,
+ iq->dp->name, iq->dp->namelen,
+ (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream), qstate);
if(!outq) {
log_addr(VERB_DETAIL, "error sending query to auth server",
&target->addr, target->addrlen);
@@ -2143,9 +2194,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
int dnsseclame = 0;
enum response_type type;
iq->num_current_queries--;
+
+ if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response))
+ log_err("unable to call query_response callback");
+
if(iq->response == NULL) {
/* Don't increment qname when QNAME minimisation is enabled */
- if (qstate->env->cfg->qname_minimisation)
+ if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = SKIP_MINIMISE_STATE;
iq->chase_to_rd = 0;
iq->dnssec_lame_query = 0;
@@ -2161,8 +2216,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* differently. No queries should be sent elsewhere */
type = RESPONSE_TYPE_ANSWER;
}
- if(iq->dnssec_expected && !iq->dnssec_lame_query &&
+ if(!qstate->env->cfg->disable_dnssec_lame_check && iq->dnssec_expected
+ && !iq->dnssec_lame_query &&
!(iq->chase_flags&BIT_RD)
+ && iq->sent_count < DNSSEC_LAME_DETECT_COUNT
&& type != RESPONSE_TYPE_LAME
&& type != RESPONSE_TYPE_REC_LAME
&& type != RESPONSE_TYPE_THROWAWAY
@@ -2205,6 +2262,22 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
} else
iter_scrub_ds(iq->response, ns, iq->dp->name);
} else iter_scrub_ds(iq->response, NULL, NULL);
+ if(type == RESPONSE_TYPE_THROWAWAY &&
+ FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
+ /* YXDOMAIN is a permanent error, no need to retry */
+ type = RESPONSE_TYPE_ANSWER;
+ }
+ if(type == RESPONSE_TYPE_CNAME && iq->response->rep->an_numrrsets >= 1
+ && ntohs(iq->response->rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_DNAME) {
+ uint8_t* sname = NULL;
+ size_t snamelen = 0;
+ get_cname_target(iq->response->rep->rrsets[0], &sname,
+ &snamelen);
+ if(snamelen && dname_subdomain_c(sname, iq->response->rep->rrsets[0]->rk.dname)) {
+ /* DNAME to a subdomain loop; do not recurse */
+ type = RESPONSE_TYPE_ANSWER;
+ }
+ }
/* handle each of the type cases */
if(type == RESPONSE_TYPE_ANSWER) {
@@ -2232,10 +2305,11 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->num_target_queries = 0;
return processDSNSFind(qstate, iq, id);
}
- 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->query_flags);
+ if(!qstate->no_cache_store)
+ 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->query_flags);
/* close down outstanding requests to be discarded */
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
@@ -2248,12 +2322,44 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
&qstate->reply->addr, qstate->reply->addrlen,
qstate->region);
if(iq->minimisation_state != DONOT_MINIMISE_STATE) {
- /* Best effort qname-minimisation.
- * Stop minimising and send full query when RCODE
- * is not NOERROR */
if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
- LDNS_RCODE_NOERROR)
+ LDNS_RCODE_NOERROR) {
+ if(qstate->env->cfg->qname_minimisation_strict)
+ return final_state(iq);
+ /* Best effort qname-minimisation.
+ * Stop minimising and send full query when
+ * RCODE is not NOERROR. */
iq->minimisation_state = DONOT_MINIMISE_STATE;
+ }
+ if(FLAGS_GET_RCODE(iq->response->rep->flags) ==
+ LDNS_RCODE_NXDOMAIN) {
+ /* Stop resolving when NXDOMAIN is DNSSEC
+ * signed. Based on assumption that namservers
+ * serving signed zones do not return NXDOMAIN
+ * for empty-non-terminals. */
+ if(iq->dnssec_expected)
+ return final_state(iq);
+ /* Make subrequest to validate intermediate
+ * NXDOMAIN if harden-below-nxdomain is
+ * enabled. */
+ if(qstate->env->cfg->harden_below_nxdomain) {
+ struct module_qstate* subq = NULL;
+ log_query_info(VERB_QUERY,
+ "schedule NXDOMAIN validation:",
+ &iq->response->qinfo);
+ if(!generate_sub_request(
+ iq->response->qinfo.qname,
+ iq->response->qinfo.qname_len,
+ iq->response->qinfo.qtype,
+ iq->response->qinfo.qclass,
+ qstate, id, iq,
+ INIT_REQUEST_STATE,
+ FINISHED_STATE, &subq, 1))
+ verbose(VERB_ALGO,
+ "could not validate NXDOMAIN "
+ "response");
+ }
+ }
return next_state(iq, QUERYTARGETS_STATE);
}
return final_state(iq);
@@ -2271,7 +2377,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
}
/* if hardened, only store referral if we asked for it */
- if(!qstate->env->cfg->harden_referral_path ||
+ if(!qstate->no_cache_store &&
+ (!qstate->env->cfg->harden_referral_path ||
( qstate->qinfo.qtype == LDNS_RR_TYPE_NS
&& (qstate->query_flags&BIT_RD)
&& !(qstate->query_flags&BIT_CD)
@@ -2286,7 +2393,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qchase.qname, iq->qchase.qname_len,
LDNS_RR_TYPE_NS, iq->qchase.qclass)
)
- )) {
+ ))) {
/* Store the referral under the current query */
/* no prefetch-leeway, since its not the answer */
iter_dns_store(qstate->env, &iq->response->qinfo,
@@ -2299,16 +2406,17 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->response->rep, iq->dp->name);
}
/* store parent-side-in-zone-glue, if directly queried for */
- if(iq->query_for_pside_glue && !iq->pside_glue) {
- iq->pside_glue = reply_find_rrset(iq->response->rep,
- iq->qchase.qname, iq->qchase.qname_len,
- iq->qchase.qtype, iq->qchase.qclass);
- if(iq->pside_glue) {
- log_rrset_key(VERB_ALGO, "found parent-side "
- "glue", iq->pside_glue);
- iter_store_parentside_rrset(qstate->env,
- iq->pside_glue);
- }
+ if(!qstate->no_cache_store && iq->query_for_pside_glue
+ && !iq->pside_glue) {
+ iq->pside_glue = reply_find_rrset(iq->response->rep,
+ iq->qchase.qname, iq->qchase.qname_len,
+ iq->qchase.qtype, iq->qchase.qclass);
+ if(iq->pside_glue) {
+ log_rrset_key(VERB_ALGO, "found parent-side "
+ "glue", iq->pside_glue);
+ iter_store_parentside_rrset(qstate->env,
+ iq->pside_glue);
+ }
}
/* Reset the event state, setting the current delegation
@@ -2389,10 +2497,11 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* NOTE : set referral=1, so that rrsets get stored but not
* the partial query answer (CNAME only). */
/* 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,
- qstate->query_flags);
+ if(!qstate->no_cache_store)
+ iter_dns_store(qstate->env, &iq->response->qinfo,
+ iq->response->rep, 1, qstate->prefetch_leeway,
+ 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;
@@ -2471,7 +2580,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* LAME, THROWAWAY and "unknown" all end up here.
* Recycle to the QUERYTARGETS state to hopefully try a
* different target. */
- if (qstate->env->cfg->qname_minimisation)
+ if (qstate->env->cfg->qname_minimisation &&
+ !qstate->env->cfg->qname_minimisation_strict)
iq->minimisation_state = DONOT_MINIMISE_STATE;
return next_state(iq, QUERYTARGETS_STATE);
}
@@ -2605,6 +2715,10 @@ processTargetResponse(struct module_qstate* qstate, int id,
log_query_info(VERB_ALGO, "processTargetResponse", &qstate->qinfo);
log_query_info(VERB_ALGO, "processTargetResponse super", &forq->qinfo);
+ /* Tell the originating event that this target query has finished
+ * (regardless if it succeeded or not). */
+ foriq->num_target_queries--;
+
/* check to see if parent event is still interested (in orig name). */
if(!foriq->dp) {
verbose(VERB_ALGO, "subq: parent not interested, was reset");
@@ -2620,10 +2734,6 @@ processTargetResponse(struct module_qstate* qstate, int id,
return;
}
- /* Tell the originating event that this target query has finished
- * (regardless if it succeeded or not). */
- foriq->num_target_queries--;
-
/* if iq->query_for_pside_glue then add the pside_glue (marked lame) */
if(iq->pside_glue) {
/* if the pside_glue is NULL, then it could not be found,
@@ -2871,10 +2981,11 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
&qstate->qinfo);
/* store negative cache element for parent side glue. */
- if(iq->query_for_pside_glue && !iq->pside_glue)
- iter_store_parentside_neg(qstate->env, &qstate->qinfo,
- iq->deleg_msg?iq->deleg_msg->rep:
- (iq->response?iq->response->rep:NULL));
+ if(!qstate->no_cache_store && iq->query_for_pside_glue
+ && !iq->pside_glue)
+ iter_store_parentside_neg(qstate->env, &qstate->qinfo,
+ iq->deleg_msg?iq->deleg_msg->rep:
+ (iq->response?iq->response->rep:NULL));
if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@@ -2910,7 +3021,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
/* store message with the finished prepended items,
* but only if we did recursion. The nonrecursion referral
* from cache does not need to be stored in the msg cache. */
- if(qstate->query_flags&BIT_RD) {
+ if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) {
iter_dns_store(qstate->env, &qstate->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
@@ -3082,8 +3193,25 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
goto handle_it;
}
/* edns is not examined, but removed from message to help cache */
- if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR)
+ if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
+ LDNS_RCODE_NOERROR)
goto handle_it;
+
+ /* Copy the edns options we may got from the back end */
+ if(edns.opt_list) {
+ qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list,
+ qstate->region);
+ if(!qstate->edns_opts_back_in) {
+ log_err("out of memory on incoming message");
+ /* like packet got dropped */
+ goto handle_it;
+ }
+ if(!inplace_cb_edns_back_parsed_call(qstate->env, qstate)) {
+ log_err("unable to call edns_back_parsed callback");
+ goto handle_it;
+ }
+ }
+
/* remove CD-bit, we asked for in case we handle validation ourself */
prs->flags &= ~BIT_CD;