diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2016-09-03 15:08:13 +0000 | 
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2016-09-03 15:08:13 +0000 | 
| commit | a6533d88996e7570cf04db0d99b6012d25a953d3 (patch) | |
| tree | cb1552d6fa59b30201907edc56208f6fe720c283 /iterator | |
| parent | 21d2013cbd382bc99b9c1a31146ec76a2792b92c (diff) | |
Diffstat (limited to 'iterator')
| -rw-r--r-- | iterator/iter_fwd.c | 1 | ||||
| -rw-r--r-- | iterator/iter_utils.c | 21 | ||||
| -rw-r--r-- | iterator/iter_utils.h | 12 | ||||
| -rw-r--r-- | iterator/iterator.c | 119 | ||||
| -rw-r--r-- | iterator/iterator.h | 22 | 
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;  };  /** | 
