xref: /openbsd-src/usr.sbin/unbound/iterator/iterator.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1933707f3Ssthen /*
2933707f3Ssthen  * iterator/iterator.c - iterative resolver DNS query response module
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39bdfc4d55Sflorian  * This file contains a module that performs recursive iterative DNS query
40933707f3Ssthen  * processing.
41933707f3Ssthen  */
42933707f3Ssthen 
43933707f3Ssthen #include "config.h"
44933707f3Ssthen #include "iterator/iterator.h"
45933707f3Ssthen #include "iterator/iter_utils.h"
46933707f3Ssthen #include "iterator/iter_hints.h"
47933707f3Ssthen #include "iterator/iter_fwd.h"
48933707f3Ssthen #include "iterator/iter_donotq.h"
49933707f3Ssthen #include "iterator/iter_delegpt.h"
50933707f3Ssthen #include "iterator/iter_resptype.h"
51933707f3Ssthen #include "iterator/iter_scrub.h"
52933707f3Ssthen #include "iterator/iter_priv.h"
53933707f3Ssthen #include "validator/val_neg.h"
54933707f3Ssthen #include "services/cache/dns.h"
552bdc0ed1Ssthen #include "services/cache/rrset.h"
56933707f3Ssthen #include "services/cache/infra.h"
57938a3a5eSflorian #include "services/authzone.h"
58933707f3Ssthen #include "util/module.h"
59933707f3Ssthen #include "util/netevent.h"
60933707f3Ssthen #include "util/net_help.h"
61933707f3Ssthen #include "util/regional.h"
62933707f3Ssthen #include "util/data/dname.h"
63933707f3Ssthen #include "util/data/msgencode.h"
64933707f3Ssthen #include "util/fptr_wlist.h"
65933707f3Ssthen #include "util/config_file.h"
66a58bff56Ssthen #include "util/random.h"
67a58bff56Ssthen #include "sldns/rrdef.h"
68a58bff56Ssthen #include "sldns/wire2str.h"
6924893edcSsthen #include "sldns/str2wire.h"
70a58bff56Ssthen #include "sldns/parseutil.h"
71a58bff56Ssthen #include "sldns/sbuffer.h"
72933707f3Ssthen 
733150e5f6Ssthen /* in msec */
743150e5f6Ssthen int UNKNOWN_SERVER_NICENESS = 376;
75d1e2768aSsthen /* in msec */
76d1e2768aSsthen int USEFUL_SERVER_TOP_TIMEOUT = 120000;
77d1e2768aSsthen /* Equals USEFUL_SERVER_TOP_TIMEOUT*4 */
78d1e2768aSsthen int BLACKLIST_PENALTY = (120000*4);
793150e5f6Ssthen 
8006a13c09Ssthen static void target_count_increase_nx(struct iter_qstate* iq, int num);
8106a13c09Ssthen 
82933707f3Ssthen int
83933707f3Ssthen iter_init(struct module_env* env, int id)
84933707f3Ssthen {
85933707f3Ssthen 	struct iter_env* iter_env = (struct iter_env*)calloc(1,
86933707f3Ssthen 		sizeof(struct iter_env));
87933707f3Ssthen 	if(!iter_env) {
88933707f3Ssthen 		log_err("malloc failure");
89933707f3Ssthen 		return 0;
90933707f3Ssthen 	}
91933707f3Ssthen 	env->modinfo[id] = (void*)iter_env;
927191de28Ssthen 
937191de28Ssthen 	lock_basic_init(&iter_env->queries_ratelimit_lock);
947191de28Ssthen 	lock_protect(&iter_env->queries_ratelimit_lock,
957191de28Ssthen 			&iter_env->num_queries_ratelimited,
967191de28Ssthen 		sizeof(iter_env->num_queries_ratelimited));
977191de28Ssthen 
98933707f3Ssthen 	if(!iter_apply_cfg(iter_env, env->cfg)) {
99933707f3Ssthen 		log_err("iterator: could not apply configuration settings.");
100933707f3Ssthen 		return 0;
101933707f3Ssthen 	}
10224893edcSsthen 
103933707f3Ssthen 	return 1;
104933707f3Ssthen }
105933707f3Ssthen 
106a58bff56Ssthen /** delete caps_whitelist element */
107a58bff56Ssthen static void
10877079be7Ssthen caps_free(struct rbnode_type* n, void* ATTR_UNUSED(d))
109a58bff56Ssthen {
110a58bff56Ssthen 	if(n) {
111a58bff56Ssthen 		free(((struct name_tree_node*)n)->name);
112a58bff56Ssthen 		free(n);
113a58bff56Ssthen 	}
114a58bff56Ssthen }
115a58bff56Ssthen 
116933707f3Ssthen void
117933707f3Ssthen iter_deinit(struct module_env* env, int id)
118933707f3Ssthen {
119933707f3Ssthen 	struct iter_env* iter_env;
120933707f3Ssthen 	if(!env || !env->modinfo[id])
121933707f3Ssthen 		return;
122933707f3Ssthen 	iter_env = (struct iter_env*)env->modinfo[id];
1237191de28Ssthen 	lock_basic_destroy(&iter_env->queries_ratelimit_lock);
124933707f3Ssthen 	free(iter_env->target_fetch_policy);
125933707f3Ssthen 	priv_delete(iter_env->priv);
126933707f3Ssthen 	donotq_delete(iter_env->donotq);
127a58bff56Ssthen 	if(iter_env->caps_white) {
128a58bff56Ssthen 		traverse_postorder(iter_env->caps_white, caps_free, NULL);
129a58bff56Ssthen 		free(iter_env->caps_white);
130a58bff56Ssthen 	}
131933707f3Ssthen 	free(iter_env);
132933707f3Ssthen 	env->modinfo[id] = NULL;
133933707f3Ssthen }
134933707f3Ssthen 
135933707f3Ssthen /** new query for iterator */
136933707f3Ssthen static int
137933707f3Ssthen iter_new(struct module_qstate* qstate, int id)
138933707f3Ssthen {
139933707f3Ssthen 	struct iter_qstate* iq = (struct iter_qstate*)regional_alloc(
140933707f3Ssthen 		qstate->region, sizeof(struct iter_qstate));
141933707f3Ssthen 	qstate->minfo[id] = iq;
142933707f3Ssthen 	if(!iq)
143933707f3Ssthen 		return 0;
144933707f3Ssthen 	memset(iq, 0, sizeof(*iq));
145933707f3Ssthen 	iq->state = INIT_REQUEST_STATE;
146933707f3Ssthen 	iq->final_state = FINISHED_STATE;
147933707f3Ssthen 	iq->an_prepend_list = NULL;
148933707f3Ssthen 	iq->an_prepend_last = NULL;
149933707f3Ssthen 	iq->ns_prepend_list = NULL;
150933707f3Ssthen 	iq->ns_prepend_last = NULL;
151933707f3Ssthen 	iq->dp = NULL;
152933707f3Ssthen 	iq->depth = 0;
153933707f3Ssthen 	iq->num_target_queries = 0;
154933707f3Ssthen 	iq->num_current_queries = 0;
155933707f3Ssthen 	iq->query_restart_count = 0;
156933707f3Ssthen 	iq->referral_count = 0;
157933707f3Ssthen 	iq->sent_count = 0;
158a58bff56Ssthen 	iq->ratelimit_ok = 0;
159ae1dea89Sflorian 	iq->target_count = NULL;
16006a13c09Ssthen 	iq->dp_target_count = 0;
161933707f3Ssthen 	iq->wait_priming_stub = 0;
162933707f3Ssthen 	iq->refetch_glue = 0;
163933707f3Ssthen 	iq->dnssec_expected = 0;
164933707f3Ssthen 	iq->dnssec_lame_query = 0;
165933707f3Ssthen 	iq->chase_flags = qstate->query_flags;
166933707f3Ssthen 	/* Start with the (current) qname. */
167933707f3Ssthen 	iq->qchase = qstate->qinfo;
168933707f3Ssthen 	outbound_list_init(&iq->outlist);
1692ee382b6Ssthen 	iq->minimise_count = 0;
170a3167c07Ssthen 	iq->timeout_count = 0;
17124893edcSsthen 	if (qstate->env->cfg->qname_minimisation)
17224893edcSsthen 		iq->minimisation_state = INIT_MINIMISE_STATE;
17324893edcSsthen 	else
17424893edcSsthen 		iq->minimisation_state = DONOT_MINIMISE_STATE;
17524893edcSsthen 
17624893edcSsthen 	memset(&iq->qinfo_out, 0, sizeof(struct query_info));
177933707f3Ssthen 	return 1;
178933707f3Ssthen }
179933707f3Ssthen 
180933707f3Ssthen /**
181933707f3Ssthen  * Transition to the next state. This can be used to advance a currently
182933707f3Ssthen  * processing event. It cannot be used to reactivate a forEvent.
183933707f3Ssthen  *
184933707f3Ssthen  * @param iq: iterator query state
185933707f3Ssthen  * @param nextstate The state to transition to.
186933707f3Ssthen  * @return true. This is so this can be called as the return value for the
187933707f3Ssthen  *         actual process*State() methods. (Transitioning to the next state
188933707f3Ssthen  *         implies further processing).
189933707f3Ssthen  */
190933707f3Ssthen static int
191933707f3Ssthen next_state(struct iter_qstate* iq, enum iter_state nextstate)
192933707f3Ssthen {
193933707f3Ssthen 	/* If transitioning to a "response" state, make sure that there is a
194933707f3Ssthen 	 * response */
195933707f3Ssthen 	if(iter_state_is_responsestate(nextstate)) {
196933707f3Ssthen 		if(iq->response == NULL) {
197933707f3Ssthen 			log_err("transitioning to response state sans "
198933707f3Ssthen 				"response.");
199933707f3Ssthen 		}
200933707f3Ssthen 	}
201933707f3Ssthen 	iq->state = nextstate;
202933707f3Ssthen 	return 1;
203933707f3Ssthen }
204933707f3Ssthen 
205933707f3Ssthen /**
206933707f3Ssthen  * Transition an event to its final state. Final states always either return
207933707f3Ssthen  * a result up the module chain, or reactivate a dependent event. Which
2084bfc71b0Ssthen  * final state to transition to is set in the module state for the event when
209933707f3Ssthen  * it was created, and depends on the original purpose of the event.
210933707f3Ssthen  *
211933707f3Ssthen  * The response is stored in the qstate->buf buffer.
212933707f3Ssthen  *
213933707f3Ssthen  * @param iq: iterator query state
214933707f3Ssthen  * @return false. This is so this method can be used as the return value for
215933707f3Ssthen  *         the processState methods. (Transitioning to the final state
216933707f3Ssthen  */
217933707f3Ssthen static int
218933707f3Ssthen final_state(struct iter_qstate* iq)
219933707f3Ssthen {
220933707f3Ssthen 	return next_state(iq, iq->final_state);
221933707f3Ssthen }
222933707f3Ssthen 
223933707f3Ssthen /**
224933707f3Ssthen  * Callback routine to handle errors in parent query states
225933707f3Ssthen  * @param qstate: query state that failed.
226933707f3Ssthen  * @param id: module id.
227933707f3Ssthen  * @param super: super state.
228933707f3Ssthen  */
229933707f3Ssthen static void
230933707f3Ssthen error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
231933707f3Ssthen {
23206a13c09Ssthen 	struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
233933707f3Ssthen 	struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id];
234933707f3Ssthen 
235933707f3Ssthen 	if(qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
236933707f3Ssthen 		qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) {
237933707f3Ssthen 		/* mark address as failed. */
238933707f3Ssthen 		struct delegpt_ns* dpns = NULL;
239e024f976Ssthen 		super_iq->num_target_queries--;
240933707f3Ssthen 		if(super_iq->dp)
241933707f3Ssthen 			dpns = delegpt_find_ns(super_iq->dp,
242933707f3Ssthen 				qstate->qinfo.qname, qstate->qinfo.qname_len);
243933707f3Ssthen 		if(!dpns) {
244933707f3Ssthen 			/* not interested */
2452308e98cSsthen 			/* this can happen, for eg. qname minimisation asked
2462308e98cSsthen 			 * for an NXDOMAIN to be validated, and used qtype
2472308e98cSsthen 			 * A for that, and the error of that, the name, is
2482308e98cSsthen 			 * not listed in super_iq->dp */
249933707f3Ssthen 			verbose(VERB_ALGO, "subq error, but not interested");
250933707f3Ssthen 			log_query_info(VERB_ALGO, "superq", &super->qinfo);
251933707f3Ssthen 			return;
252933707f3Ssthen 		} else {
253933707f3Ssthen 			/* see if the failure did get (parent-lame) info */
25477079be7Ssthen 			if(!cache_fill_missing(super->env, super_iq->qchase.qclass,
25577079be7Ssthen 				super->region, super_iq->dp))
256933707f3Ssthen 				log_err("out of memory adding missing");
257933707f3Ssthen 		}
25806a13c09Ssthen 		delegpt_mark_neg(dpns, qstate->qinfo.qtype);
2598b7325afSsthen 		if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
260d1e2768aSsthen 			(dpns->got6 == 2 || !ie->supports_ipv6)) {
26145872187Ssthen 			dpns->resolved = 1; /* mark as failed */
26206a13c09Ssthen 			target_count_increase_nx(super_iq, 1);
263933707f3Ssthen 		}
264d1e2768aSsthen 	}
265933707f3Ssthen 	if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
266933707f3Ssthen 		/* prime failed to get delegation */
267933707f3Ssthen 		super_iq->dp = NULL;
268933707f3Ssthen 	}
269933707f3Ssthen 	/* evaluate targets again */
270933707f3Ssthen 	super_iq->state = QUERYTARGETS_STATE;
271933707f3Ssthen 	/* super becomes runnable, and will process this change */
272933707f3Ssthen }
273933707f3Ssthen 
274933707f3Ssthen /**
275933707f3Ssthen  * Return an error to the client
276933707f3Ssthen  * @param qstate: our query state
277933707f3Ssthen  * @param id: module id
278933707f3Ssthen  * @param rcode: error code (DNS errcode).
279933707f3Ssthen  * @return: 0 for use by caller, to make notation easy, like:
280933707f3Ssthen  * 	return error_response(..).
281933707f3Ssthen  */
282933707f3Ssthen static int
283933707f3Ssthen error_response(struct module_qstate* qstate, int id, int rcode)
284933707f3Ssthen {
285933707f3Ssthen 	verbose(VERB_QUERY, "return error response %s",
2865d76a658Ssthen 		sldns_lookup_by_id(sldns_rcodes, rcode)?
2875d76a658Ssthen 		sldns_lookup_by_id(sldns_rcodes, rcode)->name:"??");
288933707f3Ssthen 	qstate->return_rcode = rcode;
289933707f3Ssthen 	qstate->return_msg = NULL;
290933707f3Ssthen 	qstate->ext_state[id] = module_finished;
291933707f3Ssthen 	return 0;
292933707f3Ssthen }
293933707f3Ssthen 
294933707f3Ssthen /**
295933707f3Ssthen  * Return an error to the client and cache the error code in the
296933707f3Ssthen  * message cache (so per qname, qtype, qclass).
297933707f3Ssthen  * @param qstate: our query state
298933707f3Ssthen  * @param id: module id
299933707f3Ssthen  * @param rcode: error code (DNS errcode).
300933707f3Ssthen  * @return: 0 for use by caller, to make notation easy, like:
301933707f3Ssthen  * 	return error_response(..).
302933707f3Ssthen  */
303933707f3Ssthen static int
304933707f3Ssthen error_response_cache(struct module_qstate* qstate, int id, int rcode)
305933707f3Ssthen {
306933707f3Ssthen 	struct reply_info err;
3078b7325afSsthen 	struct msgreply_entry* msg;
3088b7325afSsthen 	if(qstate->no_cache_store) {
3098b7325afSsthen 		return error_response(qstate, id, rcode);
3108b7325afSsthen 	}
31198f3ca02Sbrad 	if(qstate->prefetch_leeway > NORR_TTL) {
31298f3ca02Sbrad 		verbose(VERB_ALGO, "error response for prefetch in cache");
31398f3ca02Sbrad 		/* attempt to adjust the cache entry prefetch */
31498f3ca02Sbrad 		if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo,
31557dceb2aSbrad 			NORR_TTL, qstate->query_flags))
31698f3ca02Sbrad 			return error_response(qstate, id, rcode);
31798f3ca02Sbrad 		/* if that fails (not in cache), fall through to store err */
31898f3ca02Sbrad 	}
3192be9e038Ssthen 	if((msg=msg_cache_lookup(qstate->env,
3202be9e038Ssthen 		qstate->qinfo.qname, qstate->qinfo.qname_len,
3212be9e038Ssthen 		qstate->qinfo.qtype, qstate->qinfo.qclass,
3222308e98cSsthen 		qstate->query_flags, 0,
3238b7325afSsthen 		qstate->env->cfg->serve_expired_ttl_reset)) != NULL) {
3248b7325afSsthen 		struct reply_info* rep = (struct reply_info*)msg->entry.data;
3258b7325afSsthen 		if(qstate->env->cfg->serve_expired &&
3268b7325afSsthen 			qstate->env->cfg->serve_expired_ttl_reset && rep &&
3278b7325afSsthen 			*qstate->env->now + qstate->env->cfg->serve_expired_ttl
3288b7325afSsthen 			> rep->serve_expired_ttl) {
3298b7325afSsthen 			verbose(VERB_ALGO, "reset serve-expired-ttl for "
3308b7325afSsthen 				"response in cache");
3318b7325afSsthen 			rep->serve_expired_ttl = *qstate->env->now +
3322308e98cSsthen 				qstate->env->cfg->serve_expired_ttl;
3332308e98cSsthen 		}
3348b7325afSsthen 		if(rep && (FLAGS_GET_RCODE(rep->flags) ==
3353150e5f6Ssthen 			LDNS_RCODE_NOERROR ||
3363150e5f6Ssthen 			FLAGS_GET_RCODE(rep->flags) ==
3378b7325afSsthen 			LDNS_RCODE_NXDOMAIN ||
3388b7325afSsthen 			FLAGS_GET_RCODE(rep->flags) ==
3398b7325afSsthen 			LDNS_RCODE_YXDOMAIN) &&
3408b7325afSsthen 			(qstate->env->cfg->serve_expired ||
3418b7325afSsthen 			*qstate->env->now <= rep->ttl)) {
3428b7325afSsthen 			/* we have a good entry, don't overwrite */
3433150e5f6Ssthen 			lock_rw_unlock(&msg->entry.lock);
3443150e5f6Ssthen 			return error_response(qstate, id, rcode);
3453150e5f6Ssthen 		}
3463150e5f6Ssthen 		lock_rw_unlock(&msg->entry.lock);
3478b7325afSsthen 		/* nothing interesting is cached (already error response or
3488b7325afSsthen 		 * expired good record when we don't serve expired), so this
3498b7325afSsthen 		 * servfail cache entry is useful (stops waste of time on this
3508b7325afSsthen 		 * servfail NORR_TTL) */
3513150e5f6Ssthen 	}
3528b7325afSsthen 	/* store in cache */
353933707f3Ssthen 	memset(&err, 0, sizeof(err));
354933707f3Ssthen 	err.flags = (uint16_t)(BIT_QR | BIT_RA);
355933707f3Ssthen 	FLAGS_SET_RCODE(err.flags, rcode);
356933707f3Ssthen 	err.qdcount = 1;
357933707f3Ssthen 	err.ttl = NORR_TTL;
358933707f3Ssthen 	err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl);
3592308e98cSsthen 	err.serve_expired_ttl = NORR_TTL;
360933707f3Ssthen 	/* do not waste time trying to validate this servfail */
361933707f3Ssthen 	err.security = sec_status_indeterminate;
362933707f3Ssthen 	verbose(VERB_ALGO, "store error response in message cache");
36357dceb2aSbrad 	iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL,
364d1e2768aSsthen 		qstate->query_flags, qstate->qstarttime);
365933707f3Ssthen 	return error_response(qstate, id, rcode);
366933707f3Ssthen }
367933707f3Ssthen 
368933707f3Ssthen /** check if prepend item is duplicate item */
369933707f3Ssthen static int
370933707f3Ssthen prepend_is_duplicate(struct ub_packed_rrset_key** sets, size_t to,
371933707f3Ssthen 	struct ub_packed_rrset_key* dup)
372933707f3Ssthen {
373933707f3Ssthen 	size_t i;
374933707f3Ssthen 	for(i=0; i<to; i++) {
375933707f3Ssthen 		if(sets[i]->rk.type == dup->rk.type &&
376933707f3Ssthen 			sets[i]->rk.rrset_class == dup->rk.rrset_class &&
377933707f3Ssthen 			sets[i]->rk.dname_len == dup->rk.dname_len &&
378933707f3Ssthen 			query_dname_compare(sets[i]->rk.dname, dup->rk.dname)
379933707f3Ssthen 			== 0)
380933707f3Ssthen 			return 1;
381933707f3Ssthen 	}
382933707f3Ssthen 	return 0;
383933707f3Ssthen }
384933707f3Ssthen 
385933707f3Ssthen /** prepend the prepend list in the answer and authority section of dns_msg */
386933707f3Ssthen static int
387933707f3Ssthen iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
388933707f3Ssthen 	struct regional* region)
389933707f3Ssthen {
390933707f3Ssthen 	struct iter_prep_list* p;
391933707f3Ssthen 	struct ub_packed_rrset_key** sets;
392933707f3Ssthen 	size_t num_an = 0, num_ns = 0;;
393933707f3Ssthen 	for(p = iq->an_prepend_list; p; p = p->next)
394933707f3Ssthen 		num_an++;
395933707f3Ssthen 	for(p = iq->ns_prepend_list; p; p = p->next)
396933707f3Ssthen 		num_ns++;
397933707f3Ssthen 	if(num_an + num_ns == 0)
398933707f3Ssthen 		return 1;
399933707f3Ssthen 	verbose(VERB_ALGO, "prepending %d rrsets", (int)num_an + (int)num_ns);
400a58bff56Ssthen 	if(num_an > RR_COUNT_MAX || num_ns > RR_COUNT_MAX ||
401a58bff56Ssthen 		msg->rep->rrset_count > RR_COUNT_MAX) return 0; /* overflow */
402933707f3Ssthen 	sets = regional_alloc(region, (num_an+num_ns+msg->rep->rrset_count) *
403933707f3Ssthen 		sizeof(struct ub_packed_rrset_key*));
404933707f3Ssthen 	if(!sets)
405933707f3Ssthen 		return 0;
406933707f3Ssthen 	/* ANSWER section */
407933707f3Ssthen 	num_an = 0;
408933707f3Ssthen 	for(p = iq->an_prepend_list; p; p = p->next) {
409933707f3Ssthen 		sets[num_an++] = p->rrset;
410ebf5bb73Ssthen 		if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl)
411ebf5bb73Ssthen 			msg->rep->ttl = ub_packed_rrset_ttl(p->rrset);
412933707f3Ssthen 	}
413933707f3Ssthen 	memcpy(sets+num_an, msg->rep->rrsets, msg->rep->an_numrrsets *
414933707f3Ssthen 		sizeof(struct ub_packed_rrset_key*));
415933707f3Ssthen 	/* AUTH section */
416933707f3Ssthen 	num_ns = 0;
417933707f3Ssthen 	for(p = iq->ns_prepend_list; p; p = p->next) {
418933707f3Ssthen 		if(prepend_is_duplicate(sets+msg->rep->an_numrrsets+num_an,
419933707f3Ssthen 			num_ns, p->rrset) || prepend_is_duplicate(
420933707f3Ssthen 			msg->rep->rrsets+msg->rep->an_numrrsets,
421933707f3Ssthen 			msg->rep->ns_numrrsets, p->rrset))
422933707f3Ssthen 			continue;
423933707f3Ssthen 		sets[msg->rep->an_numrrsets + num_an + num_ns++] = p->rrset;
424ebf5bb73Ssthen 		if(ub_packed_rrset_ttl(p->rrset) < msg->rep->ttl)
425ebf5bb73Ssthen 			msg->rep->ttl = ub_packed_rrset_ttl(p->rrset);
426933707f3Ssthen 	}
427933707f3Ssthen 	memcpy(sets + num_an + msg->rep->an_numrrsets + num_ns,
428933707f3Ssthen 		msg->rep->rrsets + msg->rep->an_numrrsets,
429933707f3Ssthen 		(msg->rep->ns_numrrsets + msg->rep->ar_numrrsets) *
430933707f3Ssthen 		sizeof(struct ub_packed_rrset_key*));
431933707f3Ssthen 
432933707f3Ssthen 	/* NXDOMAIN rcode can stay if we prepended DNAME/CNAMEs, because
433933707f3Ssthen 	 * this is what recursors should give. */
434933707f3Ssthen 	msg->rep->rrset_count += num_an + num_ns;
435933707f3Ssthen 	msg->rep->an_numrrsets += num_an;
436933707f3Ssthen 	msg->rep->ns_numrrsets += num_ns;
437933707f3Ssthen 	msg->rep->rrsets = sets;
438933707f3Ssthen 	return 1;
439933707f3Ssthen }
440933707f3Ssthen 
441933707f3Ssthen /**
4422be9e038Ssthen  * Find rrset in ANSWER prepend list.
4432be9e038Ssthen  * to avoid duplicate DNAMEs when a DNAME is traversed twice.
4442be9e038Ssthen  * @param iq: iterator query state.
4452be9e038Ssthen  * @param rrset: rrset to add.
4462be9e038Ssthen  * @return false if not found
4472be9e038Ssthen  */
4482be9e038Ssthen static int
4492be9e038Ssthen iter_find_rrset_in_prepend_answer(struct iter_qstate* iq,
4502be9e038Ssthen 	struct ub_packed_rrset_key* rrset)
4512be9e038Ssthen {
4522be9e038Ssthen 	struct iter_prep_list* p = iq->an_prepend_list;
4532be9e038Ssthen 	while(p) {
4542be9e038Ssthen 		if(ub_rrset_compare(p->rrset, rrset) == 0 &&
4552be9e038Ssthen 			rrsetdata_equal((struct packed_rrset_data*)p->rrset
4562be9e038Ssthen 			->entry.data, (struct packed_rrset_data*)rrset
4572be9e038Ssthen 			->entry.data))
4582be9e038Ssthen 			return 1;
4592be9e038Ssthen 		p = p->next;
4602be9e038Ssthen 	}
4612be9e038Ssthen 	return 0;
4622be9e038Ssthen }
4632be9e038Ssthen 
4642be9e038Ssthen /**
465933707f3Ssthen  * Add rrset to ANSWER prepend list
466933707f3Ssthen  * @param qstate: query state.
467933707f3Ssthen  * @param iq: iterator query state.
468933707f3Ssthen  * @param rrset: rrset to add.
469933707f3Ssthen  * @return false on failure (malloc).
470933707f3Ssthen  */
471933707f3Ssthen static int
472933707f3Ssthen iter_add_prepend_answer(struct module_qstate* qstate, struct iter_qstate* iq,
473933707f3Ssthen 	struct ub_packed_rrset_key* rrset)
474933707f3Ssthen {
475933707f3Ssthen 	struct iter_prep_list* p = (struct iter_prep_list*)regional_alloc(
476933707f3Ssthen 		qstate->region, sizeof(struct iter_prep_list));
477933707f3Ssthen 	if(!p)
478933707f3Ssthen 		return 0;
479933707f3Ssthen 	p->rrset = rrset;
480933707f3Ssthen 	p->next = NULL;
481933707f3Ssthen 	/* add at end */
482933707f3Ssthen 	if(iq->an_prepend_last)
483933707f3Ssthen 		iq->an_prepend_last->next = p;
484933707f3Ssthen 	else	iq->an_prepend_list = p;
485933707f3Ssthen 	iq->an_prepend_last = p;
486933707f3Ssthen 	return 1;
487933707f3Ssthen }
488933707f3Ssthen 
489933707f3Ssthen /**
490933707f3Ssthen  * Add rrset to AUTHORITY prepend list
491933707f3Ssthen  * @param qstate: query state.
492933707f3Ssthen  * @param iq: iterator query state.
493933707f3Ssthen  * @param rrset: rrset to add.
494933707f3Ssthen  * @return false on failure (malloc).
495933707f3Ssthen  */
496933707f3Ssthen static int
497933707f3Ssthen iter_add_prepend_auth(struct module_qstate* qstate, struct iter_qstate* iq,
498933707f3Ssthen 	struct ub_packed_rrset_key* rrset)
499933707f3Ssthen {
500933707f3Ssthen 	struct iter_prep_list* p = (struct iter_prep_list*)regional_alloc(
501933707f3Ssthen 		qstate->region, sizeof(struct iter_prep_list));
502933707f3Ssthen 	if(!p)
503933707f3Ssthen 		return 0;
504933707f3Ssthen 	p->rrset = rrset;
505933707f3Ssthen 	p->next = NULL;
506933707f3Ssthen 	/* add at end */
507933707f3Ssthen 	if(iq->ns_prepend_last)
508933707f3Ssthen 		iq->ns_prepend_last->next = p;
509933707f3Ssthen 	else	iq->ns_prepend_list = p;
510933707f3Ssthen 	iq->ns_prepend_last = p;
511933707f3Ssthen 	return 1;
512933707f3Ssthen }
513933707f3Ssthen 
514933707f3Ssthen /**
515933707f3Ssthen  * Given a CNAME response (defined as a response containing a CNAME or DNAME
516933707f3Ssthen  * that does not answer the request), process the response, modifying the
517933707f3Ssthen  * state as necessary. This follows the CNAME/DNAME chain and returns the
518933707f3Ssthen  * final query name.
519933707f3Ssthen  *
520933707f3Ssthen  * sets the new query name, after following the CNAME/DNAME chain.
521933707f3Ssthen  * @param qstate: query state.
522933707f3Ssthen  * @param iq: iterator query state.
523933707f3Ssthen  * @param msg: the response.
524933707f3Ssthen  * @param mname: returned target new query name.
525933707f3Ssthen  * @param mname_len: length of mname.
526933707f3Ssthen  * @return false on (malloc) error.
527933707f3Ssthen  */
528933707f3Ssthen static int
529933707f3Ssthen handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
530933707f3Ssthen         struct dns_msg* msg, uint8_t** mname, size_t* mname_len)
531933707f3Ssthen {
532933707f3Ssthen 	size_t i;
533933707f3Ssthen 	/* Start with the (current) qname. */
534933707f3Ssthen 	*mname = iq->qchase.qname;
535933707f3Ssthen 	*mname_len = iq->qchase.qname_len;
536933707f3Ssthen 
537933707f3Ssthen 	/* Iterate over the ANSWER rrsets in order, looking for CNAMEs and
538933707f3Ssthen 	 * DNAMES. */
539933707f3Ssthen 	for(i=0; i<msg->rep->an_numrrsets; i++) {
540933707f3Ssthen 		struct ub_packed_rrset_key* r = msg->rep->rrsets[i];
541933707f3Ssthen 		/* If there is a (relevant) DNAME, add it to the list.
542933707f3Ssthen 		 * We always expect there to be CNAME that was generated
543933707f3Ssthen 		 * by this DNAME following, so we don't process the DNAME
544933707f3Ssthen 		 * directly.  */
545933707f3Ssthen 		if(ntohs(r->rk.type) == LDNS_RR_TYPE_DNAME &&
5462be9e038Ssthen 			dname_strict_subdomain_c(*mname, r->rk.dname) &&
5472be9e038Ssthen 			!iter_find_rrset_in_prepend_answer(iq, r)) {
548933707f3Ssthen 			if(!iter_add_prepend_answer(qstate, iq, r))
549933707f3Ssthen 				return 0;
550933707f3Ssthen 			continue;
551933707f3Ssthen 		}
552933707f3Ssthen 
553933707f3Ssthen 		if(ntohs(r->rk.type) == LDNS_RR_TYPE_CNAME &&
5542be9e038Ssthen 			query_dname_compare(*mname, r->rk.dname) == 0 &&
5552be9e038Ssthen 			!iter_find_rrset_in_prepend_answer(iq, r)) {
556933707f3Ssthen 			/* Add this relevant CNAME rrset to the prepend list.*/
557933707f3Ssthen 			if(!iter_add_prepend_answer(qstate, iq, r))
558933707f3Ssthen 				return 0;
559933707f3Ssthen 			get_cname_target(r, mname, mname_len);
560933707f3Ssthen 		}
561933707f3Ssthen 
562933707f3Ssthen 		/* Other rrsets in the section are ignored. */
563933707f3Ssthen 	}
564933707f3Ssthen 	/* add authority rrsets to authority prepend, for wildcarded CNAMEs */
565933707f3Ssthen 	for(i=msg->rep->an_numrrsets; i<msg->rep->an_numrrsets +
566933707f3Ssthen 		msg->rep->ns_numrrsets; i++) {
567933707f3Ssthen 		struct ub_packed_rrset_key* r = msg->rep->rrsets[i];
568933707f3Ssthen 		/* only add NSEC/NSEC3, as they may be needed for validation */
569933707f3Ssthen 		if(ntohs(r->rk.type) == LDNS_RR_TYPE_NSEC ||
570933707f3Ssthen 			ntohs(r->rk.type) == LDNS_RR_TYPE_NSEC3) {
571933707f3Ssthen 			if(!iter_add_prepend_auth(qstate, iq, r))
572933707f3Ssthen 				return 0;
573933707f3Ssthen 		}
574933707f3Ssthen 	}
575933707f3Ssthen 	return 1;
576933707f3Ssthen }
577933707f3Ssthen 
5788b7325afSsthen /** fill fail address for later recovery */
5798b7325afSsthen static void
5808b7325afSsthen fill_fail_addr(struct iter_qstate* iq, struct sockaddr_storage* addr,
5818b7325afSsthen 	socklen_t addrlen)
5828b7325afSsthen {
5838b7325afSsthen 	if(addrlen == 0) {
5848b7325afSsthen 		iq->fail_addr_type = 0;
5858b7325afSsthen 		return;
5868b7325afSsthen 	}
5878b7325afSsthen 	if(((struct sockaddr_in*)addr)->sin_family == AF_INET) {
5888b7325afSsthen 		iq->fail_addr_type = 4;
5898b7325afSsthen 		memcpy(&iq->fail_addr.in,
5908b7325afSsthen 			&((struct sockaddr_in*)addr)->sin_addr,
5918b7325afSsthen 			sizeof(iq->fail_addr.in));
5928b7325afSsthen 	}
5938b7325afSsthen #ifdef AF_INET6
5948b7325afSsthen 	else if(((struct sockaddr_in*)addr)->sin_family == AF_INET6) {
5958b7325afSsthen 		iq->fail_addr_type = 6;
5968b7325afSsthen 		memcpy(&iq->fail_addr.in6,
5978b7325afSsthen 			&((struct sockaddr_in6*)addr)->sin6_addr,
5988b7325afSsthen 			sizeof(iq->fail_addr.in6));
5998b7325afSsthen 	}
6008b7325afSsthen #endif
6018b7325afSsthen 	else {
6028b7325afSsthen 		iq->fail_addr_type = 0;
6038b7325afSsthen 	}
6048b7325afSsthen }
6058b7325afSsthen 
6068b7325afSsthen /** print fail addr to string */
6078b7325afSsthen static void
6088b7325afSsthen print_fail_addr(struct iter_qstate* iq, char* buf, size_t len)
6098b7325afSsthen {
6108b7325afSsthen 	if(iq->fail_addr_type == 4) {
6118b7325afSsthen 		if(inet_ntop(AF_INET, &iq->fail_addr.in, buf,
6128b7325afSsthen 			(socklen_t)len) == 0)
6138b7325afSsthen 			(void)strlcpy(buf, "(inet_ntop error)", len);
6148b7325afSsthen 	}
6158b7325afSsthen #ifdef AF_INET6
6168b7325afSsthen 	else if(iq->fail_addr_type == 6) {
6178b7325afSsthen 		if(inet_ntop(AF_INET6, &iq->fail_addr.in6, buf,
6188b7325afSsthen 			(socklen_t)len) == 0)
6198b7325afSsthen 			(void)strlcpy(buf, "(inet_ntop error)", len);
6208b7325afSsthen 	}
6218b7325afSsthen #endif
6228b7325afSsthen 	else
6238b7325afSsthen 		(void)strlcpy(buf, "", len);
6248b7325afSsthen }
6258b7325afSsthen 
626191f22c6Ssthen /** add response specific error information for log servfail */
627191f22c6Ssthen static void
628191f22c6Ssthen errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq)
629191f22c6Ssthen {
630191f22c6Ssthen 	if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
631191f22c6Ssthen 		return;
63245872187Ssthen 	if((qstate->reply && qstate->reply->remote_addrlen != 0) ||
6338b7325afSsthen 		(iq->fail_addr_type != 0)) {
634191f22c6Ssthen 		char from[256], frm[512];
63545872187Ssthen 		if(qstate->reply && qstate->reply->remote_addrlen != 0)
63645872187Ssthen 			addr_to_str(&qstate->reply->remote_addr,
63745872187Ssthen 				qstate->reply->remote_addrlen, from,
63845872187Ssthen 				sizeof(from));
639191f22c6Ssthen 		else
6408b7325afSsthen 			print_fail_addr(iq, from, sizeof(from));
641191f22c6Ssthen 		snprintf(frm, sizeof(frm), "from %s", from);
642191f22c6Ssthen 		errinf(qstate, frm);
643191f22c6Ssthen 	}
644191f22c6Ssthen 	if(iq->scrub_failures || iq->parse_failures) {
645191f22c6Ssthen 		if(iq->scrub_failures)
646191f22c6Ssthen 			errinf(qstate, "upstream response failed scrub");
647191f22c6Ssthen 		if(iq->parse_failures)
648191f22c6Ssthen 			errinf(qstate, "could not parse upstream response");
649191f22c6Ssthen 	} else if(iq->response == NULL && iq->timeout_count != 0) {
650191f22c6Ssthen 		errinf(qstate, "upstream server timeout");
651191f22c6Ssthen 	} else if(iq->response == NULL) {
652191f22c6Ssthen 		errinf(qstate, "no server to query");
653191f22c6Ssthen 		if(iq->dp) {
654191f22c6Ssthen 			if(iq->dp->target_list == NULL)
655191f22c6Ssthen 				errinf(qstate, "no addresses for nameservers");
656191f22c6Ssthen 			else	errinf(qstate, "nameserver addresses not usable");
657191f22c6Ssthen 			if(iq->dp->nslist == NULL)
658191f22c6Ssthen 				errinf(qstate, "have no nameserver names");
659191f22c6Ssthen 			if(iq->dp->bogus)
660191f22c6Ssthen 				errinf(qstate, "NS record was dnssec bogus");
661191f22c6Ssthen 		}
662191f22c6Ssthen 	}
663191f22c6Ssthen 	if(iq->response && iq->response->rep) {
664191f22c6Ssthen 		if(FLAGS_GET_RCODE(iq->response->rep->flags) != 0) {
665191f22c6Ssthen 			char rcode[256], rc[32];
666191f22c6Ssthen 			(void)sldns_wire2str_rcode_buf(
667191f22c6Ssthen 				FLAGS_GET_RCODE(iq->response->rep->flags),
668191f22c6Ssthen 				rc, sizeof(rc));
669191f22c6Ssthen 			snprintf(rcode, sizeof(rcode), "got %s", rc);
670191f22c6Ssthen 			errinf(qstate, rcode);
671191f22c6Ssthen 		} else {
672191f22c6Ssthen 			/* rcode NOERROR */
673191f22c6Ssthen 			if(iq->response->rep->an_numrrsets == 0) {
674191f22c6Ssthen 				errinf(qstate, "nodata answer");
675191f22c6Ssthen 			}
676191f22c6Ssthen 		}
677191f22c6Ssthen 	}
678191f22c6Ssthen }
679191f22c6Ssthen 
6802be9e038Ssthen /** see if last resort is possible - does config allow queries to parent */
6812be9e038Ssthen static int
6822bdc0ed1Ssthen can_have_last_resort(struct module_env* env, uint8_t* nm, size_t ATTR_UNUSED(nmlen),
6832bdc0ed1Ssthen 	uint16_t qclass, int* have_dp, struct delegpt** retdp,
6842bdc0ed1Ssthen 	struct regional* region)
6852be9e038Ssthen {
6862bdc0ed1Ssthen 	struct delegpt* dp = NULL;
6872bdc0ed1Ssthen 	int nolock = 0;
6882be9e038Ssthen 	/* do not process a last resort (the parent side) if a stub
6892be9e038Ssthen 	 * or forward is configured, because we do not want to go 'above'
6902be9e038Ssthen 	 * the configured servers */
6912bdc0ed1Ssthen 	if(!dname_is_root(nm) &&
6922bdc0ed1Ssthen 		(dp = hints_find(env->hints, nm, qclass, nolock)) &&
6932be9e038Ssthen 		/* has_parent side is turned off for stub_first, where we
6942be9e038Ssthen 		 * are allowed to go to the parent */
6952bdc0ed1Ssthen 		dp->has_parent_side_NS) {
6962bdc0ed1Ssthen 		if(retdp) *retdp = delegpt_copy(dp, region);
6972bdc0ed1Ssthen 		lock_rw_unlock(&env->hints->lock);
6982bdc0ed1Ssthen 		if(have_dp) *have_dp = 1;
6992be9e038Ssthen 		return 0;
7002be9e038Ssthen 	}
7012bdc0ed1Ssthen 	if(dp) {
7022bdc0ed1Ssthen 		lock_rw_unlock(&env->hints->lock);
7032bdc0ed1Ssthen 		dp = NULL;
7042bdc0ed1Ssthen 	}
7052bdc0ed1Ssthen 	if((dp = forwards_find(env->fwds, nm, qclass, nolock)) &&
7062be9e038Ssthen 		/* has_parent_side is turned off for forward_first, where
7072be9e038Ssthen 		 * we are allowed to go to the parent */
7082bdc0ed1Ssthen 		dp->has_parent_side_NS) {
7092bdc0ed1Ssthen 		if(retdp) *retdp = delegpt_copy(dp, region);
7102bdc0ed1Ssthen 		lock_rw_unlock(&env->fwds->lock);
7112bdc0ed1Ssthen 		if(have_dp) *have_dp = 1;
7122be9e038Ssthen 		return 0;
7132be9e038Ssthen 	}
7142bdc0ed1Ssthen 	/* lock_() calls are macros that could be nothing, surround in {} */
7152bdc0ed1Ssthen 	if(dp) { lock_rw_unlock(&env->fwds->lock); }
7162be9e038Ssthen 	return 1;
7172be9e038Ssthen }
7182be9e038Ssthen 
719a58bff56Ssthen /** see if target name is caps-for-id whitelisted */
720a58bff56Ssthen static int
721a58bff56Ssthen is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
722a58bff56Ssthen {
723a58bff56Ssthen 	if(!ie->caps_white) return 0; /* no whitelist, or no capsforid */
724a58bff56Ssthen 	return name_tree_lookup(ie->caps_white, iq->qchase.qname,
725a58bff56Ssthen 		iq->qchase.qname_len, dname_count_labels(iq->qchase.qname),
726a58bff56Ssthen 		iq->qchase.qclass) != NULL;
727a58bff56Ssthen }
728a58bff56Ssthen 
729d1e2768aSsthen /**
730d1e2768aSsthen  * Create target count structure for this query. This is always explicitly
731d1e2768aSsthen  * created for the parent query.
732d1e2768aSsthen  */
733ae1dea89Sflorian static void
734ae1dea89Sflorian target_count_create(struct iter_qstate* iq)
735ae1dea89Sflorian {
736ae1dea89Sflorian 	if(!iq->target_count) {
737d1e2768aSsthen 		iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
738ae1dea89Sflorian 		/* if calloc fails we simply do not track this number */
739d1e2768aSsthen 		if(iq->target_count) {
740d1e2768aSsthen 			iq->target_count[TARGET_COUNT_REF] = 1;
741d1e2768aSsthen 			iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
742d1e2768aSsthen 		}
743ae1dea89Sflorian 	}
744ae1dea89Sflorian }
745ae1dea89Sflorian 
746ae1dea89Sflorian static void
747ae1dea89Sflorian target_count_increase(struct iter_qstate* iq, int num)
748ae1dea89Sflorian {
749ae1dea89Sflorian 	target_count_create(iq);
750ae1dea89Sflorian 	if(iq->target_count)
751d1e2768aSsthen 		iq->target_count[TARGET_COUNT_QUERIES] += num;
75206a13c09Ssthen 	iq->dp_target_count++;
75306a13c09Ssthen }
75406a13c09Ssthen 
75506a13c09Ssthen static void
75606a13c09Ssthen target_count_increase_nx(struct iter_qstate* iq, int num)
75706a13c09Ssthen {
75806a13c09Ssthen 	target_count_create(iq);
75906a13c09Ssthen 	if(iq->target_count)
760d1e2768aSsthen 		iq->target_count[TARGET_COUNT_NX] += num;
761ae1dea89Sflorian }
762ae1dea89Sflorian 
763*98bc733bSsthen static void
764*98bc733bSsthen target_count_increase_global_quota(struct iter_qstate* iq, int num)
765*98bc733bSsthen {
766*98bc733bSsthen 	target_count_create(iq);
767*98bc733bSsthen 	if(iq->target_count)
768*98bc733bSsthen 		iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
769*98bc733bSsthen }
770*98bc733bSsthen 
771933707f3Ssthen /**
772933707f3Ssthen  * Generate a subrequest.
773933707f3Ssthen  * Generate a local request event. Local events are tied to this module, and
7744bfc71b0Ssthen  * have a corresponding (first tier) event that is waiting for this event to
775933707f3Ssthen  * resolve to continue.
776933707f3Ssthen  *
777933707f3Ssthen  * @param qname The query name for this request.
778933707f3Ssthen  * @param qnamelen length of qname
779933707f3Ssthen  * @param qtype The query type for this request.
780933707f3Ssthen  * @param qclass The query class for this request.
781933707f3Ssthen  * @param qstate The event that is generating this event.
782933707f3Ssthen  * @param id: module id.
783933707f3Ssthen  * @param iq: The iterator state that is generating this event.
784933707f3Ssthen  * @param initial_state The initial response state (normally this
785933707f3Ssthen  *          is QUERY_RESP_STATE, unless it is known that the request won't
786933707f3Ssthen  *          need iterative processing
787933707f3Ssthen  * @param finalstate The final state for the response to this request.
788933707f3Ssthen  * @param subq_ret: if newly allocated, the subquerystate, or NULL if it does
789933707f3Ssthen  * 	not need initialisation.
790933707f3Ssthen  * @param v: if true, validation is done on the subquery.
79106a13c09Ssthen  * @param detached: true if this qstate should not attach to the subquery
792933707f3Ssthen  * @return false on error (malloc).
793933707f3Ssthen  */
794933707f3Ssthen static int
795933707f3Ssthen generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
796933707f3Ssthen 	uint16_t qclass, struct module_qstate* qstate, int id,
797933707f3Ssthen 	struct iter_qstate* iq, enum iter_state initial_state,
79806a13c09Ssthen 	enum iter_state finalstate, struct module_qstate** subq_ret, int v,
79906a13c09Ssthen 	int detached)
800933707f3Ssthen {
801933707f3Ssthen 	struct module_qstate* subq = NULL;
802933707f3Ssthen 	struct iter_qstate* subiq = NULL;
803933707f3Ssthen 	uint16_t qflags = 0; /* OPCODE QUERY, no flags */
804933707f3Ssthen 	struct query_info qinf;
805933707f3Ssthen 	int prime = (finalstate == PRIME_RESP_STATE)?1:0;
80657dceb2aSbrad 	int valrec = 0;
807933707f3Ssthen 	qinf.qname = qname;
808933707f3Ssthen 	qinf.qname_len = qnamelen;
809933707f3Ssthen 	qinf.qtype = qtype;
810933707f3Ssthen 	qinf.qclass = qclass;
81177079be7Ssthen 	qinf.local_alias = NULL;
812933707f3Ssthen 
813933707f3Ssthen 	/* RD should be set only when sending the query back through the INIT
814933707f3Ssthen 	 * state. */
815933707f3Ssthen 	if(initial_state == INIT_REQUEST_STATE)
816933707f3Ssthen 		qflags |= BIT_RD;
817933707f3Ssthen 	/* We set the CD flag so we can send this through the "head" of
818933707f3Ssthen 	 * the resolution chain, which might have a validator. We are
819933707f3Ssthen 	 * uninterested in validating things not on the direct resolution
820933707f3Ssthen 	 * path.  */
82157dceb2aSbrad 	if(!v) {
822933707f3Ssthen 		qflags |= BIT_CD;
82357dceb2aSbrad 		valrec = 1;
82457dceb2aSbrad 	}
825933707f3Ssthen 
82606a13c09Ssthen 	if(detached) {
82706a13c09Ssthen 		struct mesh_state* sub = NULL;
82806a13c09Ssthen 		fptr_ok(fptr_whitelist_modenv_add_sub(
82906a13c09Ssthen 			qstate->env->add_sub));
83006a13c09Ssthen 		if(!(*qstate->env->add_sub)(qstate, &qinf,
83106a13c09Ssthen 			qflags, prime, valrec, &subq, &sub)){
832933707f3Ssthen 			return 0;
833933707f3Ssthen 		}
83406a13c09Ssthen 	}
83506a13c09Ssthen 	else {
83606a13c09Ssthen 		/* attach subquery, lookup existing or make a new one */
83706a13c09Ssthen 		fptr_ok(fptr_whitelist_modenv_attach_sub(
83806a13c09Ssthen 			qstate->env->attach_sub));
83906a13c09Ssthen 		if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime,
84006a13c09Ssthen 			valrec, &subq)) {
84106a13c09Ssthen 			return 0;
84206a13c09Ssthen 		}
84306a13c09Ssthen 	}
844933707f3Ssthen 	*subq_ret = subq;
845933707f3Ssthen 	if(subq) {
846933707f3Ssthen 		/* initialise the new subquery */
847933707f3Ssthen 		subq->curmod = id;
848933707f3Ssthen 		subq->ext_state[id] = module_state_initial;
849933707f3Ssthen 		subq->minfo[id] = regional_alloc(subq->region,
850933707f3Ssthen 			sizeof(struct iter_qstate));
851933707f3Ssthen 		if(!subq->minfo[id]) {
852933707f3Ssthen 			log_err("init subq: out of memory");
853933707f3Ssthen 			fptr_ok(fptr_whitelist_modenv_kill_sub(
854933707f3Ssthen 				qstate->env->kill_sub));
855933707f3Ssthen 			(*qstate->env->kill_sub)(subq);
856933707f3Ssthen 			return 0;
857933707f3Ssthen 		}
858933707f3Ssthen 		subiq = (struct iter_qstate*)subq->minfo[id];
859933707f3Ssthen 		memset(subiq, 0, sizeof(*subiq));
860933707f3Ssthen 		subiq->num_target_queries = 0;
861ae1dea89Sflorian 		target_count_create(iq);
862ae1dea89Sflorian 		subiq->target_count = iq->target_count;
863d1e2768aSsthen 		if(iq->target_count) {
864d1e2768aSsthen 			iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
865d1e2768aSsthen 			subiq->nxns_dp = iq->nxns_dp;
866d1e2768aSsthen 		}
86706a13c09Ssthen 		subiq->dp_target_count = 0;
868933707f3Ssthen 		subiq->num_current_queries = 0;
869933707f3Ssthen 		subiq->depth = iq->depth+1;
870933707f3Ssthen 		outbound_list_init(&subiq->outlist);
871933707f3Ssthen 		subiq->state = initial_state;
872933707f3Ssthen 		subiq->final_state = finalstate;
873933707f3Ssthen 		subiq->qchase = subq->qinfo;
874933707f3Ssthen 		subiq->chase_flags = subq->query_flags;
875933707f3Ssthen 		subiq->refetch_glue = 0;
87624893edcSsthen 		if(qstate->env->cfg->qname_minimisation)
87724893edcSsthen 			subiq->minimisation_state = INIT_MINIMISE_STATE;
87824893edcSsthen 		else
87924893edcSsthen 			subiq->minimisation_state = DONOT_MINIMISE_STATE;
88024893edcSsthen 		memset(&subiq->qinfo_out, 0, sizeof(struct query_info));
881933707f3Ssthen 	}
882933707f3Ssthen 	return 1;
883933707f3Ssthen }
884933707f3Ssthen 
885933707f3Ssthen /**
886933707f3Ssthen  * Generate and send a root priming request.
887933707f3Ssthen  * @param qstate: the qtstate that triggered the need to prime.
888933707f3Ssthen  * @param iq: iterator query state.
889933707f3Ssthen  * @param id: module id.
890933707f3Ssthen  * @param qclass: the class to prime.
891933707f3Ssthen  * @return 0 on failure
892933707f3Ssthen  */
893933707f3Ssthen static int
894d8d14d0cSsthen prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
895d8d14d0cSsthen 	uint16_t qclass)
896933707f3Ssthen {
897933707f3Ssthen 	struct delegpt* dp;
898933707f3Ssthen 	struct module_qstate* subq;
8992bdc0ed1Ssthen 	int nolock = 0;
900933707f3Ssthen 	verbose(VERB_DETAIL, "priming . %s NS",
9015d76a658Ssthen 		sldns_lookup_by_id(sldns_rr_classes, (int)qclass)?
9025d76a658Ssthen 		sldns_lookup_by_id(sldns_rr_classes, (int)qclass)->name:"??");
9032bdc0ed1Ssthen 	dp = hints_find_root(qstate->env->hints, qclass, nolock);
904933707f3Ssthen 	if(!dp) {
905933707f3Ssthen 		verbose(VERB_ALGO, "Cannot prime due to lack of hints");
906933707f3Ssthen 		return 0;
907933707f3Ssthen 	}
908933707f3Ssthen 	/* Priming requests start at the QUERYTARGETS state, skipping
909933707f3Ssthen 	 * the normal INIT state logic (which would cause an infloop). */
910933707f3Ssthen 	if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS,
911933707f3Ssthen 		qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
91206a13c09Ssthen 		&subq, 0, 0)) {
9132bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
914933707f3Ssthen 		verbose(VERB_ALGO, "could not prime root");
915933707f3Ssthen 		return 0;
916933707f3Ssthen 	}
917933707f3Ssthen 	if(subq) {
918933707f3Ssthen 		struct iter_qstate* subiq =
919933707f3Ssthen 			(struct iter_qstate*)subq->minfo[id];
920933707f3Ssthen 		/* Set the initial delegation point to the hint.
921933707f3Ssthen 		 * copy dp, it is now part of the root prime query.
922933707f3Ssthen 		 * dp was part of in the fixed hints structure. */
923933707f3Ssthen 		subiq->dp = delegpt_copy(dp, subq->region);
9242bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
925933707f3Ssthen 		if(!subiq->dp) {
926933707f3Ssthen 			log_err("out of memory priming root, copydp");
927933707f3Ssthen 			fptr_ok(fptr_whitelist_modenv_kill_sub(
928933707f3Ssthen 				qstate->env->kill_sub));
929933707f3Ssthen 			(*qstate->env->kill_sub)(subq);
930933707f3Ssthen 			return 0;
931933707f3Ssthen 		}
932933707f3Ssthen 		/* there should not be any target queries. */
933933707f3Ssthen 		subiq->num_target_queries = 0;
934933707f3Ssthen 		subiq->dnssec_expected = iter_indicates_dnssec(
935933707f3Ssthen 			qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
9362bdc0ed1Ssthen 	} else {
9372bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
938933707f3Ssthen 	}
939933707f3Ssthen 
940933707f3Ssthen 	/* this module stops, our submodule starts, and does the query. */
941933707f3Ssthen 	qstate->ext_state[id] = module_wait_subquery;
942933707f3Ssthen 	return 1;
943933707f3Ssthen }
944933707f3Ssthen 
945933707f3Ssthen /**
946933707f3Ssthen  * Generate and process a stub priming request. This method tests for the
947933707f3Ssthen  * need to prime a stub zone, so it is safe to call for every request.
948933707f3Ssthen  *
949933707f3Ssthen  * @param qstate: the qtstate that triggered the need to prime.
950933707f3Ssthen  * @param iq: iterator query state.
951933707f3Ssthen  * @param id: module id.
952d8d14d0cSsthen  * @param qname: request name.
953d8d14d0cSsthen  * @param qclass: request class.
954933707f3Ssthen  * @return true if a priming subrequest was made, false if not. The will only
955933707f3Ssthen  *         issue a priming request if it detects an unprimed stub.
956933707f3Ssthen  *         Uses value of 2 to signal during stub-prime in root-prime situation
957933707f3Ssthen  *         that a noprime-stub is available and resolution can continue.
958933707f3Ssthen  */
959933707f3Ssthen static int
960d8d14d0cSsthen prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
961d8d14d0cSsthen 	uint8_t* qname, uint16_t qclass)
962933707f3Ssthen {
963933707f3Ssthen 	/* Lookup the stub hint. This will return null if the stub doesn't
964933707f3Ssthen 	 * need to be re-primed. */
965933707f3Ssthen 	struct iter_hints_stub* stub;
966933707f3Ssthen 	struct delegpt* stub_dp;
967933707f3Ssthen 	struct module_qstate* subq;
9682bdc0ed1Ssthen 	int nolock = 0;
969933707f3Ssthen 
970d8d14d0cSsthen 	if(!qname) return 0;
9712bdc0ed1Ssthen 	stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp,
9722bdc0ed1Ssthen 		nolock);
973933707f3Ssthen 	/* The stub (if there is one) does not need priming. */
9742bdc0ed1Ssthen 	if(!stub) return 0;
975933707f3Ssthen 	stub_dp = stub->dp;
976938a3a5eSflorian 	/* if we have an auth_zone dp, and stub is equal, don't prime stub
977938a3a5eSflorian 	 * yet, unless we want to fallback and avoid the auth_zone */
978938a3a5eSflorian 	if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp &&
9792bdc0ed1Ssthen 		query_dname_compare(iq->dp->name, stub_dp->name) == 0) {
9802bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
981938a3a5eSflorian 		return 0;
9822bdc0ed1Ssthen 	}
983933707f3Ssthen 
984933707f3Ssthen 	/* is it a noprime stub (always use) */
985933707f3Ssthen 	if(stub->noprime) {
986933707f3Ssthen 		int r = 0;
987933707f3Ssthen 		if(iq->dp == NULL) r = 2;
988933707f3Ssthen 		/* copy the dp out of the fixed hints structure, so that
989933707f3Ssthen 		 * it can be changed when servicing this query */
990933707f3Ssthen 		iq->dp = delegpt_copy(stub_dp, qstate->region);
9912bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
992933707f3Ssthen 		if(!iq->dp) {
993933707f3Ssthen 			log_err("out of memory priming stub");
9942308e98cSsthen 			errinf(qstate, "malloc failure, priming stub");
995933707f3Ssthen 			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
996933707f3Ssthen 			return 1; /* return 1 to make module stop, with error */
997933707f3Ssthen 		}
9982bdc0ed1Ssthen 		log_nametypeclass(VERB_DETAIL, "use stub", iq->dp->name,
999d8d14d0cSsthen 			LDNS_RR_TYPE_NS, qclass);
1000933707f3Ssthen 		return r;
1001933707f3Ssthen 	}
1002933707f3Ssthen 
1003933707f3Ssthen 	/* Otherwise, we need to (re)prime the stub. */
1004933707f3Ssthen 	log_nametypeclass(VERB_DETAIL, "priming stub", stub_dp->name,
1005d8d14d0cSsthen 		LDNS_RR_TYPE_NS, qclass);
1006933707f3Ssthen 
1007933707f3Ssthen 	/* Stub priming events start at the QUERYTARGETS state to avoid the
1008933707f3Ssthen 	 * redundant INIT state processing. */
1009933707f3Ssthen 	if(!generate_sub_request(stub_dp->name, stub_dp->namelen,
1010d8d14d0cSsthen 		LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
101106a13c09Ssthen 		QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) {
10122bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
1013933707f3Ssthen 		verbose(VERB_ALGO, "could not prime stub");
10142308e98cSsthen 		errinf(qstate, "could not generate lookup for stub prime");
1015933707f3Ssthen 		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1016933707f3Ssthen 		return 1; /* return 1 to make module stop, with error */
1017933707f3Ssthen 	}
1018933707f3Ssthen 	if(subq) {
1019933707f3Ssthen 		struct iter_qstate* subiq =
1020933707f3Ssthen 			(struct iter_qstate*)subq->minfo[id];
1021933707f3Ssthen 
1022933707f3Ssthen 		/* Set the initial delegation point to the hint. */
1023933707f3Ssthen 		/* make copy to avoid use of stub dp by different qs/threads */
1024933707f3Ssthen 		subiq->dp = delegpt_copy(stub_dp, subq->region);
10252bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
1026933707f3Ssthen 		if(!subiq->dp) {
1027933707f3Ssthen 			log_err("out of memory priming stub, copydp");
1028933707f3Ssthen 			fptr_ok(fptr_whitelist_modenv_kill_sub(
1029933707f3Ssthen 				qstate->env->kill_sub));
1030933707f3Ssthen 			(*qstate->env->kill_sub)(subq);
10312308e98cSsthen 			errinf(qstate, "malloc failure, in stub prime");
1032933707f3Ssthen 			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1033933707f3Ssthen 			return 1; /* return 1 to make module stop, with error */
1034933707f3Ssthen 		}
1035933707f3Ssthen 		/* there should not be any target queries -- although there
1036933707f3Ssthen 		 * wouldn't be anyway, since stub hints never have
1037933707f3Ssthen 		 * missing targets. */
1038933707f3Ssthen 		subiq->num_target_queries = 0;
1039933707f3Ssthen 		subiq->wait_priming_stub = 1;
1040933707f3Ssthen 		subiq->dnssec_expected = iter_indicates_dnssec(
1041933707f3Ssthen 			qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
10422bdc0ed1Ssthen 	} else {
10432bdc0ed1Ssthen 		lock_rw_unlock(&qstate->env->hints->lock);
1044933707f3Ssthen 	}
1045933707f3Ssthen 
1046933707f3Ssthen 	/* this module stops, our submodule starts, and does the query. */
1047933707f3Ssthen 	qstate->ext_state[id] = module_wait_subquery;
1048933707f3Ssthen 	return 1;
1049933707f3Ssthen }
1050933707f3Ssthen 
1051933707f3Ssthen /**
1052938a3a5eSflorian  * Generate a delegation point for an auth zone (unless cached dp is better)
1053938a3a5eSflorian  * false on alloc failure.
1054938a3a5eSflorian  */
1055938a3a5eSflorian static int
1056938a3a5eSflorian auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq,
1057938a3a5eSflorian 	uint8_t* delname, size_t delnamelen)
1058938a3a5eSflorian {
1059938a3a5eSflorian 	struct auth_zone* z;
1060938a3a5eSflorian 	if(iq->auth_zone_avoid)
1061938a3a5eSflorian 		return 1;
1062938a3a5eSflorian 	if(!delname) {
1063938a3a5eSflorian 		delname = iq->qchase.qname;
1064938a3a5eSflorian 		delnamelen = iq->qchase.qname_len;
1065938a3a5eSflorian 	}
1066938a3a5eSflorian 	lock_rw_rdlock(&qstate->env->auth_zones->lock);
1067938a3a5eSflorian 	z = auth_zones_find_zone(qstate->env->auth_zones, delname, delnamelen,
1068938a3a5eSflorian 		qstate->qinfo.qclass);
1069938a3a5eSflorian 	if(!z) {
1070938a3a5eSflorian 		lock_rw_unlock(&qstate->env->auth_zones->lock);
1071938a3a5eSflorian 		return 1;
1072938a3a5eSflorian 	}
1073938a3a5eSflorian 	lock_rw_rdlock(&z->lock);
1074938a3a5eSflorian 	lock_rw_unlock(&qstate->env->auth_zones->lock);
1075938a3a5eSflorian 	if(z->for_upstream) {
1076938a3a5eSflorian 		if(iq->dp && query_dname_compare(z->name, iq->dp->name) == 0
1077938a3a5eSflorian 			&& iq->dp->auth_dp && qstate->blacklist &&
1078938a3a5eSflorian 			z->fallback_enabled) {
1079938a3a5eSflorian 			/* cache is blacklisted and fallback, and we
1080938a3a5eSflorian 			 * already have an auth_zone dp */
1081938a3a5eSflorian 			if(verbosity>=VERB_ALGO) {
1082938a3a5eSflorian 				char buf[255+1];
1083938a3a5eSflorian 				dname_str(z->name, buf);
1084938a3a5eSflorian 				verbose(VERB_ALGO, "auth_zone %s "
1085938a3a5eSflorian 				  "fallback because cache blacklisted",
1086938a3a5eSflorian 				  buf);
1087938a3a5eSflorian 			}
1088938a3a5eSflorian 			lock_rw_unlock(&z->lock);
1089938a3a5eSflorian 			iq->dp = NULL;
1090938a3a5eSflorian 			return 1;
1091938a3a5eSflorian 		}
1092938a3a5eSflorian 		if(iq->dp==NULL || dname_subdomain_c(z->name, iq->dp->name)) {
1093938a3a5eSflorian 			struct delegpt* dp;
1094938a3a5eSflorian 			if(qstate->blacklist && z->fallback_enabled) {
1095938a3a5eSflorian 				/* cache is blacklisted because of a DNSSEC
1096938a3a5eSflorian 				 * validation failure, and the zone allows
1097938a3a5eSflorian 				 * fallback to the internet, query there. */
1098938a3a5eSflorian 				if(verbosity>=VERB_ALGO) {
1099938a3a5eSflorian 					char buf[255+1];
1100938a3a5eSflorian 					dname_str(z->name, buf);
1101938a3a5eSflorian 					verbose(VERB_ALGO, "auth_zone %s "
1102938a3a5eSflorian 					  "fallback because cache blacklisted",
1103938a3a5eSflorian 					  buf);
1104938a3a5eSflorian 				}
1105938a3a5eSflorian 				lock_rw_unlock(&z->lock);
1106938a3a5eSflorian 				return 1;
1107938a3a5eSflorian 			}
1108938a3a5eSflorian 			dp = (struct delegpt*)regional_alloc_zero(
1109938a3a5eSflorian 				qstate->region, sizeof(*dp));
1110938a3a5eSflorian 			if(!dp) {
1111938a3a5eSflorian 				log_err("alloc failure");
1112938a3a5eSflorian 				if(z->fallback_enabled) {
1113938a3a5eSflorian 					lock_rw_unlock(&z->lock);
1114938a3a5eSflorian 					return 1; /* just fallback */
1115938a3a5eSflorian 				}
1116938a3a5eSflorian 				lock_rw_unlock(&z->lock);
11172308e98cSsthen 				errinf(qstate, "malloc failure");
1118938a3a5eSflorian 				return 0;
1119938a3a5eSflorian 			}
1120938a3a5eSflorian 			dp->name = regional_alloc_init(qstate->region,
1121938a3a5eSflorian 				z->name, z->namelen);
1122938a3a5eSflorian 			if(!dp->name) {
1123938a3a5eSflorian 				log_err("alloc failure");
1124938a3a5eSflorian 				if(z->fallback_enabled) {
1125938a3a5eSflorian 					lock_rw_unlock(&z->lock);
1126938a3a5eSflorian 					return 1; /* just fallback */
1127938a3a5eSflorian 				}
1128938a3a5eSflorian 				lock_rw_unlock(&z->lock);
11292308e98cSsthen 				errinf(qstate, "malloc failure");
1130938a3a5eSflorian 				return 0;
1131938a3a5eSflorian 			}
1132938a3a5eSflorian 			dp->namelen = z->namelen;
1133938a3a5eSflorian 			dp->namelabs = z->namelabs;
1134938a3a5eSflorian 			dp->auth_dp = 1;
1135938a3a5eSflorian 			iq->dp = dp;
1136938a3a5eSflorian 		}
1137938a3a5eSflorian 	}
1138938a3a5eSflorian 
1139938a3a5eSflorian 	lock_rw_unlock(&z->lock);
1140938a3a5eSflorian 	return 1;
1141938a3a5eSflorian }
1142938a3a5eSflorian 
1143938a3a5eSflorian /**
1144933707f3Ssthen  * Generate A and AAAA checks for glue that is in-zone for the referral
1145bdfc4d55Sflorian  * we just got to obtain authoritative information on the addresses.
1146933707f3Ssthen  *
1147933707f3Ssthen  * @param qstate: the qtstate that triggered the need to prime.
1148933707f3Ssthen  * @param iq: iterator query state.
1149933707f3Ssthen  * @param id: module id.
1150933707f3Ssthen  */
1151933707f3Ssthen static void
1152933707f3Ssthen generate_a_aaaa_check(struct module_qstate* qstate, struct iter_qstate* iq,
1153933707f3Ssthen 	int id)
1154933707f3Ssthen {
1155933707f3Ssthen 	struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
1156933707f3Ssthen 	struct module_qstate* subq;
1157933707f3Ssthen 	size_t i;
1158933707f3Ssthen 	struct reply_info* rep = iq->response->rep;
1159933707f3Ssthen 	struct ub_packed_rrset_key* s;
1160933707f3Ssthen 	log_assert(iq->dp);
1161933707f3Ssthen 
1162933707f3Ssthen 	if(iq->depth == ie->max_dependency_depth)
1163933707f3Ssthen 		return;
1164933707f3Ssthen 	/* walk through additional, and check if in-zone,
1165933707f3Ssthen 	 * only relevant A, AAAA are left after scrub anyway */
1166933707f3Ssthen 	for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
1167933707f3Ssthen 		s = rep->rrsets[i];
1168933707f3Ssthen 		/* check *ALL* addresses that are transmitted in additional*/
1169933707f3Ssthen 		/* is it an address ? */
1170933707f3Ssthen 		if( !(ntohs(s->rk.type)==LDNS_RR_TYPE_A ||
1171933707f3Ssthen 			ntohs(s->rk.type)==LDNS_RR_TYPE_AAAA)) {
1172933707f3Ssthen 			continue;
1173933707f3Ssthen 		}
1174933707f3Ssthen 		/* is this query the same as the A/AAAA check for it */
1175933707f3Ssthen 		if(qstate->qinfo.qtype == ntohs(s->rk.type) &&
1176933707f3Ssthen 			qstate->qinfo.qclass == ntohs(s->rk.rrset_class) &&
1177933707f3Ssthen 			query_dname_compare(qstate->qinfo.qname,
1178933707f3Ssthen 				s->rk.dname)==0 &&
1179933707f3Ssthen 			(qstate->query_flags&BIT_RD) &&
1180933707f3Ssthen 			!(qstate->query_flags&BIT_CD))
1181933707f3Ssthen 			continue;
1182933707f3Ssthen 
1183933707f3Ssthen 		/* generate subrequest for it */
1184933707f3Ssthen 		log_nametypeclass(VERB_ALGO, "schedule addr fetch",
1185933707f3Ssthen 			s->rk.dname, ntohs(s->rk.type),
1186933707f3Ssthen 			ntohs(s->rk.rrset_class));
1187933707f3Ssthen 		if(!generate_sub_request(s->rk.dname, s->rk.dname_len,
1188933707f3Ssthen 			ntohs(s->rk.type), ntohs(s->rk.rrset_class),
1189933707f3Ssthen 			qstate, id, iq,
119006a13c09Ssthen 			INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
1191933707f3Ssthen 			verbose(VERB_ALGO, "could not generate addr check");
1192933707f3Ssthen 			return;
1193933707f3Ssthen 		}
1194933707f3Ssthen 		/* ignore subq - not need for more init */
1195933707f3Ssthen 	}
1196933707f3Ssthen }
1197933707f3Ssthen 
1198933707f3Ssthen /**
1199933707f3Ssthen  * Generate a NS check request to obtain authoritative information
1200933707f3Ssthen  * on an NS rrset.
1201933707f3Ssthen  *
12028b7325afSsthen  * @param qstate: the qstate that triggered the need to prime.
1203933707f3Ssthen  * @param iq: iterator query state.
1204933707f3Ssthen  * @param id: module id.
1205933707f3Ssthen  */
1206933707f3Ssthen static void
1207933707f3Ssthen generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
1208933707f3Ssthen {
1209933707f3Ssthen 	struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
1210933707f3Ssthen 	struct module_qstate* subq;
1211933707f3Ssthen 	log_assert(iq->dp);
1212933707f3Ssthen 
1213933707f3Ssthen 	if(iq->depth == ie->max_dependency_depth)
1214933707f3Ssthen 		return;
12152be9e038Ssthen 	if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
12162bdc0ed1Ssthen 		iq->qchase.qclass, NULL, NULL, NULL))
12172be9e038Ssthen 		return;
1218933707f3Ssthen 	/* is this query the same as the nscheck? */
1219933707f3Ssthen 	if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS &&
1220933707f3Ssthen 		query_dname_compare(iq->dp->name, qstate->qinfo.qname)==0 &&
1221933707f3Ssthen 		(qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){
1222933707f3Ssthen 		/* spawn off A, AAAA queries for in-zone glue to check */
1223933707f3Ssthen 		generate_a_aaaa_check(qstate, iq, id);
1224933707f3Ssthen 		return;
1225933707f3Ssthen 	}
1226bdfc4d55Sflorian 	/* no need to get the NS record for DS, it is above the zonecut */
1227bdfc4d55Sflorian 	if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS)
1228bdfc4d55Sflorian 		return;
1229933707f3Ssthen 
1230933707f3Ssthen 	log_nametypeclass(VERB_ALGO, "schedule ns fetch",
1231933707f3Ssthen 		iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
1232933707f3Ssthen 	if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
1233933707f3Ssthen 		LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
123406a13c09Ssthen 		INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
1235933707f3Ssthen 		verbose(VERB_ALGO, "could not generate ns check");
1236933707f3Ssthen 		return;
1237933707f3Ssthen 	}
1238933707f3Ssthen 	if(subq) {
1239933707f3Ssthen 		struct iter_qstate* subiq =
1240933707f3Ssthen 			(struct iter_qstate*)subq->minfo[id];
1241933707f3Ssthen 
1242933707f3Ssthen 		/* make copy to avoid use of stub dp by different qs/threads */
1243933707f3Ssthen 		/* refetch glue to start higher up the tree */
1244933707f3Ssthen 		subiq->refetch_glue = 1;
1245933707f3Ssthen 		subiq->dp = delegpt_copy(iq->dp, subq->region);
1246933707f3Ssthen 		if(!subiq->dp) {
1247933707f3Ssthen 			log_err("out of memory generating ns check, copydp");
1248933707f3Ssthen 			fptr_ok(fptr_whitelist_modenv_kill_sub(
1249933707f3Ssthen 				qstate->env->kill_sub));
1250933707f3Ssthen 			(*qstate->env->kill_sub)(subq);
1251933707f3Ssthen 			return;
1252933707f3Ssthen 		}
1253933707f3Ssthen 	}
1254933707f3Ssthen }
1255933707f3Ssthen 
1256933707f3Ssthen /**
1257933707f3Ssthen  * Generate a DNSKEY prefetch query to get the DNSKEY for the DS record we
1258933707f3Ssthen  * just got in a referral (where we have dnssec_expected, thus have trust
1259933707f3Ssthen  * anchors above it).  Note that right after calling this routine the
1260933707f3Ssthen  * iterator detached subqueries (because of following the referral), and thus
1261933707f3Ssthen  * the DNSKEY query becomes detached, its return stored in the cache for
1262933707f3Ssthen  * later lookup by the validator.  This cache lookup by the validator avoids
1263933707f3Ssthen  * the roundtrip incurred by the DNSKEY query.  The DNSKEY query is now
1264933707f3Ssthen  * performed at about the same time the original query is sent to the domain,
1265933707f3Ssthen  * thus the two answers are likely to be returned at about the same time,
1266933707f3Ssthen  * saving a roundtrip from the validated lookup.
1267933707f3Ssthen  *
1268933707f3Ssthen  * @param qstate: the qtstate that triggered the need to prime.
1269933707f3Ssthen  * @param iq: iterator query state.
1270933707f3Ssthen  * @param id: module id.
1271933707f3Ssthen  */
1272933707f3Ssthen static void
1273933707f3Ssthen generate_dnskey_prefetch(struct module_qstate* qstate,
1274933707f3Ssthen 	struct iter_qstate* iq, int id)
1275933707f3Ssthen {
1276933707f3Ssthen 	struct module_qstate* subq;
1277933707f3Ssthen 	log_assert(iq->dp);
1278933707f3Ssthen 
1279933707f3Ssthen 	/* is this query the same as the prefetch? */
1280933707f3Ssthen 	if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY &&
1281933707f3Ssthen 		query_dname_compare(iq->dp->name, qstate->qinfo.qname)==0 &&
1282933707f3Ssthen 		(qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){
1283933707f3Ssthen 		return;
1284933707f3Ssthen 	}
12857dd170e2Ssthen 	/* we do not generate this prefetch when the query list is full,
12867dd170e2Ssthen 	 * the query is fetched, if needed, when the validator wants it.
12877dd170e2Ssthen 	 * At that time the validator waits for it, after spawning it.
12887dd170e2Ssthen 	 * This means there is one state that uses cpu and a socket, the
12897dd170e2Ssthen 	 * spawned while this one waits, and not several at the same time,
12907dd170e2Ssthen 	 * if we had created the lookup here. And this helps to keep
12917dd170e2Ssthen 	 * the total load down, but the query still succeeds to resolve. */
12927dd170e2Ssthen 	if(mesh_jostle_exceeded(qstate->env->mesh))
12937dd170e2Ssthen 		return;
1294933707f3Ssthen 
1295933707f3Ssthen 	/* if the DNSKEY is in the cache this lookup will stop quickly */
1296933707f3Ssthen 	log_nametypeclass(VERB_ALGO, "schedule dnskey prefetch",
1297933707f3Ssthen 		iq->dp->name, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass);
1298933707f3Ssthen 	if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
1299933707f3Ssthen 		LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass, qstate, id, iq,
130006a13c09Ssthen 		INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) {
1301933707f3Ssthen 		/* we'll be slower, but it'll work */
1302933707f3Ssthen 		verbose(VERB_ALGO, "could not generate dnskey prefetch");
1303933707f3Ssthen 		return;
1304933707f3Ssthen 	}
1305933707f3Ssthen 	if(subq) {
1306933707f3Ssthen 		struct iter_qstate* subiq =
1307933707f3Ssthen 			(struct iter_qstate*)subq->minfo[id];
1308933707f3Ssthen 		/* this qstate has the right delegation for the dnskey lookup*/
1309933707f3Ssthen 		/* make copy to avoid use of stub dp by different qs/threads */
1310933707f3Ssthen 		subiq->dp = delegpt_copy(iq->dp, subq->region);
1311933707f3Ssthen 		/* if !subiq->dp, it'll start from the cache, no problem */
1312933707f3Ssthen 	}
1313933707f3Ssthen }
1314933707f3Ssthen 
1315933707f3Ssthen /**
1316933707f3Ssthen  * See if the query needs forwarding.
1317933707f3Ssthen  *
1318933707f3Ssthen  * @param qstate: query state.
1319933707f3Ssthen  * @param iq: iterator query state.
1320933707f3Ssthen  * @return true if the request is forwarded, false if not.
1321933707f3Ssthen  * 	If returns true but, iq->dp is NULL then a malloc failure occurred.
1322933707f3Ssthen  */
1323933707f3Ssthen static int
1324933707f3Ssthen forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
1325933707f3Ssthen {
1326933707f3Ssthen 	struct delegpt* dp;
1327933707f3Ssthen 	uint8_t* delname = iq->qchase.qname;
1328933707f3Ssthen 	size_t delnamelen = iq->qchase.qname_len;
13292bdc0ed1Ssthen 	int nolock = 0;
1330452a1548Ssthen 	if(iq->refetch_glue && iq->dp) {
1331d8d14d0cSsthen 		delname = iq->dp->name;
1332d8d14d0cSsthen 		delnamelen = iq->dp->namelen;
1333d8d14d0cSsthen 	}
1334933707f3Ssthen 	/* strip one label off of DS query to lookup higher for it */
1335d8d14d0cSsthen 	if( (iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue)
1336933707f3Ssthen 		&& !dname_is_root(iq->qchase.qname))
1337933707f3Ssthen 		dname_remove_label(&delname, &delnamelen);
13382bdc0ed1Ssthen 	dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass,
13392bdc0ed1Ssthen 		nolock);
13402bdc0ed1Ssthen 	if(!dp) return 0;
1341933707f3Ssthen 	/* send recursion desired to forward addr */
1342933707f3Ssthen 	iq->chase_flags |= BIT_RD;
1343933707f3Ssthen 	iq->dp = delegpt_copy(dp, qstate->region);
13442bdc0ed1Ssthen 	lock_rw_unlock(&qstate->env->fwds->lock);
1345933707f3Ssthen 	/* iq->dp checked by caller */
1346933707f3Ssthen 	verbose(VERB_ALGO, "forwarding request");
1347933707f3Ssthen 	return 1;
1348933707f3Ssthen }
1349933707f3Ssthen 
1350933707f3Ssthen /**
1351933707f3Ssthen  * Process the initial part of the request handling. This state roughly
1352933707f3Ssthen  * corresponds to resolver algorithms steps 1 (find answer in cache) and 2
1353933707f3Ssthen  * (find the best servers to ask).
1354933707f3Ssthen  *
1355933707f3Ssthen  * Note that all requests start here, and query restarts revisit this state.
1356933707f3Ssthen  *
1357933707f3Ssthen  * This state either generates: 1) a response, from cache or error, 2) a
1358933707f3Ssthen  * priming event, or 3) forwards the request to the next state (init2,
1359933707f3Ssthen  * generally).
1360933707f3Ssthen  *
1361933707f3Ssthen  * @param qstate: query state.
1362933707f3Ssthen  * @param iq: iterator query state.
1363933707f3Ssthen  * @param ie: iterator shared global environment.
1364933707f3Ssthen  * @param id: module id.
1365933707f3Ssthen  * @return true if the event needs more request processing immediately,
1366933707f3Ssthen  *         false if not.
1367933707f3Ssthen  */
1368933707f3Ssthen static int
1369933707f3Ssthen processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
1370933707f3Ssthen 	struct iter_env* ie, int id)
1371933707f3Ssthen {
13722bdc0ed1Ssthen 	uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
1373191f22c6Ssthen 	uint8_t* delname, *dpname=NULL;
1374191f22c6Ssthen 	size_t delnamelen, dpnamelen=0;
137577079be7Ssthen 	struct dns_msg* msg = NULL;
1376933707f3Ssthen 
1377933707f3Ssthen 	log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo);
1378933707f3Ssthen 	/* check effort */
1379933707f3Ssthen 
1380933707f3Ssthen 	/* We enforce a maximum number of query restarts. This is primarily a
1381933707f3Ssthen 	 * cheap way to prevent CNAME loops. */
13828b7325afSsthen 	if(iq->query_restart_count > ie->max_query_restarts) {
1383933707f3Ssthen 		verbose(VERB_QUERY, "request has exceeded the maximum number"
1384933707f3Ssthen 			" of query restarts with %d", iq->query_restart_count);
13852308e98cSsthen 		errinf(qstate, "request has exceeded the maximum number "
13862308e98cSsthen 			"restarts (eg. indirections)");
13872308e98cSsthen 		if(iq->qchase.qname)
13882308e98cSsthen 			errinf_dname(qstate, "stop at", iq->qchase.qname);
1389*98bc733bSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
1390933707f3Ssthen 	}
1391933707f3Ssthen 
1392933707f3Ssthen 	/* We enforce a maximum recursion/dependency depth -- in general,
1393933707f3Ssthen 	 * this is unnecessary for dependency loops (although it will
1394933707f3Ssthen 	 * catch those), but it provides a sensible limit to the amount
1395933707f3Ssthen 	 * of work required to answer a given query. */
1396933707f3Ssthen 	verbose(VERB_ALGO, "request has dependency depth of %d", iq->depth);
1397933707f3Ssthen 	if(iq->depth > ie->max_dependency_depth) {
1398933707f3Ssthen 		verbose(VERB_QUERY, "request has exceeded the maximum "
1399933707f3Ssthen 			"dependency depth with depth of %d", iq->depth);
14002308e98cSsthen 		errinf(qstate, "request has exceeded the maximum dependency "
14012308e98cSsthen 			"depth (eg. nameserver lookup recursion)");
1402933707f3Ssthen 		return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1403933707f3Ssthen 	}
1404933707f3Ssthen 
1405933707f3Ssthen 	/* If the request is qclass=ANY, setup to generate each class */
1406933707f3Ssthen 	if(qstate->qinfo.qclass == LDNS_RR_CLASS_ANY) {
1407933707f3Ssthen 		iq->qchase.qclass = 0;
1408933707f3Ssthen 		return next_state(iq, COLLECT_CLASS_STATE);
1409933707f3Ssthen 	}
1410933707f3Ssthen 
14112be9e038Ssthen 	/*
14122be9e038Ssthen 	 * If we are restricted by a forward-zone or a stub-zone, we
14132be9e038Ssthen 	 * can't re-fetch glue for this delegation point.
14142be9e038Ssthen 	 * we won’t try to re-fetch glue if the iq->dp is null.
14152be9e038Ssthen 	 */
14162be9e038Ssthen 	if (iq->refetch_glue &&
14172be9e038Ssthen 	        iq->dp &&
141820237c55Ssthen 	        !can_have_last_resort(qstate->env, iq->dp->name,
14192bdc0ed1Ssthen 	             iq->dp->namelen, iq->qchase.qclass, NULL, NULL, NULL)) {
14202be9e038Ssthen 	    iq->refetch_glue = 0;
14212be9e038Ssthen 	}
14222be9e038Ssthen 
1423933707f3Ssthen 	/* Resolver Algorithm Step 1 -- Look for the answer in local data. */
1424933707f3Ssthen 
1425933707f3Ssthen 	/* This either results in a query restart (CNAME cache response), a
1426933707f3Ssthen 	 * terminating response (ANSWER), or a cache miss (null). */
1427933707f3Ssthen 
14282bdc0ed1Ssthen 	/* Check RPZ for override */
14292bdc0ed1Ssthen 	if(qstate->env->auth_zones) {
14302bdc0ed1Ssthen 		/* apply rpz qname triggers, like after cname */
14312bdc0ed1Ssthen 		struct dns_msg* forged_response =
14322bdc0ed1Ssthen 			rpz_callback_from_iterator_cname(qstate, iq);
14332bdc0ed1Ssthen 		if(forged_response) {
14342bdc0ed1Ssthen 			uint8_t* sname = 0;
14352bdc0ed1Ssthen 			size_t slen = 0;
14362bdc0ed1Ssthen 			int count = 0;
14372bdc0ed1Ssthen 			while(forged_response && reply_find_rrset_section_an(
14382bdc0ed1Ssthen 				forged_response->rep, iq->qchase.qname,
14392bdc0ed1Ssthen 				iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
14402bdc0ed1Ssthen 				iq->qchase.qclass) &&
14412bdc0ed1Ssthen 				iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
14422bdc0ed1Ssthen 				count++ < ie->max_query_restarts) {
14432bdc0ed1Ssthen 				/* another cname to follow */
14442bdc0ed1Ssthen 				if(!handle_cname_response(qstate, iq, forged_response,
14452bdc0ed1Ssthen 					&sname, &slen)) {
14462bdc0ed1Ssthen 					errinf(qstate, "malloc failure, CNAME info");
14472bdc0ed1Ssthen 					return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
14482bdc0ed1Ssthen 				}
14492bdc0ed1Ssthen 				iq->qchase.qname = sname;
14502bdc0ed1Ssthen 				iq->qchase.qname_len = slen;
14512bdc0ed1Ssthen 				forged_response =
14522bdc0ed1Ssthen 					rpz_callback_from_iterator_cname(qstate, iq);
14532bdc0ed1Ssthen 			}
14542bdc0ed1Ssthen 			if(forged_response != NULL) {
14552bdc0ed1Ssthen 				qstate->ext_state[id] = module_finished;
14562bdc0ed1Ssthen 				qstate->return_rcode = LDNS_RCODE_NOERROR;
14572bdc0ed1Ssthen 				qstate->return_msg = forged_response;
14582bdc0ed1Ssthen 				iq->response = forged_response;
14592bdc0ed1Ssthen 				next_state(iq, FINISHED_STATE);
14602bdc0ed1Ssthen 				if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
14612bdc0ed1Ssthen 					log_err("rpz: after cached cname, prepend rrsets: out of memory");
14622bdc0ed1Ssthen 					return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
14632bdc0ed1Ssthen 				}
14642bdc0ed1Ssthen 				qstate->return_msg->qinfo = qstate->qinfo;
14652bdc0ed1Ssthen 				return 0;
14662bdc0ed1Ssthen 			}
14672bdc0ed1Ssthen 			/* Follow the CNAME response */
14682bdc0ed1Ssthen 			iq->dp = NULL;
14692bdc0ed1Ssthen 			iq->refetch_glue = 0;
14702bdc0ed1Ssthen 			iq->query_restart_count++;
14712bdc0ed1Ssthen 			iq->sent_count = 0;
14722bdc0ed1Ssthen 			iq->dp_target_count = 0;
14732bdc0ed1Ssthen 			sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
14742bdc0ed1Ssthen 			if(qstate->env->cfg->qname_minimisation)
14752bdc0ed1Ssthen 				iq->minimisation_state = INIT_MINIMISE_STATE;
14762bdc0ed1Ssthen 			return next_state(iq, INIT_REQUEST_STATE);
14772bdc0ed1Ssthen 		}
14782bdc0ed1Ssthen 	}
14792bdc0ed1Ssthen 
14802bdc0ed1Ssthen 	if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen,
14812bdc0ed1Ssthen 		dpname_storage, sizeof(dpname_storage))) {
14822308e98cSsthen 		/* Asked to not query cache. */
14832308e98cSsthen 		verbose(VERB_ALGO, "no-cache set, going to the network");
14842308e98cSsthen 		qstate->no_cache_lookup = 1;
14852308e98cSsthen 		qstate->no_cache_store = 1;
14862308e98cSsthen 		msg = NULL;
14872308e98cSsthen 	} else if(qstate->blacklist) {
1488933707f3Ssthen 		/* if cache, or anything else, was blacklisted then
1489933707f3Ssthen 		 * getting older results from cache is a bad idea, no cache */
1490933707f3Ssthen 		verbose(VERB_ALGO, "cache blacklisted, going to the network");
1491933707f3Ssthen 		msg = NULL;
149277079be7Ssthen 	} else if(!qstate->no_cache_lookup) {
1493933707f3Ssthen 		msg = dns_cache_lookup(qstate->env, iq->qchase.qname,
1494933707f3Ssthen 			iq->qchase.qname_len, iq->qchase.qtype,
149557dceb2aSbrad 			iq->qchase.qclass, qstate->query_flags,
1496191f22c6Ssthen 			qstate->region, qstate->env->scratch, 0, dpname,
1497191f22c6Ssthen 			dpnamelen);
149820237c55Ssthen 		if(!msg && qstate->env->neg_cache &&
149920237c55Ssthen 			iter_qname_indicates_dnssec(qstate->env, &iq->qchase)) {
1500933707f3Ssthen 			/* lookup in negative cache; may result in
1501933707f3Ssthen 			 * NOERROR/NODATA or NXDOMAIN answers that need validation */
1502933707f3Ssthen 			msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
1503933707f3Ssthen 				qstate->region, qstate->env->rrset_cache,
1504933707f3Ssthen 				qstate->env->scratch_buffer,
1505938a3a5eSflorian 				*qstate->env->now, 1/*add SOA*/, NULL,
1506938a3a5eSflorian 				qstate->env->cfg);
1507933707f3Ssthen 		}
1508933707f3Ssthen 		/* item taken from cache does not match our query name, thus
1509933707f3Ssthen 		 * security needs to be re-examined later */
1510933707f3Ssthen 		if(msg && query_dname_compare(qstate->qinfo.qname,
1511933707f3Ssthen 			iq->qchase.qname) != 0)
1512933707f3Ssthen 			msg->rep->security = sec_status_unchecked;
1513933707f3Ssthen 	}
1514933707f3Ssthen 	if(msg) {
1515933707f3Ssthen 		/* handle positive cache response */
1516933707f3Ssthen 		enum response_type type = response_type_from_cache(msg,
1517933707f3Ssthen 			&iq->qchase);
1518933707f3Ssthen 		if(verbosity >= VERB_ALGO) {
1519933707f3Ssthen 			log_dns_msg("msg from cache lookup", &msg->qinfo,
1520933707f3Ssthen 				msg->rep);
1521933707f3Ssthen 			verbose(VERB_ALGO, "msg ttl is %d, prefetch ttl %d",
1522933707f3Ssthen 				(int)msg->rep->ttl,
1523933707f3Ssthen 				(int)msg->rep->prefetch_ttl);
1524933707f3Ssthen 		}
1525933707f3Ssthen 
1526933707f3Ssthen 		if(type == RESPONSE_TYPE_CNAME) {
1527933707f3Ssthen 			uint8_t* sname = 0;
1528933707f3Ssthen 			size_t slen = 0;
1529933707f3Ssthen 			verbose(VERB_ALGO, "returning CNAME response from "
1530933707f3Ssthen 				"cache");
1531933707f3Ssthen 			if(!handle_cname_response(qstate, iq, msg,
15322308e98cSsthen 				&sname, &slen)) {
15332308e98cSsthen 				errinf(qstate, "failed to prepend CNAME "
15342308e98cSsthen 					"components, malloc failure");
1535933707f3Ssthen 				return error_response(qstate, id,
1536933707f3Ssthen 					LDNS_RCODE_SERVFAIL);
15372308e98cSsthen 			}
1538933707f3Ssthen 			iq->qchase.qname = sname;
1539933707f3Ssthen 			iq->qchase.qname_len = slen;
1540933707f3Ssthen 			/* This *is* a query restart, even if it is a cheap
1541933707f3Ssthen 			 * one. */
1542933707f3Ssthen 			iq->dp = NULL;
1543933707f3Ssthen 			iq->refetch_glue = 0;
1544933707f3Ssthen 			iq->query_restart_count++;
1545933707f3Ssthen 			iq->sent_count = 0;
154606a13c09Ssthen 			iq->dp_target_count = 0;
1547933707f3Ssthen 			sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
154824893edcSsthen 			if(qstate->env->cfg->qname_minimisation)
154924893edcSsthen 				iq->minimisation_state = INIT_MINIMISE_STATE;
1550933707f3Ssthen 			return next_state(iq, INIT_REQUEST_STATE);
1551933707f3Ssthen 		}
1552933707f3Ssthen 		/* if from cache, NULL, else insert 'cache IP' len=0 */
1553933707f3Ssthen 		if(qstate->reply_origin)
1554933707f3Ssthen 			sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
15552308e98cSsthen 		if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_SERVFAIL)
15562308e98cSsthen 			errinf(qstate, "SERVFAIL in cache");
1557933707f3Ssthen 		/* it is an answer, response, to final state */
1558933707f3Ssthen 		verbose(VERB_ALGO, "returning answer from cache.");
1559933707f3Ssthen 		iq->response = msg;
1560933707f3Ssthen 		return final_state(iq);
1561933707f3Ssthen 	}
1562933707f3Ssthen 
1563933707f3Ssthen 	/* attempt to forward the request */
1564933707f3Ssthen 	if(forward_request(qstate, iq))
1565933707f3Ssthen 	{
1566933707f3Ssthen 		if(!iq->dp) {
1567933707f3Ssthen 			log_err("alloc failure for forward dp");
15682308e98cSsthen 			errinf(qstate, "malloc failure for forward zone");
1569933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1570933707f3Ssthen 		}
1571*98bc733bSsthen 		if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
1572*98bc733bSsthen 			qstate->region, iq->dp)) {
1573*98bc733bSsthen 			errinf(qstate, "malloc failure, copy extra info into delegation point");
1574*98bc733bSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1575*98bc733bSsthen 		}
15768b7325afSsthen 		if((qstate->query_flags&BIT_RD)==0) {
15778b7325afSsthen 			/* If the server accepts RD=0 queries and forwards
15788b7325afSsthen 			 * with RD=1, then if the server is listed as an NS
15798b7325afSsthen 			 * entry, it starts query loops. Stop that loop by
15808b7325afSsthen 			 * disallowing the query. The RD=0 was previously used
15818b7325afSsthen 			 * to check the cache with allow_snoop. For stubs,
15828b7325afSsthen 			 * the iterator pass would have primed the stub and
15838b7325afSsthen 			 * then cached information can be used for further
15848b7325afSsthen 			 * queries. */
15858b7325afSsthen 			verbose(VERB_ALGO, "cannot forward RD=0 query, to stop query loops");
15868b7325afSsthen 			errinf(qstate, "cannot forward RD=0 query");
15878b7325afSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
15888b7325afSsthen 		}
1589933707f3Ssthen 		iq->refetch_glue = 0;
159024893edcSsthen 		iq->minimisation_state = DONOT_MINIMISE_STATE;
1591933707f3Ssthen 		/* the request has been forwarded.
1592933707f3Ssthen 		 * forwarded requests need to be immediately sent to the
1593933707f3Ssthen 		 * next state, QUERYTARGETS. */
1594933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
1595933707f3Ssthen 	}
1596933707f3Ssthen 
1597933707f3Ssthen 	/* Resolver Algorithm Step 2 -- find the "best" servers. */
1598933707f3Ssthen 
1599933707f3Ssthen 	/* first, adjust for DS queries. To avoid the grandparent problem,
1600933707f3Ssthen 	 * we just look for the closest set of server to the parent of qname.
1601933707f3Ssthen 	 * When re-fetching glue we also need to ask the parent.
1602933707f3Ssthen 	 */
1603933707f3Ssthen 	if(iq->refetch_glue) {
1604933707f3Ssthen 		if(!iq->dp) {
1605933707f3Ssthen 			log_err("internal or malloc fail: no dp for refetch");
16062308e98cSsthen 			errinf(qstate, "malloc failure, for delegation info");
1607933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1608933707f3Ssthen 		}
1609933707f3Ssthen 		delname = iq->dp->name;
1610933707f3Ssthen 		delnamelen = iq->dp->namelen;
1611933707f3Ssthen 	} else {
1612933707f3Ssthen 		delname = iq->qchase.qname;
1613933707f3Ssthen 		delnamelen = iq->qchase.qname_len;
1614933707f3Ssthen 	}
1615933707f3Ssthen 	if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue ||
161620237c55Ssthen 	   (iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway
16172bdc0ed1Ssthen 	   && can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL, NULL, NULL))) {
1618933707f3Ssthen 		/* remove first label from delname, root goes to hints,
1619933707f3Ssthen 		 * but only to fetch glue, not for qtype=DS. */
1620933707f3Ssthen 		/* also when prefetching an NS record, fetch it again from
1621933707f3Ssthen 		 * its parent, just as if it expired, so that you do not
1622933707f3Ssthen 		 * get stuck on an older nameserver that gives old NSrecords */
1623933707f3Ssthen 		if(dname_is_root(delname) && (iq->refetch_glue ||
1624933707f3Ssthen 			(iq->qchase.qtype == LDNS_RR_TYPE_NS &&
1625933707f3Ssthen 			qstate->prefetch_leeway)))
1626933707f3Ssthen 			delname = NULL; /* go to root priming */
1627933707f3Ssthen 		else 	dname_remove_label(&delname, &delnamelen);
1628933707f3Ssthen 	}
1629933707f3Ssthen 	/* delname is the name to lookup a delegation for. If NULL rootprime */
1630933707f3Ssthen 	while(1) {
1631933707f3Ssthen 
1632933707f3Ssthen 		/* Lookup the delegation in the cache. If null, then the
1633933707f3Ssthen 		 * cache needs to be primed for the qclass. */
1634933707f3Ssthen 		if(delname)
1635933707f3Ssthen 		     iq->dp = dns_cache_find_delegation(qstate->env, delname,
1636933707f3Ssthen 			delnamelen, iq->qchase.qtype, iq->qchase.qclass,
1637d8d14d0cSsthen 			qstate->region, &iq->deleg_msg,
1638d1e2768aSsthen 			*qstate->env->now+qstate->prefetch_leeway, 1,
1639d1e2768aSsthen 			dpname, dpnamelen);
1640933707f3Ssthen 		else iq->dp = NULL;
1641933707f3Ssthen 
1642933707f3Ssthen 		/* If the cache has returned nothing, then we have a
1643933707f3Ssthen 		 * root priming situation. */
1644933707f3Ssthen 		if(iq->dp == NULL) {
1645938a3a5eSflorian 			int r;
16462bdc0ed1Ssthen 			int nolock = 0;
1647938a3a5eSflorian 			/* if under auth zone, no prime needed */
1648938a3a5eSflorian 			if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
1649938a3a5eSflorian 				return error_response(qstate, id,
1650938a3a5eSflorian 					LDNS_RCODE_SERVFAIL);
1651938a3a5eSflorian 			if(iq->dp) /* use auth zone dp */
1652938a3a5eSflorian 				return next_state(iq, INIT_REQUEST_2_STATE);
1653933707f3Ssthen 			/* if there is a stub, then no root prime needed */
1654938a3a5eSflorian 			r = prime_stub(qstate, iq, id, delname,
1655d8d14d0cSsthen 				iq->qchase.qclass);
1656933707f3Ssthen 			if(r == 2)
1657933707f3Ssthen 				break; /* got noprime-stub-zone, continue */
1658933707f3Ssthen 			else if(r)
1659933707f3Ssthen 				return 0; /* stub prime request made */
1660933707f3Ssthen 			if(forwards_lookup_root(qstate->env->fwds,
16612bdc0ed1Ssthen 				iq->qchase.qclass, nolock)) {
16622bdc0ed1Ssthen 				lock_rw_unlock(&qstate->env->fwds->lock);
1663933707f3Ssthen 				/* forward zone root, no root prime needed */
1664933707f3Ssthen 				/* fill in some dp - safety belt */
16652bdc0ed1Ssthen 				iq->dp = hints_find_root(qstate->env->hints,
16662bdc0ed1Ssthen 					iq->qchase.qclass, nolock);
1667933707f3Ssthen 				if(!iq->dp) {
1668933707f3Ssthen 					log_err("internal error: no hints dp");
16692308e98cSsthen 					errinf(qstate, "no hints for this class");
1670*98bc733bSsthen 					return error_response_cache(qstate, id,
1671933707f3Ssthen 						LDNS_RCODE_SERVFAIL);
1672933707f3Ssthen 				}
1673933707f3Ssthen 				iq->dp = delegpt_copy(iq->dp, qstate->region);
16742bdc0ed1Ssthen 				lock_rw_unlock(&qstate->env->hints->lock);
1675933707f3Ssthen 				if(!iq->dp) {
1676933707f3Ssthen 					log_err("out of memory in safety belt");
16772308e98cSsthen 					errinf(qstate, "malloc failure, in safety belt");
1678933707f3Ssthen 					return error_response(qstate, id,
1679933707f3Ssthen 						LDNS_RCODE_SERVFAIL);
1680933707f3Ssthen 				}
1681933707f3Ssthen 				return next_state(iq, INIT_REQUEST_2_STATE);
1682933707f3Ssthen 			}
1683933707f3Ssthen 			/* Note that the result of this will set a new
1684933707f3Ssthen 			 * DelegationPoint based on the result of priming. */
1685d8d14d0cSsthen 			if(!prime_root(qstate, iq, id, iq->qchase.qclass))
1686933707f3Ssthen 				return error_response(qstate, id,
1687933707f3Ssthen 					LDNS_RCODE_REFUSED);
1688933707f3Ssthen 
1689933707f3Ssthen 			/* priming creates and sends a subordinate query, with
1690933707f3Ssthen 			 * this query as the parent. So further processing for
1691933707f3Ssthen 			 * this event will stop until reactivated by the
1692933707f3Ssthen 			 * results of priming. */
1693933707f3Ssthen 			return 0;
1694933707f3Ssthen 		}
1695a58bff56Ssthen 		if(!iq->ratelimit_ok && qstate->prefetch_leeway)
1696a58bff56Ssthen 			iq->ratelimit_ok = 1; /* allow prefetches, this keeps
1697a58bff56Ssthen 			otherwise valid data in the cache */
1698933707f3Ssthen 
1699933707f3Ssthen 		/* see if this dp not useless.
1700933707f3Ssthen 		 * It is useless if:
1701933707f3Ssthen 		 *	o all NS items are required glue.
1702933707f3Ssthen 		 *	  or the query is for NS item that is required glue.
1703933707f3Ssthen 		 *	o no addresses are provided.
1704933707f3Ssthen 		 *	o RD qflag is on.
1705933707f3Ssthen 		 * Instead, go up one level, and try to get even further
1706933707f3Ssthen 		 * If the root was useless, use safety belt information.
1707933707f3Ssthen 		 * Only check cache returns, because replies for servers
1708933707f3Ssthen 		 * could be useless but lead to loops (bumping into the
1709933707f3Ssthen 		 * same server reply) if useless-checked.
1710933707f3Ssthen 		 */
1711933707f3Ssthen 		if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
17128b7325afSsthen 			iq->dp, ie->supports_ipv4, ie->supports_ipv6,
17138b7325afSsthen 			ie->use_nat64)) {
17142bdc0ed1Ssthen 			int have_dp = 0;
17152bdc0ed1Ssthen 			if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) {
17162bdc0ed1Ssthen 				if(have_dp) {
171720237c55Ssthen 					verbose(VERB_QUERY, "cache has stub "
171820237c55Ssthen 						"or fwd but no addresses, "
171920237c55Ssthen 						"fallback to config");
17202bdc0ed1Ssthen 					if(have_dp && !iq->dp) {
172120237c55Ssthen 						log_err("out of memory in "
172220237c55Ssthen 							"stub/fwd fallback");
17232308e98cSsthen 						errinf(qstate, "malloc failure, for fallback to config");
172420237c55Ssthen 						return error_response(qstate,
172520237c55Ssthen 						    id, LDNS_RCODE_SERVFAIL);
172620237c55Ssthen 					}
172720237c55Ssthen 					break;
172820237c55Ssthen 				}
172920237c55Ssthen 				verbose(VERB_ALGO, "useless dp "
173020237c55Ssthen 					"but cannot go up, servfail");
173120237c55Ssthen 				delegpt_log(VERB_ALGO, iq->dp);
17322308e98cSsthen 				errinf(qstate, "no useful nameservers, "
17332308e98cSsthen 					"and cannot go up");
17342308e98cSsthen 				errinf_dname(qstate, "for zone", iq->dp->name);
173520237c55Ssthen 				return error_response(qstate, id,
173620237c55Ssthen 					LDNS_RCODE_SERVFAIL);
173720237c55Ssthen 			}
1738933707f3Ssthen 			if(dname_is_root(iq->dp->name)) {
1739933707f3Ssthen 				/* use safety belt */
17402bdc0ed1Ssthen 				int nolock = 0;
1741933707f3Ssthen 				verbose(VERB_QUERY, "Cache has root NS but "
1742933707f3Ssthen 				"no addresses. Fallback to the safety belt.");
17432bdc0ed1Ssthen 				iq->dp = hints_find_root(qstate->env->hints,
17442bdc0ed1Ssthen 					iq->qchase.qclass, nolock);
1745933707f3Ssthen 				/* note deleg_msg is from previous lookup,
1746933707f3Ssthen 				 * but RD is on, so it is not used */
1747933707f3Ssthen 				if(!iq->dp) {
1748933707f3Ssthen 					log_err("internal error: no hints dp");
1749933707f3Ssthen 					return error_response(qstate, id,
1750933707f3Ssthen 						LDNS_RCODE_REFUSED);
1751933707f3Ssthen 				}
1752933707f3Ssthen 				iq->dp = delegpt_copy(iq->dp, qstate->region);
17532bdc0ed1Ssthen 				lock_rw_unlock(&qstate->env->hints->lock);
1754933707f3Ssthen 				if(!iq->dp) {
1755933707f3Ssthen 					log_err("out of memory in safety belt");
17562308e98cSsthen 					errinf(qstate, "malloc failure, in safety belt, for root");
1757933707f3Ssthen 					return error_response(qstate, id,
1758933707f3Ssthen 						LDNS_RCODE_SERVFAIL);
1759933707f3Ssthen 				}
1760933707f3Ssthen 				break;
1761933707f3Ssthen 			} else {
1762933707f3Ssthen 				verbose(VERB_ALGO,
1763933707f3Ssthen 					"cache delegation was useless:");
1764933707f3Ssthen 				delegpt_log(VERB_ALGO, iq->dp);
1765933707f3Ssthen 				/* go up */
1766933707f3Ssthen 				delname = iq->dp->name;
1767933707f3Ssthen 				delnamelen = iq->dp->namelen;
1768933707f3Ssthen 				dname_remove_label(&delname, &delnamelen);
1769933707f3Ssthen 			}
1770933707f3Ssthen 		} else break;
1771933707f3Ssthen 	}
1772933707f3Ssthen 
1773933707f3Ssthen 	verbose(VERB_ALGO, "cache delegation returns delegpt");
1774933707f3Ssthen 	delegpt_log(VERB_ALGO, iq->dp);
1775933707f3Ssthen 
1776933707f3Ssthen 	/* Otherwise, set the current delegation point and move on to the
1777933707f3Ssthen 	 * next state. */
1778933707f3Ssthen 	return next_state(iq, INIT_REQUEST_2_STATE);
1779933707f3Ssthen }
1780933707f3Ssthen 
1781933707f3Ssthen /**
1782933707f3Ssthen  * Process the second part of the initial request handling. This state
1783933707f3Ssthen  * basically exists so that queries that generate root priming events have
1784933707f3Ssthen  * the same init processing as ones that do not. Request events that reach
1785933707f3Ssthen  * this state must have a valid currentDelegationPoint set.
1786933707f3Ssthen  *
1787bdfc4d55Sflorian  * This part is primarily handling stub zone priming. Events that reach this
1788933707f3Ssthen  * state must have a current delegation point.
1789933707f3Ssthen  *
1790933707f3Ssthen  * @param qstate: query state.
1791933707f3Ssthen  * @param iq: iterator query state.
1792933707f3Ssthen  * @param id: module id.
1793933707f3Ssthen  * @return true if the event needs more request processing immediately,
1794933707f3Ssthen  *         false if not.
1795933707f3Ssthen  */
1796933707f3Ssthen static int
1797933707f3Ssthen processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
1798d8d14d0cSsthen 	int id)
1799933707f3Ssthen {
1800d8d14d0cSsthen 	uint8_t* delname;
1801d8d14d0cSsthen 	size_t delnamelen;
1802933707f3Ssthen 	log_query_info(VERB_QUERY, "resolving (init part 2): ",
1803933707f3Ssthen 		&qstate->qinfo);
1804933707f3Ssthen 
1805bdfc4d55Sflorian 	delname = iq->qchase.qname;
1806bdfc4d55Sflorian 	delnamelen = iq->qchase.qname_len;
1807d8d14d0cSsthen 	if(iq->refetch_glue) {
1808bdfc4d55Sflorian 		struct iter_hints_stub* stub;
18092bdc0ed1Ssthen 		int nolock = 0;
1810d8d14d0cSsthen 		if(!iq->dp) {
1811d8d14d0cSsthen 			log_err("internal or malloc fail: no dp for refetch");
18122308e98cSsthen 			errinf(qstate, "malloc failure, no delegation info");
1813d8d14d0cSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1814d8d14d0cSsthen 		}
1815bdfc4d55Sflorian 		/* Do not send queries above stub, do not set delname to dp if
1816bdfc4d55Sflorian 		 * this is above stub without stub-first. */
1817bdfc4d55Sflorian 		stub = hints_lookup_stub(
1818bdfc4d55Sflorian 			qstate->env->hints, iq->qchase.qname, iq->qchase.qclass,
18192bdc0ed1Ssthen 			iq->dp, nolock);
1820bdfc4d55Sflorian 		if(!stub || !stub->dp->has_parent_side_NS ||
1821bdfc4d55Sflorian 			dname_subdomain_c(iq->dp->name, stub->dp->name)) {
1822d8d14d0cSsthen 			delname = iq->dp->name;
1823d8d14d0cSsthen 			delnamelen = iq->dp->namelen;
1824bdfc4d55Sflorian 		}
18252bdc0ed1Ssthen 		/* lock_() calls are macros that could be nothing, surround in {} */
18262bdc0ed1Ssthen 		if(stub) { lock_rw_unlock(&qstate->env->hints->lock); }
1827d8d14d0cSsthen 	}
1828d8d14d0cSsthen 	if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) {
1829d8d14d0cSsthen 		if(!dname_is_root(delname))
1830d8d14d0cSsthen 			dname_remove_label(&delname, &delnamelen);
1831d8d14d0cSsthen 		iq->refetch_glue = 0; /* if CNAME causes restart, no refetch */
1832d8d14d0cSsthen 	}
1833938a3a5eSflorian 
1834938a3a5eSflorian 	/* see if we have an auth zone to answer from, improves dp from cache
1835938a3a5eSflorian 	 * (if any dp from cache) with auth zone dp, if that is lower */
1836938a3a5eSflorian 	if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
1837938a3a5eSflorian 		return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
1838938a3a5eSflorian 
1839933707f3Ssthen 	/* Check to see if we need to prime a stub zone. */
1840d8d14d0cSsthen 	if(prime_stub(qstate, iq, id, delname, iq->qchase.qclass)) {
1841933707f3Ssthen 		/* A priming sub request was made */
1842933707f3Ssthen 		return 0;
1843933707f3Ssthen 	}
1844933707f3Ssthen 
1845933707f3Ssthen 	/* most events just get forwarded to the next state. */
1846933707f3Ssthen 	return next_state(iq, INIT_REQUEST_3_STATE);
1847933707f3Ssthen }
1848933707f3Ssthen 
1849933707f3Ssthen /**
1850933707f3Ssthen  * Process the third part of the initial request handling. This state exists
1851933707f3Ssthen  * as a separate state so that queries that generate stub priming events
1852933707f3Ssthen  * will get the tail end of the init process but not repeat the stub priming
1853933707f3Ssthen  * check.
1854933707f3Ssthen  *
1855933707f3Ssthen  * @param qstate: query state.
1856933707f3Ssthen  * @param iq: iterator query state.
1857933707f3Ssthen  * @param id: module id.
1858933707f3Ssthen  * @return true, advancing the event to the QUERYTARGETS_STATE.
1859933707f3Ssthen  */
1860933707f3Ssthen static int
1861933707f3Ssthen processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq,
1862933707f3Ssthen 	int id)
1863933707f3Ssthen {
1864933707f3Ssthen 	log_query_info(VERB_QUERY, "resolving (init part 3): ",
1865933707f3Ssthen 		&qstate->qinfo);
1866933707f3Ssthen 	/* if the cache reply dp equals a validation anchor or msg has DS,
1867933707f3Ssthen 	 * then DNSSEC RRSIGs are expected in the reply */
1868933707f3Ssthen 	iq->dnssec_expected = iter_indicates_dnssec(qstate->env, iq->dp,
1869933707f3Ssthen 		iq->deleg_msg, iq->qchase.qclass);
1870933707f3Ssthen 
1871933707f3Ssthen 	/* If the RD flag wasn't set, then we just finish with the
1872933707f3Ssthen 	 * cached referral as the response. */
18732be9e038Ssthen 	if(!(qstate->query_flags & BIT_RD) && iq->deleg_msg) {
1874933707f3Ssthen 		iq->response = iq->deleg_msg;
18755d76a658Ssthen 		if(verbosity >= VERB_ALGO && iq->response)
1876933707f3Ssthen 			log_dns_msg("no RD requested, using delegation msg",
1877933707f3Ssthen 				&iq->response->qinfo, iq->response->rep);
1878933707f3Ssthen 		if(qstate->reply_origin)
1879933707f3Ssthen 			sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
1880933707f3Ssthen 		return final_state(iq);
1881933707f3Ssthen 	}
1882933707f3Ssthen 	/* After this point, unset the RD flag -- this query is going to
1883933707f3Ssthen 	 * be sent to an auth. server. */
1884933707f3Ssthen 	iq->chase_flags &= ~BIT_RD;
1885933707f3Ssthen 
1886933707f3Ssthen 	/* if dnssec expected, fetch key for the trust-anchor or cached-DS */
1887933707f3Ssthen 	if(iq->dnssec_expected && qstate->env->cfg->prefetch_key &&
1888933707f3Ssthen 		!(qstate->query_flags&BIT_CD)) {
1889933707f3Ssthen 		generate_dnskey_prefetch(qstate, iq, id);
1890933707f3Ssthen 		fptr_ok(fptr_whitelist_modenv_detach_subs(
1891933707f3Ssthen 			qstate->env->detach_subs));
1892933707f3Ssthen 		(*qstate->env->detach_subs)(qstate);
1893933707f3Ssthen 	}
1894933707f3Ssthen 
1895933707f3Ssthen 	/* Jump to the next state. */
1896933707f3Ssthen 	return next_state(iq, QUERYTARGETS_STATE);
1897933707f3Ssthen }
1898933707f3Ssthen 
1899933707f3Ssthen /**
1900933707f3Ssthen  * Given a basic query, generate a parent-side "target" query.
1901933707f3Ssthen  * These are subordinate queries for missing delegation point target addresses,
1902933707f3Ssthen  * for which only the parent of the delegation provides correct IP addresses.
1903933707f3Ssthen  *
1904933707f3Ssthen  * @param qstate: query state.
1905933707f3Ssthen  * @param iq: iterator query state.
1906933707f3Ssthen  * @param id: module id.
1907933707f3Ssthen  * @param name: target qname.
1908933707f3Ssthen  * @param namelen: target qname length.
1909933707f3Ssthen  * @param qtype: target qtype (either A or AAAA).
1910933707f3Ssthen  * @param qclass: target qclass.
1911933707f3Ssthen  * @return true on success, false on failure.
1912933707f3Ssthen  */
1913933707f3Ssthen static int
1914933707f3Ssthen generate_parentside_target_query(struct module_qstate* qstate,
1915933707f3Ssthen 	struct iter_qstate* iq, int id, uint8_t* name, size_t namelen,
1916933707f3Ssthen 	uint16_t qtype, uint16_t qclass)
1917933707f3Ssthen {
1918933707f3Ssthen 	struct module_qstate* subq;
1919933707f3Ssthen 	if(!generate_sub_request(name, namelen, qtype, qclass, qstate,
192006a13c09Ssthen 		id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0))
1921933707f3Ssthen 		return 0;
1922933707f3Ssthen 	if(subq) {
1923933707f3Ssthen 		struct iter_qstate* subiq =
1924933707f3Ssthen 			(struct iter_qstate*)subq->minfo[id];
1925933707f3Ssthen 		/* blacklist the cache - we want to fetch parent stuff */
1926933707f3Ssthen 		sock_list_insert(&subq->blacklist, NULL, 0, subq->region);
1927933707f3Ssthen 		subiq->query_for_pside_glue = 1;
1928933707f3Ssthen 		if(dname_subdomain_c(name, iq->dp->name)) {
1929933707f3Ssthen 			subiq->dp = delegpt_copy(iq->dp, subq->region);
1930933707f3Ssthen 			subiq->dnssec_expected = iter_indicates_dnssec(
1931933707f3Ssthen 				qstate->env, subiq->dp, NULL,
1932933707f3Ssthen 				subq->qinfo.qclass);
1933933707f3Ssthen 			subiq->refetch_glue = 1;
1934933707f3Ssthen 		} else {
1935933707f3Ssthen 			subiq->dp = dns_cache_find_delegation(qstate->env,
1936933707f3Ssthen 				name, namelen, qtype, qclass, subq->region,
1937d8d14d0cSsthen 				&subiq->deleg_msg,
1938d1e2768aSsthen 				*qstate->env->now+subq->prefetch_leeway,
1939d1e2768aSsthen 				1, NULL, 0);
1940933707f3Ssthen 			/* if no dp, then it's from root, refetch unneeded */
1941933707f3Ssthen 			if(subiq->dp) {
1942933707f3Ssthen 				subiq->dnssec_expected = iter_indicates_dnssec(
1943933707f3Ssthen 					qstate->env, subiq->dp, NULL,
1944933707f3Ssthen 					subq->qinfo.qclass);
1945933707f3Ssthen 				subiq->refetch_glue = 1;
1946933707f3Ssthen 			}
1947933707f3Ssthen 		}
1948933707f3Ssthen 	}
1949933707f3Ssthen 	log_nametypeclass(VERB_QUERY, "new pside target", name, qtype, qclass);
1950933707f3Ssthen 	return 1;
1951933707f3Ssthen }
1952933707f3Ssthen 
1953933707f3Ssthen /**
1954933707f3Ssthen  * Given a basic query, generate a "target" query. These are subordinate
1955933707f3Ssthen  * queries for missing delegation point target addresses.
1956933707f3Ssthen  *
1957933707f3Ssthen  * @param qstate: query state.
1958933707f3Ssthen  * @param iq: iterator query state.
1959933707f3Ssthen  * @param id: module id.
1960933707f3Ssthen  * @param name: target qname.
1961933707f3Ssthen  * @param namelen: target qname length.
1962933707f3Ssthen  * @param qtype: target qtype (either A or AAAA).
1963933707f3Ssthen  * @param qclass: target qclass.
1964933707f3Ssthen  * @return true on success, false on failure.
1965933707f3Ssthen  */
1966933707f3Ssthen static int
1967933707f3Ssthen generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
1968933707f3Ssthen         int id, uint8_t* name, size_t namelen, uint16_t qtype, uint16_t qclass)
1969933707f3Ssthen {
1970933707f3Ssthen 	struct module_qstate* subq;
1971933707f3Ssthen 	if(!generate_sub_request(name, namelen, qtype, qclass, qstate,
197206a13c09Ssthen 		id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0))
1973933707f3Ssthen 		return 0;
1974933707f3Ssthen 	log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass);
1975933707f3Ssthen 	return 1;
1976933707f3Ssthen }
1977933707f3Ssthen 
1978933707f3Ssthen /**
1979933707f3Ssthen  * Given an event at a certain state, generate zero or more target queries
1980933707f3Ssthen  * for it's current delegation point.
1981933707f3Ssthen  *
1982933707f3Ssthen  * @param qstate: query state.
1983933707f3Ssthen  * @param iq: iterator query state.
1984933707f3Ssthen  * @param ie: iterator shared global environment.
1985933707f3Ssthen  * @param id: module id.
1986933707f3Ssthen  * @param maxtargets: The maximum number of targets to query for.
1987933707f3Ssthen  *	if it is negative, there is no maximum number of targets.
1988933707f3Ssthen  * @param num: returns the number of queries generated and processed,
1989933707f3Ssthen  *	which may be zero if there were no missing targets.
1990*98bc733bSsthen  * @return 0 on success, nonzero on error. 1 means temporary failure and
1991*98bc733bSsthen  * 	2 means the failure can be cached.
1992933707f3Ssthen  */
1993933707f3Ssthen static int
1994933707f3Ssthen query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
1995933707f3Ssthen         struct iter_env* ie, int id, int maxtargets, int* num)
1996933707f3Ssthen {
1997933707f3Ssthen 	int query_count = 0;
1998933707f3Ssthen 	struct delegpt_ns* ns;
1999933707f3Ssthen 	int missing;
2000933707f3Ssthen 	int toget = 0;
2001933707f3Ssthen 
20020bdb4f62Ssthen 	iter_mark_cycle_targets(qstate, iq->dp);
2003d1e2768aSsthen 	missing = (int)delegpt_count_missing_targets(iq->dp, NULL);
20040bdb4f62Ssthen 	log_assert(maxtargets != 0); /* that would not be useful */
20050bdb4f62Ssthen 
20060bdb4f62Ssthen 	/* Generate target requests. Basically, any missing targets
20070bdb4f62Ssthen 	 * are queried for here, regardless if it is necessary to do
20080bdb4f62Ssthen 	 * so to continue processing. */
20090bdb4f62Ssthen 	if(maxtargets < 0 || maxtargets > missing)
20100bdb4f62Ssthen 		toget = missing;
20110bdb4f62Ssthen 	else	toget = maxtargets;
20120bdb4f62Ssthen 	if(toget == 0) {
20130bdb4f62Ssthen 		*num = 0;
2014*98bc733bSsthen 		return 0;
20150bdb4f62Ssthen 	}
20160bdb4f62Ssthen 
20170bdb4f62Ssthen 	/* now that we are sure that a target query is going to be made,
20180bdb4f62Ssthen 	 * check the limits. */
2019933707f3Ssthen 	if(iq->depth == ie->max_dependency_depth)
2020*98bc733bSsthen 		return 1;
2021ae1dea89Sflorian 	if(iq->depth > 0 && iq->target_count &&
2022d1e2768aSsthen 		iq->target_count[TARGET_COUNT_QUERIES] > MAX_TARGET_COUNT) {
202331f127bbSsthen 		char s[LDNS_MAX_DOMAINLEN+1];
202431f127bbSsthen 		dname_str(qstate->qinfo.qname, s);
202531f127bbSsthen 		verbose(VERB_QUERY, "request %s has exceeded the maximum "
2026d1e2768aSsthen 			"number of glue fetches %d", s,
2027d1e2768aSsthen 			iq->target_count[TARGET_COUNT_QUERIES]);
2028*98bc733bSsthen 		return 2;
2029ae1dea89Sflorian 	}
203006a13c09Ssthen 	if(iq->dp_target_count > MAX_DP_TARGET_COUNT) {
203106a13c09Ssthen 		char s[LDNS_MAX_DOMAINLEN+1];
203206a13c09Ssthen 		dname_str(qstate->qinfo.qname, s);
203306a13c09Ssthen 		verbose(VERB_QUERY, "request %s has exceeded the maximum "
203406a13c09Ssthen 			"number of glue fetches %d to a single delegation point",
203506a13c09Ssthen 			s, iq->dp_target_count);
2036*98bc733bSsthen 		return 2;
203706a13c09Ssthen 	}
2038933707f3Ssthen 
2039933707f3Ssthen 	/* select 'toget' items from the total of 'missing' items */
2040933707f3Ssthen 	log_assert(toget <= missing);
2041933707f3Ssthen 
2042933707f3Ssthen 	/* loop over missing targets */
2043933707f3Ssthen 	for(ns = iq->dp->nslist; ns; ns = ns->next) {
2044933707f3Ssthen 		if(ns->resolved)
2045933707f3Ssthen 			continue;
2046933707f3Ssthen 
2047933707f3Ssthen 		/* randomly select this item with probability toget/missing */
2048933707f3Ssthen 		if(!iter_ns_probability(qstate->env->rnd, toget, missing)) {
2049933707f3Ssthen 			/* do not select this one, next; select toget number
2050933707f3Ssthen 			 * of items from a list one less in size */
2051933707f3Ssthen 			missing --;
2052933707f3Ssthen 			continue;
2053933707f3Ssthen 		}
2054933707f3Ssthen 
2055d1e2768aSsthen 		if(ie->supports_ipv6 &&
2056d1e2768aSsthen 			((ns->lame && !ns->done_pside6) ||
2057d1e2768aSsthen 			(!ns->lame && !ns->got6))) {
2058933707f3Ssthen 			/* Send the AAAA request. */
2059933707f3Ssthen 			if(!generate_target_query(qstate, iq, id,
2060933707f3Ssthen 				ns->name, ns->namelen,
2061933707f3Ssthen 				LDNS_RR_TYPE_AAAA, iq->qchase.qclass)) {
2062933707f3Ssthen 				*num = query_count;
2063933707f3Ssthen 				if(query_count > 0)
2064933707f3Ssthen 					qstate->ext_state[id] = module_wait_subquery;
2065*98bc733bSsthen 				return 1;
2066933707f3Ssthen 			}
2067933707f3Ssthen 			query_count++;
20687dd170e2Ssthen 			/* If the mesh query list is full, exit the loop here.
20697dd170e2Ssthen 			 * This makes the routine spawn one query at a time,
20707dd170e2Ssthen 			 * and this means there is no query state load
20717dd170e2Ssthen 			 * increase, because the spawned state uses cpu and a
20727dd170e2Ssthen 			 * socket while this state waits for that spawned
20737dd170e2Ssthen 			 * state. Next time we can look up further targets */
2074*98bc733bSsthen 			if(mesh_jostle_exceeded(qstate->env->mesh)) {
2075*98bc733bSsthen 				/* If no ip4 query is possible, that makes
2076*98bc733bSsthen 				 * this ns resolved. */
2077*98bc733bSsthen 				if(!((ie->supports_ipv4 || ie->use_nat64) &&
2078*98bc733bSsthen 					((ns->lame && !ns->done_pside4) ||
2079*98bc733bSsthen 					(!ns->lame && !ns->got4)))) {
2080*98bc733bSsthen 					ns->resolved = 1;
2081*98bc733bSsthen 				}
20827dd170e2Ssthen 				break;
2083933707f3Ssthen 		}
2084*98bc733bSsthen 		}
2085933707f3Ssthen 		/* Send the A request. */
20868b7325afSsthen 		if((ie->supports_ipv4 || ie->use_nat64) &&
2087d1e2768aSsthen 			((ns->lame && !ns->done_pside4) ||
2088d1e2768aSsthen 			(!ns->lame && !ns->got4))) {
2089933707f3Ssthen 			if(!generate_target_query(qstate, iq, id,
2090933707f3Ssthen 				ns->name, ns->namelen,
2091933707f3Ssthen 				LDNS_RR_TYPE_A, iq->qchase.qclass)) {
2092933707f3Ssthen 				*num = query_count;
2093933707f3Ssthen 				if(query_count > 0)
2094933707f3Ssthen 					qstate->ext_state[id] = module_wait_subquery;
2095*98bc733bSsthen 				return 1;
2096933707f3Ssthen 			}
2097933707f3Ssthen 			query_count++;
20987dd170e2Ssthen 			/* If the mesh query list is full, exit the loop. */
2099*98bc733bSsthen 			if(mesh_jostle_exceeded(qstate->env->mesh)) {
2100*98bc733bSsthen 				/* With the ip6 query already checked for,
2101*98bc733bSsthen 				 * this makes the ns resolved. It is no longer
2102*98bc733bSsthen 				 * a missing target. */
2103*98bc733bSsthen 				ns->resolved = 1;
21047dd170e2Ssthen 				break;
2105933707f3Ssthen 		}
2106*98bc733bSsthen 		}
2107933707f3Ssthen 
2108933707f3Ssthen 		/* mark this target as in progress. */
2109933707f3Ssthen 		ns->resolved = 1;
2110933707f3Ssthen 		missing--;
2111933707f3Ssthen 		toget--;
2112933707f3Ssthen 		if(toget == 0)
2113933707f3Ssthen 			break;
2114933707f3Ssthen 	}
2115933707f3Ssthen 	*num = query_count;
2116933707f3Ssthen 	if(query_count > 0)
2117933707f3Ssthen 		qstate->ext_state[id] = module_wait_subquery;
2118933707f3Ssthen 
2119*98bc733bSsthen 	return 0;
2120933707f3Ssthen }
2121933707f3Ssthen 
2122933707f3Ssthen /**
2123933707f3Ssthen  * Called by processQueryTargets when it would like extra targets to query
2124933707f3Ssthen  * but it seems to be out of options.  At last resort some less appealing
2125933707f3Ssthen  * options are explored.  If there are no more options, the result is SERVFAIL
2126933707f3Ssthen  *
2127933707f3Ssthen  * @param qstate: query state.
2128933707f3Ssthen  * @param iq: iterator query state.
2129933707f3Ssthen  * @param ie: iterator shared global environment.
2130933707f3Ssthen  * @param id: module id.
2131933707f3Ssthen  * @return true if the event requires more request processing immediately,
2132933707f3Ssthen  *         false if not.
2133933707f3Ssthen  */
2134933707f3Ssthen static int
2135933707f3Ssthen processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
2136933707f3Ssthen 	struct iter_env* ie, int id)
2137933707f3Ssthen {
2138933707f3Ssthen 	struct delegpt_ns* ns;
2139933707f3Ssthen 	int query_count = 0;
2140933707f3Ssthen 	verbose(VERB_ALGO, "No more query targets, attempting last resort");
2141933707f3Ssthen 	log_assert(iq->dp);
2142933707f3Ssthen 
21432be9e038Ssthen 	if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
21442bdc0ed1Ssthen 		iq->qchase.qclass, NULL, NULL, NULL)) {
2145229e174cSsthen 		/* fail -- no more targets, no more hope of targets, no hope
2146229e174cSsthen 		 * of a response. */
21472308e98cSsthen 		errinf(qstate, "all the configured stub or forward servers failed,");
21482308e98cSsthen 		errinf_dname(qstate, "at zone", iq->dp->name);
2149191f22c6Ssthen 		errinf_reply(qstate, iq);
21502be9e038Ssthen 		verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL");
2151229e174cSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2152229e174cSsthen 	}
21533dcb24b8Ssthen 	if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
21542bdc0ed1Ssthen 		struct delegpt* dp;
21552bdc0ed1Ssthen 		int nolock = 0;
21562bdc0ed1Ssthen 		dp = hints_find_root(qstate->env->hints,
21572bdc0ed1Ssthen 			iq->qchase.qclass, nolock);
21582bdc0ed1Ssthen 		if(dp) {
21593dcb24b8Ssthen 			struct delegpt_addr* a;
2160229e174cSsthen 			iq->chase_flags &= ~BIT_RD; /* go to authorities */
21612bdc0ed1Ssthen 			for(ns = dp->nslist; ns; ns=ns->next) {
21623dcb24b8Ssthen 				(void)delegpt_add_ns(iq->dp, qstate->region,
2163e21c60efSsthen 					ns->name, ns->lame, ns->tls_auth_name,
2164e21c60efSsthen 					ns->port);
21653dcb24b8Ssthen 			}
21662bdc0ed1Ssthen 			for(a = dp->target_list; a; a=a->next_target) {
21673dcb24b8Ssthen 				(void)delegpt_add_addr(iq->dp, qstate->region,
21683dcb24b8Ssthen 					&a->addr, a->addrlen, a->bogus,
2169e21c60efSsthen 					a->lame, a->tls_auth_name, -1, NULL);
21703dcb24b8Ssthen 			}
21712bdc0ed1Ssthen 			lock_rw_unlock(&qstate->env->hints->lock);
21723dcb24b8Ssthen 		}
21733dcb24b8Ssthen 		iq->dp->has_parent_side_NS = 1;
21743dcb24b8Ssthen 	} else if(!iq->dp->has_parent_side_NS) {
2175933707f3Ssthen 		if(!iter_lookup_parent_NS_from_cache(qstate->env, iq->dp,
2176933707f3Ssthen 			qstate->region, &qstate->qinfo)
2177933707f3Ssthen 			|| !iq->dp->has_parent_side_NS) {
2178933707f3Ssthen 			/* if: malloc failure in lookup go up to try */
2179933707f3Ssthen 			/* if: no parent NS in cache - go up one level */
2180933707f3Ssthen 			verbose(VERB_ALGO, "try to grab parent NS");
2181933707f3Ssthen 			iq->store_parent_NS = iq->dp;
2182229e174cSsthen 			iq->chase_flags &= ~BIT_RD; /* go to authorities */
2183933707f3Ssthen 			iq->deleg_msg = NULL;
2184933707f3Ssthen 			iq->refetch_glue = 1;
2185933707f3Ssthen 			iq->query_restart_count++;
2186933707f3Ssthen 			iq->sent_count = 0;
218706a13c09Ssthen 			iq->dp_target_count = 0;
218824893edcSsthen 			if(qstate->env->cfg->qname_minimisation)
218924893edcSsthen 				iq->minimisation_state = INIT_MINIMISE_STATE;
2190933707f3Ssthen 			return next_state(iq, INIT_REQUEST_STATE);
2191933707f3Ssthen 		}
2192933707f3Ssthen 	}
2193933707f3Ssthen 	/* see if that makes new names available */
2194933707f3Ssthen 	if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
2195933707f3Ssthen 		qstate->region, iq->dp))
2196933707f3Ssthen 		log_err("out of memory in cache_fill_missing");
2197933707f3Ssthen 	if(iq->dp->usable_list) {
2198933707f3Ssthen 		verbose(VERB_ALGO, "try parent-side-name, w. glue from cache");
2199933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
2200933707f3Ssthen 	}
2201933707f3Ssthen 	/* try to fill out parent glue from cache */
2202933707f3Ssthen 	if(iter_lookup_parent_glue_from_cache(qstate->env, iq->dp,
2203933707f3Ssthen 		qstate->region, &qstate->qinfo)) {
2204933707f3Ssthen 		/* got parent stuff from cache, see if we can continue */
2205933707f3Ssthen 		verbose(VERB_ALGO, "try parent-side glue from cache");
2206933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
2207933707f3Ssthen 	}
2208933707f3Ssthen 	/* query for an extra name added by the parent-NS record */
2209d1e2768aSsthen 	if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
2210*98bc733bSsthen 		int qs = 0, ret;
2211933707f3Ssthen 		verbose(VERB_ALGO, "try parent-side target name");
2212*98bc733bSsthen 		if((ret=query_for_targets(qstate, iq, ie, id, 1, &qs))!=0) {
22132308e98cSsthen 			errinf(qstate, "could not fetch nameserver");
22142308e98cSsthen 			errinf_dname(qstate, "at zone", iq->dp->name);
2215*98bc733bSsthen 			if(ret == 1)
2216933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2217*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2218933707f3Ssthen 		}
2219933707f3Ssthen 		iq->num_target_queries += qs;
2220ae1dea89Sflorian 		target_count_increase(iq, qs);
2221933707f3Ssthen 		if(qs != 0) {
2222933707f3Ssthen 			qstate->ext_state[id] = module_wait_subquery;
2223933707f3Ssthen 			return 0; /* and wait for them */
2224933707f3Ssthen 		}
2225933707f3Ssthen 	}
2226933707f3Ssthen 	if(iq->depth == ie->max_dependency_depth) {
2227933707f3Ssthen 		verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
22282308e98cSsthen 		errinf(qstate, "cannot fetch more nameservers because at max dependency depth");
2229933707f3Ssthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2230933707f3Ssthen 	}
2231ae1dea89Sflorian 	if(iq->depth > 0 && iq->target_count &&
2232d1e2768aSsthen 		iq->target_count[TARGET_COUNT_QUERIES] > MAX_TARGET_COUNT) {
223331f127bbSsthen 		char s[LDNS_MAX_DOMAINLEN+1];
223431f127bbSsthen 		dname_str(qstate->qinfo.qname, s);
223531f127bbSsthen 		verbose(VERB_QUERY, "request %s has exceeded the maximum "
2236d1e2768aSsthen 			"number of glue fetches %d", s,
2237d1e2768aSsthen 			iq->target_count[TARGET_COUNT_QUERIES]);
22382308e98cSsthen 		errinf(qstate, "exceeded the maximum number of glue fetches");
2239ae1dea89Sflorian 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2240ae1dea89Sflorian 	}
2241933707f3Ssthen 	/* mark cycle targets for parent-side lookups */
2242933707f3Ssthen 	iter_mark_pside_cycle_targets(qstate, iq->dp);
2243933707f3Ssthen 	/* see if we can issue queries to get nameserver addresses */
2244933707f3Ssthen 	/* this lookup is not randomized, but sequential. */
2245933707f3Ssthen 	for(ns = iq->dp->nslist; ns; ns = ns->next) {
22462be9e038Ssthen 		/* if this nameserver is at a delegation point, but that
22472be9e038Ssthen 		 * delegation point is a stub and we cannot go higher, skip*/
22482be9e038Ssthen 		if( ((ie->supports_ipv6 && !ns->done_pside6) ||
22498b7325afSsthen 		    ((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) &&
22502be9e038Ssthen 		    !can_have_last_resort(qstate->env, ns->name, ns->namelen,
22512bdc0ed1Ssthen 			iq->qchase.qclass, NULL, NULL, NULL)) {
22522be9e038Ssthen 			log_nametypeclass(VERB_ALGO, "cannot pside lookup ns "
22532be9e038Ssthen 				"because it is also a stub/forward,",
22542be9e038Ssthen 				ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
22552be9e038Ssthen 			if(ie->supports_ipv6) ns->done_pside6 = 1;
22568b7325afSsthen 			if(ie->supports_ipv4 || ie->use_nat64) ns->done_pside4 = 1;
22572be9e038Ssthen 			continue;
22582be9e038Ssthen 		}
2259933707f3Ssthen 		/* query for parent-side A and AAAA for nameservers */
2260933707f3Ssthen 		if(ie->supports_ipv6 && !ns->done_pside6) {
2261933707f3Ssthen 			/* Send the AAAA request. */
2262933707f3Ssthen 			if(!generate_parentside_target_query(qstate, iq, id,
2263933707f3Ssthen 				ns->name, ns->namelen,
22642308e98cSsthen 				LDNS_RR_TYPE_AAAA, iq->qchase.qclass)) {
22652308e98cSsthen 				errinf_dname(qstate, "could not generate nameserver AAAA lookup for", ns->name);
2266933707f3Ssthen 				return error_response(qstate, id,
2267933707f3Ssthen 					LDNS_RCODE_SERVFAIL);
22682308e98cSsthen 			}
2269933707f3Ssthen 			ns->done_pside6 = 1;
2270933707f3Ssthen 			query_count++;
22717dd170e2Ssthen 			if(mesh_jostle_exceeded(qstate->env->mesh)) {
22727dd170e2Ssthen 				/* Wait for the lookup; do not spawn multiple
22737dd170e2Ssthen 				 * lookups at a time. */
22747dd170e2Ssthen 				verbose(VERB_ALGO, "try parent-side glue lookup");
22757dd170e2Ssthen 				iq->num_target_queries += query_count;
22767dd170e2Ssthen 				target_count_increase(iq, query_count);
22777dd170e2Ssthen 				qstate->ext_state[id] = module_wait_subquery;
22787dd170e2Ssthen 				return 0;
22797dd170e2Ssthen 			}
2280933707f3Ssthen 		}
22818b7325afSsthen 		if((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4) {
2282933707f3Ssthen 			/* Send the A request. */
2283933707f3Ssthen 			if(!generate_parentside_target_query(qstate, iq, id,
2284933707f3Ssthen 				ns->name, ns->namelen,
22852308e98cSsthen 				LDNS_RR_TYPE_A, iq->qchase.qclass)) {
22862308e98cSsthen 				errinf_dname(qstate, "could not generate nameserver A lookup for", ns->name);
2287933707f3Ssthen 				return error_response(qstate, id,
2288933707f3Ssthen 					LDNS_RCODE_SERVFAIL);
22892308e98cSsthen 			}
2290933707f3Ssthen 			ns->done_pside4 = 1;
2291933707f3Ssthen 			query_count++;
2292933707f3Ssthen 		}
2293933707f3Ssthen 		if(query_count != 0) { /* suspend to await results */
2294933707f3Ssthen 			verbose(VERB_ALGO, "try parent-side glue lookup");
2295933707f3Ssthen 			iq->num_target_queries += query_count;
2296ae1dea89Sflorian 			target_count_increase(iq, query_count);
2297933707f3Ssthen 			qstate->ext_state[id] = module_wait_subquery;
2298933707f3Ssthen 			return 0;
2299933707f3Ssthen 		}
2300933707f3Ssthen 	}
2301933707f3Ssthen 
2302933707f3Ssthen 	/* if this was a parent-side glue query itself, then store that
2303933707f3Ssthen 	 * failure in cache. */
230477079be7Ssthen 	if(!qstate->no_cache_store && iq->query_for_pside_glue
230577079be7Ssthen 		&& !iq->pside_glue)
2306933707f3Ssthen 			iter_store_parentside_neg(qstate->env, &qstate->qinfo,
2307933707f3Ssthen 				iq->deleg_msg?iq->deleg_msg->rep:
2308933707f3Ssthen 				(iq->response?iq->response->rep:NULL));
2309933707f3Ssthen 
23102308e98cSsthen 	errinf(qstate, "all servers for this domain failed,");
23112308e98cSsthen 	errinf_dname(qstate, "at zone", iq->dp->name);
2312191f22c6Ssthen 	errinf_reply(qstate, iq);
2313933707f3Ssthen 	verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL");
2314933707f3Ssthen 	/* fail -- no more targets, no more hope of targets, no hope
2315933707f3Ssthen 	 * of a response. */
2316933707f3Ssthen 	return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2317933707f3Ssthen }
2318933707f3Ssthen 
2319933707f3Ssthen /**
2320d8d14d0cSsthen  * Try to find the NS record set that will resolve a qtype DS query. Due
2321d8d14d0cSsthen  * to grandparent/grandchild reasons we did not get a proper lookup right
2322d8d14d0cSsthen  * away.  We need to create type NS queries until we get the right parent
2323d8d14d0cSsthen  * for this lookup.  We remove labels from the query to find the right point.
2324d8d14d0cSsthen  * If we end up at the old dp name, then there is no solution.
2325d8d14d0cSsthen  *
2326d8d14d0cSsthen  * @param qstate: query state.
2327d8d14d0cSsthen  * @param iq: iterator query state.
2328d8d14d0cSsthen  * @param id: module id.
2329d8d14d0cSsthen  * @return true if the event requires more immediate processing, false if
2330d8d14d0cSsthen  *         not. This is generally only true when forwarding the request to
2331d8d14d0cSsthen  *         the final state (i.e., on answer).
2332d8d14d0cSsthen  */
2333d8d14d0cSsthen static int
23343dcb24b8Ssthen processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
2335d8d14d0cSsthen {
2336d8d14d0cSsthen 	struct module_qstate* subq = NULL;
2337d8d14d0cSsthen 	verbose(VERB_ALGO, "processDSNSFind");
2338d8d14d0cSsthen 
2339d8d14d0cSsthen 	if(!iq->dsns_point) {
2340d8d14d0cSsthen 		/* initialize */
2341d8d14d0cSsthen 		iq->dsns_point = iq->qchase.qname;
2342d8d14d0cSsthen 		iq->dsns_point_len = iq->qchase.qname_len;
2343d8d14d0cSsthen 	}
2344d8d14d0cSsthen 	/* robustcheck for internal error: we are not underneath the dp */
2345d8d14d0cSsthen 	if(!dname_subdomain_c(iq->dsns_point, iq->dp->name)) {
23462308e98cSsthen 		errinf_dname(qstate, "for DS query parent-child nameserver search the query is not under the zone", iq->dp->name);
2347d8d14d0cSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2348d8d14d0cSsthen 	}
2349d8d14d0cSsthen 
2350d8d14d0cSsthen 	/* go up one (more) step, until we hit the dp, if so, end */
2351d8d14d0cSsthen 	dname_remove_label(&iq->dsns_point, &iq->dsns_point_len);
2352d8d14d0cSsthen 	if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) {
2353d8d14d0cSsthen 		/* there was no inbetween nameserver, use the old delegation
2354d8d14d0cSsthen 		 * point again.  And this time, because dsns_point is nonNULL
2355d8d14d0cSsthen 		 * we are going to accept the (bad) result */
2356d8d14d0cSsthen 		iq->state = QUERYTARGETS_STATE;
2357d8d14d0cSsthen 		return 1;
2358d8d14d0cSsthen 	}
2359d8d14d0cSsthen 	iq->state = DSNS_FIND_STATE;
2360d8d14d0cSsthen 
2361d8d14d0cSsthen 	/* spawn NS lookup (validation not needed, this is for DS lookup) */
2362d8d14d0cSsthen 	log_nametypeclass(VERB_ALGO, "fetch nameservers",
2363d8d14d0cSsthen 		iq->dsns_point, LDNS_RR_TYPE_NS, iq->qchase.qclass);
2364d8d14d0cSsthen 	if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len,
2365d8d14d0cSsthen 		LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
236606a13c09Ssthen 		INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) {
23672308e98cSsthen 		errinf_dname(qstate, "for DS query parent-child nameserver search, could not generate NS lookup for", iq->dsns_point);
2368d8d14d0cSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2369d8d14d0cSsthen 	}
2370d8d14d0cSsthen 
2371d8d14d0cSsthen 	return 0;
2372d8d14d0cSsthen }
2373d8d14d0cSsthen 
2374d8d14d0cSsthen /**
2375d1e2768aSsthen  * Check if we wait responses for sent queries and update the iterator's
2376d1e2768aSsthen  * external state.
2377d1e2768aSsthen  */
2378d1e2768aSsthen static void
2379d1e2768aSsthen check_waiting_queries(struct iter_qstate* iq, struct module_qstate* qstate,
2380d1e2768aSsthen 	int id)
2381d1e2768aSsthen {
2382d1e2768aSsthen 	if(iq->num_target_queries>0 && iq->num_current_queries>0) {
2383d1e2768aSsthen 		verbose(VERB_ALGO, "waiting for %d targets to "
2384d1e2768aSsthen 			"resolve or %d outstanding queries to "
2385d1e2768aSsthen 			"respond", iq->num_target_queries,
2386d1e2768aSsthen 			iq->num_current_queries);
2387d1e2768aSsthen 		qstate->ext_state[id] = module_wait_reply;
2388d1e2768aSsthen 	} else if(iq->num_target_queries>0) {
2389d1e2768aSsthen 		verbose(VERB_ALGO, "waiting for %d targets to "
2390d1e2768aSsthen 			"resolve", iq->num_target_queries);
2391d1e2768aSsthen 		qstate->ext_state[id] = module_wait_subquery;
2392d1e2768aSsthen 	} else {
2393d1e2768aSsthen 		verbose(VERB_ALGO, "waiting for %d "
2394d1e2768aSsthen 			"outstanding queries to respond",
2395d1e2768aSsthen 			iq->num_current_queries);
2396d1e2768aSsthen 		qstate->ext_state[id] = module_wait_reply;
2397d1e2768aSsthen 	}
2398d1e2768aSsthen }
2399d1e2768aSsthen 
2400d1e2768aSsthen /**
2401933707f3Ssthen  * This is the request event state where the request will be sent to one of
2402933707f3Ssthen  * its current query targets. This state also handles issuing target lookup
2403933707f3Ssthen  * queries for missing target IP addresses. Queries typically iterate on
2404933707f3Ssthen  * this state, both when they are just trying different targets for a given
2405933707f3Ssthen  * delegation point, and when they change delegation points. This state
2406933707f3Ssthen  * roughly corresponds to RFC 1034 algorithm steps 3 and 4.
2407933707f3Ssthen  *
2408933707f3Ssthen  * @param qstate: query state.
2409933707f3Ssthen  * @param iq: iterator query state.
2410933707f3Ssthen  * @param ie: iterator shared global environment.
2411933707f3Ssthen  * @param id: module id.
2412933707f3Ssthen  * @return true if the event requires more request processing immediately,
2413933707f3Ssthen  *         false if not. This state only returns true when it is generating
2414933707f3Ssthen  *         a SERVFAIL response because the query has hit a dead end.
2415933707f3Ssthen  */
2416933707f3Ssthen static int
2417933707f3Ssthen processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
2418933707f3Ssthen 	struct iter_env* ie, int id)
2419933707f3Ssthen {
2420933707f3Ssthen 	int tf_policy;
2421933707f3Ssthen 	struct delegpt_addr* target;
2422933707f3Ssthen 	struct outbound_entry* outq;
24238b7325afSsthen 	struct sockaddr_storage real_addr;
24248b7325afSsthen 	socklen_t real_addrlen;
2425938a3a5eSflorian 	int auth_fallback = 0;
2426c3b38330Ssthen 	uint8_t* qout_orig = NULL;
2427c3b38330Ssthen 	size_t qout_orig_len = 0;
2428e21c60efSsthen 	int sq_check_ratelimit = 1;
2429e21c60efSsthen 	int sq_was_ratelimited = 0;
243045872187Ssthen 	int can_do_promisc = 0;
2431933707f3Ssthen 
2432933707f3Ssthen 	/* NOTE: a request will encounter this state for each target it
2433933707f3Ssthen 	 * needs to send a query to. That is, at least one per referral,
2434933707f3Ssthen 	 * more if some targets timeout or return throwaway answers. */
2435933707f3Ssthen 
2436933707f3Ssthen 	log_query_info(VERB_QUERY, "processQueryTargets:", &qstate->qinfo);
2437933707f3Ssthen 	verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
2438933707f3Ssthen 		"currentqueries %d sentcount %d", iq->num_target_queries,
2439933707f3Ssthen 		iq->num_current_queries, iq->sent_count);
2440933707f3Ssthen 
2441933707f3Ssthen 	/* Make sure that we haven't run away */
2442933707f3Ssthen 	if(iq->referral_count > MAX_REFERRAL_COUNT) {
2443933707f3Ssthen 		verbose(VERB_QUERY, "request has exceeded the maximum "
2444933707f3Ssthen 			"number of referrrals with %d", iq->referral_count);
24452308e98cSsthen 		errinf(qstate, "exceeded the maximum of referrals");
2446*98bc733bSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2447933707f3Ssthen 	}
24488b7325afSsthen 	if(iq->sent_count > ie->max_sent_count) {
2449933707f3Ssthen 		verbose(VERB_QUERY, "request has exceeded the maximum "
2450933707f3Ssthen 			"number of sends with %d", iq->sent_count);
24512308e98cSsthen 		errinf(qstate, "exceeded the maximum number of sends");
2452*98bc733bSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2453933707f3Ssthen 	}
2454d1e2768aSsthen 
2455d1e2768aSsthen 	/* Check if we reached MAX_TARGET_NX limit without a fallback activation. */
2456d1e2768aSsthen 	if(iq->target_count && !*iq->nxns_dp &&
2457d1e2768aSsthen 		iq->target_count[TARGET_COUNT_NX] > MAX_TARGET_NX) {
2458d1e2768aSsthen 		struct delegpt_ns* ns;
2459d1e2768aSsthen 		/* If we can wait for resolution, do so. */
2460d1e2768aSsthen 		if(iq->num_target_queries>0 || iq->num_current_queries>0) {
2461d1e2768aSsthen 			check_waiting_queries(iq, qstate, id);
2462d1e2768aSsthen 			return 0;
2463d1e2768aSsthen 		}
2464d1e2768aSsthen 		verbose(VERB_ALGO, "request has exceeded the maximum "
2465d1e2768aSsthen 			"number of nxdomain nameserver lookups (%d) with %d",
2466d1e2768aSsthen 			MAX_TARGET_NX, iq->target_count[TARGET_COUNT_NX]);
2467d1e2768aSsthen 		/* Check for dp because we require one below */
2468d1e2768aSsthen 		if(!iq->dp) {
2469d1e2768aSsthen 			verbose(VERB_QUERY, "Failed to get a delegation, "
2470d1e2768aSsthen 				"giving up");
2471d1e2768aSsthen 			errinf(qstate, "failed to get a delegation (eg. prime "
2472d1e2768aSsthen 				"failure)");
2473d1e2768aSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2474d1e2768aSsthen 		}
2475d1e2768aSsthen 		/* We reached the limit but we already have parent side
2476d1e2768aSsthen 		 * information; stop resolution */
2477d1e2768aSsthen 		if(iq->dp->has_parent_side_NS) {
2478d1e2768aSsthen 			verbose(VERB_ALGO, "parent-side information is "
2479d1e2768aSsthen 				"already present for the delegation point, no "
2480d1e2768aSsthen 				"fallback possible");
248106a13c09Ssthen 			errinf(qstate, "exceeded the maximum nameserver nxdomains");
2482*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
248306a13c09Ssthen 		}
2484d1e2768aSsthen 		verbose(VERB_ALGO, "initiating parent-side fallback for "
2485d1e2768aSsthen 			"nxdomain nameserver lookups");
2486d1e2768aSsthen 		/* Mark all the current NSes as resolved to allow for parent
2487d1e2768aSsthen 		 * fallback */
2488d1e2768aSsthen 		for(ns=iq->dp->nslist; ns; ns=ns->next) {
2489d1e2768aSsthen 			ns->resolved = 1;
2490d1e2768aSsthen 		}
2491d1e2768aSsthen 		/* Note the delegation point that triggered the NXNS fallback;
2492d1e2768aSsthen 		 * no reason for shared queries to keep trying there.
2493d1e2768aSsthen 		 * This also marks the fallback activation. */
2494d1e2768aSsthen 		*iq->nxns_dp = malloc(iq->dp->namelen);
2495d1e2768aSsthen 		if(!*iq->nxns_dp) {
2496d1e2768aSsthen 			verbose(VERB_ALGO, "out of memory while initiating "
2497d1e2768aSsthen 				"fallback");
2498d1e2768aSsthen 			errinf(qstate, "exceeded the maximum nameserver "
2499d1e2768aSsthen 				"nxdomains (malloc)");
2500d1e2768aSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2501d1e2768aSsthen 		}
2502d1e2768aSsthen 		memcpy(*iq->nxns_dp, iq->dp->name, iq->dp->namelen);
2503d1e2768aSsthen 	} else if(iq->target_count && *iq->nxns_dp) {
2504d1e2768aSsthen 		/* Handle the NXNS fallback case. */
2505d1e2768aSsthen 		/* If we can wait for resolution, do so. */
2506d1e2768aSsthen 		if(iq->num_target_queries>0 || iq->num_current_queries>0) {
2507d1e2768aSsthen 			check_waiting_queries(iq, qstate, id);
2508d1e2768aSsthen 			return 0;
2509d1e2768aSsthen 		}
2510d1e2768aSsthen 		/* Check for dp because we require one below */
2511d1e2768aSsthen 		if(!iq->dp) {
2512d1e2768aSsthen 			verbose(VERB_QUERY, "Failed to get a delegation, "
2513d1e2768aSsthen 				"giving up");
2514d1e2768aSsthen 			errinf(qstate, "failed to get a delegation (eg. prime "
2515d1e2768aSsthen 				"failure)");
2516d1e2768aSsthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2517d1e2768aSsthen 		}
2518d1e2768aSsthen 
2519d1e2768aSsthen 		if(iq->target_count[TARGET_COUNT_NX] > MAX_TARGET_NX_FALLBACK) {
2520d1e2768aSsthen 			verbose(VERB_ALGO, "request has exceeded the maximum "
2521d1e2768aSsthen 				"number of fallback nxdomain nameserver "
2522d1e2768aSsthen 				"lookups (%d) with %d", MAX_TARGET_NX_FALLBACK,
2523d1e2768aSsthen 				iq->target_count[TARGET_COUNT_NX]);
2524d1e2768aSsthen 			errinf(qstate, "exceeded the maximum nameserver nxdomains");
2525*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2526d1e2768aSsthen 		}
2527d1e2768aSsthen 
2528d1e2768aSsthen 		if(!iq->dp->has_parent_side_NS) {
2529d1e2768aSsthen 			struct delegpt_ns* ns;
2530d1e2768aSsthen 			if(!dname_canonical_compare(*iq->nxns_dp, iq->dp->name)) {
2531d1e2768aSsthen 				verbose(VERB_ALGO, "this delegation point "
2532d1e2768aSsthen 					"initiated the fallback, marking the "
2533d1e2768aSsthen 					"nslist as resolved");
2534d1e2768aSsthen 				for(ns=iq->dp->nslist; ns; ns=ns->next) {
2535d1e2768aSsthen 					ns->resolved = 1;
2536d1e2768aSsthen 				}
2537d1e2768aSsthen 			}
2538d1e2768aSsthen 		}
2539d1e2768aSsthen 	}
2540933707f3Ssthen 
2541933707f3Ssthen 	/* Make sure we have a delegation point, otherwise priming failed
2542933707f3Ssthen 	 * or another failure occurred */
2543933707f3Ssthen 	if(!iq->dp) {
2544933707f3Ssthen 		verbose(VERB_QUERY, "Failed to get a delegation, giving up");
25452308e98cSsthen 		errinf(qstate, "failed to get a delegation (eg. prime failure)");
2546933707f3Ssthen 		return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2547933707f3Ssthen 	}
2548933707f3Ssthen 	if(!ie->supports_ipv6)
2549933707f3Ssthen 		delegpt_no_ipv6(iq->dp);
25508b7325afSsthen 	if(!ie->supports_ipv4 && !ie->use_nat64)
2551933707f3Ssthen 		delegpt_no_ipv4(iq->dp);
2552933707f3Ssthen 	delegpt_log(VERB_ALGO, iq->dp);
2553933707f3Ssthen 
2554933707f3Ssthen 	if(iq->num_current_queries>0) {
2555933707f3Ssthen 		/* already busy answering a query, this restart is because
2556933707f3Ssthen 		 * more delegpt addrs became available, wait for existing
2557933707f3Ssthen 		 * query. */
2558933707f3Ssthen 		verbose(VERB_ALGO, "woke up, but wait for outstanding query");
2559933707f3Ssthen 		qstate->ext_state[id] = module_wait_reply;
2560933707f3Ssthen 		return 0;
2561933707f3Ssthen 	}
2562933707f3Ssthen 
2563452a1548Ssthen 	if(iq->minimisation_state == INIT_MINIMISE_STATE
2564452a1548Ssthen 		&& !(iq->chase_flags & BIT_RD)) {
2565938a3a5eSflorian 		/* (Re)set qinfo_out to (new) delegation point, except when
2566938a3a5eSflorian 		 * qinfo_out is already a subdomain of dp. This happens when
2567938a3a5eSflorian 		 * increasing by more than one label at once (QNAMEs with more
2568938a3a5eSflorian 		 * than MAX_MINIMISE_COUNT labels). */
2569938a3a5eSflorian 		if(!(iq->qinfo_out.qname_len
2570938a3a5eSflorian 			&& dname_subdomain_c(iq->qchase.qname,
2571938a3a5eSflorian 				iq->qinfo_out.qname)
2572938a3a5eSflorian 			&& dname_subdomain_c(iq->qinfo_out.qname,
2573938a3a5eSflorian 				iq->dp->name))) {
2574938a3a5eSflorian 			iq->qinfo_out.qname = iq->dp->name;
2575938a3a5eSflorian 			iq->qinfo_out.qname_len = iq->dp->namelen;
2576938a3a5eSflorian 			iq->qinfo_out.qtype = LDNS_RR_TYPE_A;
2577938a3a5eSflorian 			iq->qinfo_out.qclass = iq->qchase.qclass;
2578938a3a5eSflorian 			iq->qinfo_out.local_alias = NULL;
2579938a3a5eSflorian 			iq->minimise_count = 0;
2580938a3a5eSflorian 		}
2581938a3a5eSflorian 
2582938a3a5eSflorian 		iq->minimisation_state = MINIMISE_STATE;
2583938a3a5eSflorian 	}
2584938a3a5eSflorian 	if(iq->minimisation_state == MINIMISE_STATE) {
2585938a3a5eSflorian 		int qchaselabs = dname_count_labels(iq->qchase.qname);
2586938a3a5eSflorian 		int labdiff = qchaselabs -
2587938a3a5eSflorian 			dname_count_labels(iq->qinfo_out.qname);
2588938a3a5eSflorian 
2589c3b38330Ssthen 		qout_orig = iq->qinfo_out.qname;
2590c3b38330Ssthen 		qout_orig_len = iq->qinfo_out.qname_len;
2591938a3a5eSflorian 		iq->qinfo_out.qname = iq->qchase.qname;
2592938a3a5eSflorian 		iq->qinfo_out.qname_len = iq->qchase.qname_len;
2593938a3a5eSflorian 		iq->minimise_count++;
2594a3167c07Ssthen 		iq->timeout_count = 0;
2595938a3a5eSflorian 
2596e21c60efSsthen 		iter_dec_attempts(iq->dp, 1, ie->outbound_msg_retry);
2597938a3a5eSflorian 
2598938a3a5eSflorian 		/* Limit number of iterations for QNAMEs with more
2599938a3a5eSflorian 		 * than MAX_MINIMISE_COUNT labels. Send first MINIMISE_ONE_LAB
2600938a3a5eSflorian 		 * labels of QNAME always individually.
2601938a3a5eSflorian 		 */
2602938a3a5eSflorian 		if(qchaselabs > MAX_MINIMISE_COUNT && labdiff > 1 &&
2603938a3a5eSflorian 			iq->minimise_count > MINIMISE_ONE_LAB) {
2604938a3a5eSflorian 			if(iq->minimise_count < MAX_MINIMISE_COUNT) {
2605938a3a5eSflorian 				int multilabs = qchaselabs - 1 -
2606938a3a5eSflorian 					MINIMISE_ONE_LAB;
2607938a3a5eSflorian 				int extralabs = multilabs /
2608938a3a5eSflorian 					MINIMISE_MULTIPLE_LABS;
2609938a3a5eSflorian 
2610938a3a5eSflorian 				if (MAX_MINIMISE_COUNT - iq->minimise_count >=
2611938a3a5eSflorian 					multilabs % MINIMISE_MULTIPLE_LABS)
2612938a3a5eSflorian 					/* Default behaviour is to add 1 label
2613938a3a5eSflorian 					 * every iteration. Therefore, decrement
2614938a3a5eSflorian 					 * the extralabs by 1 */
2615938a3a5eSflorian 					extralabs--;
2616938a3a5eSflorian 				if (extralabs < labdiff)
2617938a3a5eSflorian 					labdiff -= extralabs;
2618938a3a5eSflorian 				else
2619938a3a5eSflorian 					labdiff = 1;
2620938a3a5eSflorian 			}
2621938a3a5eSflorian 			/* Last minimised iteration, send all labels with
2622938a3a5eSflorian 			 * QTYPE=NS */
2623938a3a5eSflorian 			else
2624938a3a5eSflorian 				labdiff = 1;
2625938a3a5eSflorian 		}
2626938a3a5eSflorian 
2627938a3a5eSflorian 		if(labdiff > 1) {
2628938a3a5eSflorian 			verbose(VERB_QUERY, "removing %d labels", labdiff-1);
2629938a3a5eSflorian 			dname_remove_labels(&iq->qinfo_out.qname,
2630938a3a5eSflorian 				&iq->qinfo_out.qname_len,
2631938a3a5eSflorian 				labdiff-1);
2632938a3a5eSflorian 		}
2633938a3a5eSflorian 		if(labdiff < 1 || (labdiff < 2
2634938a3a5eSflorian 			&& (iq->qchase.qtype == LDNS_RR_TYPE_DS
2635938a3a5eSflorian 			|| iq->qchase.qtype == LDNS_RR_TYPE_A)))
2636938a3a5eSflorian 			/* Stop minimising this query, resolve "as usual" */
2637938a3a5eSflorian 			iq->minimisation_state = DONOT_MINIMISE_STATE;
2638938a3a5eSflorian 		else if(!qstate->no_cache_lookup) {
2639938a3a5eSflorian 			struct dns_msg* msg = dns_cache_lookup(qstate->env,
2640938a3a5eSflorian 				iq->qinfo_out.qname, iq->qinfo_out.qname_len,
2641938a3a5eSflorian 				iq->qinfo_out.qtype, iq->qinfo_out.qclass,
2642938a3a5eSflorian 				qstate->query_flags, qstate->region,
2643191f22c6Ssthen 				qstate->env->scratch, 0, iq->dp->name,
2644191f22c6Ssthen 				iq->dp->namelen);
264506a13c09Ssthen 			if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
2646938a3a5eSflorian 				LDNS_RCODE_NOERROR)
2647938a3a5eSflorian 				/* no need to send query if it is already
264806a13c09Ssthen 				 * cached as NOERROR */
2649938a3a5eSflorian 				return 1;
265006a13c09Ssthen 			if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
265106a13c09Ssthen 				LDNS_RCODE_NXDOMAIN &&
265206a13c09Ssthen 				qstate->env->need_to_validate &&
265306a13c09Ssthen 				qstate->env->cfg->harden_below_nxdomain) {
265406a13c09Ssthen 				if(msg->rep->security == sec_status_secure) {
265506a13c09Ssthen 					iq->response = msg;
265606a13c09Ssthen 					return final_state(iq);
265706a13c09Ssthen 				}
265806a13c09Ssthen 				if(msg->rep->security == sec_status_unchecked) {
265906a13c09Ssthen 					struct module_qstate* subq = NULL;
266006a13c09Ssthen 					if(!generate_sub_request(
266106a13c09Ssthen 						iq->qinfo_out.qname,
266206a13c09Ssthen 						iq->qinfo_out.qname_len,
266306a13c09Ssthen 						iq->qinfo_out.qtype,
266406a13c09Ssthen 						iq->qinfo_out.qclass,
266506a13c09Ssthen 						qstate, id, iq,
266606a13c09Ssthen 						INIT_REQUEST_STATE,
266706a13c09Ssthen 						FINISHED_STATE, &subq, 1, 1))
266806a13c09Ssthen 						verbose(VERB_ALGO,
266906a13c09Ssthen 						"could not validate NXDOMAIN "
267006a13c09Ssthen 						"response");
267106a13c09Ssthen 				}
267206a13c09Ssthen 			}
267306a13c09Ssthen 			if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
267406a13c09Ssthen 				LDNS_RCODE_NXDOMAIN) {
267506a13c09Ssthen 				/* return and add a label in the next
267606a13c09Ssthen 				 * minimisation iteration.
267706a13c09Ssthen 				 */
267806a13c09Ssthen 				return 1;
267906a13c09Ssthen 			}
2680938a3a5eSflorian 		}
2681938a3a5eSflorian 	}
2682938a3a5eSflorian 	if(iq->minimisation_state == SKIP_MINIMISE_STATE) {
2683a3167c07Ssthen 		if(iq->timeout_count < MAX_MINIMISE_TIMEOUT_COUNT)
2684938a3a5eSflorian 			/* Do not increment qname, continue incrementing next
2685938a3a5eSflorian 			 * iteration */
2686938a3a5eSflorian 			iq->minimisation_state = MINIMISE_STATE;
2687938a3a5eSflorian 		else if(!qstate->env->cfg->qname_minimisation_strict)
2688938a3a5eSflorian 			/* Too many time-outs detected for this QNAME and QTYPE.
2689938a3a5eSflorian 			 * We give up, disable QNAME minimisation. */
2690938a3a5eSflorian 			iq->minimisation_state = DONOT_MINIMISE_STATE;
2691938a3a5eSflorian 	}
2692938a3a5eSflorian 	if(iq->minimisation_state == DONOT_MINIMISE_STATE)
2693938a3a5eSflorian 		iq->qinfo_out = iq->qchase;
2694938a3a5eSflorian 
2695938a3a5eSflorian 	/* now find an answer to this query */
2696938a3a5eSflorian 	/* see if authority zones have an answer */
2697938a3a5eSflorian 	/* now we know the dp, we can check the auth zone for locally hosted
2698938a3a5eSflorian 	 * contents */
2699938a3a5eSflorian 	if(!iq->auth_zone_avoid && qstate->blacklist) {
2700938a3a5eSflorian 		if(auth_zones_can_fallback(qstate->env->auth_zones,
2701938a3a5eSflorian 			iq->dp->name, iq->dp->namelen, iq->qinfo_out.qclass)) {
2702938a3a5eSflorian 			/* if cache is blacklisted and this zone allows us
2703938a3a5eSflorian 			 * to fallback to the internet, then do so, and
2704938a3a5eSflorian 			 * fetch results from the internet servers */
2705938a3a5eSflorian 			iq->auth_zone_avoid = 1;
2706938a3a5eSflorian 		}
2707938a3a5eSflorian 	}
2708938a3a5eSflorian 	if(iq->auth_zone_avoid) {
2709938a3a5eSflorian 		iq->auth_zone_avoid = 0;
2710938a3a5eSflorian 		auth_fallback = 1;
2711938a3a5eSflorian 	} else if(auth_zones_lookup(qstate->env->auth_zones, &iq->qinfo_out,
2712938a3a5eSflorian 		qstate->region, &iq->response, &auth_fallback, iq->dp->name,
2713938a3a5eSflorian 		iq->dp->namelen)) {
2714938a3a5eSflorian 		/* use this as a response to be processed by the iterator */
2715938a3a5eSflorian 		if(verbosity >= VERB_ALGO) {
2716938a3a5eSflorian 			log_dns_msg("msg from auth zone",
2717938a3a5eSflorian 				&iq->response->qinfo, iq->response->rep);
2718938a3a5eSflorian 		}
271920237c55Ssthen 		if((iq->chase_flags&BIT_RD) && !(iq->response->rep->flags&BIT_AA)) {
272020237c55Ssthen 			verbose(VERB_ALGO, "forwarder, ignoring referral from auth zone");
272120237c55Ssthen 		} else {
272220237c55Ssthen 			lock_rw_wrlock(&qstate->env->auth_zones->lock);
272320237c55Ssthen 			qstate->env->auth_zones->num_query_up++;
272420237c55Ssthen 			lock_rw_unlock(&qstate->env->auth_zones->lock);
2725938a3a5eSflorian 			iq->num_current_queries++;
2726938a3a5eSflorian 			iq->chase_to_rd = 0;
2727938a3a5eSflorian 			iq->dnssec_lame_query = 0;
2728938a3a5eSflorian 			iq->auth_zone_response = 1;
2729938a3a5eSflorian 			return next_state(iq, QUERY_RESP_STATE);
2730938a3a5eSflorian 		}
273120237c55Ssthen 	}
2732938a3a5eSflorian 	iq->auth_zone_response = 0;
2733938a3a5eSflorian 	if(auth_fallback == 0) {
2734938a3a5eSflorian 		/* like we got servfail from the auth zone lookup, and
2735938a3a5eSflorian 		 * no internet fallback */
2736938a3a5eSflorian 		verbose(VERB_ALGO, "auth zone lookup failed, no fallback,"
2737938a3a5eSflorian 			" servfail");
27382308e98cSsthen 		errinf(qstate, "auth zone lookup failed, fallback is off");
2739*98bc733bSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2740938a3a5eSflorian 	}
2741f6b99bafSsthen 	if(iq->dp->auth_dp) {
2742938a3a5eSflorian 		/* we wanted to fallback, but had no delegpt, only the
2743938a3a5eSflorian 		 * auth zone generated delegpt, create an actual one */
2744938a3a5eSflorian 		iq->auth_zone_avoid = 1;
2745938a3a5eSflorian 		return next_state(iq, INIT_REQUEST_STATE);
2746938a3a5eSflorian 	}
2747938a3a5eSflorian 	/* but mostly, fallback==1 (like, when no such auth zone exists)
2748938a3a5eSflorian 	 * and we continue with lookups */
2749938a3a5eSflorian 
2750933707f3Ssthen 	tf_policy = 0;
2751933707f3Ssthen 	/* < not <=, because although the array is large enough for <=, the
2752933707f3Ssthen 	 * generated query will immediately be discarded due to depth and
2753933707f3Ssthen 	 * that servfail is cached, which is not good as opportunism goes. */
2754933707f3Ssthen 	if(iq->depth < ie->max_dependency_depth
275506a13c09Ssthen 		&& iq->num_target_queries == 0
2756d1e2768aSsthen 		&& (!iq->target_count || iq->target_count[TARGET_COUNT_NX]==0)
275745872187Ssthen 		&& iq->sent_count < TARGET_FETCH_STOP) {
275845872187Ssthen 		can_do_promisc = 1;
275945872187Ssthen 	}
276045872187Ssthen 	/* if the mesh query list is full, then do not waste cpu and sockets to
276145872187Ssthen 	 * fetch promiscuous targets. They can be looked up when needed. */
276245872187Ssthen 	if(can_do_promisc && !mesh_jostle_exceeded(qstate->env->mesh)) {
2763933707f3Ssthen 		tf_policy = ie->target_fetch_policy[iq->depth];
2764933707f3Ssthen 	}
2765933707f3Ssthen 
2766933707f3Ssthen 	/* if in 0x20 fallback get as many targets as possible */
2767933707f3Ssthen 	if(iq->caps_fallback) {
2768*98bc733bSsthen 		int extra = 0, ret;
2769933707f3Ssthen 		size_t naddr, nres, navail;
2770*98bc733bSsthen 		if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) {
27712308e98cSsthen 			errinf(qstate, "could not fetch nameservers for 0x20 fallback");
2772*98bc733bSsthen 			if(ret == 1)
2773933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2774*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
2775933707f3Ssthen 		}
2776933707f3Ssthen 		iq->num_target_queries += extra;
2777ae1dea89Sflorian 		target_count_increase(iq, extra);
2778933707f3Ssthen 		if(iq->num_target_queries > 0) {
2779933707f3Ssthen 			/* wait to get all targets, we want to try em */
2780933707f3Ssthen 			verbose(VERB_ALGO, "wait for all targets for fallback");
2781933707f3Ssthen 			qstate->ext_state[id] = module_wait_reply;
2782c3b38330Ssthen 			/* undo qname minimise step because we'll get back here
2783c3b38330Ssthen 			 * to do it again */
2784c3b38330Ssthen 			if(qout_orig && iq->minimise_count > 0) {
2785c3b38330Ssthen 				iq->minimise_count--;
2786c3b38330Ssthen 				iq->qinfo_out.qname = qout_orig;
2787c3b38330Ssthen 				iq->qinfo_out.qname_len = qout_orig_len;
2788c3b38330Ssthen 			}
2789933707f3Ssthen 			return 0;
2790933707f3Ssthen 		}
2791933707f3Ssthen 		/* did we do enough fallback queries already? */
2792933707f3Ssthen 		delegpt_count_addr(iq->dp, &naddr, &nres, &navail);
2793933707f3Ssthen 		/* the current caps_server is the number of fallbacks sent.
2794933707f3Ssthen 		 * the original query is one that matched too, so we have
2795933707f3Ssthen 		 * caps_server+1 number of matching queries now */
2796933707f3Ssthen 		if(iq->caps_server+1 >= naddr*3 ||
27978b7325afSsthen 			iq->caps_server*2+2 >= (size_t)ie->max_sent_count) {
2798a58bff56Ssthen 			/* *2 on sentcount check because ipv6 may fail */
2799933707f3Ssthen 			/* we're done, process the response */
2800933707f3Ssthen 			verbose(VERB_ALGO, "0x20 fallback had %d responses "
2801933707f3Ssthen 				"match for %d wanted, done.",
2802933707f3Ssthen 				(int)iq->caps_server+1, (int)naddr*3);
2803a58bff56Ssthen 			iq->response = iq->caps_response;
2804933707f3Ssthen 			iq->caps_fallback = 0;
2805e21c60efSsthen 			iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
2806933707f3Ssthen 			iq->num_current_queries++; /* RespState decrements it*/
2807933707f3Ssthen 			iq->referral_count++; /* make sure we don't loop */
2808933707f3Ssthen 			iq->sent_count = 0;
280906a13c09Ssthen 			iq->dp_target_count = 0;
2810933707f3Ssthen 			iq->state = QUERY_RESP_STATE;
2811933707f3Ssthen 			return 1;
2812933707f3Ssthen 		}
2813933707f3Ssthen 		verbose(VERB_ALGO, "0x20 fallback number %d",
2814933707f3Ssthen 			(int)iq->caps_server);
2815933707f3Ssthen 
2816933707f3Ssthen 	/* if there is a policy to fetch missing targets
2817933707f3Ssthen 	 * opportunistically, do it. we rely on the fact that once a
2818933707f3Ssthen 	 * query (or queries) for a missing name have been issued,
2819933707f3Ssthen 	 * they will not show up again. */
2820933707f3Ssthen 	} else if(tf_policy != 0) {
2821933707f3Ssthen 		int extra = 0;
2822933707f3Ssthen 		verbose(VERB_ALGO, "attempt to get extra %d targets",
2823933707f3Ssthen 			tf_policy);
2824933707f3Ssthen 		(void)query_for_targets(qstate, iq, ie, id, tf_policy, &extra);
2825933707f3Ssthen 		/* errors ignored, these targets are not strictly necessary for
2826933707f3Ssthen 		 * this result, we do not have to reply with SERVFAIL */
2827933707f3Ssthen 		iq->num_target_queries += extra;
2828ae1dea89Sflorian 		target_count_increase(iq, extra);
2829933707f3Ssthen 	}
2830933707f3Ssthen 
2831933707f3Ssthen 	/* Add the current set of unused targets to our queue. */
2832933707f3Ssthen 	delegpt_add_unused_targets(iq->dp);
2833933707f3Ssthen 
2834e21c60efSsthen 	if(qstate->env->auth_zones) {
28352bdc0ed1Ssthen 		uint8_t* sname = NULL;
28362bdc0ed1Ssthen 		size_t snamelen = 0;
28372bdc0ed1Ssthen 		/* apply rpz triggers at query time; nameserver IP and dname */
28382bdc0ed1Ssthen 		struct dns_msg* forged_response_after_cname;
2839e21c60efSsthen 		struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq);
28402bdc0ed1Ssthen 		int count = 0;
28412bdc0ed1Ssthen 		while(forged_response && reply_find_rrset_section_an(
28422bdc0ed1Ssthen 			forged_response->rep, iq->qchase.qname,
28432bdc0ed1Ssthen 			iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
28442bdc0ed1Ssthen 			iq->qchase.qclass) &&
28452bdc0ed1Ssthen 			iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
28462bdc0ed1Ssthen 			count++ < ie->max_query_restarts) {
28472bdc0ed1Ssthen 			/* another cname to follow */
28482bdc0ed1Ssthen 			if(!handle_cname_response(qstate, iq, forged_response,
28492bdc0ed1Ssthen 				&sname, &snamelen)) {
28502bdc0ed1Ssthen 				errinf(qstate, "malloc failure, CNAME info");
28512bdc0ed1Ssthen 				return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
28522bdc0ed1Ssthen 			}
28532bdc0ed1Ssthen 			iq->qchase.qname = sname;
28542bdc0ed1Ssthen 			iq->qchase.qname_len = snamelen;
28552bdc0ed1Ssthen 			forged_response_after_cname =
28562bdc0ed1Ssthen 				rpz_callback_from_iterator_cname(qstate, iq);
28572bdc0ed1Ssthen 			if(forged_response_after_cname) {
28582bdc0ed1Ssthen 				forged_response = forged_response_after_cname;
28592bdc0ed1Ssthen 			} else {
28602bdc0ed1Ssthen 				/* Follow the CNAME with a query restart */
28612bdc0ed1Ssthen 				iq->deleg_msg = NULL;
28622bdc0ed1Ssthen 				iq->dp = NULL;
28632bdc0ed1Ssthen 				iq->dsns_point = NULL;
28642bdc0ed1Ssthen 				iq->auth_zone_response = 0;
28652bdc0ed1Ssthen 				iq->refetch_glue = 0;
28662bdc0ed1Ssthen 				iq->query_restart_count++;
28672bdc0ed1Ssthen 				iq->sent_count = 0;
28682bdc0ed1Ssthen 				iq->dp_target_count = 0;
28692bdc0ed1Ssthen 				if(qstate->env->cfg->qname_minimisation)
28702bdc0ed1Ssthen 					iq->minimisation_state = INIT_MINIMISE_STATE;
28712bdc0ed1Ssthen 				outbound_list_clear(&iq->outlist);
28722bdc0ed1Ssthen 				iq->num_current_queries = 0;
28732bdc0ed1Ssthen 				fptr_ok(fptr_whitelist_modenv_detach_subs(
28742bdc0ed1Ssthen 					qstate->env->detach_subs));
28752bdc0ed1Ssthen 				(*qstate->env->detach_subs)(qstate);
28762bdc0ed1Ssthen 				iq->num_target_queries = 0;
28772bdc0ed1Ssthen 				return next_state(iq, INIT_REQUEST_STATE);
28782bdc0ed1Ssthen 			}
28792bdc0ed1Ssthen 		}
2880e21c60efSsthen 		if(forged_response != NULL) {
2881e21c60efSsthen 			qstate->ext_state[id] = module_finished;
2882e21c60efSsthen 			qstate->return_rcode = LDNS_RCODE_NOERROR;
2883e21c60efSsthen 			qstate->return_msg = forged_response;
2884e21c60efSsthen 			iq->response = forged_response;
2885e21c60efSsthen 			next_state(iq, FINISHED_STATE);
2886e21c60efSsthen 			if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
28870bdb4f62Ssthen 				log_err("rpz: prepend rrsets: out of memory");
2888e21c60efSsthen 				return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
2889e21c60efSsthen 			}
2890e21c60efSsthen 			return 0;
2891e21c60efSsthen 		}
2892e21c60efSsthen 	}
2893e21c60efSsthen 
2894933707f3Ssthen 	/* Select the next usable target, filtering out unsuitable targets. */
2895933707f3Ssthen 	target = iter_server_selection(ie, qstate->env, iq->dp,
2896933707f3Ssthen 		iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
2897933707f3Ssthen 		&iq->dnssec_lame_query, &iq->chase_to_rd,
289820237c55Ssthen 		iq->num_target_queries, qstate->blacklist,
289920237c55Ssthen 		qstate->prefetch_leeway);
2900933707f3Ssthen 
2901933707f3Ssthen 	/* If no usable target was selected... */
2902933707f3Ssthen 	if(!target) {
2903933707f3Ssthen 		/* Here we distinguish between three states: generate a new
2904933707f3Ssthen 		 * target query, just wait, or quit (with a SERVFAIL).
2905933707f3Ssthen 		 * We have the following information: number of active
2906933707f3Ssthen 		 * target queries, number of active current queries,
2907933707f3Ssthen 		 * the presence of missing targets at this delegation
2908933707f3Ssthen 		 * point, and the given query target policy. */
2909933707f3Ssthen 
2910933707f3Ssthen 		/* Check for the wait condition. If this is true, then
2911933707f3Ssthen 		 * an action must be taken. */
2912933707f3Ssthen 		if(iq->num_target_queries==0 && iq->num_current_queries==0) {
2913933707f3Ssthen 			/* If there is nothing to wait for, then we need
2914933707f3Ssthen 			 * to distinguish between generating (a) new target
2915933707f3Ssthen 			 * query, or failing. */
2916d1e2768aSsthen 			if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
2917*98bc733bSsthen 				int qs = 0, ret;
2918933707f3Ssthen 				verbose(VERB_ALGO, "querying for next "
2919933707f3Ssthen 					"missing target");
2920*98bc733bSsthen 				if((ret=query_for_targets(qstate, iq, ie, id,
2921*98bc733bSsthen 					1, &qs))!=0) {
29222308e98cSsthen 					errinf(qstate, "could not fetch nameserver");
29232308e98cSsthen 					errinf_dname(qstate, "at zone", iq->dp->name);
2924*98bc733bSsthen 					if(ret == 1)
2925933707f3Ssthen 					return error_response(qstate, id,
2926933707f3Ssthen 						LDNS_RCODE_SERVFAIL);
2927*98bc733bSsthen 					return error_response_cache(qstate, id,
2928*98bc733bSsthen 						LDNS_RCODE_SERVFAIL);
2929933707f3Ssthen 				}
2930933707f3Ssthen 				if(qs == 0 &&
2931d1e2768aSsthen 				   delegpt_count_missing_targets(iq->dp, NULL) == 0){
2932933707f3Ssthen 					/* it looked like there were missing
2933933707f3Ssthen 					 * targets, but they did not turn up.
2934933707f3Ssthen 					 * Try the bad choices again (if any),
2935933707f3Ssthen 					 * when we get back here missing==0,
2936933707f3Ssthen 					 * so this is not a loop. */
2937933707f3Ssthen 					return 1;
2938933707f3Ssthen 				}
2939*98bc733bSsthen 				if(qs == 0) {
2940*98bc733bSsthen 					/* There should be targets now, and
2941*98bc733bSsthen 					 * if there are not, it should not
2942*98bc733bSsthen 					 * wait for no targets. Stop it from
2943*98bc733bSsthen 					 * waiting forever, or looping to
2944*98bc733bSsthen 					 * here, as a safeguard. */
2945*98bc733bSsthen 					errinf(qstate, "could not generate nameserver lookups");
2946*98bc733bSsthen 					errinf_dname(qstate, "at zone", iq->dp->name);
2947*98bc733bSsthen 					return error_response(qstate, id,
2948*98bc733bSsthen 						LDNS_RCODE_SERVFAIL);
2949*98bc733bSsthen 				}
2950933707f3Ssthen 				iq->num_target_queries += qs;
2951ae1dea89Sflorian 				target_count_increase(iq, qs);
2952933707f3Ssthen 			}
2953933707f3Ssthen 			/* Since a target query might have been made, we
2954933707f3Ssthen 			 * need to check again. */
2955933707f3Ssthen 			if(iq->num_target_queries == 0) {
2956a58bff56Ssthen 				/* if in capsforid fallback, instead of last
2957a58bff56Ssthen 				 * resort, we agree with the current reply
2958a58bff56Ssthen 				 * we have (if any) (our count of addrs bad)*/
2959a58bff56Ssthen 				if(iq->caps_fallback && iq->caps_reply) {
2960a58bff56Ssthen 					/* we're done, process the response */
2961a58bff56Ssthen 					verbose(VERB_ALGO, "0x20 fallback had %d responses, "
2962a58bff56Ssthen 						"but no more servers except "
2963a58bff56Ssthen 						"last resort, done.",
2964a58bff56Ssthen 						(int)iq->caps_server+1);
2965a58bff56Ssthen 					iq->response = iq->caps_response;
2966a58bff56Ssthen 					iq->caps_fallback = 0;
2967e21c60efSsthen 					iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry); /* space for fallback */
2968a58bff56Ssthen 					iq->num_current_queries++; /* RespState decrements it*/
2969a58bff56Ssthen 					iq->referral_count++; /* make sure we don't loop */
2970a58bff56Ssthen 					iq->sent_count = 0;
297106a13c09Ssthen 					iq->dp_target_count = 0;
2972a58bff56Ssthen 					iq->state = QUERY_RESP_STATE;
2973a58bff56Ssthen 					return 1;
2974a58bff56Ssthen 				}
2975933707f3Ssthen 				return processLastResort(qstate, iq, ie, id);
2976933707f3Ssthen 			}
2977933707f3Ssthen 		}
2978933707f3Ssthen 
2979933707f3Ssthen 		/* otherwise, we have no current targets, so submerge
2980933707f3Ssthen 		 * until one of the target or direct queries return. */
2981d1e2768aSsthen 		verbose(VERB_ALGO, "no current targets");
2982d1e2768aSsthen 		check_waiting_queries(iq, qstate, id);
2983c3b38330Ssthen 		/* undo qname minimise step because we'll get back here
2984c3b38330Ssthen 		 * to do it again */
2985c3b38330Ssthen 		if(qout_orig && iq->minimise_count > 0) {
2986c3b38330Ssthen 			iq->minimise_count--;
2987c3b38330Ssthen 			iq->qinfo_out.qname = qout_orig;
2988c3b38330Ssthen 			iq->qinfo_out.qname_len = qout_orig_len;
2989c3b38330Ssthen 		}
2990933707f3Ssthen 		return 0;
2991933707f3Ssthen 	}
2992933707f3Ssthen 
299345872187Ssthen 	/* We have a target. We could have created promiscuous target
299445872187Ssthen 	 * queries but we are currently under pressure (mesh_jostle_exceeded).
299545872187Ssthen 	 * If we are configured to allow promiscuous target queries and haven't
299645872187Ssthen 	 * gone out to the network for a target query for this delegation, then
299745872187Ssthen 	 * it is possible to slip in a promiscuous one with a 1/10 chance. */
299845872187Ssthen 	if(can_do_promisc && tf_policy == 0 && iq->depth == 0
299945872187Ssthen 		&& iq->depth < ie->max_dependency_depth
300045872187Ssthen 		&& ie->target_fetch_policy[iq->depth] != 0
300145872187Ssthen 		&& iq->dp_target_count == 0
300245872187Ssthen 		&& !ub_random_max(qstate->env->rnd, 10)) {
300345872187Ssthen 		int extra = 0;
300445872187Ssthen 		verbose(VERB_ALGO, "available target exists in cache but "
300545872187Ssthen 			"attempt to get extra 1 target");
300645872187Ssthen 		(void)query_for_targets(qstate, iq, ie, id, 1, &extra);
300745872187Ssthen 		/* errors ignored, these targets are not strictly necessary for
300845872187Ssthen 		* this result, we do not have to reply with SERVFAIL */
300945872187Ssthen 		if(extra > 0) {
301045872187Ssthen 			iq->num_target_queries += extra;
301145872187Ssthen 			target_count_increase(iq, extra);
301245872187Ssthen 			check_waiting_queries(iq, qstate, id);
301345872187Ssthen 			/* undo qname minimise step because we'll get back here
301445872187Ssthen 			 * to do it again */
301545872187Ssthen 			if(qout_orig && iq->minimise_count > 0) {
301645872187Ssthen 				iq->minimise_count--;
301745872187Ssthen 				iq->qinfo_out.qname = qout_orig;
301845872187Ssthen 				iq->qinfo_out.qname_len = qout_orig_len;
301945872187Ssthen 			}
302045872187Ssthen 			return 0;
302145872187Ssthen 		}
302245872187Ssthen 	}
302345872187Ssthen 
3024*98bc733bSsthen 	target_count_increase_global_quota(iq, 1);
3025*98bc733bSsthen 	if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
3026*98bc733bSsthen 		> MAX_GLOBAL_QUOTA) {
3027*98bc733bSsthen 		char s[LDNS_MAX_DOMAINLEN+1];
3028*98bc733bSsthen 		dname_str(qstate->qinfo.qname, s);
3029*98bc733bSsthen 		verbose(VERB_QUERY, "request %s has exceeded the maximum "
3030*98bc733bSsthen 			"global quota on number of upstream queries %d", s,
3031*98bc733bSsthen 			iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]);
3032*98bc733bSsthen 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
3033*98bc733bSsthen 	}
3034*98bc733bSsthen 
3035e21c60efSsthen 	/* Do not check ratelimit for forwarding queries or if we already got a
3036e21c60efSsthen 	 * pass. */
3037e21c60efSsthen 	sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
3038933707f3Ssthen 	/* We have a valid target. */
3039933707f3Ssthen 	if(verbosity >= VERB_QUERY) {
304024893edcSsthen 		log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
3041933707f3Ssthen 		log_name_addr(VERB_QUERY, "sending to target:", iq->dp->name,
3042933707f3Ssthen 			&target->addr, target->addrlen);
3043933707f3Ssthen 		verbose(VERB_ALGO, "dnssec status: %s%s",
3044933707f3Ssthen 			iq->dnssec_expected?"expected": "not expected",
3045933707f3Ssthen 			iq->dnssec_lame_query?" but lame_query anyway": "");
3046933707f3Ssthen 	}
30478b7325afSsthen 
30488b7325afSsthen 	real_addr = target->addr;
30498b7325afSsthen 	real_addrlen = target->addrlen;
30508b7325afSsthen 
30518b7325afSsthen 	if(ie->use_nat64 && target->addr.ss_family == AF_INET) {
30528b7325afSsthen 		addr_to_nat64(&target->addr, &ie->nat64_prefix_addr,
30538b7325afSsthen 			ie->nat64_prefix_addrlen, ie->nat64_prefix_net,
30548b7325afSsthen 			&real_addr, &real_addrlen);
30558b7325afSsthen 		log_name_addr(VERB_QUERY, "applied NAT64:",
30568b7325afSsthen 			iq->dp->name, &real_addr, real_addrlen);
30578b7325afSsthen 	}
30588b7325afSsthen 
3059933707f3Ssthen 	fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
306077079be7Ssthen 	outq = (*qstate->env->send_query)(&iq->qinfo_out,
30612ee382b6Ssthen 		iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
30622ee382b6Ssthen 		/* unset CD if to forwarder(RD set) and not dnssec retry
30632ee382b6Ssthen 		 * (blacklist nonempty) and no trust-anchors are configured
30642ee382b6Ssthen 		 * above the qname or on the first attempt when dnssec is on */
3065d896b962Ssthen 		(qstate->env->cfg->disable_edns_do?0:EDNS_DO)|
3066d896b962Ssthen 		((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&&
306720237c55Ssthen 		!qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env,
30682ee382b6Ssthen 		&iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
3069a58bff56Ssthen 		iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
30708b7325afSsthen 		ie, iq), sq_check_ratelimit, &real_addr, real_addrlen,
307177079be7Ssthen 		iq->dp->name, iq->dp->namelen,
3072e21c60efSsthen 		(iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
307320237c55Ssthen 		(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
3074e21c60efSsthen 		target->tls_auth_name, qstate, &sq_was_ratelimited);
3075933707f3Ssthen 	if(!outq) {
3076e21c60efSsthen 		if(sq_was_ratelimited) {
3077e21c60efSsthen 			lock_basic_lock(&ie->queries_ratelimit_lock);
3078e21c60efSsthen 			ie->num_queries_ratelimited++;
3079e21c60efSsthen 			lock_basic_unlock(&ie->queries_ratelimit_lock);
3080e21c60efSsthen 			verbose(VERB_ALGO, "query exceeded ratelimits");
3081e21c60efSsthen 			qstate->was_ratelimited = 1;
3082e21c60efSsthen 			errinf_dname(qstate, "exceeded ratelimit for zone",
3083e21c60efSsthen 				iq->dp->name);
3084*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
3085e21c60efSsthen 		}
3086191f22c6Ssthen 		log_addr(VERB_QUERY, "error sending query to auth server",
30878b7325afSsthen 			&real_addr, real_addrlen);
30887191de28Ssthen 		if(qstate->env->cfg->qname_minimisation)
30897191de28Ssthen 			iq->minimisation_state = SKIP_MINIMISE_STATE;
3090933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
3091933707f3Ssthen 	}
3092933707f3Ssthen 	outbound_list_insert(&iq->outlist, outq);
3093933707f3Ssthen 	iq->num_current_queries++;
3094933707f3Ssthen 	iq->sent_count++;
3095933707f3Ssthen 	qstate->ext_state[id] = module_wait_reply;
3096933707f3Ssthen 
3097933707f3Ssthen 	return 0;
3098933707f3Ssthen }
3099933707f3Ssthen 
3100933707f3Ssthen /** find NS rrset in given list */
3101933707f3Ssthen static struct ub_packed_rrset_key*
3102933707f3Ssthen find_NS(struct reply_info* rep, size_t from, size_t to)
3103933707f3Ssthen {
3104933707f3Ssthen 	size_t i;
3105933707f3Ssthen 	for(i=from; i<to; i++) {
3106933707f3Ssthen 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
3107933707f3Ssthen 			return rep->rrsets[i];
3108933707f3Ssthen 	}
3109933707f3Ssthen 	return NULL;
3110933707f3Ssthen }
3111933707f3Ssthen 
3112933707f3Ssthen 
3113933707f3Ssthen /**
3114933707f3Ssthen  * Process the query response. All queries end up at this state first. This
3115933707f3Ssthen  * process generally consists of analyzing the response and routing the
3116933707f3Ssthen  * event to the next state (either bouncing it back to a request state, or
3117933707f3Ssthen  * terminating the processing for this event).
3118933707f3Ssthen  *
3119933707f3Ssthen  * @param qstate: query state.
3120933707f3Ssthen  * @param iq: iterator query state.
3121e21c60efSsthen  * @param ie: iterator shared global environment.
3122933707f3Ssthen  * @param id: module id.
3123933707f3Ssthen  * @return true if the event requires more immediate processing, false if
3124933707f3Ssthen  *         not. This is generally only true when forwarding the request to
3125933707f3Ssthen  *         the final state (i.e., on answer).
3126933707f3Ssthen  */
3127933707f3Ssthen static int
3128933707f3Ssthen processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
3129e21c60efSsthen 	struct iter_env* ie, int id)
3130933707f3Ssthen {
3131d896b962Ssthen 	int dnsseclame = 0, origtypecname = 0, orig_empty_nodata_found;
3132933707f3Ssthen 	enum response_type type;
3133e21c60efSsthen 
3134933707f3Ssthen 	iq->num_current_queries--;
31352be9e038Ssthen 
31362be9e038Ssthen 	if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response))
31372be9e038Ssthen 		log_err("unable to call query_response callback");
31382be9e038Ssthen 
3139933707f3Ssthen 	if(iq->response == NULL) {
314024893edcSsthen 		/* Don't increment qname when QNAME minimisation is enabled */
31417191de28Ssthen 		if(qstate->env->cfg->qname_minimisation) {
314224893edcSsthen 			iq->minimisation_state = SKIP_MINIMISE_STATE;
31437191de28Ssthen 		}
3144a3167c07Ssthen 		iq->timeout_count++;
3145933707f3Ssthen 		iq->chase_to_rd = 0;
3146933707f3Ssthen 		iq->dnssec_lame_query = 0;
3147933707f3Ssthen 		verbose(VERB_ALGO, "query response was timeout");
3148933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
3149933707f3Ssthen 	}
3150a3167c07Ssthen 	iq->timeout_count = 0;
3151d896b962Ssthen 	orig_empty_nodata_found = iq->empty_nodata_found;
3152933707f3Ssthen 	type = response_type_from_server(
3153933707f3Ssthen 		(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
3154d896b962Ssthen 		iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found);
3155933707f3Ssthen 	iq->chase_to_rd = 0;
315645872187Ssthen 	/* remove TC flag, if this is erroneously set by TCP upstream */
315745872187Ssthen 	iq->response->rep->flags &= ~BIT_TC;
3158d896b962Ssthen 	if(orig_empty_nodata_found != iq->empty_nodata_found &&
3159d896b962Ssthen 		iq->empty_nodata_found < EMPTY_NODATA_RETRY_COUNT) {
3160d896b962Ssthen 		/* try to search at another server */
3161d896b962Ssthen 		if(qstate->reply) {
3162d896b962Ssthen 			struct delegpt_addr* a = delegpt_find_addr(
3163d896b962Ssthen 				iq->dp, &qstate->reply->remote_addr,
3164d896b962Ssthen 				qstate->reply->remote_addrlen);
3165d896b962Ssthen 			/* make selection disprefer it */
3166d896b962Ssthen 			if(a) a->lame = 1;
3167d896b962Ssthen 		}
3168d896b962Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
3169d896b962Ssthen 	}
317020237c55Ssthen 	if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD) &&
317120237c55Ssthen 		!iq->auth_zone_response) {
3172933707f3Ssthen 		/* When forwarding (RD bit is set), we handle referrals
3173933707f3Ssthen 		 * differently. No queries should be sent elsewhere */
3174933707f3Ssthen 		type = RESPONSE_TYPE_ANSWER;
3175933707f3Ssthen 	}
31762ee382b6Ssthen 	if(!qstate->env->cfg->disable_dnssec_lame_check && iq->dnssec_expected
31772ee382b6Ssthen                 && !iq->dnssec_lame_query &&
3178933707f3Ssthen 		!(iq->chase_flags&BIT_RD)
31792ee382b6Ssthen 		&& iq->sent_count < DNSSEC_LAME_DETECT_COUNT
3180933707f3Ssthen 		&& type != RESPONSE_TYPE_LAME
3181933707f3Ssthen 		&& type != RESPONSE_TYPE_REC_LAME
3182933707f3Ssthen 		&& type != RESPONSE_TYPE_THROWAWAY
3183933707f3Ssthen 		&& type != RESPONSE_TYPE_UNTYPED) {
3184933707f3Ssthen 		/* a possible answer, see if it is missing DNSSEC */
3185933707f3Ssthen 		/* but not when forwarding, so we dont mark fwder lame */
3186229e174cSsthen 		if(!iter_msg_has_dnssec(iq->response)) {
3187229e174cSsthen 			/* Mark this address as dnsseclame in this dp,
3188229e174cSsthen 			 * because that will make serverselection disprefer
3189229e174cSsthen 			 * it, but also, once it is the only final option,
3190229e174cSsthen 			 * use dnssec-lame-bypass if it needs to query there.*/
3191229e174cSsthen 			if(qstate->reply) {
3192229e174cSsthen 				struct delegpt_addr* a = delegpt_find_addr(
319345872187Ssthen 					iq->dp, &qstate->reply->remote_addr,
319445872187Ssthen 					qstate->reply->remote_addrlen);
3195229e174cSsthen 				if(a) a->dnsseclame = 1;
3196229e174cSsthen 			}
3197229e174cSsthen 			/* test the answer is from the zone we expected,
3198933707f3Ssthen 		 	 * otherwise, (due to parent,child on same server), we
3199933707f3Ssthen 		 	 * might mark the server,zone lame inappropriately */
3200229e174cSsthen 			if(!iter_msg_from_zone(iq->response, iq->dp, type,
3201229e174cSsthen 				iq->qchase.qclass))
3202229e174cSsthen 				qstate->reply = NULL;
3203933707f3Ssthen 			type = RESPONSE_TYPE_LAME;
3204933707f3Ssthen 			dnsseclame = 1;
3205933707f3Ssthen 		}
3206933707f3Ssthen 	} else iq->dnssec_lame_query = 0;
3207933707f3Ssthen 	/* see if referral brings us close to the target */
3208933707f3Ssthen 	if(type == RESPONSE_TYPE_REFERRAL) {
3209933707f3Ssthen 		struct ub_packed_rrset_key* ns = find_NS(
3210933707f3Ssthen 			iq->response->rep, iq->response->rep->an_numrrsets,
3211933707f3Ssthen 			iq->response->rep->an_numrrsets
3212933707f3Ssthen 			+ iq->response->rep->ns_numrrsets);
3213933707f3Ssthen 		if(!ns) ns = find_NS(iq->response->rep, 0,
3214933707f3Ssthen 				iq->response->rep->an_numrrsets);
3215933707f3Ssthen 		if(!ns || !dname_strict_subdomain_c(ns->rk.dname, iq->dp->name)
3216933707f3Ssthen 			|| !dname_subdomain_c(iq->qchase.qname, ns->rk.dname)){
3217933707f3Ssthen 			verbose(VERB_ALGO, "bad referral, throwaway");
3218933707f3Ssthen 			type = RESPONSE_TYPE_THROWAWAY;
3219933707f3Ssthen 		} else
3220933707f3Ssthen 			iter_scrub_ds(iq->response, ns, iq->dp->name);
3221933707f3Ssthen 	} else iter_scrub_ds(iq->response, NULL, NULL);
32222be9e038Ssthen 	if(type == RESPONSE_TYPE_THROWAWAY &&
32232be9e038Ssthen 		FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
32242be9e038Ssthen 		/* YXDOMAIN is a permanent error, no need to retry */
32252be9e038Ssthen 		type = RESPONSE_TYPE_ANSWER;
32262be9e038Ssthen 	}
32278b7325afSsthen 	if(type == RESPONSE_TYPE_CNAME)
32288b7325afSsthen 		origtypecname = 1;
32292be9e038Ssthen 	if(type == RESPONSE_TYPE_CNAME && iq->response->rep->an_numrrsets >= 1
32302be9e038Ssthen 		&& ntohs(iq->response->rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_DNAME) {
32312be9e038Ssthen 		uint8_t* sname = NULL;
32322be9e038Ssthen 		size_t snamelen = 0;
32332be9e038Ssthen 		get_cname_target(iq->response->rep->rrsets[0], &sname,
32342be9e038Ssthen 			&snamelen);
32352be9e038Ssthen 		if(snamelen && dname_subdomain_c(sname, iq->response->rep->rrsets[0]->rk.dname)) {
32362be9e038Ssthen 			/* DNAME to a subdomain loop; do not recurse */
32372be9e038Ssthen 			type = RESPONSE_TYPE_ANSWER;
32382be9e038Ssthen 		}
32392bdc0ed1Ssthen 	}
32402bdc0ed1Ssthen 	if(type == RESPONSE_TYPE_CNAME &&
32412308e98cSsthen 		iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
32422308e98cSsthen 		iq->minimisation_state == MINIMISE_STATE &&
32432308e98cSsthen 		query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) {
32442308e98cSsthen 		/* The minimised query for full QTYPE and hidden QTYPE can be
32452308e98cSsthen 		 * classified as CNAME response type, even when the original
32462308e98cSsthen 		 * QTYPE=CNAME. This should be treated as answer response type.
32472308e98cSsthen 		 */
32482308e98cSsthen 		type = RESPONSE_TYPE_ANSWER;
32492be9e038Ssthen 	}
3250933707f3Ssthen 
3251933707f3Ssthen 	/* handle each of the type cases */
3252933707f3Ssthen 	if(type == RESPONSE_TYPE_ANSWER) {
3253933707f3Ssthen 		/* ANSWER type responses terminate the query algorithm,
3254933707f3Ssthen 		 * so they sent on their */
3255933707f3Ssthen 		if(verbosity >= VERB_DETAIL) {
3256933707f3Ssthen 			verbose(VERB_DETAIL, "query response was %s",
3257933707f3Ssthen 				FLAGS_GET_RCODE(iq->response->rep->flags)
3258933707f3Ssthen 				==LDNS_RCODE_NXDOMAIN?"NXDOMAIN ANSWER":
3259933707f3Ssthen 				(iq->response->rep->an_numrrsets?"ANSWER":
3260933707f3Ssthen 				"nodata ANSWER"));
3261933707f3Ssthen 		}
3262d8d14d0cSsthen 		/* if qtype is DS, check we have the right level of answer,
3263d8d14d0cSsthen 		 * like grandchild answer but we need the middle, reject it */
3264d8d14d0cSsthen 		if(iq->qchase.qtype == LDNS_RR_TYPE_DS && !iq->dsns_point
3265d8d14d0cSsthen 			&& !(iq->chase_flags&BIT_RD)
3266d8d14d0cSsthen 			&& iter_ds_toolow(iq->response, iq->dp)
32673dcb24b8Ssthen 			&& iter_dp_cangodown(&iq->qchase, iq->dp)) {
32683dcb24b8Ssthen 			/* close down outstanding requests to be discarded */
32693dcb24b8Ssthen 			outbound_list_clear(&iq->outlist);
32703dcb24b8Ssthen 			iq->num_current_queries = 0;
32713dcb24b8Ssthen 			fptr_ok(fptr_whitelist_modenv_detach_subs(
32723dcb24b8Ssthen 				qstate->env->detach_subs));
32733dcb24b8Ssthen 			(*qstate->env->detach_subs)(qstate);
32743dcb24b8Ssthen 			iq->num_target_queries = 0;
3275d8d14d0cSsthen 			return processDSNSFind(qstate, iq, id);
32763dcb24b8Ssthen 		}
327777079be7Ssthen 		if(!qstate->no_cache_store)
32783dcb24b8Ssthen 			iter_dns_store(qstate->env, &iq->response->qinfo,
32790bdb4f62Ssthen 				iq->response->rep,
32800bdb4f62Ssthen 				iq->qchase.qtype != iq->response->qinfo.qtype,
32810bdb4f62Ssthen 				qstate->prefetch_leeway,
3282d8d14d0cSsthen 				iq->dp&&iq->dp->has_parent_side_NS,
3283d1e2768aSsthen 				qstate->region, qstate->query_flags,
3284d1e2768aSsthen 				qstate->qstarttime);
3285933707f3Ssthen 		/* close down outstanding requests to be discarded */
3286933707f3Ssthen 		outbound_list_clear(&iq->outlist);
3287933707f3Ssthen 		iq->num_current_queries = 0;
3288933707f3Ssthen 		fptr_ok(fptr_whitelist_modenv_detach_subs(
3289933707f3Ssthen 			qstate->env->detach_subs));
3290933707f3Ssthen 		(*qstate->env->detach_subs)(qstate);
3291933707f3Ssthen 		iq->num_target_queries = 0;
3292933707f3Ssthen 		if(qstate->reply)
3293933707f3Ssthen 			sock_list_insert(&qstate->reply_origin,
329445872187Ssthen 				&qstate->reply->remote_addr,
329545872187Ssthen 				qstate->reply->remote_addrlen, qstate->region);
3296452a1548Ssthen 		if(iq->minimisation_state != DONOT_MINIMISE_STATE
3297452a1548Ssthen 			&& !(iq->chase_flags & BIT_RD)) {
329824893edcSsthen 			if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
329977079be7Ssthen 				LDNS_RCODE_NOERROR) {
3300550cf4a9Ssthen 				if(qstate->env->cfg->qname_minimisation_strict) {
3301550cf4a9Ssthen 					if(FLAGS_GET_RCODE(iq->response->rep->flags) ==
3302550cf4a9Ssthen 						LDNS_RCODE_NXDOMAIN) {
3303550cf4a9Ssthen 						iter_scrub_nxdomain(iq->response);
330477079be7Ssthen 						return final_state(iq);
3305550cf4a9Ssthen 					}
3306*98bc733bSsthen 					return error_response_cache(qstate, id,
3307550cf4a9Ssthen 						LDNS_RCODE_SERVFAIL);
3308550cf4a9Ssthen 				}
330977079be7Ssthen 				/* Best effort qname-minimisation.
331077079be7Ssthen 				 * Stop minimising and send full query when
331177079be7Ssthen 				 * RCODE is not NOERROR. */
331224893edcSsthen 				iq->minimisation_state = DONOT_MINIMISE_STATE;
331377079be7Ssthen 			}
33142ee382b6Ssthen 			if(FLAGS_GET_RCODE(iq->response->rep->flags) ==
33158b7325afSsthen 				LDNS_RCODE_NXDOMAIN && !origtypecname) {
33162ee382b6Ssthen 				/* Stop resolving when NXDOMAIN is DNSSEC
3317bdfc4d55Sflorian 				 * signed. Based on assumption that nameservers
33182ee382b6Ssthen 				 * serving signed zones do not return NXDOMAIN
33192ee382b6Ssthen 				 * for empty-non-terminals. */
33208b7325afSsthen 				/* If this response is actually a CNAME type,
33218b7325afSsthen 				 * the nxdomain rcode may not be for the qname,
33228b7325afSsthen 				 * and so it is not the final response. */
33232ee382b6Ssthen 				if(iq->dnssec_expected)
33242ee382b6Ssthen 					return final_state(iq);
33252ee382b6Ssthen 				/* Make subrequest to validate intermediate
33262ee382b6Ssthen 				 * NXDOMAIN if harden-below-nxdomain is
33272ee382b6Ssthen 				 * enabled. */
332806a13c09Ssthen 				if(qstate->env->cfg->harden_below_nxdomain &&
332906a13c09Ssthen 					qstate->env->need_to_validate) {
33302ee382b6Ssthen 					struct module_qstate* subq = NULL;
33312ee382b6Ssthen 					log_query_info(VERB_QUERY,
33322ee382b6Ssthen 						"schedule NXDOMAIN validation:",
33332ee382b6Ssthen 						&iq->response->qinfo);
33342ee382b6Ssthen 					if(!generate_sub_request(
33352ee382b6Ssthen 						iq->response->qinfo.qname,
33362ee382b6Ssthen 						iq->response->qinfo.qname_len,
33372ee382b6Ssthen 						iq->response->qinfo.qtype,
33382ee382b6Ssthen 						iq->response->qinfo.qclass,
33392ee382b6Ssthen 						qstate, id, iq,
33402ee382b6Ssthen 						INIT_REQUEST_STATE,
334106a13c09Ssthen 						FINISHED_STATE, &subq, 1, 1))
33422ee382b6Ssthen 						verbose(VERB_ALGO,
33432ee382b6Ssthen 						"could not validate NXDOMAIN "
33442ee382b6Ssthen 						"response");
33452ee382b6Ssthen 				}
33462ee382b6Ssthen 			}
334724893edcSsthen 			return next_state(iq, QUERYTARGETS_STATE);
334824893edcSsthen 		}
3349933707f3Ssthen 		return final_state(iq);
3350933707f3Ssthen 	} else if(type == RESPONSE_TYPE_REFERRAL) {
33512bdc0ed1Ssthen 		struct delegpt* old_dp = NULL;
3352933707f3Ssthen 		/* REFERRAL type responses get a reset of the
3353933707f3Ssthen 		 * delegation point, and back to the QUERYTARGETS_STATE. */
3354933707f3Ssthen 		verbose(VERB_DETAIL, "query response was REFERRAL");
3355933707f3Ssthen 
3356933707f3Ssthen 		/* if hardened, only store referral if we asked for it */
335777079be7Ssthen 		if(!qstate->no_cache_store &&
335877079be7Ssthen 		(!qstate->env->cfg->harden_referral_path ||
3359933707f3Ssthen 		    (  qstate->qinfo.qtype == LDNS_RR_TYPE_NS
3360933707f3Ssthen 			&& (qstate->query_flags&BIT_RD)
3361933707f3Ssthen 			&& !(qstate->query_flags&BIT_CD)
3362933707f3Ssthen 			   /* we know that all other NS rrsets are scrubbed
3363933707f3Ssthen 			    * away, thus on referral only one is left.
3364933707f3Ssthen 			    * see if that equals the query name... */
3365933707f3Ssthen 			&& ( /* auth section, but sometimes in answer section*/
3366933707f3Ssthen 			  reply_find_rrset_section_ns(iq->response->rep,
3367933707f3Ssthen 				iq->qchase.qname, iq->qchase.qname_len,
3368933707f3Ssthen 				LDNS_RR_TYPE_NS, iq->qchase.qclass)
3369933707f3Ssthen 			  || reply_find_rrset_section_an(iq->response->rep,
3370933707f3Ssthen 				iq->qchase.qname, iq->qchase.qname_len,
3371933707f3Ssthen 				LDNS_RR_TYPE_NS, iq->qchase.qclass)
3372933707f3Ssthen 			  )
337377079be7Ssthen 		    ))) {
3374933707f3Ssthen 			/* Store the referral under the current query */
3375933707f3Ssthen 			/* no prefetch-leeway, since its not the answer */
33763dcb24b8Ssthen 			iter_dns_store(qstate->env, &iq->response->qinfo,
3377d1e2768aSsthen 				iq->response->rep, 1, 0, 0, NULL, 0,
3378d1e2768aSsthen 				qstate->qstarttime);
3379933707f3Ssthen 			if(iq->store_parent_NS)
3380933707f3Ssthen 				iter_store_parentside_NS(qstate->env,
3381933707f3Ssthen 					iq->response->rep);
3382933707f3Ssthen 			if(qstate->env->neg_cache)
3383933707f3Ssthen 				val_neg_addreferral(qstate->env->neg_cache,
3384933707f3Ssthen 					iq->response->rep, iq->dp->name);
3385933707f3Ssthen 		}
3386933707f3Ssthen 		/* store parent-side-in-zone-glue, if directly queried for */
338777079be7Ssthen 		if(!qstate->no_cache_store && iq->query_for_pside_glue
338877079be7Ssthen 			&& !iq->pside_glue) {
3389933707f3Ssthen 				iq->pside_glue = reply_find_rrset(iq->response->rep,
3390933707f3Ssthen 					iq->qchase.qname, iq->qchase.qname_len,
3391933707f3Ssthen 					iq->qchase.qtype, iq->qchase.qclass);
3392933707f3Ssthen 				if(iq->pside_glue) {
3393933707f3Ssthen 					log_rrset_key(VERB_ALGO, "found parent-side "
3394933707f3Ssthen 						"glue", iq->pside_glue);
3395933707f3Ssthen 					iter_store_parentside_rrset(qstate->env,
3396933707f3Ssthen 						iq->pside_glue);
3397933707f3Ssthen 				}
3398933707f3Ssthen 		}
3399933707f3Ssthen 
3400933707f3Ssthen 		/* Reset the event state, setting the current delegation
3401933707f3Ssthen 		 * point to the referral. */
3402933707f3Ssthen 		iq->deleg_msg = iq->response;
34032bdc0ed1Ssthen 		/* Keep current delegation point for label comparison */
34042bdc0ed1Ssthen 		old_dp = iq->dp;
3405933707f3Ssthen 		iq->dp = delegpt_from_message(iq->response, qstate->region);
340624893edcSsthen 		if (qstate->env->cfg->qname_minimisation)
340724893edcSsthen 			iq->minimisation_state = INIT_MINIMISE_STATE;
34082308e98cSsthen 		if(!iq->dp) {
34092308e98cSsthen 			errinf(qstate, "malloc failure, for delegation point");
3410933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
34112308e98cSsthen 		}
34122bdc0ed1Ssthen 		if(old_dp->namelabs + 1 < iq->dp->namelabs) {
34132bdc0ed1Ssthen 			/* We got a grandchild delegation (more than one label
34142bdc0ed1Ssthen 			 * difference) than expected. Check for in-between
34152bdc0ed1Ssthen 			 * delegations in the cache and remove them.
34162bdc0ed1Ssthen 			 * They could prove problematic when they expire
34172bdc0ed1Ssthen 			 * and rrset_expired_above() encounters them during
34182bdc0ed1Ssthen 			 * delegation cache lookups. */
34192bdc0ed1Ssthen 			uint8_t* qname = iq->dp->name;
34202bdc0ed1Ssthen 			size_t qnamelen = iq->dp->namelen;
34212bdc0ed1Ssthen 			rrset_cache_remove_above(qstate->env->rrset_cache,
34222bdc0ed1Ssthen 				&qname, &qnamelen, LDNS_RR_TYPE_NS,
34232bdc0ed1Ssthen 				iq->qchase.qclass, *qstate->env->now,
34242bdc0ed1Ssthen 				old_dp->name, old_dp->namelen);
34252bdc0ed1Ssthen 		}
3426933707f3Ssthen 		if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
34272308e98cSsthen 			qstate->region, iq->dp)) {
34282308e98cSsthen 			errinf(qstate, "malloc failure, copy extra info into delegation point");
3429933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
34302308e98cSsthen 		}
3431933707f3Ssthen 		if(iq->store_parent_NS && query_dname_compare(iq->dp->name,
3432933707f3Ssthen 			iq->store_parent_NS->name) == 0)
3433e21c60efSsthen 			iter_merge_retry_counts(iq->dp, iq->store_parent_NS,
3434e21c60efSsthen 				ie->outbound_msg_retry);
3435933707f3Ssthen 		delegpt_log(VERB_ALGO, iq->dp);
3436933707f3Ssthen 		/* Count this as a referral. */
3437933707f3Ssthen 		iq->referral_count++;
3438933707f3Ssthen 		iq->sent_count = 0;
343906a13c09Ssthen 		iq->dp_target_count = 0;
3440933707f3Ssthen 		/* see if the next dp is a trust anchor, or a DS was sent
3441933707f3Ssthen 		 * along, indicating dnssec is expected for next zone */
3442933707f3Ssthen 		iq->dnssec_expected = iter_indicates_dnssec(qstate->env,
3443933707f3Ssthen 			iq->dp, iq->response, iq->qchase.qclass);
3444933707f3Ssthen 		/* if dnssec, validating then also fetch the key for the DS */
3445933707f3Ssthen 		if(iq->dnssec_expected && qstate->env->cfg->prefetch_key &&
3446933707f3Ssthen 			!(qstate->query_flags&BIT_CD))
3447933707f3Ssthen 			generate_dnskey_prefetch(qstate, iq, id);
3448933707f3Ssthen 
3449933707f3Ssthen 		/* spawn off NS and addr to auth servers for the NS we just
3450933707f3Ssthen 		 * got in the referral. This gets authoritative answer
3451933707f3Ssthen 		 * (answer section trust level) rrset.
3452933707f3Ssthen 		 * right after, we detach the subs, answer goes to cache. */
3453933707f3Ssthen 		if(qstate->env->cfg->harden_referral_path)
3454933707f3Ssthen 			generate_ns_check(qstate, iq, id);
3455933707f3Ssthen 
3456933707f3Ssthen 		/* stop current outstanding queries.
3457933707f3Ssthen 		 * FIXME: should the outstanding queries be waited for and
3458933707f3Ssthen 		 * handled? Say by a subquery that inherits the outbound_entry.
3459933707f3Ssthen 		 */
3460933707f3Ssthen 		outbound_list_clear(&iq->outlist);
3461933707f3Ssthen 		iq->num_current_queries = 0;
3462933707f3Ssthen 		fptr_ok(fptr_whitelist_modenv_detach_subs(
3463933707f3Ssthen 			qstate->env->detach_subs));
3464933707f3Ssthen 		(*qstate->env->detach_subs)(qstate);
3465933707f3Ssthen 		iq->num_target_queries = 0;
3466191f22c6Ssthen 		iq->response = NULL;
34678b7325afSsthen 		iq->fail_addr_type = 0;
3468933707f3Ssthen 		verbose(VERB_ALGO, "cleared outbound list for next round");
3469933707f3Ssthen 		return next_state(iq, QUERYTARGETS_STATE);
3470933707f3Ssthen 	} else if(type == RESPONSE_TYPE_CNAME) {
3471933707f3Ssthen 		uint8_t* sname = NULL;
3472933707f3Ssthen 		size_t snamelen = 0;
3473933707f3Ssthen 		/* CNAME type responses get a query restart (i.e., get a
3474933707f3Ssthen 		 * reset of the query state and go back to INIT_REQUEST_STATE).
3475933707f3Ssthen 		 */
3476933707f3Ssthen 		verbose(VERB_DETAIL, "query response was CNAME");
3477933707f3Ssthen 		if(verbosity >= VERB_ALGO)
3478933707f3Ssthen 			log_dns_msg("cname msg", &iq->response->qinfo,
3479933707f3Ssthen 				iq->response->rep);
3480d8d14d0cSsthen 		/* if qtype is DS, check we have the right level of answer,
3481d8d14d0cSsthen 		 * like grandchild answer but we need the middle, reject it */
3482d8d14d0cSsthen 		if(iq->qchase.qtype == LDNS_RR_TYPE_DS && !iq->dsns_point
3483d8d14d0cSsthen 			&& !(iq->chase_flags&BIT_RD)
3484d8d14d0cSsthen 			&& iter_ds_toolow(iq->response, iq->dp)
34853dcb24b8Ssthen 			&& iter_dp_cangodown(&iq->qchase, iq->dp)) {
34863dcb24b8Ssthen 			outbound_list_clear(&iq->outlist);
34873dcb24b8Ssthen 			iq->num_current_queries = 0;
34883dcb24b8Ssthen 			fptr_ok(fptr_whitelist_modenv_detach_subs(
34893dcb24b8Ssthen 				qstate->env->detach_subs));
34903dcb24b8Ssthen 			(*qstate->env->detach_subs)(qstate);
34913dcb24b8Ssthen 			iq->num_target_queries = 0;
3492d8d14d0cSsthen 			return processDSNSFind(qstate, iq, id);
34933dcb24b8Ssthen 		}
3494933707f3Ssthen 		/* Process the CNAME response. */
3495933707f3Ssthen 		if(!handle_cname_response(qstate, iq, iq->response,
34962308e98cSsthen 			&sname, &snamelen)) {
34972308e98cSsthen 			errinf(qstate, "malloc failure, CNAME info");
3498933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
34992308e98cSsthen 		}
3500933707f3Ssthen 		/* cache the CNAME response under the current query */
3501933707f3Ssthen 		/* NOTE : set referral=1, so that rrsets get stored but not
3502933707f3Ssthen 		 * the partial query answer (CNAME only). */
3503933707f3Ssthen 		/* prefetchleeway applied because this updates answer parts */
350477079be7Ssthen 		if(!qstate->no_cache_store)
35053dcb24b8Ssthen 			iter_dns_store(qstate->env, &iq->response->qinfo,
3506d8d14d0cSsthen 				iq->response->rep, 1, qstate->prefetch_leeway,
350757dceb2aSbrad 				iq->dp&&iq->dp->has_parent_side_NS, NULL,
3508d1e2768aSsthen 				qstate->query_flags, qstate->qstarttime);
3509933707f3Ssthen 		/* set the current request's qname to the new value. */
3510933707f3Ssthen 		iq->qchase.qname = sname;
3511933707f3Ssthen 		iq->qchase.qname_len = snamelen;
3512e21c60efSsthen 		if(qstate->env->auth_zones) {
3513e21c60efSsthen 			/* apply rpz qname triggers after cname */
3514e21c60efSsthen 			struct dns_msg* forged_response =
3515e21c60efSsthen 				rpz_callback_from_iterator_cname(qstate, iq);
35162bdc0ed1Ssthen 			int count = 0;
3517e21c60efSsthen 			while(forged_response && reply_find_rrset_section_an(
3518e21c60efSsthen 				forged_response->rep, iq->qchase.qname,
3519e21c60efSsthen 				iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
35202bdc0ed1Ssthen 				iq->qchase.qclass) &&
35212bdc0ed1Ssthen 				iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
35222bdc0ed1Ssthen 				count++ < ie->max_query_restarts) {
3523e21c60efSsthen 				/* another cname to follow */
3524e21c60efSsthen 				if(!handle_cname_response(qstate, iq, forged_response,
3525e21c60efSsthen 					&sname, &snamelen)) {
3526e21c60efSsthen 					errinf(qstate, "malloc failure, CNAME info");
3527e21c60efSsthen 					return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
3528e21c60efSsthen 				}
3529e21c60efSsthen 				iq->qchase.qname = sname;
3530e21c60efSsthen 				iq->qchase.qname_len = snamelen;
3531e21c60efSsthen 				forged_response =
3532e21c60efSsthen 					rpz_callback_from_iterator_cname(qstate, iq);
3533e21c60efSsthen 			}
3534e21c60efSsthen 			if(forged_response != NULL) {
3535e21c60efSsthen 				qstate->ext_state[id] = module_finished;
3536e21c60efSsthen 				qstate->return_rcode = LDNS_RCODE_NOERROR;
3537e21c60efSsthen 				qstate->return_msg = forged_response;
3538e21c60efSsthen 				iq->response = forged_response;
3539e21c60efSsthen 				next_state(iq, FINISHED_STATE);
3540e21c60efSsthen 				if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
35410bdb4f62Ssthen 					log_err("rpz: after cname, prepend rrsets: out of memory");
3542e21c60efSsthen 					return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
3543e21c60efSsthen 				}
3544e21c60efSsthen 				qstate->return_msg->qinfo = qstate->qinfo;
3545e21c60efSsthen 				return 0;
3546e21c60efSsthen 			}
3547e21c60efSsthen 		}
3548933707f3Ssthen 		/* Clear the query state, since this is a query restart. */
3549933707f3Ssthen 		iq->deleg_msg = NULL;
3550933707f3Ssthen 		iq->dp = NULL;
3551d8d14d0cSsthen 		iq->dsns_point = NULL;
3552938a3a5eSflorian 		iq->auth_zone_response = 0;
3553933707f3Ssthen 		iq->sent_count = 0;
355406a13c09Ssthen 		iq->dp_target_count = 0;
355520237c55Ssthen 		if(iq->minimisation_state != MINIMISE_STATE)
355620237c55Ssthen 			/* Only count as query restart when it is not an extra
355720237c55Ssthen 			 * query as result of qname minimisation. */
355820237c55Ssthen 			iq->query_restart_count++;
355920237c55Ssthen 		if(qstate->env->cfg->qname_minimisation)
356020237c55Ssthen 			iq->minimisation_state = INIT_MINIMISE_STATE;
3561933707f3Ssthen 
3562933707f3Ssthen 		/* stop current outstanding queries.
3563933707f3Ssthen 		 * FIXME: should the outstanding queries be waited for and
3564933707f3Ssthen 		 * handled? Say by a subquery that inherits the outbound_entry.
3565933707f3Ssthen 		 */
3566933707f3Ssthen 		outbound_list_clear(&iq->outlist);
3567933707f3Ssthen 		iq->num_current_queries = 0;
3568933707f3Ssthen 		fptr_ok(fptr_whitelist_modenv_detach_subs(
3569933707f3Ssthen 			qstate->env->detach_subs));
3570933707f3Ssthen 		(*qstate->env->detach_subs)(qstate);
3571933707f3Ssthen 		iq->num_target_queries = 0;
3572933707f3Ssthen 		if(qstate->reply)
3573933707f3Ssthen 			sock_list_insert(&qstate->reply_origin,
357445872187Ssthen 				&qstate->reply->remote_addr,
357545872187Ssthen 				qstate->reply->remote_addrlen, qstate->region);
3576933707f3Ssthen 		verbose(VERB_ALGO, "cleared outbound list for query restart");
3577933707f3Ssthen 		/* go to INIT_REQUEST_STATE for new qname. */
3578933707f3Ssthen 		return next_state(iq, INIT_REQUEST_STATE);
3579933707f3Ssthen 	} else if(type == RESPONSE_TYPE_LAME) {
3580933707f3Ssthen 		/* Cache the LAMEness. */
3581933707f3Ssthen 		verbose(VERB_DETAIL, "query response was %sLAME",
3582933707f3Ssthen 			dnsseclame?"DNSSEC ":"");
3583933707f3Ssthen 		if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) {
3584933707f3Ssthen 			log_err("mark lame: mismatch in qname and dpname");
3585933707f3Ssthen 			/* throwaway this reply below */
3586933707f3Ssthen 		} else if(qstate->reply) {
3587933707f3Ssthen 			/* need addr for lameness cache, but we may have
3588933707f3Ssthen 			 * gotten this from cache, so test to be sure */
3589933707f3Ssthen 			if(!infra_set_lame(qstate->env->infra_cache,
359045872187Ssthen 				&qstate->reply->remote_addr,
359145872187Ssthen 				qstate->reply->remote_addrlen,
3592933707f3Ssthen 				iq->dp->name, iq->dp->namelen,
3593933707f3Ssthen 				*qstate->env->now, dnsseclame, 0,
3594933707f3Ssthen 				iq->qchase.qtype))
3595933707f3Ssthen 				log_err("mark host lame: out of memory");
3596229e174cSsthen 		}
3597933707f3Ssthen 	} else if(type == RESPONSE_TYPE_REC_LAME) {
3598933707f3Ssthen 		/* Cache the LAMEness. */
3599933707f3Ssthen 		verbose(VERB_DETAIL, "query response REC_LAME: "
3600933707f3Ssthen 			"recursive but not authoritative server");
3601933707f3Ssthen 		if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) {
3602933707f3Ssthen 			log_err("mark rec_lame: mismatch in qname and dpname");
3603933707f3Ssthen 			/* throwaway this reply below */
3604933707f3Ssthen 		} else if(qstate->reply) {
3605933707f3Ssthen 			/* need addr for lameness cache, but we may have
3606933707f3Ssthen 			 * gotten this from cache, so test to be sure */
3607933707f3Ssthen 			verbose(VERB_DETAIL, "mark as REC_LAME");
3608933707f3Ssthen 			if(!infra_set_lame(qstate->env->infra_cache,
360945872187Ssthen 				&qstate->reply->remote_addr,
361045872187Ssthen 				qstate->reply->remote_addrlen,
3611933707f3Ssthen 				iq->dp->name, iq->dp->namelen,
3612933707f3Ssthen 				*qstate->env->now, 0, 1, iq->qchase.qtype))
3613933707f3Ssthen 				log_err("mark host lame: out of memory");
3614933707f3Ssthen 		}
3615933707f3Ssthen 	} else if(type == RESPONSE_TYPE_THROWAWAY) {
3616933707f3Ssthen 		/* LAME and THROWAWAY responses are handled the same way.
3617933707f3Ssthen 		 * In this case, the event is just sent directly back to
3618933707f3Ssthen 		 * the QUERYTARGETS_STATE without resetting anything,
3619933707f3Ssthen 		 * because, clearly, the next target must be tried. */
3620933707f3Ssthen 		verbose(VERB_DETAIL, "query response was THROWAWAY");
3621933707f3Ssthen 	} else {
3622933707f3Ssthen 		log_warn("A query response came back with an unknown type: %d",
3623933707f3Ssthen 			(int)type);
3624933707f3Ssthen 	}
3625933707f3Ssthen 
3626933707f3Ssthen 	/* LAME, THROWAWAY and "unknown" all end up here.
3627933707f3Ssthen 	 * Recycle to the QUERYTARGETS state to hopefully try a
3628933707f3Ssthen 	 * different target. */
362977079be7Ssthen 	if (qstate->env->cfg->qname_minimisation &&
363077079be7Ssthen 		!qstate->env->cfg->qname_minimisation_strict)
363124893edcSsthen 		iq->minimisation_state = DONOT_MINIMISE_STATE;
3632938a3a5eSflorian 	if(iq->auth_zone_response) {
3633938a3a5eSflorian 		/* can we fallback? */
3634938a3a5eSflorian 		iq->auth_zone_response = 0;
3635938a3a5eSflorian 		if(!auth_zones_can_fallback(qstate->env->auth_zones,
3636938a3a5eSflorian 			iq->dp->name, iq->dp->namelen, qstate->qinfo.qclass)) {
3637938a3a5eSflorian 			verbose(VERB_ALGO, "auth zone response bad, and no"
3638938a3a5eSflorian 				" fallback possible, servfail");
3639452a1548Ssthen 			errinf_dname(qstate, "response is bad, no fallback, "
36402308e98cSsthen 				"for auth zone", iq->dp->name);
3641*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
3642938a3a5eSflorian 		}
3643938a3a5eSflorian 		verbose(VERB_ALGO, "auth zone response was bad, "
3644938a3a5eSflorian 			"fallback enabled");
3645938a3a5eSflorian 		iq->auth_zone_avoid = 1;
3646938a3a5eSflorian 		if(iq->dp->auth_dp) {
3647938a3a5eSflorian 			/* we are using a dp for the auth zone, with no
3648938a3a5eSflorian 			 * nameservers, get one first */
3649938a3a5eSflorian 			iq->dp = NULL;
3650938a3a5eSflorian 			return next_state(iq, INIT_REQUEST_STATE);
3651938a3a5eSflorian 		}
3652938a3a5eSflorian 	}
3653933707f3Ssthen 	return next_state(iq, QUERYTARGETS_STATE);
3654933707f3Ssthen }
3655933707f3Ssthen 
3656933707f3Ssthen /**
365757dceb2aSbrad  * Return priming query results to interested super querystates.
3658933707f3Ssthen  *
3659933707f3Ssthen  * Sets the delegation point and delegation message (not nonRD queries).
3660933707f3Ssthen  * This is a callback from walk_supers.
3661933707f3Ssthen  *
3662933707f3Ssthen  * @param qstate: priming query state that finished.
3663933707f3Ssthen  * @param id: module id.
3664933707f3Ssthen  * @param forq: the qstate for which priming has been done.
3665933707f3Ssthen  */
3666933707f3Ssthen static void
3667933707f3Ssthen prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
3668933707f3Ssthen {
3669933707f3Ssthen 	struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
3670933707f3Ssthen 	struct delegpt* dp = NULL;
3671933707f3Ssthen 
3672933707f3Ssthen 	log_assert(qstate->is_priming || foriq->wait_priming_stub);
3673933707f3Ssthen 	log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR);
3674933707f3Ssthen 	/* Convert our response to a delegation point */
3675933707f3Ssthen 	dp = delegpt_from_message(qstate->return_msg, forq->region);
3676933707f3Ssthen 	if(!dp) {
3677e21c60efSsthen 		/* if there is no convertible delegation point, then
3678933707f3Ssthen 		 * the ANSWER type was (presumably) a negative answer. */
3679933707f3Ssthen 		verbose(VERB_ALGO, "prime response was not a positive "
3680933707f3Ssthen 			"ANSWER; failing");
3681933707f3Ssthen 		foriq->dp = NULL;
3682933707f3Ssthen 		foriq->state = QUERYTARGETS_STATE;
3683933707f3Ssthen 		return;
3684933707f3Ssthen 	}
3685933707f3Ssthen 
3686933707f3Ssthen 	log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo);
3687933707f3Ssthen 	delegpt_log(VERB_ALGO, dp);
3688933707f3Ssthen 	foriq->dp = dp;
3689933707f3Ssthen 	foriq->deleg_msg = dns_copy_msg(qstate->return_msg, forq->region);
3690933707f3Ssthen 	if(!foriq->deleg_msg) {
3691933707f3Ssthen 		log_err("copy prime response: out of memory");
3692933707f3Ssthen 		foriq->dp = NULL;
3693933707f3Ssthen 		foriq->state = QUERYTARGETS_STATE;
3694933707f3Ssthen 		return;
3695933707f3Ssthen 	}
3696933707f3Ssthen 
3697933707f3Ssthen 	/* root priming responses go to init stage 2, priming stub
3698933707f3Ssthen 	 * responses to to stage 3. */
3699933707f3Ssthen 	if(foriq->wait_priming_stub) {
3700933707f3Ssthen 		foriq->state = INIT_REQUEST_3_STATE;
3701933707f3Ssthen 		foriq->wait_priming_stub = 0;
3702933707f3Ssthen 	} else	foriq->state = INIT_REQUEST_2_STATE;
3703933707f3Ssthen 	/* because we are finished, the parent will be reactivated */
3704933707f3Ssthen }
3705933707f3Ssthen 
3706933707f3Ssthen /**
3707933707f3Ssthen  * This handles the response to a priming query. This is used to handle both
3708933707f3Ssthen  * root and stub priming responses. This is basically the equivalent of the
3709933707f3Ssthen  * QUERY_RESP_STATE, but will not handle CNAME responses and will treat
3710933707f3Ssthen  * REFERRALs as ANSWERS. It will also update and reactivate the originating
3711933707f3Ssthen  * event.
3712933707f3Ssthen  *
3713933707f3Ssthen  * @param qstate: query state.
3714933707f3Ssthen  * @param id: module id.
3715933707f3Ssthen  * @return true if the event needs more immediate processing, false if not.
3716933707f3Ssthen  *         This state always returns false.
3717933707f3Ssthen  */
3718933707f3Ssthen static int
3719933707f3Ssthen processPrimeResponse(struct module_qstate* qstate, int id)
3720933707f3Ssthen {
3721933707f3Ssthen 	struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
3722933707f3Ssthen 	enum response_type type;
3723933707f3Ssthen 	iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */
3724933707f3Ssthen 	type = response_type_from_server(
3725933707f3Ssthen 		(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
3726d896b962Ssthen 		iq->response, &iq->qchase, iq->dp, NULL);
3727933707f3Ssthen 	if(type == RESPONSE_TYPE_ANSWER) {
3728933707f3Ssthen 		qstate->return_rcode = LDNS_RCODE_NOERROR;
3729933707f3Ssthen 		qstate->return_msg = iq->response;
3730933707f3Ssthen 	} else {
37312308e98cSsthen 		errinf(qstate, "prime response did not get an answer");
37322308e98cSsthen 		errinf_dname(qstate, "for", qstate->qinfo.qname);
3733933707f3Ssthen 		qstate->return_rcode = LDNS_RCODE_SERVFAIL;
3734933707f3Ssthen 		qstate->return_msg = NULL;
3735933707f3Ssthen 	}
3736933707f3Ssthen 
3737933707f3Ssthen 	/* validate the root or stub after priming (if enabled).
3738933707f3Ssthen 	 * This is the same query as the prime query, but with validation.
3739933707f3Ssthen 	 * Now that we are primed, the additional queries that validation
37402c144df0Ssthen 	 * may need can be resolved. */
3741933707f3Ssthen 	if(qstate->env->cfg->harden_referral_path) {
3742933707f3Ssthen 		struct module_qstate* subq = NULL;
3743933707f3Ssthen 		log_nametypeclass(VERB_ALGO, "schedule prime validation",
3744933707f3Ssthen 			qstate->qinfo.qname, qstate->qinfo.qtype,
3745933707f3Ssthen 			qstate->qinfo.qclass);
3746933707f3Ssthen 		if(!generate_sub_request(qstate->qinfo.qname,
3747933707f3Ssthen 			qstate->qinfo.qname_len, qstate->qinfo.qtype,
3748933707f3Ssthen 			qstate->qinfo.qclass, qstate, id, iq,
374906a13c09Ssthen 			INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
3750933707f3Ssthen 			verbose(VERB_ALGO, "could not generate prime check");
3751933707f3Ssthen 		}
3752933707f3Ssthen 		generate_a_aaaa_check(qstate, iq, id);
3753933707f3Ssthen 	}
3754933707f3Ssthen 
3755933707f3Ssthen 	/* This event is finished. */
3756933707f3Ssthen 	qstate->ext_state[id] = module_finished;
3757933707f3Ssthen 	return 0;
3758933707f3Ssthen }
3759933707f3Ssthen 
3760933707f3Ssthen /**
3761933707f3Ssthen  * Do final processing on responses to target queries. Events reach this
3762933707f3Ssthen  * state after the iterative resolution algorithm terminates. This state is
3763bdfc4d55Sflorian  * responsible for reactivating the original event, and housekeeping related
3764933707f3Ssthen  * to received target responses (caching, updating the current delegation
3765933707f3Ssthen  * point, etc).
3766933707f3Ssthen  * Callback from walk_supers for every super state that is interested in
3767933707f3Ssthen  * the results from this query.
3768933707f3Ssthen  *
3769933707f3Ssthen  * @param qstate: query state.
3770933707f3Ssthen  * @param id: module id.
3771933707f3Ssthen  * @param forq: super query state.
3772933707f3Ssthen  */
3773933707f3Ssthen static void
3774933707f3Ssthen processTargetResponse(struct module_qstate* qstate, int id,
3775933707f3Ssthen 	struct module_qstate* forq)
3776933707f3Ssthen {
377706a13c09Ssthen 	struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
3778933707f3Ssthen 	struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
3779933707f3Ssthen 	struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
3780933707f3Ssthen 	struct ub_packed_rrset_key* rrset;
3781933707f3Ssthen 	struct delegpt_ns* dpns;
3782933707f3Ssthen 	log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR);
3783933707f3Ssthen 
3784933707f3Ssthen 	foriq->state = QUERYTARGETS_STATE;
3785933707f3Ssthen 	log_query_info(VERB_ALGO, "processTargetResponse", &qstate->qinfo);
3786933707f3Ssthen 	log_query_info(VERB_ALGO, "processTargetResponse super", &forq->qinfo);
3787933707f3Ssthen 
3788e024f976Ssthen 	/* Tell the originating event that this target query has finished
3789e024f976Ssthen 	 * (regardless if it succeeded or not). */
3790e024f976Ssthen 	foriq->num_target_queries--;
3791e024f976Ssthen 
3792933707f3Ssthen 	/* check to see if parent event is still interested (in orig name).  */
3793933707f3Ssthen 	if(!foriq->dp) {
3794933707f3Ssthen 		verbose(VERB_ALGO, "subq: parent not interested, was reset");
3795933707f3Ssthen 		return; /* not interested anymore */
3796933707f3Ssthen 	}
3797933707f3Ssthen 	dpns = delegpt_find_ns(foriq->dp, qstate->qinfo.qname,
3798933707f3Ssthen 			qstate->qinfo.qname_len);
3799933707f3Ssthen 	if(!dpns) {
3800933707f3Ssthen 		/* If not interested, just stop processing this event */
3801933707f3Ssthen 		verbose(VERB_ALGO, "subq: parent not interested anymore");
3802933707f3Ssthen 		/* could be because parent was jostled out of the cache,
3803933707f3Ssthen 		   and a new identical query arrived, that does not want it*/
3804933707f3Ssthen 		return;
3805933707f3Ssthen 	}
3806933707f3Ssthen 
3807933707f3Ssthen 	/* if iq->query_for_pside_glue then add the pside_glue (marked lame) */
3808933707f3Ssthen 	if(iq->pside_glue) {
3809933707f3Ssthen 		/* if the pside_glue is NULL, then it could not be found,
3810933707f3Ssthen 		 * the done_pside is already set when created and a cache
3811933707f3Ssthen 		 * entry created in processFinished so nothing to do here */
3812933707f3Ssthen 		log_rrset_key(VERB_ALGO, "add parentside glue to dp",
3813933707f3Ssthen 			iq->pside_glue);
3814933707f3Ssthen 		if(!delegpt_add_rrset(foriq->dp, forq->region,
381506a13c09Ssthen 			iq->pside_glue, 1, NULL))
3816933707f3Ssthen 			log_err("out of memory adding pside glue");
3817933707f3Ssthen 	}
3818933707f3Ssthen 
3819933707f3Ssthen 	/* This response is relevant to the current query, so we
3820933707f3Ssthen 	 * add (attempt to add, anyway) this target(s) and reactivate
3821933707f3Ssthen 	 * the original event.
3822933707f3Ssthen 	 * NOTE: we could only look for the AnswerRRset if the
3823933707f3Ssthen 	 * response type was ANSWER. */
3824933707f3Ssthen 	rrset = reply_find_answer_rrset(&iq->qchase, qstate->return_msg->rep);
3825933707f3Ssthen 	if(rrset) {
382606a13c09Ssthen 		int additions = 0;
3827933707f3Ssthen 		/* if CNAMEs have been followed - add new NS to delegpt. */
3828933707f3Ssthen 		/* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */
3829933707f3Ssthen 		if(!delegpt_find_ns(foriq->dp, rrset->rk.dname,
3830933707f3Ssthen 			rrset->rk.dname_len)) {
3831933707f3Ssthen 			/* if dpns->lame then set newcname ns lame too */
3832933707f3Ssthen 			if(!delegpt_add_ns(foriq->dp, forq->region,
3833e21c60efSsthen 				rrset->rk.dname, dpns->lame, dpns->tls_auth_name,
3834e21c60efSsthen 				dpns->port))
3835933707f3Ssthen 				log_err("out of memory adding cnamed-ns");
3836933707f3Ssthen 		}
3837933707f3Ssthen 		/* if dpns->lame then set the address(es) lame too */
3838933707f3Ssthen 		if(!delegpt_add_rrset(foriq->dp, forq->region, rrset,
383906a13c09Ssthen 			dpns->lame, &additions))
3840933707f3Ssthen 			log_err("out of memory adding targets");
384106a13c09Ssthen 		if(!additions) {
384206a13c09Ssthen 			/* no new addresses, increase the nxns counter, like
384306a13c09Ssthen 			 * this could be a list of wildcards with no new
384406a13c09Ssthen 			 * addresses */
384506a13c09Ssthen 			target_count_increase_nx(foriq, 1);
384606a13c09Ssthen 		}
3847933707f3Ssthen 		verbose(VERB_ALGO, "added target response");
3848933707f3Ssthen 		delegpt_log(VERB_ALGO, foriq->dp);
3849933707f3Ssthen 	} else {
3850933707f3Ssthen 		verbose(VERB_ALGO, "iterator TargetResponse failed");
385106a13c09Ssthen 		delegpt_mark_neg(dpns, qstate->qinfo.qtype);
38528b7325afSsthen 		if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
385345872187Ssthen 			(dpns->got6 == 2 || !ie->supports_ipv6)) {
385445872187Ssthen 			dpns->resolved = 1; /* fail the target */
3855d1e2768aSsthen 			/* do not count cached answers */
385645872187Ssthen 			if(qstate->reply_origin && qstate->reply_origin->len != 0) {
385706a13c09Ssthen 				target_count_increase_nx(foriq, 1);
3858933707f3Ssthen 			}
3859933707f3Ssthen 		}
3860d1e2768aSsthen 	}
386145872187Ssthen }
3862933707f3Ssthen 
3863933707f3Ssthen /**
3864d8d14d0cSsthen  * Process response for DS NS Find queries, that attempt to find the delegation
3865d8d14d0cSsthen  * point where we ask the DS query from.
3866d8d14d0cSsthen  *
3867d8d14d0cSsthen  * @param qstate: query state.
3868d8d14d0cSsthen  * @param id: module id.
3869d8d14d0cSsthen  * @param forq: super query state.
3870d8d14d0cSsthen  */
3871d8d14d0cSsthen static void
3872d8d14d0cSsthen processDSNSResponse(struct module_qstate* qstate, int id,
3873d8d14d0cSsthen 	struct module_qstate* forq)
3874d8d14d0cSsthen {
3875d8d14d0cSsthen 	struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
3876d8d14d0cSsthen 
3877d8d14d0cSsthen 	/* if the finished (iq->response) query has no NS set: continue
3878d8d14d0cSsthen 	 * up to look for the right dp; nothing to change, do DPNSstate */
3879d8d14d0cSsthen 	if(qstate->return_rcode != LDNS_RCODE_NOERROR)
3880d8d14d0cSsthen 		return; /* seek further */
3881d8d14d0cSsthen 	/* find the NS RRset (without allowing CNAMEs) */
3882d8d14d0cSsthen 	if(!reply_find_rrset(qstate->return_msg->rep, qstate->qinfo.qname,
3883d8d14d0cSsthen 		qstate->qinfo.qname_len, LDNS_RR_TYPE_NS,
3884d8d14d0cSsthen 		qstate->qinfo.qclass)){
3885d8d14d0cSsthen 		return; /* seek further */
3886d8d14d0cSsthen 	}
3887d8d14d0cSsthen 
3888d8d14d0cSsthen 	/* else, store as DP and continue at querytargets */
3889d8d14d0cSsthen 	foriq->state = QUERYTARGETS_STATE;
3890d8d14d0cSsthen 	foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
3891d8d14d0cSsthen 	if(!foriq->dp) {
3892d8d14d0cSsthen 		log_err("out of memory in dsns dp alloc");
38932308e98cSsthen 		errinf(qstate, "malloc failure, in DS search");
3894d8d14d0cSsthen 		return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */
3895d8d14d0cSsthen 	}
3896d8d14d0cSsthen 	/* success, go query the querytargets in the new dp (and go down) */
3897d8d14d0cSsthen }
3898d8d14d0cSsthen 
3899d8d14d0cSsthen /**
3900933707f3Ssthen  * Process response for qclass=ANY queries for a particular class.
3901933707f3Ssthen  * Append to result or error-exit.
3902933707f3Ssthen  *
3903933707f3Ssthen  * @param qstate: query state.
3904933707f3Ssthen  * @param id: module id.
3905933707f3Ssthen  * @param forq: super query state.
3906933707f3Ssthen  */
3907933707f3Ssthen static void
3908933707f3Ssthen processClassResponse(struct module_qstate* qstate, int id,
3909933707f3Ssthen 	struct module_qstate* forq)
3910933707f3Ssthen {
3911933707f3Ssthen 	struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
3912933707f3Ssthen 	struct dns_msg* from = qstate->return_msg;
3913933707f3Ssthen 	log_query_info(VERB_ALGO, "processClassResponse", &qstate->qinfo);
3914933707f3Ssthen 	log_query_info(VERB_ALGO, "processClassResponse super", &forq->qinfo);
3915933707f3Ssthen 	if(qstate->return_rcode != LDNS_RCODE_NOERROR) {
3916933707f3Ssthen 		/* cause servfail for qclass ANY query */
3917933707f3Ssthen 		foriq->response = NULL;
3918933707f3Ssthen 		foriq->state = FINISHED_STATE;
3919933707f3Ssthen 		return;
3920933707f3Ssthen 	}
3921933707f3Ssthen 	/* append result */
3922933707f3Ssthen 	if(!foriq->response) {
3923933707f3Ssthen 		/* allocate the response: copy RCODE, sec_state */
3924933707f3Ssthen 		foriq->response = dns_copy_msg(from, forq->region);
3925933707f3Ssthen 		if(!foriq->response) {
3926933707f3Ssthen 			log_err("malloc failed for qclass ANY response");
3927933707f3Ssthen 			foriq->state = FINISHED_STATE;
3928933707f3Ssthen 			return;
3929933707f3Ssthen 		}
3930933707f3Ssthen 		foriq->response->qinfo.qclass = forq->qinfo.qclass;
3931933707f3Ssthen 		/* qclass ANY does not receive the AA flag on replies */
3932933707f3Ssthen 		foriq->response->rep->authoritative = 0;
3933933707f3Ssthen 	} else {
3934933707f3Ssthen 		struct dns_msg* to = foriq->response;
3935933707f3Ssthen 		/* add _from_ this response _to_ existing collection */
3936933707f3Ssthen 		/* if there are records, copy RCODE */
3937933707f3Ssthen 		/* lower sec_state if this message is lower */
3938933707f3Ssthen 		if(from->rep->rrset_count != 0) {
3939933707f3Ssthen 			size_t n = from->rep->rrset_count+to->rep->rrset_count;
3940933707f3Ssthen 			struct ub_packed_rrset_key** dest, **d;
3941933707f3Ssthen 			/* copy appropriate rcode */
3942933707f3Ssthen 			to->rep->flags = from->rep->flags;
3943933707f3Ssthen 			/* copy rrsets */
3944a58bff56Ssthen 			if(from->rep->rrset_count > RR_COUNT_MAX ||
3945a58bff56Ssthen 				to->rep->rrset_count > RR_COUNT_MAX) {
3946a58bff56Ssthen 				log_err("malloc failed (too many rrsets) in collect ANY");
3947a58bff56Ssthen 				foriq->state = FINISHED_STATE;
3948a58bff56Ssthen 				return; /* integer overflow protection */
3949a58bff56Ssthen 			}
3950933707f3Ssthen 			dest = regional_alloc(forq->region, sizeof(dest[0])*n);
3951933707f3Ssthen 			if(!dest) {
3952933707f3Ssthen 				log_err("malloc failed in collect ANY");
3953933707f3Ssthen 				foriq->state = FINISHED_STATE;
3954933707f3Ssthen 				return;
3955933707f3Ssthen 			}
3956933707f3Ssthen 			d = dest;
3957933707f3Ssthen 			/* copy AN */
3958933707f3Ssthen 			memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
3959933707f3Ssthen 				* sizeof(dest[0]));
3960933707f3Ssthen 			dest += to->rep->an_numrrsets;
3961933707f3Ssthen 			memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
3962933707f3Ssthen 				* sizeof(dest[0]));
3963933707f3Ssthen 			dest += from->rep->an_numrrsets;
3964933707f3Ssthen 			/* copy NS */
3965933707f3Ssthen 			memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
3966933707f3Ssthen 				to->rep->ns_numrrsets * sizeof(dest[0]));
3967933707f3Ssthen 			dest += to->rep->ns_numrrsets;
3968933707f3Ssthen 			memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
3969933707f3Ssthen 				from->rep->ns_numrrsets * sizeof(dest[0]));
3970933707f3Ssthen 			dest += from->rep->ns_numrrsets;
3971933707f3Ssthen 			/* copy AR */
3972933707f3Ssthen 			memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
3973933707f3Ssthen 				to->rep->ns_numrrsets,
3974933707f3Ssthen 				to->rep->ar_numrrsets * sizeof(dest[0]));
3975933707f3Ssthen 			dest += to->rep->ar_numrrsets;
3976933707f3Ssthen 			memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
3977933707f3Ssthen 				from->rep->ns_numrrsets,
3978933707f3Ssthen 				from->rep->ar_numrrsets * sizeof(dest[0]));
3979933707f3Ssthen 			/* update counts */
3980933707f3Ssthen 			to->rep->rrsets = d;
3981933707f3Ssthen 			to->rep->an_numrrsets += from->rep->an_numrrsets;
3982933707f3Ssthen 			to->rep->ns_numrrsets += from->rep->ns_numrrsets;
3983933707f3Ssthen 			to->rep->ar_numrrsets += from->rep->ar_numrrsets;
3984933707f3Ssthen 			to->rep->rrset_count = n;
3985933707f3Ssthen 		}
3986933707f3Ssthen 		if(from->rep->security < to->rep->security) /* lowest sec */
3987933707f3Ssthen 			to->rep->security = from->rep->security;
3988933707f3Ssthen 		if(from->rep->qdcount != 0) /* insert qd if appropriate */
3989933707f3Ssthen 			to->rep->qdcount = from->rep->qdcount;
3990933707f3Ssthen 		if(from->rep->ttl < to->rep->ttl) /* use smallest TTL */
3991933707f3Ssthen 			to->rep->ttl = from->rep->ttl;
3992933707f3Ssthen 		if(from->rep->prefetch_ttl < to->rep->prefetch_ttl)
3993933707f3Ssthen 			to->rep->prefetch_ttl = from->rep->prefetch_ttl;
39942308e98cSsthen 		if(from->rep->serve_expired_ttl < to->rep->serve_expired_ttl)
39952308e98cSsthen 			to->rep->serve_expired_ttl = from->rep->serve_expired_ttl;
3996933707f3Ssthen 	}
3997933707f3Ssthen 	/* are we done? */
3998933707f3Ssthen 	foriq->num_current_queries --;
3999933707f3Ssthen 	if(foriq->num_current_queries == 0)
4000933707f3Ssthen 		foriq->state = FINISHED_STATE;
4001933707f3Ssthen }
4002933707f3Ssthen 
4003933707f3Ssthen /**
4004933707f3Ssthen  * Collect class ANY responses and make them into one response.  This
4005933707f3Ssthen  * state is started and it creates queries for all classes (that have
4006933707f3Ssthen  * root hints).  The answers are then collected.
4007933707f3Ssthen  *
4008933707f3Ssthen  * @param qstate: query state.
4009933707f3Ssthen  * @param id: module id.
4010933707f3Ssthen  * @return true if the event needs more immediate processing, false if not.
4011933707f3Ssthen  */
4012933707f3Ssthen static int
4013933707f3Ssthen processCollectClass(struct module_qstate* qstate, int id)
4014933707f3Ssthen {
4015933707f3Ssthen 	struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
4016933707f3Ssthen 	struct module_qstate* subq;
4017933707f3Ssthen 	/* If qchase.qclass == 0 then send out queries for all classes.
4018933707f3Ssthen 	 * Otherwise, do nothing (wait for all answers to arrive and the
4019933707f3Ssthen 	 * processClassResponse to put them together, and that moves us
4020933707f3Ssthen 	 * towards the Finished state when done. */
4021933707f3Ssthen 	if(iq->qchase.qclass == 0) {
4022933707f3Ssthen 		uint16_t c = 0;
4023933707f3Ssthen 		iq->qchase.qclass = LDNS_RR_CLASS_ANY;
4024d8d14d0cSsthen 		while(iter_get_next_root(qstate->env->hints,
4025d8d14d0cSsthen 			qstate->env->fwds, &c)) {
4026933707f3Ssthen 			/* generate query for this class */
4027933707f3Ssthen 			log_nametypeclass(VERB_ALGO, "spawn collect query",
4028933707f3Ssthen 				qstate->qinfo.qname, qstate->qinfo.qtype, c);
4029933707f3Ssthen 			if(!generate_sub_request(qstate->qinfo.qname,
4030933707f3Ssthen 				qstate->qinfo.qname_len, qstate->qinfo.qtype,
4031933707f3Ssthen 				c, qstate, id, iq, INIT_REQUEST_STATE,
4032933707f3Ssthen 				FINISHED_STATE, &subq,
403306a13c09Ssthen 				(int)!(qstate->query_flags&BIT_CD), 0)) {
40342308e98cSsthen 				errinf(qstate, "could not generate class ANY"
40352308e98cSsthen 					" lookup query");
4036933707f3Ssthen 				return error_response(qstate, id,
4037933707f3Ssthen 					LDNS_RCODE_SERVFAIL);
4038933707f3Ssthen 			}
4039933707f3Ssthen 			/* ignore subq, no special init required */
4040933707f3Ssthen 			iq->num_current_queries ++;
4041933707f3Ssthen 			if(c == 0xffff)
4042933707f3Ssthen 				break;
4043933707f3Ssthen 			else c++;
4044933707f3Ssthen 		}
4045933707f3Ssthen 		/* if no roots are configured at all, return */
4046933707f3Ssthen 		if(iq->num_current_queries == 0) {
4047933707f3Ssthen 			verbose(VERB_ALGO, "No root hints or fwds, giving up "
4048933707f3Ssthen 				"on qclass ANY");
4049*98bc733bSsthen 			return error_response_cache(qstate, id, LDNS_RCODE_REFUSED);
4050933707f3Ssthen 		}
4051933707f3Ssthen 		/* return false, wait for queries to return */
4052933707f3Ssthen 	}
4053933707f3Ssthen 	/* if woke up here because of an answer, wait for more answers */
4054933707f3Ssthen 	return 0;
4055933707f3Ssthen }
4056933707f3Ssthen 
4057933707f3Ssthen /**
4058933707f3Ssthen  * This handles the final state for first-tier responses (i.e., responses to
4059933707f3Ssthen  * externally generated queries).
4060933707f3Ssthen  *
4061933707f3Ssthen  * @param qstate: query state.
4062933707f3Ssthen  * @param iq: iterator query state.
4063933707f3Ssthen  * @param id: module id.
4064933707f3Ssthen  * @return true if the event needs more processing, false if not. Since this
4065933707f3Ssthen  *         is the final state for an event, it always returns false.
4066933707f3Ssthen  */
4067933707f3Ssthen static int
4068933707f3Ssthen processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
4069933707f3Ssthen 	int id)
4070933707f3Ssthen {
4071933707f3Ssthen 	log_query_info(VERB_QUERY, "finishing processing for",
4072933707f3Ssthen 		&qstate->qinfo);
4073933707f3Ssthen 
4074933707f3Ssthen 	/* store negative cache element for parent side glue. */
407577079be7Ssthen 	if(!qstate->no_cache_store && iq->query_for_pside_glue
407677079be7Ssthen 		&& !iq->pside_glue)
4077933707f3Ssthen 			iter_store_parentside_neg(qstate->env, &qstate->qinfo,
4078933707f3Ssthen 				iq->deleg_msg?iq->deleg_msg->rep:
4079933707f3Ssthen 				(iq->response?iq->response->rep:NULL));
4080933707f3Ssthen 	if(!iq->response) {
4081933707f3Ssthen 		verbose(VERB_ALGO, "No response is set, servfail");
40822308e98cSsthen 		errinf(qstate, "(no response found at query finish)");
4083933707f3Ssthen 		return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4084933707f3Ssthen 	}
4085933707f3Ssthen 
4086933707f3Ssthen 	/* Make sure that the RA flag is set (since the presence of
4087933707f3Ssthen 	 * this module means that recursion is available) */
4088933707f3Ssthen 	iq->response->rep->flags |= BIT_RA;
4089933707f3Ssthen 
4090933707f3Ssthen 	/* Clear the AA flag */
4091933707f3Ssthen 	/* FIXME: does this action go here or in some other module? */
4092933707f3Ssthen 	iq->response->rep->flags &= ~BIT_AA;
4093933707f3Ssthen 
4094933707f3Ssthen 	/* make sure QR flag is on */
4095933707f3Ssthen 	iq->response->rep->flags |= BIT_QR;
4096933707f3Ssthen 
40978b7325afSsthen 	/* explicitly set the EDE string to NULL */
40988b7325afSsthen 	iq->response->rep->reason_bogus_str = NULL;
4099d896b962Ssthen 	if((qstate->env->cfg->val_log_level >= 2 ||
4100d896b962Ssthen 		qstate->env->cfg->log_servfail) && qstate->errinf &&
4101d896b962Ssthen 		!qstate->env->cfg->val_log_squelch) {
4102d896b962Ssthen 		char* err_str = errinf_to_str_misc(qstate);
4103d896b962Ssthen 		if(err_str) {
4104d896b962Ssthen 			verbose(VERB_ALGO, "iterator EDE: %s", err_str);
41052bdc0ed1Ssthen 			iq->response->rep->reason_bogus_str = err_str;
4106d896b962Ssthen 		}
4107d896b962Ssthen 	}
41088b7325afSsthen 
4109933707f3Ssthen 	/* we have finished processing this query */
4110933707f3Ssthen 	qstate->ext_state[id] = module_finished;
4111933707f3Ssthen 
4112933707f3Ssthen 	/* TODO:  we are using a private TTL, trim the response. */
4113933707f3Ssthen 	/* if (mPrivateTTL > 0){IterUtils.setPrivateTTL(resp, mPrivateTTL); } */
4114933707f3Ssthen 
4115933707f3Ssthen 	/* prepend any items we have accumulated */
4116933707f3Ssthen 	if(iq->an_prepend_list || iq->ns_prepend_list) {
4117933707f3Ssthen 		if(!iter_prepend(iq, iq->response, qstate->region)) {
4118933707f3Ssthen 			log_err("prepend rrsets: out of memory");
4119933707f3Ssthen 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4120933707f3Ssthen 		}
4121933707f3Ssthen 		/* reset the query name back */
4122933707f3Ssthen 		iq->response->qinfo = qstate->qinfo;
4123933707f3Ssthen 		/* the security state depends on the combination */
4124933707f3Ssthen 		iq->response->rep->security = sec_status_unchecked;
4125933707f3Ssthen 		/* store message with the finished prepended items,
4126933707f3Ssthen 		 * but only if we did recursion. The nonrecursion referral
4127933707f3Ssthen 		 * from cache does not need to be stored in the msg cache. */
412877079be7Ssthen 		if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) {
41293dcb24b8Ssthen 			iter_dns_store(qstate->env, &qstate->qinfo,
4130933707f3Ssthen 				iq->response->rep, 0, qstate->prefetch_leeway,
4131d8d14d0cSsthen 				iq->dp&&iq->dp->has_parent_side_NS,
4132d1e2768aSsthen 				qstate->region, qstate->query_flags,
4133d1e2768aSsthen 				qstate->qstarttime);
4134933707f3Ssthen 		}
4135933707f3Ssthen 	}
4136933707f3Ssthen 	qstate->return_rcode = LDNS_RCODE_NOERROR;
4137933707f3Ssthen 	qstate->return_msg = iq->response;
4138933707f3Ssthen 	return 0;
4139933707f3Ssthen }
4140933707f3Ssthen 
4141933707f3Ssthen /*
4142bdfc4d55Sflorian  * Return priming query results to interested super querystates.
4143933707f3Ssthen  *
4144933707f3Ssthen  * Sets the delegation point and delegation message (not nonRD queries).
4145933707f3Ssthen  * This is a callback from walk_supers.
4146933707f3Ssthen  *
4147933707f3Ssthen  * @param qstate: query state that finished.
4148933707f3Ssthen  * @param id: module id.
4149933707f3Ssthen  * @param super: the qstate to inform.
4150933707f3Ssthen  */
4151933707f3Ssthen void
4152933707f3Ssthen iter_inform_super(struct module_qstate* qstate, int id,
4153933707f3Ssthen 	struct module_qstate* super)
4154933707f3Ssthen {
4155933707f3Ssthen 	if(!qstate->is_priming && super->qinfo.qclass == LDNS_RR_CLASS_ANY)
4156933707f3Ssthen 		processClassResponse(qstate, id, super);
4157d8d14d0cSsthen 	else if(super->qinfo.qtype == LDNS_RR_TYPE_DS && ((struct iter_qstate*)
4158d8d14d0cSsthen 		super->minfo[id])->state == DSNS_FIND_STATE)
4159d8d14d0cSsthen 		processDSNSResponse(qstate, id, super);
4160933707f3Ssthen 	else if(qstate->return_rcode != LDNS_RCODE_NOERROR)
4161933707f3Ssthen 		error_supers(qstate, id, super);
4162933707f3Ssthen 	else if(qstate->is_priming)
4163933707f3Ssthen 		prime_supers(qstate, id, super);
4164933707f3Ssthen 	else	processTargetResponse(qstate, id, super);
4165933707f3Ssthen }
4166933707f3Ssthen 
4167933707f3Ssthen /**
4168933707f3Ssthen  * Handle iterator state.
4169933707f3Ssthen  * Handle events. This is the real processing loop for events, responsible
4170933707f3Ssthen  * for moving events through the various states. If a processing method
4171933707f3Ssthen  * returns true, then it will be advanced to the next state. If false, then
4172933707f3Ssthen  * processing will stop.
4173933707f3Ssthen  *
4174933707f3Ssthen  * @param qstate: query state.
4175933707f3Ssthen  * @param ie: iterator shared global environment.
4176933707f3Ssthen  * @param iq: iterator query state.
4177933707f3Ssthen  * @param id: module id.
4178933707f3Ssthen  */
4179933707f3Ssthen static void
4180933707f3Ssthen iter_handle(struct module_qstate* qstate, struct iter_qstate* iq,
4181933707f3Ssthen 	struct iter_env* ie, int id)
4182933707f3Ssthen {
4183933707f3Ssthen 	int cont = 1;
4184933707f3Ssthen 	while(cont) {
4185933707f3Ssthen 		verbose(VERB_ALGO, "iter_handle processing q with state %s",
4186933707f3Ssthen 			iter_state_to_string(iq->state));
4187933707f3Ssthen 		switch(iq->state) {
4188933707f3Ssthen 			case INIT_REQUEST_STATE:
4189933707f3Ssthen 				cont = processInitRequest(qstate, iq, ie, id);
4190933707f3Ssthen 				break;
4191933707f3Ssthen 			case INIT_REQUEST_2_STATE:
4192d8d14d0cSsthen 				cont = processInitRequest2(qstate, iq, id);
4193933707f3Ssthen 				break;
4194933707f3Ssthen 			case INIT_REQUEST_3_STATE:
4195933707f3Ssthen 				cont = processInitRequest3(qstate, iq, id);
4196933707f3Ssthen 				break;
4197933707f3Ssthen 			case QUERYTARGETS_STATE:
4198933707f3Ssthen 				cont = processQueryTargets(qstate, iq, ie, id);
4199933707f3Ssthen 				break;
4200933707f3Ssthen 			case QUERY_RESP_STATE:
4201e21c60efSsthen 				cont = processQueryResponse(qstate, iq, ie, id);
4202933707f3Ssthen 				break;
4203933707f3Ssthen 			case PRIME_RESP_STATE:
4204933707f3Ssthen 				cont = processPrimeResponse(qstate, id);
4205933707f3Ssthen 				break;
4206933707f3Ssthen 			case COLLECT_CLASS_STATE:
4207933707f3Ssthen 				cont = processCollectClass(qstate, id);
4208933707f3Ssthen 				break;
4209d8d14d0cSsthen 			case DSNS_FIND_STATE:
4210d8d14d0cSsthen 				cont = processDSNSFind(qstate, iq, id);
4211d8d14d0cSsthen 				break;
4212933707f3Ssthen 			case FINISHED_STATE:
4213933707f3Ssthen 				cont = processFinished(qstate, iq, id);
4214933707f3Ssthen 				break;
4215933707f3Ssthen 			default:
4216933707f3Ssthen 				log_warn("iterator: invalid state: %d",
4217933707f3Ssthen 					iq->state);
4218933707f3Ssthen 				cont = 0;
4219933707f3Ssthen 				break;
4220933707f3Ssthen 		}
4221933707f3Ssthen 	}
4222933707f3Ssthen }
4223933707f3Ssthen 
4224933707f3Ssthen /**
4225933707f3Ssthen  * This is the primary entry point for processing request events. Note that
4226933707f3Ssthen  * this method should only be used by external modules.
4227933707f3Ssthen  * @param qstate: query state.
4228933707f3Ssthen  * @param ie: iterator shared global environment.
4229933707f3Ssthen  * @param iq: iterator query state.
4230933707f3Ssthen  * @param id: module id.
4231933707f3Ssthen  */
4232933707f3Ssthen static void
4233933707f3Ssthen process_request(struct module_qstate* qstate, struct iter_qstate* iq,
4234933707f3Ssthen 	struct iter_env* ie, int id)
4235933707f3Ssthen {
4236933707f3Ssthen 	/* external requests start in the INIT state, and finish using the
4237933707f3Ssthen 	 * FINISHED state. */
4238933707f3Ssthen 	iq->state = INIT_REQUEST_STATE;
4239933707f3Ssthen 	iq->final_state = FINISHED_STATE;
4240933707f3Ssthen 	verbose(VERB_ALGO, "process_request: new external request event");
4241933707f3Ssthen 	iter_handle(qstate, iq, ie, id);
4242933707f3Ssthen }
4243933707f3Ssthen 
4244933707f3Ssthen /** process authoritative server reply */
4245933707f3Ssthen static void
4246933707f3Ssthen process_response(struct module_qstate* qstate, struct iter_qstate* iq,
4247933707f3Ssthen 	struct iter_env* ie, int id, struct outbound_entry* outbound,
4248933707f3Ssthen 	enum module_ev event)
4249933707f3Ssthen {
4250933707f3Ssthen 	struct msg_parse* prs;
4251933707f3Ssthen 	struct edns_data edns;
42525d76a658Ssthen 	sldns_buffer* pkt;
4253933707f3Ssthen 
4254933707f3Ssthen 	verbose(VERB_ALGO, "process_response: new external response event");
4255933707f3Ssthen 	iq->response = NULL;
4256933707f3Ssthen 	iq->state = QUERY_RESP_STATE;
4257933707f3Ssthen 	if(event == module_event_noreply || event == module_event_error) {
4258a3167c07Ssthen 		if(event == module_event_noreply && iq->timeout_count >= 3 &&
425998f3ca02Sbrad 			qstate->env->cfg->use_caps_bits_for_id &&
4260f6b99bafSsthen 			!iq->caps_fallback && !is_caps_whitelisted(ie, iq)) {
426198f3ca02Sbrad 			/* start fallback */
426298f3ca02Sbrad 			iq->caps_fallback = 1;
426398f3ca02Sbrad 			iq->caps_server = 0;
426498f3ca02Sbrad 			iq->caps_reply = NULL;
4265a58bff56Ssthen 			iq->caps_response = NULL;
42662308e98cSsthen 			iq->caps_minimisation_state = DONOT_MINIMISE_STATE;
426798f3ca02Sbrad 			iq->state = QUERYTARGETS_STATE;
426898f3ca02Sbrad 			iq->num_current_queries--;
426998f3ca02Sbrad 			/* need fresh attempts for the 0x20 fallback, if
427098f3ca02Sbrad 			 * that was the cause for the failure */
4271e21c60efSsthen 			iter_dec_attempts(iq->dp, 3, ie->outbound_msg_retry);
427298f3ca02Sbrad 			verbose(VERB_DETAIL, "Capsforid: timeouts, starting fallback");
427398f3ca02Sbrad 			goto handle_it;
427498f3ca02Sbrad 		}
4275933707f3Ssthen 		goto handle_it;
4276933707f3Ssthen 	}
4277933707f3Ssthen 	if( (event != module_event_reply && event != module_event_capsfail)
4278933707f3Ssthen 		|| !qstate->reply) {
4279933707f3Ssthen 		log_err("Bad event combined with response");
4280933707f3Ssthen 		outbound_list_remove(&iq->outlist, outbound);
42812308e98cSsthen 		errinf(qstate, "module iterator received wrong internal event with a response message");
4282933707f3Ssthen 		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4283933707f3Ssthen 		return;
4284933707f3Ssthen 	}
4285933707f3Ssthen 
4286933707f3Ssthen 	/* parse message */
42878b7325afSsthen 	fill_fail_addr(iq, &qstate->reply->remote_addr,
42888b7325afSsthen 		qstate->reply->remote_addrlen);
4289933707f3Ssthen 	prs = (struct msg_parse*)regional_alloc(qstate->env->scratch,
4290933707f3Ssthen 		sizeof(struct msg_parse));
4291933707f3Ssthen 	if(!prs) {
4292933707f3Ssthen 		log_err("out of memory on incoming message");
4293933707f3Ssthen 		/* like packet got dropped */
4294933707f3Ssthen 		goto handle_it;
4295933707f3Ssthen 	}
4296933707f3Ssthen 	memset(prs, 0, sizeof(*prs));
4297933707f3Ssthen 	memset(&edns, 0, sizeof(edns));
4298933707f3Ssthen 	pkt = qstate->reply->c->buffer;
42995d76a658Ssthen 	sldns_buffer_set_position(pkt, 0);
4300933707f3Ssthen 	if(parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
4301933707f3Ssthen 		verbose(VERB_ALGO, "parse error on reply packet");
4302191f22c6Ssthen 		iq->parse_failures++;
4303933707f3Ssthen 		goto handle_it;
4304933707f3Ssthen 	}
4305933707f3Ssthen 	/* edns is not examined, but removed from message to help cache */
4306e21c60efSsthen 	if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) !=
4307191f22c6Ssthen 		LDNS_RCODE_NOERROR) {
4308191f22c6Ssthen 		iq->parse_failures++;
4309933707f3Ssthen 		goto handle_it;
4310191f22c6Ssthen 	}
431177079be7Ssthen 
431277079be7Ssthen 	/* Copy the edns options we may got from the back end */
4313e21c60efSsthen 	if(edns.opt_list_in) {
4314e21c60efSsthen 		qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
431577079be7Ssthen 			qstate->region);
431677079be7Ssthen 		if(!qstate->edns_opts_back_in) {
431777079be7Ssthen 			log_err("out of memory on incoming message");
431877079be7Ssthen 			/* like packet got dropped */
431977079be7Ssthen 			goto handle_it;
432077079be7Ssthen 		}
4321f46c52bfSsthen 	}
43222be9e038Ssthen 	if(!inplace_cb_edns_back_parsed_call(qstate->env, qstate)) {
43232be9e038Ssthen 		log_err("unable to call edns_back_parsed callback");
43242be9e038Ssthen 		goto handle_it;
43252be9e038Ssthen 	}
432677079be7Ssthen 
4327933707f3Ssthen 	/* remove CD-bit, we asked for in case we handle validation ourself */
4328933707f3Ssthen 	prs->flags &= ~BIT_CD;
4329933707f3Ssthen 
4330933707f3Ssthen 	/* normalize and sanitize: easy to delete items from linked lists */
433124893edcSsthen 	if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name,
4332d896b962Ssthen 		qstate->env->scratch, qstate->env, qstate, ie)) {
4333a58bff56Ssthen 		/* if 0x20 enabled, start fallback, but we have no message */
4334a58bff56Ssthen 		if(event == module_event_capsfail && !iq->caps_fallback) {
4335a58bff56Ssthen 			iq->caps_fallback = 1;
4336a58bff56Ssthen 			iq->caps_server = 0;
4337a58bff56Ssthen 			iq->caps_reply = NULL;
4338a58bff56Ssthen 			iq->caps_response = NULL;
43392308e98cSsthen 			iq->caps_minimisation_state = DONOT_MINIMISE_STATE;
4340a58bff56Ssthen 			iq->state = QUERYTARGETS_STATE;
4341a58bff56Ssthen 			iq->num_current_queries--;
4342a58bff56Ssthen 			verbose(VERB_DETAIL, "Capsforid: scrub failed, starting fallback with no response");
4343a58bff56Ssthen 		}
4344191f22c6Ssthen 		iq->scrub_failures++;
4345933707f3Ssthen 		goto handle_it;
4346a58bff56Ssthen 	}
4347933707f3Ssthen 
4348933707f3Ssthen 	/* allocate response dns_msg in region */
4349933707f3Ssthen 	iq->response = dns_alloc_msg(pkt, prs, qstate->region);
4350933707f3Ssthen 	if(!iq->response)
4351933707f3Ssthen 		goto handle_it;
4352933707f3Ssthen 	log_query_info(VERB_DETAIL, "response for", &qstate->qinfo);
4353933707f3Ssthen 	log_name_addr(VERB_DETAIL, "reply from", iq->dp->name,
435445872187Ssthen 		&qstate->reply->remote_addr, qstate->reply->remote_addrlen);
4355933707f3Ssthen 	if(verbosity >= VERB_ALGO)
4356933707f3Ssthen 		log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
4357933707f3Ssthen 			iq->response->rep);
4358933707f3Ssthen 
435998f3ca02Sbrad 	if(event == module_event_capsfail || iq->caps_fallback) {
43602308e98cSsthen 		if(qstate->env->cfg->qname_minimisation &&
43612308e98cSsthen 			iq->minimisation_state != DONOT_MINIMISE_STATE) {
43622308e98cSsthen 			/* Skip QNAME minimisation for next query, since that
43632308e98cSsthen 			 * one has to match the current query. */
43642308e98cSsthen 			iq->minimisation_state = SKIP_MINIMISE_STATE;
43652308e98cSsthen 		}
436635fa0a9cSbrad 		/* for fallback we care about main answer, not additionals */
436735fa0a9cSbrad 		/* removing that makes comparison more likely to succeed */
436835fa0a9cSbrad 		caps_strip_reply(iq->response->rep);
43692308e98cSsthen 
43702308e98cSsthen 		if(iq->caps_fallback &&
43712308e98cSsthen 			iq->caps_minimisation_state != iq->minimisation_state) {
43722308e98cSsthen 			/* QNAME minimisation state has changed, restart caps
43732308e98cSsthen 			 * fallback. */
43742308e98cSsthen 			iq->caps_fallback = 0;
43752308e98cSsthen 		}
43762308e98cSsthen 
4377933707f3Ssthen 		if(!iq->caps_fallback) {
4378933707f3Ssthen 			/* start fallback */
4379933707f3Ssthen 			iq->caps_fallback = 1;
4380933707f3Ssthen 			iq->caps_server = 0;
4381933707f3Ssthen 			iq->caps_reply = iq->response->rep;
4382a58bff56Ssthen 			iq->caps_response = iq->response;
43832308e98cSsthen 			iq->caps_minimisation_state = iq->minimisation_state;
4384933707f3Ssthen 			iq->state = QUERYTARGETS_STATE;
4385933707f3Ssthen 			iq->num_current_queries--;
4386933707f3Ssthen 			verbose(VERB_DETAIL, "Capsforid: starting fallback");
4387933707f3Ssthen 			goto handle_it;
4388933707f3Ssthen 		} else {
4389933707f3Ssthen 			/* check if reply is the same, otherwise, fail */
439098f3ca02Sbrad 			if(!iq->caps_reply) {
439198f3ca02Sbrad 				iq->caps_reply = iq->response->rep;
4392a58bff56Ssthen 				iq->caps_response = iq->response;
439398f3ca02Sbrad 				iq->caps_server = -1; /*become zero at ++,
439498f3ca02Sbrad 				so that we start the full set of trials */
4395a58bff56Ssthen 			} else if(caps_failed_rcode(iq->caps_reply) &&
4396a58bff56Ssthen 				!caps_failed_rcode(iq->response->rep)) {
4397a58bff56Ssthen 				/* prefer to upgrade to non-SERVFAIL */
4398a58bff56Ssthen 				iq->caps_reply = iq->response->rep;
4399a58bff56Ssthen 				iq->caps_response = iq->response;
4400a58bff56Ssthen 			} else if(!caps_failed_rcode(iq->caps_reply) &&
4401a58bff56Ssthen 				caps_failed_rcode(iq->response->rep)) {
4402a58bff56Ssthen 				/* if we have non-SERVFAIL as answer then
4403a58bff56Ssthen 				 * we can ignore SERVFAILs for the equality
4404a58bff56Ssthen 				 * comparison */
4405a58bff56Ssthen 				/* no instructions here, skip other else */
4406a58bff56Ssthen 			} else if(caps_failed_rcode(iq->caps_reply) &&
4407a58bff56Ssthen 				caps_failed_rcode(iq->response->rep)) {
4408a58bff56Ssthen 				/* failure is same as other failure in fallbk*/
4409a58bff56Ssthen 				/* no instructions here, skip other else */
441098f3ca02Sbrad 			} else if(!reply_equal(iq->response->rep, iq->caps_reply,
44115d76a658Ssthen 				qstate->env->scratch)) {
4412933707f3Ssthen 				verbose(VERB_DETAIL, "Capsforid fallback: "
4413933707f3Ssthen 					"getting different replies, failed");
4414933707f3Ssthen 				outbound_list_remove(&iq->outlist, outbound);
44152308e98cSsthen 				errinf(qstate, "0x20 failed, then got different replies in fallback");
4416*98bc733bSsthen 				(void)error_response_cache(qstate, id,
4417933707f3Ssthen 					LDNS_RCODE_SERVFAIL);
4418933707f3Ssthen 				return;
4419933707f3Ssthen 			}
4420933707f3Ssthen 			/* continue the fallback procedure at next server */
4421933707f3Ssthen 			iq->caps_server++;
4422933707f3Ssthen 			iq->state = QUERYTARGETS_STATE;
4423933707f3Ssthen 			iq->num_current_queries--;
4424933707f3Ssthen 			verbose(VERB_DETAIL, "Capsforid: reply is equal. "
4425933707f3Ssthen 				"go to next fallback");
4426933707f3Ssthen 			goto handle_it;
4427933707f3Ssthen 		}
4428933707f3Ssthen 	}
4429933707f3Ssthen 	iq->caps_fallback = 0; /* if we were in fallback, 0x20 is OK now */
4430933707f3Ssthen 
4431933707f3Ssthen handle_it:
4432933707f3Ssthen 	outbound_list_remove(&iq->outlist, outbound);
4433933707f3Ssthen 	iter_handle(qstate, iq, ie, id);
4434933707f3Ssthen }
4435933707f3Ssthen 
4436933707f3Ssthen void
4437933707f3Ssthen iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
4438933707f3Ssthen 	struct outbound_entry* outbound)
4439933707f3Ssthen {
4440933707f3Ssthen 	struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
4441933707f3Ssthen 	struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
4442933707f3Ssthen 	verbose(VERB_QUERY, "iterator[module %d] operate: extstate:%s event:%s",
4443933707f3Ssthen 		id, strextstate(qstate->ext_state[id]), strmodulevent(event));
4444933707f3Ssthen 	if(iq) log_query_info(VERB_QUERY, "iterator operate: query",
4445933707f3Ssthen 		&qstate->qinfo);
4446933707f3Ssthen 	if(iq && qstate->qinfo.qname != iq->qchase.qname)
4447933707f3Ssthen 		log_query_info(VERB_QUERY, "iterator operate: chased to",
4448933707f3Ssthen 			&iq->qchase);
4449933707f3Ssthen 
4450933707f3Ssthen 	/* perform iterator state machine */
4451933707f3Ssthen 	if((event == module_event_new || event == module_event_pass) &&
4452933707f3Ssthen 		iq == NULL) {
4453933707f3Ssthen 		if(!iter_new(qstate, id)) {
44542308e98cSsthen 			errinf(qstate, "malloc failure, new iterator module allocation");
4455933707f3Ssthen 			(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4456933707f3Ssthen 			return;
4457933707f3Ssthen 		}
4458933707f3Ssthen 		iq = (struct iter_qstate*)qstate->minfo[id];
4459933707f3Ssthen 		process_request(qstate, iq, ie, id);
4460933707f3Ssthen 		return;
4461933707f3Ssthen 	}
4462933707f3Ssthen 	if(iq && event == module_event_pass) {
4463933707f3Ssthen 		iter_handle(qstate, iq, ie, id);
4464933707f3Ssthen 		return;
4465933707f3Ssthen 	}
4466933707f3Ssthen 	if(iq && outbound) {
4467933707f3Ssthen 		process_response(qstate, iq, ie, id, outbound, event);
4468933707f3Ssthen 		return;
4469933707f3Ssthen 	}
4470933707f3Ssthen 	if(event == module_event_error) {
4471933707f3Ssthen 		verbose(VERB_ALGO, "got called with event error, giving up");
44722308e98cSsthen 		errinf(qstate, "iterator module got the error event");
4473933707f3Ssthen 		(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4474933707f3Ssthen 		return;
4475933707f3Ssthen 	}
4476933707f3Ssthen 
4477933707f3Ssthen 	log_err("bad event for iterator");
44782308e98cSsthen 	errinf(qstate, "iterator module received wrong event");
4479933707f3Ssthen 	(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
4480933707f3Ssthen }
4481933707f3Ssthen 
4482933707f3Ssthen void
4483933707f3Ssthen iter_clear(struct module_qstate* qstate, int id)
4484933707f3Ssthen {
4485933707f3Ssthen 	struct iter_qstate* iq;
4486933707f3Ssthen 	if(!qstate)
4487933707f3Ssthen 		return;
4488933707f3Ssthen 	iq = (struct iter_qstate*)qstate->minfo[id];
4489933707f3Ssthen 	if(iq) {
4490933707f3Ssthen 		outbound_list_clear(&iq->outlist);
4491d1e2768aSsthen 		if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
4492ae1dea89Sflorian 			free(iq->target_count);
4493d1e2768aSsthen 			if(*iq->nxns_dp) free(*iq->nxns_dp);
4494d1e2768aSsthen 			free(iq->nxns_dp);
4495d1e2768aSsthen 		}
4496933707f3Ssthen 		iq->num_current_queries = 0;
4497933707f3Ssthen 	}
4498933707f3Ssthen 	qstate->minfo[id] = NULL;
4499933707f3Ssthen }
4500933707f3Ssthen 
4501933707f3Ssthen size_t
4502933707f3Ssthen iter_get_mem(struct module_env* env, int id)
4503933707f3Ssthen {
4504933707f3Ssthen 	struct iter_env* ie = (struct iter_env*)env->modinfo[id];
4505933707f3Ssthen 	if(!ie)
4506933707f3Ssthen 		return 0;
4507933707f3Ssthen 	return sizeof(*ie) + sizeof(int)*((size_t)ie->max_dependency_depth+1)
4508d8d14d0cSsthen 		+ donotq_get_mem(ie->donotq) + priv_get_mem(ie->priv);
4509933707f3Ssthen }
4510933707f3Ssthen 
4511933707f3Ssthen /**
4512933707f3Ssthen  * The iterator function block
4513933707f3Ssthen  */
4514933707f3Ssthen static struct module_func_block iter_block = {
4515933707f3Ssthen 	"iterator",
4516*98bc733bSsthen 	NULL, NULL, &iter_init, &iter_deinit, &iter_operate,
4517*98bc733bSsthen 	&iter_inform_super, &iter_clear, &iter_get_mem
4518933707f3Ssthen };
4519933707f3Ssthen 
4520933707f3Ssthen struct module_func_block*
4521933707f3Ssthen iter_get_funcblock(void)
4522933707f3Ssthen {
4523933707f3Ssthen 	return &iter_block;
4524933707f3Ssthen }
4525933707f3Ssthen 
4526933707f3Ssthen const char*
4527933707f3Ssthen iter_state_to_string(enum iter_state state)
4528933707f3Ssthen {
4529933707f3Ssthen 	switch (state)
4530933707f3Ssthen 	{
4531933707f3Ssthen 	case INIT_REQUEST_STATE :
4532933707f3Ssthen 		return "INIT REQUEST STATE";
4533933707f3Ssthen 	case INIT_REQUEST_2_STATE :
4534933707f3Ssthen 		return "INIT REQUEST STATE (stage 2)";
4535933707f3Ssthen 	case INIT_REQUEST_3_STATE:
4536933707f3Ssthen 		return "INIT REQUEST STATE (stage 3)";
4537933707f3Ssthen 	case QUERYTARGETS_STATE :
4538933707f3Ssthen 		return "QUERY TARGETS STATE";
4539933707f3Ssthen 	case PRIME_RESP_STATE :
4540933707f3Ssthen 		return "PRIME RESPONSE STATE";
4541933707f3Ssthen 	case COLLECT_CLASS_STATE :
4542933707f3Ssthen 		return "COLLECT CLASS STATE";
4543d8d14d0cSsthen 	case DSNS_FIND_STATE :
4544d8d14d0cSsthen 		return "DSNS FIND STATE";
4545933707f3Ssthen 	case QUERY_RESP_STATE :
4546933707f3Ssthen 		return "QUERY RESPONSE STATE";
4547933707f3Ssthen 	case FINISHED_STATE :
4548933707f3Ssthen 		return "FINISHED RESPONSE STATE";
4549933707f3Ssthen 	default :
4550933707f3Ssthen 		return "UNKNOWN ITER STATE";
4551933707f3Ssthen 	}
4552933707f3Ssthen }
4553933707f3Ssthen 
4554933707f3Ssthen int
4555933707f3Ssthen iter_state_is_responsestate(enum iter_state s)
4556933707f3Ssthen {
4557933707f3Ssthen 	switch(s) {
4558933707f3Ssthen 		case INIT_REQUEST_STATE :
4559933707f3Ssthen 		case INIT_REQUEST_2_STATE :
4560933707f3Ssthen 		case INIT_REQUEST_3_STATE :
4561933707f3Ssthen 		case QUERYTARGETS_STATE :
4562933707f3Ssthen 		case COLLECT_CLASS_STATE :
4563933707f3Ssthen 			return 0;
4564933707f3Ssthen 		default:
4565933707f3Ssthen 			break;
4566933707f3Ssthen 	}
4567933707f3Ssthen 	return 1;
4568933707f3Ssthen }
4569