diff options
Diffstat (limited to 'external/unbound/iterator/iterator.c')
-rw-r--r-- | external/unbound/iterator/iterator.c | 364 |
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; |