summaryrefslogtreecommitdiff
path: root/iterator
diff options
context:
space:
mode:
Diffstat (limited to 'iterator')
-rw-r--r--iterator/iter_delegpt.h2
-rw-r--r--iterator/iter_hints.c2
-rw-r--r--iterator/iter_scrub.c18
-rw-r--r--iterator/iter_utils.c5
-rw-r--r--iterator/iter_utils.h2
-rw-r--r--iterator/iterator.c405
-rw-r--r--iterator/iterator.h5
7 files changed, 329 insertions, 110 deletions
diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h
index 4bd79c81af09f..24f0574901d9e 100644
--- a/iterator/iter_delegpt.h
+++ b/iterator/iter_delegpt.h
@@ -83,6 +83,8 @@ struct delegpt {
uint8_t dp_type_mlc;
/** use SSL for upstream query */
uint8_t ssl_upstream;
+ /** delegpt from authoritative zone that is locally hosted */
+ uint8_t auth_dp;
};
/**
diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c
index 47af96687fe6f..1d4c228fabc21 100644
--- a/iterator/iter_hints.c
+++ b/iterator/iter_hints.c
@@ -129,7 +129,7 @@ compile_time_root_prime(int do_ip4, int do_ip6)
dp->has_parent_side_NS = 1;
if(do_ip4) {
if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4")) goto failed;
- if(!ah(dp, "B.ROOT-SERVERS.NET.", "192.228.79.201")) goto failed;
+ if(!ah(dp, "B.ROOT-SERVERS.NET.", "199.9.14.201")) goto failed;
if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12")) goto failed;
if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13")) goto failed;
if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed;
diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c
index 1bee85c0b991d..12580dcdb5395 100644
--- a/iterator/iter_scrub.c
+++ b/iterator/iter_scrub.c
@@ -503,6 +503,24 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
continue;
}
}
+ /* if this is type DS and we query for type DS we just got
+ * a referral answer for our type DS query, fix packet */
+ if(rrset->type==LDNS_RR_TYPE_DS &&
+ qinfo->qtype == LDNS_RR_TYPE_DS &&
+ dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0) {
+ rrset->section = LDNS_SECTION_ANSWER;
+ msg->ancount = rrset->rr_count + rrset->rrsig_count;
+ msg->nscount = 0;
+ msg->arcount = 0;
+ msg->an_rrsets = 1;
+ msg->ns_rrsets = 0;
+ msg->ar_rrsets = 0;
+ msg->rrset_count = 1;
+ msg->rrset_first = rrset;
+ msg->rrset_last = rrset;
+ rrset->rrset_all_next = NULL;
+ return 1;
+ }
mark_additional_rrset(pkt, msg, rrset);
prev = rrset;
rrset = rrset->rrset_all_next;
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
index 0b1b456113f7a..70cab40faa801 100644
--- a/iterator/iter_utils.c
+++ b/iterator/iter_utils.c
@@ -656,6 +656,11 @@ iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
/* a trust anchor exists with this name, RRSIGs expected */
if((a=anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
dclass))) {
+ if(a->numDS == 0 && a->numDNSKEY == 0) {
+ /* insecure trust point */
+ lock_basic_unlock(&a->lock);
+ return 0;
+ }
lock_basic_unlock(&a->lock);
return 1;
}
diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h
index d0629a83e0df8..602fa6db3d0d5 100644
--- a/iterator/iter_utils.h
+++ b/iterator/iter_utils.h
@@ -193,7 +193,7 @@ int iter_indicates_dnssec_fwd(struct module_env* env,
* @param dp: delegation point.
* @param msg: delegation message, with DS if a secure referral.
* @param dclass: class of query.
- * @return 1 if dnssec is expected, 0 if not.
+ * @return 1 if dnssec is expected, 0 if not or insecure point above qname.
*/
int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
struct dns_msg* msg, uint16_t dclass);
diff --git a/iterator/iterator.c b/iterator/iterator.c
index 6c49709adea3d..7f3c65737d595 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -53,6 +53,7 @@
#include "validator/val_neg.h"
#include "services/cache/dns.h"
#include "services/cache/infra.h"
+#include "services/authzone.h"
#include "util/module.h"
#include "util/netevent.h"
#include "util/net_help.h"
@@ -771,6 +772,11 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
if(!stub)
return 0;
stub_dp = stub->dp;
+ /* if we have an auth_zone dp, and stub is equal, don't prime stub
+ * yet, unless we want to fallback and avoid the auth_zone */
+ if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp &&
+ query_dname_compare(iq->dp->name, stub_dp->name) == 0)
+ return 0;
/* is it a noprime stub (always use) */
if(stub->noprime) {
@@ -832,6 +838,96 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
}
/**
+ * Generate a delegation point for an auth zone (unless cached dp is better)
+ * false on alloc failure.
+ */
+static int
+auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq,
+ uint8_t* delname, size_t delnamelen)
+{
+ struct auth_zone* z;
+ if(iq->auth_zone_avoid)
+ return 1;
+ if(!delname) {
+ delname = iq->qchase.qname;
+ delnamelen = iq->qchase.qname_len;
+ }
+ lock_rw_rdlock(&qstate->env->auth_zones->lock);
+ z = auth_zones_find_zone(qstate->env->auth_zones, delname, delnamelen,
+ qstate->qinfo.qclass);
+ if(!z) {
+ lock_rw_unlock(&qstate->env->auth_zones->lock);
+ return 1;
+ }
+ lock_rw_rdlock(&z->lock);
+ lock_rw_unlock(&qstate->env->auth_zones->lock);
+ if(z->for_upstream) {
+ if(iq->dp && query_dname_compare(z->name, iq->dp->name) == 0
+ && iq->dp->auth_dp && qstate->blacklist &&
+ z->fallback_enabled) {
+ /* cache is blacklisted and fallback, and we
+ * already have an auth_zone dp */
+ if(verbosity>=VERB_ALGO) {
+ char buf[255+1];
+ dname_str(z->name, buf);
+ verbose(VERB_ALGO, "auth_zone %s "
+ "fallback because cache blacklisted",
+ buf);
+ }
+ lock_rw_unlock(&z->lock);
+ iq->dp = NULL;
+ return 1;
+ }
+ if(iq->dp==NULL || dname_subdomain_c(z->name, iq->dp->name)) {
+ struct delegpt* dp;
+ if(qstate->blacklist && z->fallback_enabled) {
+ /* cache is blacklisted because of a DNSSEC
+ * validation failure, and the zone allows
+ * fallback to the internet, query there. */
+ if(verbosity>=VERB_ALGO) {
+ char buf[255+1];
+ dname_str(z->name, buf);
+ verbose(VERB_ALGO, "auth_zone %s "
+ "fallback because cache blacklisted",
+ buf);
+ }
+ lock_rw_unlock(&z->lock);
+ return 1;
+ }
+ dp = (struct delegpt*)regional_alloc_zero(
+ qstate->region, sizeof(*dp));
+ if(!dp) {
+ log_err("alloc failure");
+ if(z->fallback_enabled) {
+ lock_rw_unlock(&z->lock);
+ return 1; /* just fallback */
+ }
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ dp->name = regional_alloc_init(qstate->region,
+ z->name, z->namelen);
+ if(!dp->name) {
+ log_err("alloc failure");
+ if(z->fallback_enabled) {
+ lock_rw_unlock(&z->lock);
+ return 1; /* just fallback */
+ }
+ lock_rw_unlock(&z->lock);
+ return 0;
+ }
+ dp->namelen = z->namelen;
+ dp->namelabs = z->namelabs;
+ dp->auth_dp = 1;
+ iq->dp = dp;
+ }
+ }
+
+ lock_rw_unlock(&z->lock);
+ return 1;
+}
+
+/**
* Generate A and AAAA checks for glue that is in-zone for the referral
* we just got to obtain authoritative information on the addresses.
*
@@ -914,6 +1010,9 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
generate_a_aaaa_check(qstate, iq, id);
return;
}
+ /* no need to get the NS record for DS, it is above the zonecut */
+ if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS)
+ return;
log_nametypeclass(VERB_ALGO, "schedule ns fetch",
iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
@@ -1106,14 +1205,15 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
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);
+ qstate->region, qstate->env->scratch, 0);
if(!msg && qstate->env->neg_cache) {
/* 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,
qstate->env->scratch_buffer,
- *qstate->env->now, 1/*add SOA*/, NULL);
+ *qstate->env->now, 1/*add SOA*/, NULL,
+ qstate->env->cfg);
}
/* item taken from cache does not match our query name, thus
* security needs to be re-examined later */
@@ -1164,7 +1264,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
iq->response = msg;
return final_state(iq);
}
-
+
/* attempt to forward the request */
if(forward_request(qstate, iq))
{
@@ -1225,8 +1325,15 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
/* If the cache has returned nothing, then we have a
* root priming situation. */
if(iq->dp == NULL) {
+ int r;
+ /* if under auth zone, no prime needed */
+ if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
+ return error_response(qstate, id,
+ LDNS_RCODE_SERVFAIL);
+ if(iq->dp) /* use auth zone dp */
+ return next_state(iq, INIT_REQUEST_2_STATE);
/* if there is a stub, then no root prime needed */
- int r = prime_stub(qstate, iq, id, delname,
+ r = prime_stub(qstate, iq, id, delname,
iq->qchase.qclass);
if(r == 2)
break; /* got noprime-stub-zone, continue */
@@ -1371,22 +1478,36 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
log_query_info(VERB_QUERY, "resolving (init part 2): ",
&qstate->qinfo);
+ delname = iq->qchase.qname;
+ delnamelen = iq->qchase.qname_len;
if(iq->refetch_glue) {
+ struct iter_hints_stub* stub;
if(!iq->dp) {
log_err("internal or malloc fail: no dp for refetch");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
- delname = iq->dp->name;
- delnamelen = iq->dp->namelen;
- } else {
- delname = iq->qchase.qname;
- delnamelen = iq->qchase.qname_len;
+ /* Do not send queries above stub, do not set delname to dp if
+ * this is above stub without stub-first. */
+ stub = hints_lookup_stub(
+ qstate->env->hints, iq->qchase.qname, iq->qchase.qclass,
+ iq->dp);
+ if(!stub || !stub->dp->has_parent_side_NS ||
+ dname_subdomain_c(iq->dp->name, stub->dp->name)) {
+ delname = iq->dp->name;
+ delnamelen = iq->dp->namelen;
+ }
}
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) {
if(!dname_is_root(delname))
dname_remove_label(&delname, &delnamelen);
iq->refetch_glue = 0; /* if CNAME causes restart, no refetch */
}
+
+ /* see if we have an auth zone to answer from, improves dp from cache
+ * (if any dp from cache) with auth zone dp, if that is lower */
+ if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+
/* Check to see if we need to prime a stub zone. */
if(prime_stub(qstate, iq, id, delname, iq->qchase.qclass)) {
/* A priming sub request was made */
@@ -1871,6 +1992,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
int tf_policy;
struct delegpt_addr* target;
struct outbound_entry* outq;
+ int auth_fallback = 0;
/* NOTE: a request will encounter this state for each target it
* needs to send a query to. That is, at least one per referral,
@@ -1915,6 +2037,152 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return 0;
}
+ 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
+ * 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)
+ && dname_subdomain_c(iq->qinfo_out.qname,
+ 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_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 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;
+
+ 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) {
+ verbose(VERB_QUERY, "removing %d labels", labdiff-1);
+ dname_remove_labels(&iq->qinfo_out.qname,
+ &iq->qinfo_out.qname_len,
+ labdiff-1);
+ }
+ 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 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,
+ qstate->query_flags, qstate->region,
+ qstate->env->scratch, 0);
+ if(msg && msg->rep->an_numrrsets == 0
+ && FLAGS_GET_RCODE(msg->rep->flags) ==
+ LDNS_RCODE_NOERROR)
+ /* no need to send query if it is already
+ * cached as NOERROR/NODATA */
+ return 1;
+ }
+ }
+ if(iq->minimisation_state == SKIP_MINIMISE_STATE) {
+ 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;
+
+ /* now find an answer to this query */
+ /* see if authority zones have an answer */
+ /* now we know the dp, we can check the auth zone for locally hosted
+ * contents */
+ if(!iq->auth_zone_avoid && qstate->blacklist) {
+ if(auth_zones_can_fallback(qstate->env->auth_zones,
+ iq->dp->name, iq->dp->namelen, iq->qinfo_out.qclass)) {
+ /* if cache is blacklisted and this zone allows us
+ * to fallback to the internet, then do so, and
+ * fetch results from the internet servers */
+ iq->auth_zone_avoid = 1;
+ }
+ }
+ if(iq->auth_zone_avoid) {
+ iq->auth_zone_avoid = 0;
+ auth_fallback = 1;
+ } else if(auth_zones_lookup(qstate->env->auth_zones, &iq->qinfo_out,
+ qstate->region, &iq->response, &auth_fallback, iq->dp->name,
+ iq->dp->namelen)) {
+ /* use this as a response to be processed by the iterator */
+ if(verbosity >= VERB_ALGO) {
+ log_dns_msg("msg from auth zone",
+ &iq->response->qinfo, iq->response->rep);
+ }
+ iq->num_current_queries++;
+ iq->chase_to_rd = 0;
+ iq->dnssec_lame_query = 0;
+ iq->auth_zone_response = 1;
+ return next_state(iq, QUERY_RESP_STATE);
+ }
+ iq->auth_zone_response = 0;
+ if(auth_fallback == 0) {
+ /* like we got servfail from the auth zone lookup, and
+ * no internet fallback */
+ verbose(VERB_ALGO, "auth zone lookup failed, no fallback,"
+ " servfail");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ if(iq->dp && iq->dp->auth_dp) {
+ /* we wanted to fallback, but had no delegpt, only the
+ * auth zone generated delegpt, create an actual one */
+ iq->auth_zone_avoid = 1;
+ return next_state(iq, INIT_REQUEST_STATE);
+ }
+ /* but mostly, fallback==1 (like, when no such auth zone exists)
+ * and we continue with lookups */
+
tf_policy = 0;
/* < not <=, because although the array is large enough for <=, the
* generated query will immediately be discarded due to depth and
@@ -2082,105 +2350,6 @@ 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
- * 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)
- && dname_subdomain_c(iq->qinfo_out.qname,
- 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_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 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;
-
- 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) {
- verbose(VERB_QUERY, "removing %d labels", labdiff-1);
- dname_remove_labels(&iq->qinfo_out.qname,
- &iq->qinfo_out.qname_len,
- labdiff-1);
- }
- 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 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,
- qstate->query_flags, qstate->region,
- qstate->env->scratch);
- if(msg && msg->rep->an_numrrsets == 0
- && FLAGS_GET_RCODE(msg->rep->flags) ==
- LDNS_RCODE_NOERROR)
- /* no need to send query if it is already
- * cached as NOERROR/NODATA */
- return 1;
- }
- }
- if(iq->minimisation_state == SKIP_MINIMISE_STATE) {
- 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;
-
/* We have a valid target. */
if(verbosity >= VERB_QUERY) {
log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
@@ -2573,6 +2742,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->deleg_msg = NULL;
iq->dp = NULL;
iq->dsns_point = NULL;
+ iq->auth_zone_response = 0;
/* Note the query restart. */
iq->query_restart_count++;
iq->sent_count = 0;
@@ -2645,6 +2815,25 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
if (qstate->env->cfg->qname_minimisation &&
!qstate->env->cfg->qname_minimisation_strict)
iq->minimisation_state = DONOT_MINIMISE_STATE;
+ if(iq->auth_zone_response) {
+ /* can we fallback? */
+ iq->auth_zone_response = 0;
+ if(!auth_zones_can_fallback(qstate->env->auth_zones,
+ iq->dp->name, iq->dp->namelen, qstate->qinfo.qclass)) {
+ verbose(VERB_ALGO, "auth zone response bad, and no"
+ " fallback possible, servfail");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ verbose(VERB_ALGO, "auth zone response was bad, "
+ "fallback enabled");
+ iq->auth_zone_avoid = 1;
+ if(iq->dp->auth_dp) {
+ /* we are using a dp for the auth zone, with no
+ * nameservers, get one first */
+ iq->dp = NULL;
+ return next_state(iq, INIT_REQUEST_STATE);
+ }
+ }
return next_state(iq, QUERYTARGETS_STATE);
}
diff --git a/iterator/iterator.h b/iterator/iterator.h
index 841a3643669ca..67ffeb1476318 100644
--- a/iterator/iterator.h
+++ b/iterator/iterator.h
@@ -387,6 +387,11 @@ struct iter_qstate {
* Count number of time-outs. Used to prevent resolving failures when
* the QNAME minimisation QTYPE is blocked. */
int minimise_timeout_count;
+
+ /** True if the current response is from auth_zone */
+ int auth_zone_response;
+ /** True if the auth_zones should not be consulted for the query */
+ int auth_zone_avoid;
};
/**