aboutsummaryrefslogtreecommitdiff
path: root/iterator
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2016-09-03 15:08:13 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2016-09-03 15:08:13 +0000
commita6533d88996e7570cf04db0d99b6012d25a953d3 (patch)
treecb1552d6fa59b30201907edc56208f6fe720c283 /iterator
parent21d2013cbd382bc99b9c1a31146ec76a2792b92c (diff)
Diffstat (limited to 'iterator')
-rw-r--r--iterator/iter_fwd.c1
-rw-r--r--iterator/iter_utils.c21
-rw-r--r--iterator/iter_utils.h12
-rw-r--r--iterator/iterator.c119
-rw-r--r--iterator/iterator.h22
5 files changed, 137 insertions, 38 deletions
diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c
index 0feee032c960..3e580ca35513 100644
--- a/iterator/iter_fwd.c
+++ b/iterator/iter_fwd.c
@@ -294,6 +294,7 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
uint8_t* dname;
size_t dname_len;
for(s = cfg->stubs; s; s = s->next) {
+ if(!s->name) continue;
dname = sldns_str2wire_dname(s->name, &dname_len);
if(!dname) {
log_err("cannot parse stub name '%s'", s->name);
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
index 58e62fbeb27b..a5aefa9602c2 100644
--- a/iterator/iter_utils.c
+++ b/iterator/iter_utils.c
@@ -590,6 +590,27 @@ iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
return 1;
}
+int
+iter_indicates_dnssec_fwd(struct module_env* env, struct query_info *qinfo)
+{
+ struct trust_anchor* a;
+ if(!env || !env->anchors || !qinfo || !qinfo->qname)
+ return 0;
+ /* a trust anchor exists above the name? */
+ if((a=anchors_lookup(env->anchors, qinfo->qname, qinfo->qname_len,
+ qinfo->qclass))) {
+ if(a->numDS == 0 && a->numDNSKEY == 0) {
+ /* insecure trust point */
+ lock_basic_unlock(&a->lock);
+ return 0;
+ }
+ lock_basic_unlock(&a->lock);
+ return 1;
+ }
+ /* no trust anchor above it. */
+ return 0;
+}
+
int
iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
struct dns_msg* msg, uint16_t dclass)
diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h
index 3a4df3e45968..50c5fc093f6c 100644
--- a/iterator/iter_utils.h
+++ b/iterator/iter_utils.h
@@ -174,6 +174,18 @@ int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp);
/**
+ * See if qname has DNSSEC needs in the forwarding case. This is true if
+ * there is a trust anchor above it. Whether there is an insecure delegation
+ * to the data is unknown, but CD-retry is needed.
+ * @param env: environment with anchors.
+ * @param qinfo: query name and class.
+ * @return true if trust anchor above qname, false if no anchor or insecure
+ * point above qname.
+ */
+int iter_indicates_dnssec_fwd(struct module_env* env,
+ struct query_info *qinfo);
+
+/**
* See if delegation is expected to have DNSSEC information (RRSIGs) in
* its answers, or not. Inspects delegation point (name), trust anchors,
* and delegation message (DS RRset) to determine this.
diff --git a/iterator/iterator.c b/iterator/iterator.c
index b1bf902d583d..139cae4bae0a 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -82,20 +82,6 @@ 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;
}
@@ -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,7 @@ 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;
if (qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
else
@@ -1800,6 +1786,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
int tf_policy;
struct delegpt_addr* target;
struct outbound_entry* outq;
+ /* EDNS options to set on outgoing packet */
+ struct edns_option* opt_list = NULL;
/* NOTE: a request will encounter this state for each target it
* needs to send a query to. That is, at least one per referral,
@@ -2009,9 +1997,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)
@@ -2021,28 +2010,47 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qinfo_out.qname_len = iq->dp->namelen;
iq->qinfo_out.qtype = LDNS_RR_TYPE_NS;
iq->qinfo_out.qclass = iq->qchase.qclass;
+ 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++;
- /* 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;
+ /* 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) {
@@ -2068,7 +2076,6 @@ 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
@@ -2090,10 +2097,16 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
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,
+ 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), opt_list, &target->addr, target->addrlen,
+ iq->dp->name, iq->dp->namelen, qstate);
if(!outq) {
log_addr(VERB_DETAIL, "error sending query to auth server",
&target->addr, target->addrlen);
@@ -2161,8 +2174,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
@@ -2250,10 +2265,39 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
if(iq->minimisation_state != DONOT_MINIMISE_STATE) {
/* Best effort qname-minimisation.
* Stop minimising and send full query when RCODE
- * is not NOERROR */
+ * is not NOERROR. */
if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
LDNS_RCODE_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);
@@ -3082,7 +3126,8 @@ 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;
/* remove CD-bit, we asked for in case we handle validation ourself */
prs->flags &= ~BIT_CD;
diff --git a/iterator/iterator.h b/iterator/iterator.h
index b7aa82ebe4ed..7c32a74f800b 100644
--- a/iterator/iterator.h
+++ b/iterator/iterator.h
@@ -61,6 +61,20 @@ struct rbtree_t;
#define MAX_REFERRAL_COUNT 130
/** max number of queries-sent-out. Make sure large NS set does not loop */
#define MAX_SENT_COUNT 32
+/** max number of queries for which to perform dnsseclameness detection,
+ * (rrsigs misssing detection) after that, just pick up that response */
+#define DNSSEC_LAME_DETECT_COUNT 4
+/**
+ * max number of QNAME minimisation iterations. Limits number of queries for
+ * QNAMEs with a lot of labels.
+*/
+#define MAX_MINIMISE_COUNT 10
+/**
+ * number of labels from QNAME that are always send individually when using
+ * QNAME minimisation, even when the number of labels of the QNAME is bigger
+ * tham MAX_MINIMISE_COUNT */
+#define MINIMISE_ONE_LAB 4
+#define MINIMISE_MULTIPLE_LABS (MAX_MINIMISE_COUNT - MINIMISE_ONE_LAB)
/** at what query-sent-count to stop target fetch policy */
#define TARGET_FETCH_STOP 3
/** how nice is a server without further information, in msec
@@ -349,7 +363,7 @@ struct iter_qstate {
/** list of pending queries to authoritative servers. */
struct outbound_list outlist;
- /** QNAME minimisation state */
+ /** QNAME minimisation state, RFC7816 */
enum minimisation_state minimisation_state;
/**
@@ -357,6 +371,12 @@ struct iter_qstate {
* when qname minimisation is enabled.
*/
struct query_info qinfo_out;
+
+ /**
+ * Count number of QNAME minisation iterations. Used to limit number of
+ * outgoing queries when QNAME minimisation is enabled.
+ */
+ int minimise_count;
};
/**