xref: /openbsd-src/usr.sbin/unbound/libunbound/libworker.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1933707f3Ssthen /*
2933707f3Ssthen  * libunbound/worker.c - worker thread or process that resolves
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
240b68ff31Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
250b68ff31Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
260b68ff31Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
270b68ff31Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
280b68ff31Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
290b68ff31Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
300b68ff31Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
310b68ff31Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
320b68ff31Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
330b68ff31Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39933707f3Ssthen  * This file contains the worker process or thread that performs
40933707f3Ssthen  * the DNS resolving and validation. The worker is called by a procedure
41933707f3Ssthen  * and if in the background continues until exit, if in the foreground
42933707f3Ssthen  * returns from the procedure when done.
43933707f3Ssthen  */
44933707f3Ssthen #include "config.h"
45e9c7b4efSsthen #ifdef HAVE_SSL
46933707f3Ssthen #include <openssl/ssl.h>
47e9c7b4efSsthen #endif
48933707f3Ssthen #include "libunbound/libworker.h"
49933707f3Ssthen #include "libunbound/context.h"
50933707f3Ssthen #include "libunbound/unbound.h"
51e10d3884Sbrad #include "libunbound/worker.h"
520b68ff31Ssthen #include "libunbound/unbound-event.h"
53933707f3Ssthen #include "services/outside_network.h"
54933707f3Ssthen #include "services/mesh.h"
55933707f3Ssthen #include "services/localzone.h"
56933707f3Ssthen #include "services/cache/rrset.h"
57933707f3Ssthen #include "services/outbound_list.h"
58938a3a5eSflorian #include "services/authzone.h"
59e10d3884Sbrad #include "util/fptr_wlist.h"
60933707f3Ssthen #include "util/module.h"
61933707f3Ssthen #include "util/regional.h"
62933707f3Ssthen #include "util/random.h"
63933707f3Ssthen #include "util/config_file.h"
64933707f3Ssthen #include "util/netevent.h"
65d896b962Ssthen #include "util/proxy_protocol.h"
66933707f3Ssthen #include "util/storage/lookup3.h"
67933707f3Ssthen #include "util/storage/slabhash.h"
68933707f3Ssthen #include "util/net_help.h"
69933707f3Ssthen #include "util/data/dname.h"
70933707f3Ssthen #include "util/data/msgreply.h"
71933707f3Ssthen #include "util/data/msgencode.h"
72933707f3Ssthen #include "util/tube.h"
73a58bff56Ssthen #include "sldns/sbuffer.h"
74a58bff56Ssthen #include "sldns/str2wire.h"
759982a05dSsthen #ifdef USE_DNSTAP
769982a05dSsthen #include "dnstap/dtstream.h"
779982a05dSsthen #endif
78933707f3Ssthen 
79a3167c07Ssthen #ifdef HAVE_TARGETCONDITIONALS_H
80a3167c07Ssthen #include <TargetConditionals.h>
81a3167c07Ssthen #endif
82a3167c07Ssthen 
832c144df0Ssthen #if (defined(TARGET_OS_TV) && TARGET_OS_TV) || (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH)
84a3167c07Ssthen #undef HAVE_FORK
85a3167c07Ssthen #endif
86a3167c07Ssthen 
87933707f3Ssthen /** handle new query command for bg worker */
88933707f3Ssthen static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
89933707f3Ssthen 
900b68ff31Ssthen /** delete libworker env */
91933707f3Ssthen static void
920b68ff31Ssthen libworker_delete_env(struct libworker* w)
93933707f3Ssthen {
94933707f3Ssthen 	if(w->env) {
95933707f3Ssthen 		outside_network_quit_prepare(w->back);
96933707f3Ssthen 		mesh_delete(w->env->mesh);
97933707f3Ssthen 		context_release_alloc(w->ctx, w->env->alloc,
98933707f3Ssthen 			!w->is_bg || w->is_bg_thread);
990b68ff31Ssthen 		sldns_buffer_free(w->env->scratch_buffer);
100933707f3Ssthen 		regional_destroy(w->env->scratch);
101933707f3Ssthen 		ub_randfree(w->env->rnd);
102933707f3Ssthen 		free(w->env);
103933707f3Ssthen 	}
104e9c7b4efSsthen #ifdef HAVE_SSL
105933707f3Ssthen 	SSL_CTX_free(w->sslctx);
106e9c7b4efSsthen #endif
107933707f3Ssthen 	outside_network_delete(w->back);
1080b68ff31Ssthen }
1090b68ff31Ssthen 
1100b68ff31Ssthen /** delete libworker struct */
1110b68ff31Ssthen static void
1120b68ff31Ssthen libworker_delete(struct libworker* w)
1130b68ff31Ssthen {
1140b68ff31Ssthen 	if(!w) return;
1150b68ff31Ssthen 	libworker_delete_env(w);
116933707f3Ssthen 	comm_base_delete(w->base);
117933707f3Ssthen 	free(w);
118933707f3Ssthen }
119933707f3Ssthen 
1200b68ff31Ssthen void
1210b68ff31Ssthen libworker_delete_event(struct libworker* w)
1220b68ff31Ssthen {
1230b68ff31Ssthen 	if(!w) return;
1240b68ff31Ssthen 	libworker_delete_env(w);
1250b68ff31Ssthen 	comm_base_delete_no_base(w->base);
1260b68ff31Ssthen 	free(w);
1270b68ff31Ssthen }
1280b68ff31Ssthen 
129933707f3Ssthen /** setup fresh libworker struct */
130933707f3Ssthen static struct libworker*
1312ee382b6Ssthen libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
132933707f3Ssthen {
133933707f3Ssthen 	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
134933707f3Ssthen 	struct config_file* cfg = ctx->env->cfg;
135933707f3Ssthen 	int* ports;
136933707f3Ssthen 	int numports;
137933707f3Ssthen 	if(!w) return NULL;
138933707f3Ssthen 	w->is_bg = is_bg;
139933707f3Ssthen 	w->ctx = ctx;
140933707f3Ssthen 	w->env = (struct module_env*)malloc(sizeof(*w->env));
141933707f3Ssthen 	if(!w->env) {
142933707f3Ssthen 		free(w);
143933707f3Ssthen 		return NULL;
144933707f3Ssthen 	}
145933707f3Ssthen 	*w->env = *ctx->env;
146933707f3Ssthen 	w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
147933707f3Ssthen 	if(!w->env->alloc) {
148933707f3Ssthen 		libworker_delete(w);
149933707f3Ssthen 		return NULL;
150933707f3Ssthen 	}
151933707f3Ssthen 	w->thread_num = w->env->alloc->thread_num;
152933707f3Ssthen 	alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
153933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
154933707f3Ssthen 		lock_basic_lock(&ctx->cfglock);
155933707f3Ssthen 	}
156933707f3Ssthen 	w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
1570b68ff31Ssthen 	w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
158d896b962Ssthen #ifdef HAVE_SSL
159938a3a5eSflorian 	w->sslctx = connect_sslctx_create(NULL, NULL,
16020237c55Ssthen 		cfg->tls_cert_bundle, cfg->tls_win_cert);
161933707f3Ssthen 	if(!w->sslctx) {
162163a4143Ssthen 		/* to make the setup fail after unlock */
1632bdc0ed1Ssthen 		sldns_buffer_free(w->env->scratch_buffer);
1642bdc0ed1Ssthen 		w->env->scratch_buffer = NULL;
165933707f3Ssthen 	}
166d896b962Ssthen #endif
167933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
168933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
169933707f3Ssthen 	}
1702bdc0ed1Ssthen 	if(!w->env->scratch || !w->env->scratch_buffer) {
171933707f3Ssthen 		libworker_delete(w);
172933707f3Ssthen 		return NULL;
173933707f3Ssthen 	}
174933707f3Ssthen 	w->env->worker = (struct worker*)w;
175933707f3Ssthen 	w->env->probe_timer = NULL;
176933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
177933707f3Ssthen 		lock_basic_lock(&ctx->cfglock);
178933707f3Ssthen 	}
179ebf5bb73Ssthen 	if(!(w->env->rnd = ub_initstate(ctx->seed_rnd))) {
180933707f3Ssthen 		if(!w->is_bg || w->is_bg_thread) {
181933707f3Ssthen 			lock_basic_unlock(&ctx->cfglock);
182933707f3Ssthen 		}
183933707f3Ssthen 		libworker_delete(w);
184933707f3Ssthen 		return NULL;
185933707f3Ssthen 	}
186933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
187933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
188933707f3Ssthen 	}
189933707f3Ssthen 	if(1) {
190933707f3Ssthen 		/* primitive lockout for threading: if it overwrites another
191933707f3Ssthen 		 * thread it is like wiping the cache (which is likely empty
192933707f3Ssthen 		 * at the start) */
193933707f3Ssthen 		/* note we are holding the ctx lock in normal threaded
194933707f3Ssthen 		 * cases so that is solved properly, it is only for many ctx
195933707f3Ssthen 		 * in different threads that this may clash */
196933707f3Ssthen 		static int done_raninit = 0;
197933707f3Ssthen 		if(!done_raninit) {
198933707f3Ssthen 			done_raninit = 1;
199933707f3Ssthen 			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
200933707f3Ssthen 		}
201933707f3Ssthen 	}
202933707f3Ssthen 
2030b68ff31Ssthen 	if(eb)
2040b68ff31Ssthen 		w->base = comm_base_create_event(eb);
2050b68ff31Ssthen 	else	w->base = comm_base_create(0);
206933707f3Ssthen 	if(!w->base) {
207933707f3Ssthen 		libworker_delete(w);
208933707f3Ssthen 		return NULL;
209933707f3Ssthen 	}
210bdfc4d55Sflorian 	w->env->worker_base = w->base;
211933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
212933707f3Ssthen 		lock_basic_lock(&ctx->cfglock);
213933707f3Ssthen 	}
214933707f3Ssthen 	numports = cfg_condense_ports(cfg, &ports);
215933707f3Ssthen 	if(numports == 0) {
216c3b38330Ssthen 		if(!w->is_bg || w->is_bg_thread) {
217e9c7b4efSsthen 			lock_basic_unlock(&ctx->cfglock);
2180b68ff31Ssthen 		}
219c3b38330Ssthen 		libworker_delete(w);
220933707f3Ssthen 		return NULL;
221933707f3Ssthen 	}
222933707f3Ssthen 	w->back = outside_network_create(w->base, cfg->msg_buffer_size,
223933707f3Ssthen 		(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
224933707f3Ssthen 		cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
225a3167c07Ssthen 		cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
226933707f3Ssthen 		w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
227933707f3Ssthen 		ports, numports, cfg->unwanted_threshold,
228bdfc4d55Sflorian 		cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
229bdfc4d55Sflorian 		cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
230191f22c6Ssthen 		cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
231191f22c6Ssthen 		cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
232191f22c6Ssthen 		cfg->tcp_auth_query_timeout);
233bdfc4d55Sflorian 	w->env->outnet = w->back;
234933707f3Ssthen 	if(!w->is_bg || w->is_bg_thread) {
235933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
236933707f3Ssthen 	}
237933707f3Ssthen 	free(ports);
238933707f3Ssthen 	if(!w->back) {
239933707f3Ssthen 		libworker_delete(w);
240933707f3Ssthen 		return NULL;
241933707f3Ssthen 	}
242933707f3Ssthen 	w->env->mesh = mesh_create(&ctx->mods, w->env);
243933707f3Ssthen 	if(!w->env->mesh) {
244933707f3Ssthen 		libworker_delete(w);
245933707f3Ssthen 		return NULL;
246933707f3Ssthen 	}
247933707f3Ssthen 	w->env->send_query = &libworker_send_query;
248933707f3Ssthen 	w->env->detach_subs = &mesh_detach_subs;
249933707f3Ssthen 	w->env->attach_sub = &mesh_attach_sub;
250bdfc4d55Sflorian 	w->env->add_sub = &mesh_add_sub;
251933707f3Ssthen 	w->env->kill_sub = &mesh_state_delete;
252933707f3Ssthen 	w->env->detect_cycle = &mesh_detect_cycle;
253933707f3Ssthen 	comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
254d896b962Ssthen 	pp_init(&sldns_write_uint16, &sldns_write_uint32);
255933707f3Ssthen 	return w;
256933707f3Ssthen }
257933707f3Ssthen 
2580b68ff31Ssthen struct libworker* libworker_create_event(struct ub_ctx* ctx,
2592ee382b6Ssthen 	struct ub_event_base* eb)
2600b68ff31Ssthen {
2610b68ff31Ssthen 	return libworker_setup(ctx, 0, eb);
2620b68ff31Ssthen }
2630b68ff31Ssthen 
264933707f3Ssthen /** handle cancel command for bg worker */
265933707f3Ssthen static void
266933707f3Ssthen handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
267933707f3Ssthen {
268933707f3Ssthen 	struct ctx_query* q;
269933707f3Ssthen 	if(w->is_bg_thread) {
270933707f3Ssthen 		lock_basic_lock(&w->ctx->cfglock);
271933707f3Ssthen 		q = context_deserialize_cancel(w->ctx, buf, len);
272933707f3Ssthen 		lock_basic_unlock(&w->ctx->cfglock);
273933707f3Ssthen 	} else {
274933707f3Ssthen 		q = context_deserialize_cancel(w->ctx, buf, len);
275933707f3Ssthen 	}
276933707f3Ssthen 	if(!q) {
277933707f3Ssthen 		/* probably simply lookup failed, i.e. the message had been
278933707f3Ssthen 		 * processed and answered before the cancel arrived */
279933707f3Ssthen 		return;
280933707f3Ssthen 	}
281933707f3Ssthen 	q->cancelled = 1;
282933707f3Ssthen 	free(buf);
283933707f3Ssthen }
284933707f3Ssthen 
285933707f3Ssthen /** do control command coming into bg server */
286933707f3Ssthen static void
287933707f3Ssthen libworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
288933707f3Ssthen {
289933707f3Ssthen 	switch(context_serial_getcmd(msg, len)) {
290933707f3Ssthen 		default:
291933707f3Ssthen 		case UB_LIBCMD_ANSWER:
292933707f3Ssthen 			log_err("unknown command for bg worker %d",
293933707f3Ssthen 				(int)context_serial_getcmd(msg, len));
294933707f3Ssthen 			/* and fall through to quit */
295*98bc733bSsthen 			ATTR_FALLTHROUGH
2967191de28Ssthen 			/* fallthrough */
297933707f3Ssthen 		case UB_LIBCMD_QUIT:
298933707f3Ssthen 			free(msg);
299933707f3Ssthen 			comm_base_exit(w->base);
300933707f3Ssthen 			break;
301933707f3Ssthen 		case UB_LIBCMD_NEWQUERY:
302933707f3Ssthen 			handle_newq(w, msg, len);
303933707f3Ssthen 			break;
304933707f3Ssthen 		case UB_LIBCMD_CANCEL:
305933707f3Ssthen 			handle_cancel(w, msg, len);
306933707f3Ssthen 			break;
307933707f3Ssthen 	}
308933707f3Ssthen }
309933707f3Ssthen 
310933707f3Ssthen /** handle control command coming into server */
311933707f3Ssthen void
312933707f3Ssthen libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
313933707f3Ssthen 	uint8_t* msg, size_t len, int err, void* arg)
314933707f3Ssthen {
315933707f3Ssthen 	struct libworker* w = (struct libworker*)arg;
316933707f3Ssthen 
317933707f3Ssthen 	if(err != 0) {
318933707f3Ssthen 		free(msg);
319933707f3Ssthen 		/* it is of no use to go on, exit */
320933707f3Ssthen 		comm_base_exit(w->base);
321933707f3Ssthen 		return;
322933707f3Ssthen 	}
323933707f3Ssthen 	libworker_do_cmd(w, msg, len); /* also frees the buf */
324933707f3Ssthen }
325933707f3Ssthen 
326933707f3Ssthen /** the background thread func */
327933707f3Ssthen static void*
328933707f3Ssthen libworker_dobg(void* arg)
329933707f3Ssthen {
330933707f3Ssthen 	/* setup */
331933707f3Ssthen 	uint32_t m;
332933707f3Ssthen 	struct libworker* w = (struct libworker*)arg;
333933707f3Ssthen 	struct ub_ctx* ctx;
334933707f3Ssthen 	if(!w) {
335933707f3Ssthen 		log_err("libunbound bg worker init failed, nomem");
336933707f3Ssthen 		return NULL;
337933707f3Ssthen 	}
338933707f3Ssthen 	ctx = w->ctx;
339933707f3Ssthen 	log_thread_set(&w->thread_num);
340933707f3Ssthen #ifdef THREADS_DISABLED
341933707f3Ssthen 	/* we are forked */
342933707f3Ssthen 	w->is_bg_thread = 0;
343933707f3Ssthen 	/* close non-used parts of the pipes */
344933707f3Ssthen 	tube_close_write(ctx->qq_pipe);
345933707f3Ssthen 	tube_close_read(ctx->rr_pipe);
346933707f3Ssthen #endif
347933707f3Ssthen 	if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
348933707f3Ssthen 		libworker_handle_control_cmd, w)) {
349933707f3Ssthen 		log_err("libunbound bg worker init failed, no bglisten");
350933707f3Ssthen 		return NULL;
351933707f3Ssthen 	}
352933707f3Ssthen 	if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
353933707f3Ssthen 		log_err("libunbound bg worker init failed, no bgwrite");
354933707f3Ssthen 		return NULL;
355933707f3Ssthen 	}
356933707f3Ssthen 
357933707f3Ssthen 	/* do the work */
358933707f3Ssthen 	comm_base_dispatch(w->base);
359933707f3Ssthen 
360933707f3Ssthen 	/* cleanup */
361933707f3Ssthen 	m = UB_LIBCMD_QUIT;
36220237c55Ssthen 	w->want_quit = 1;
363933707f3Ssthen 	tube_remove_bg_listen(w->ctx->qq_pipe);
364933707f3Ssthen 	tube_remove_bg_write(w->ctx->rr_pipe);
365933707f3Ssthen 	libworker_delete(w);
366933707f3Ssthen 	(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
367933707f3Ssthen 		(uint32_t)sizeof(m), 0);
368933707f3Ssthen #ifdef THREADS_DISABLED
369933707f3Ssthen 	/* close pipes from forked process before exit */
370933707f3Ssthen 	tube_close_read(ctx->qq_pipe);
371933707f3Ssthen 	tube_close_write(ctx->rr_pipe);
372933707f3Ssthen #endif
373933707f3Ssthen 	return NULL;
374933707f3Ssthen }
375933707f3Ssthen 
376933707f3Ssthen int libworker_bg(struct ub_ctx* ctx)
377933707f3Ssthen {
378933707f3Ssthen 	struct libworker* w;
379933707f3Ssthen 	/* fork or threadcreate */
380933707f3Ssthen 	lock_basic_lock(&ctx->cfglock);
381933707f3Ssthen 	if(ctx->dothread) {
382933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
3830b68ff31Ssthen 		w = libworker_setup(ctx, 1, NULL);
384933707f3Ssthen 		if(!w) return UB_NOMEM;
385933707f3Ssthen 		w->is_bg_thread = 1;
3868b7325afSsthen 		ctx->thread_worker = w;
387933707f3Ssthen #ifdef ENABLE_LOCK_CHECKS
388933707f3Ssthen 		w->thread_num = 1; /* for nicer DEBUG checklocks */
389933707f3Ssthen #endif
390933707f3Ssthen 		ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
391933707f3Ssthen 	} else {
392933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
393933707f3Ssthen #ifndef HAVE_FORK
394933707f3Ssthen 		/* no fork on windows */
395933707f3Ssthen 		return UB_FORKFAIL;
396933707f3Ssthen #else /* HAVE_FORK */
397933707f3Ssthen 		switch((ctx->bg_pid=fork())) {
398933707f3Ssthen 			case 0:
3990b68ff31Ssthen 				w = libworker_setup(ctx, 1, NULL);
400933707f3Ssthen 				if(!w) fatal_exit("out of memory");
401933707f3Ssthen 				/* close non-used parts of the pipes */
402933707f3Ssthen 				tube_close_write(ctx->qq_pipe);
403933707f3Ssthen 				tube_close_read(ctx->rr_pipe);
404933707f3Ssthen 				(void)libworker_dobg(w);
405933707f3Ssthen 				exit(0);
406933707f3Ssthen 				break;
407933707f3Ssthen 			case -1:
408933707f3Ssthen 				return UB_FORKFAIL;
409933707f3Ssthen 			default:
410e9c7b4efSsthen 				/* close non-used parts, so that the worker
411e9c7b4efSsthen 				 * bgprocess gets 'pipe closed' when the
412e9c7b4efSsthen 				 * main process exits */
413e9c7b4efSsthen 				tube_close_read(ctx->qq_pipe);
414e9c7b4efSsthen 				tube_close_write(ctx->rr_pipe);
415933707f3Ssthen 				break;
416933707f3Ssthen 		}
417933707f3Ssthen #endif /* HAVE_FORK */
418933707f3Ssthen 	}
419933707f3Ssthen 	return UB_NOERROR;
420933707f3Ssthen }
421933707f3Ssthen 
422933707f3Ssthen /** insert canonname */
423933707f3Ssthen static int
424933707f3Ssthen fill_canon(struct ub_result* res, uint8_t* s)
425933707f3Ssthen {
426933707f3Ssthen 	char buf[255+2];
427933707f3Ssthen 	dname_str(s, buf);
428933707f3Ssthen 	res->canonname = strdup(buf);
429933707f3Ssthen 	return res->canonname != 0;
430933707f3Ssthen }
431933707f3Ssthen 
432933707f3Ssthen /** fill data into result */
433933707f3Ssthen static int
434933707f3Ssthen fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
435e9c7b4efSsthen 	uint8_t* finalcname, struct query_info* rq, struct reply_info* rep)
436933707f3Ssthen {
437933707f3Ssthen 	size_t i;
438933707f3Ssthen 	struct packed_rrset_data* data;
439e9c7b4efSsthen 	res->ttl = 0;
440933707f3Ssthen 	if(!answer) {
441933707f3Ssthen 		if(finalcname) {
442933707f3Ssthen 			if(!fill_canon(res, finalcname))
443933707f3Ssthen 				return 0; /* out of memory */
444933707f3Ssthen 		}
445e9c7b4efSsthen 		if(rep->rrset_count != 0)
446e9c7b4efSsthen 			res->ttl = (int)rep->ttl;
447933707f3Ssthen 		res->data = (char**)calloc(1, sizeof(char*));
448191f22c6Ssthen 		if(!res->data)
449191f22c6Ssthen 			return 0; /* out of memory */
450933707f3Ssthen 		res->len = (int*)calloc(1, sizeof(int));
451191f22c6Ssthen 		if(!res->len) {
452191f22c6Ssthen 			free(res->data);
453191f22c6Ssthen 			res->data = NULL;
454191f22c6Ssthen 			return 0; /* out of memory */
455191f22c6Ssthen 		}
456191f22c6Ssthen 		return 1;
457933707f3Ssthen 	}
458933707f3Ssthen 	data = (struct packed_rrset_data*)answer->entry.data;
459933707f3Ssthen 	if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
460933707f3Ssthen 		if(!fill_canon(res, answer->rk.dname))
461933707f3Ssthen 			return 0; /* out of memory */
462933707f3Ssthen 	} else	res->canonname = NULL;
463933707f3Ssthen 	res->data = (char**)calloc(data->count+1, sizeof(char*));
464191f22c6Ssthen 	if(!res->data)
465933707f3Ssthen 		return 0; /* out of memory */
466191f22c6Ssthen 	res->len = (int*)calloc(data->count+1, sizeof(int));
467191f22c6Ssthen 	if(!res->len) {
468191f22c6Ssthen 		free(res->data);
469191f22c6Ssthen 		res->data = NULL;
470191f22c6Ssthen 		return 0; /* out of memory */
471191f22c6Ssthen 	}
472933707f3Ssthen 	for(i=0; i<data->count; i++) {
473933707f3Ssthen 		/* remove rdlength from rdata */
474933707f3Ssthen 		res->len[i] = (int)(data->rr_len[i] - 2);
475933707f3Ssthen 		res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
476191f22c6Ssthen 		if(!res->data[i]) {
477191f22c6Ssthen 			size_t j;
478191f22c6Ssthen 			for(j=0; j<i; j++) {
479191f22c6Ssthen 				free(res->data[j]);
480191f22c6Ssthen 				res->data[j] = NULL;
481191f22c6Ssthen 			}
482191f22c6Ssthen 			free(res->data);
483191f22c6Ssthen 			res->data = NULL;
484191f22c6Ssthen 			free(res->len);
485191f22c6Ssthen 			res->len = NULL;
486933707f3Ssthen 			return 0; /* out of memory */
487933707f3Ssthen 		}
488191f22c6Ssthen 	}
489e9c7b4efSsthen 	/* ttl for positive answers, from CNAME and answer RRs */
490e9c7b4efSsthen 	if(data->count != 0) {
491e9c7b4efSsthen 		size_t j;
492e9c7b4efSsthen 		res->ttl = (int)data->ttl;
493e9c7b4efSsthen 		for(j=0; j<rep->an_numrrsets; j++) {
494e9c7b4efSsthen 			struct packed_rrset_data* d =
495e9c7b4efSsthen 				(struct packed_rrset_data*)rep->rrsets[j]->
496e9c7b4efSsthen 				entry.data;
497e9c7b4efSsthen 			if((int)d->ttl < res->ttl)
498e9c7b4efSsthen 				res->ttl = (int)d->ttl;
499e9c7b4efSsthen 		}
500e9c7b4efSsthen 	}
501e9c7b4efSsthen 	/* ttl for negative answers */
502e9c7b4efSsthen 	if(data->count == 0 && rep->rrset_count != 0)
503e9c7b4efSsthen 		res->ttl = (int)rep->ttl;
504933707f3Ssthen 	res->data[data->count] = NULL;
505933707f3Ssthen 	res->len[data->count] = 0;
506933707f3Ssthen 	return 1;
507933707f3Ssthen }
508933707f3Ssthen 
509933707f3Ssthen /** fill result from parsed message, on error fills servfail */
510933707f3Ssthen void
5110b68ff31Ssthen libworker_enter_result(struct ub_result* res, sldns_buffer* buf,
512933707f3Ssthen 	struct regional* temp, enum sec_status msg_security)
513933707f3Ssthen {
514933707f3Ssthen 	struct query_info rq;
515933707f3Ssthen 	struct reply_info* rep;
516933707f3Ssthen 	res->rcode = LDNS_RCODE_SERVFAIL;
517bdfc4d55Sflorian 	rep = parse_reply_in_temp_region(buf, temp, &rq);
518933707f3Ssthen 	if(!rep) {
519933707f3Ssthen 		log_err("cannot parse buf");
520933707f3Ssthen 		return; /* error parsing buf, or out of memory */
521933707f3Ssthen 	}
522933707f3Ssthen 	if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
523e9c7b4efSsthen 		reply_find_final_cname_target(&rq, rep), &rq, rep))
524933707f3Ssthen 		return; /* out of memory */
525933707f3Ssthen 	/* rcode, havedata, nxdomain, secure, bogus */
526933707f3Ssthen 	res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
527933707f3Ssthen 	if(res->data && res->data[0])
528933707f3Ssthen 		res->havedata = 1;
529933707f3Ssthen 	if(res->rcode == LDNS_RCODE_NXDOMAIN)
530933707f3Ssthen 		res->nxdomain = 1;
531933707f3Ssthen 	if(msg_security == sec_status_secure)
532933707f3Ssthen 		res->secure = 1;
53320237c55Ssthen 	if(msg_security == sec_status_bogus ||
53420237c55Ssthen 		msg_security == sec_status_secure_sentinel_fail)
535933707f3Ssthen 		res->bogus = 1;
536933707f3Ssthen }
537933707f3Ssthen 
538933707f3Ssthen /** fillup fg results */
539933707f3Ssthen static void
5400b68ff31Ssthen libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
5412308e98cSsthen 	enum sec_status s, char* why_bogus, int was_ratelimited)
542933707f3Ssthen {
5432308e98cSsthen 	q->res->was_ratelimited = was_ratelimited;
544933707f3Ssthen 	if(why_bogus)
545933707f3Ssthen 		q->res->why_bogus = strdup(why_bogus);
546933707f3Ssthen 	if(rcode != 0) {
547933707f3Ssthen 		q->res->rcode = rcode;
548933707f3Ssthen 		q->msg_security = s;
549933707f3Ssthen 		return;
550933707f3Ssthen 	}
551933707f3Ssthen 
552933707f3Ssthen 	q->res->rcode = LDNS_RCODE_SERVFAIL;
553ebf5bb73Ssthen 	q->msg_security = sec_status_unchecked;
5540b68ff31Ssthen 	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
5550b68ff31Ssthen 	q->msg_len = sldns_buffer_limit(buf);
556933707f3Ssthen 	if(!q->msg) {
557933707f3Ssthen 		return; /* the error is in the rcode */
558933707f3Ssthen 	}
559933707f3Ssthen 
560933707f3Ssthen 	/* canonname and results */
561933707f3Ssthen 	q->msg_security = s;
562933707f3Ssthen 	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
563933707f3Ssthen }
564933707f3Ssthen 
565933707f3Ssthen void
5660b68ff31Ssthen libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
5672308e98cSsthen 	char* why_bogus, int was_ratelimited)
568933707f3Ssthen {
569933707f3Ssthen 	struct ctx_query* q = (struct ctx_query*)arg;
570933707f3Ssthen 	/* fg query is done; exit comm base */
571933707f3Ssthen 	comm_base_exit(q->w->base);
572933707f3Ssthen 
5732308e98cSsthen 	libworker_fillup_fg(q, rcode, buf, s, why_bogus, was_ratelimited);
574933707f3Ssthen }
575933707f3Ssthen 
576933707f3Ssthen /** setup qinfo and edns */
577933707f3Ssthen static int
578933707f3Ssthen setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
579933707f3Ssthen 	struct query_info* qinfo, struct edns_data* edns)
580933707f3Ssthen {
581933707f3Ssthen 	qinfo->qtype = (uint16_t)q->res->qtype;
582933707f3Ssthen 	qinfo->qclass = (uint16_t)q->res->qclass;
58377079be7Ssthen 	qinfo->local_alias = NULL;
5840b68ff31Ssthen 	qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len);
5850b68ff31Ssthen 	if(!qinfo->qname) {
586933707f3Ssthen 		return 0;
587933707f3Ssthen 	}
588933707f3Ssthen 	edns->edns_present = 1;
589933707f3Ssthen 	edns->ext_rcode = 0;
590933707f3Ssthen 	edns->edns_version = 0;
591933707f3Ssthen 	edns->bits = EDNS_DO;
592e21c60efSsthen 	edns->opt_list_in = NULL;
593e21c60efSsthen 	edns->opt_list_out = NULL;
594e21c60efSsthen 	edns->opt_list_inplace_cb_out = NULL;
5959982a05dSsthen 	edns->padding_block_size = 0;
5968b7325afSsthen 	edns->cookie_present = 0;
5978b7325afSsthen 	edns->cookie_valid = 0;
5980b68ff31Ssthen 	if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
5990b68ff31Ssthen 		edns->udp_size = (uint16_t)sldns_buffer_capacity(
600933707f3Ssthen 			w->back->udp_buff);
601933707f3Ssthen 	else	edns->udp_size = 65535;
602933707f3Ssthen 	return 1;
603933707f3Ssthen }
604933707f3Ssthen 
605933707f3Ssthen int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
606933707f3Ssthen {
6070b68ff31Ssthen 	struct libworker* w = libworker_setup(ctx, 0, NULL);
608933707f3Ssthen 	uint16_t qflags, qid;
609933707f3Ssthen 	struct query_info qinfo;
610933707f3Ssthen 	struct edns_data edns;
611933707f3Ssthen 	if(!w)
612933707f3Ssthen 		return UB_INITFAIL;
613933707f3Ssthen 	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
614933707f3Ssthen 		libworker_delete(w);
615933707f3Ssthen 		return UB_SYNTAX;
616933707f3Ssthen 	}
617933707f3Ssthen 	qid = 0;
618933707f3Ssthen 	qflags = BIT_RD;
619933707f3Ssthen 	q->w = w;
620933707f3Ssthen 	/* see if there is a fixed answer */
6210b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
6220b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
62377079be7Ssthen 	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
62477079be7Ssthen 		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
62577079be7Ssthen 		NULL, 0, NULL, 0, NULL)) {
626933707f3Ssthen 		regional_free_all(w->env->scratch);
627933707f3Ssthen 		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
6282308e98cSsthen 			w->back->udp_buff, sec_status_insecure, NULL, 0);
629933707f3Ssthen 		libworker_delete(w);
630933707f3Ssthen 		free(qinfo.qname);
631933707f3Ssthen 		return UB_NOERROR;
632933707f3Ssthen 	}
633938a3a5eSflorian 	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
6342308e98cSsthen 		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
635938a3a5eSflorian 		regional_free_all(w->env->scratch);
636938a3a5eSflorian 		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
6372308e98cSsthen 			w->back->udp_buff, sec_status_insecure, NULL, 0);
638938a3a5eSflorian 		libworker_delete(w);
639938a3a5eSflorian 		free(qinfo.qname);
640938a3a5eSflorian 		return UB_NOERROR;
641938a3a5eSflorian 	}
642933707f3Ssthen 	/* process new query */
643933707f3Ssthen 	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
6440bdb4f62Ssthen 		w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
645933707f3Ssthen 		free(qinfo.qname);
646933707f3Ssthen 		return UB_NOMEM;
647933707f3Ssthen 	}
648933707f3Ssthen 	free(qinfo.qname);
649933707f3Ssthen 
650933707f3Ssthen 	/* wait for reply */
651933707f3Ssthen 	comm_base_dispatch(w->base);
652933707f3Ssthen 
653933707f3Ssthen 	libworker_delete(w);
654933707f3Ssthen 	return UB_NOERROR;
655933707f3Ssthen }
656933707f3Ssthen 
6570b68ff31Ssthen void
6580b68ff31Ssthen libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
6592308e98cSsthen 	enum sec_status s, char* why_bogus, int was_ratelimited)
6600b68ff31Ssthen {
6610b68ff31Ssthen 	struct ctx_query* q = (struct ctx_query*)arg;
66220237c55Ssthen 	ub_event_callback_type cb = q->cb_event;
6630b68ff31Ssthen 	void* cb_arg = q->cb_arg;
6640b68ff31Ssthen 	int cancelled = q->cancelled;
6650b68ff31Ssthen 
6660b68ff31Ssthen 	/* delete it now */
6670b68ff31Ssthen 	struct ub_ctx* ctx = q->w->ctx;
6680b68ff31Ssthen 	lock_basic_lock(&ctx->cfglock);
6690b68ff31Ssthen 	(void)rbtree_delete(&ctx->queries, q->node.key);
6700b68ff31Ssthen 	ctx->num_async--;
6710b68ff31Ssthen 	context_query_delete(q);
6720b68ff31Ssthen 	lock_basic_unlock(&ctx->cfglock);
6730b68ff31Ssthen 
6740b68ff31Ssthen 	if(!cancelled) {
6750b68ff31Ssthen 		/* call callback */
6760b68ff31Ssthen 		int sec = 0;
6770b68ff31Ssthen 		if(s == sec_status_bogus)
6780b68ff31Ssthen 			sec = 1;
6790b68ff31Ssthen 		else if(s == sec_status_secure)
6800b68ff31Ssthen 			sec = 2;
6813150e5f6Ssthen 		(*cb)(cb_arg, rcode, (buf?(void*)sldns_buffer_begin(buf):NULL),
6823150e5f6Ssthen 			(buf?(int)sldns_buffer_limit(buf):0), sec, why_bogus, was_ratelimited);
6830b68ff31Ssthen 	}
6840b68ff31Ssthen }
6850b68ff31Ssthen 
6860b68ff31Ssthen int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
6870b68ff31Ssthen 	int* async_id)
6880b68ff31Ssthen {
6890b68ff31Ssthen 	struct libworker* w = ctx->event_worker;
6900b68ff31Ssthen 	uint16_t qflags, qid;
6910b68ff31Ssthen 	struct query_info qinfo;
6920b68ff31Ssthen 	struct edns_data edns;
6930b68ff31Ssthen 	if(!w)
6940b68ff31Ssthen 		return UB_INITFAIL;
6950b68ff31Ssthen 	if(!setup_qinfo_edns(w, q, &qinfo, &edns))
6960b68ff31Ssthen 		return UB_SYNTAX;
6970b68ff31Ssthen 	qid = 0;
6980b68ff31Ssthen 	qflags = BIT_RD;
6990b68ff31Ssthen 	q->w = w;
7000b68ff31Ssthen 	/* see if there is a fixed answer */
7010b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
7020b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
70377079be7Ssthen 	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
70477079be7Ssthen 		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
70577079be7Ssthen 		NULL, 0, NULL, 0, NULL)) {
7060b68ff31Ssthen 		regional_free_all(w->env->scratch);
7070b68ff31Ssthen 		free(qinfo.qname);
7080b68ff31Ssthen 		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
7092308e98cSsthen 			w->back->udp_buff, sec_status_insecure, NULL, 0);
7100b68ff31Ssthen 		return UB_NOERROR;
7110b68ff31Ssthen 	}
712938a3a5eSflorian 	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
7132308e98cSsthen 		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
714938a3a5eSflorian 		regional_free_all(w->env->scratch);
715938a3a5eSflorian 		free(qinfo.qname);
716938a3a5eSflorian 		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
7172308e98cSsthen 			w->back->udp_buff, sec_status_insecure, NULL, 0);
718938a3a5eSflorian 		return UB_NOERROR;
719938a3a5eSflorian 	}
7200b68ff31Ssthen 	/* process new query */
7210b68ff31Ssthen 	if(async_id)
7220b68ff31Ssthen 		*async_id = q->querynum;
7230b68ff31Ssthen 	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
7240bdb4f62Ssthen 		w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
7250b68ff31Ssthen 		free(qinfo.qname);
7260b68ff31Ssthen 		return UB_NOMEM;
7270b68ff31Ssthen 	}
7280b68ff31Ssthen 	free(qinfo.qname);
7290b68ff31Ssthen 	return UB_NOERROR;
7300b68ff31Ssthen }
7310b68ff31Ssthen 
732933707f3Ssthen /** add result to the bg worker result queue */
733933707f3Ssthen static void
7340b68ff31Ssthen add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
7352308e98cSsthen 	int err, char* reason, int was_ratelimited)
736933707f3Ssthen {
737933707f3Ssthen 	uint8_t* msg = NULL;
738933707f3Ssthen 	uint32_t len = 0;
739933707f3Ssthen 
74020237c55Ssthen 	if(w->want_quit) {
74120237c55Ssthen 		context_query_delete(q);
74220237c55Ssthen 		return;
74320237c55Ssthen 	}
744933707f3Ssthen 	/* serialize and delete unneeded q */
745933707f3Ssthen 	if(w->is_bg_thread) {
746933707f3Ssthen 		lock_basic_lock(&w->ctx->cfglock);
747933707f3Ssthen 		if(reason)
748933707f3Ssthen 			q->res->why_bogus = strdup(reason);
7492308e98cSsthen 		q->res->was_ratelimited = was_ratelimited;
750933707f3Ssthen 		if(pkt) {
7510b68ff31Ssthen 			q->msg_len = sldns_buffer_remaining(pkt);
7520b68ff31Ssthen 			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
7532308e98cSsthen 			if(!q->msg) {
7542308e98cSsthen 				msg = context_serialize_answer(q, UB_NOMEM, NULL, &len);
7552308e98cSsthen 			} else {
7562308e98cSsthen 				msg = context_serialize_answer(q, err, NULL, &len);
7572308e98cSsthen 			}
7582308e98cSsthen 		} else {
7592308e98cSsthen 			msg = context_serialize_answer(q, err, NULL, &len);
7602308e98cSsthen 		}
761933707f3Ssthen 		lock_basic_unlock(&w->ctx->cfglock);
762933707f3Ssthen 	} else {
763933707f3Ssthen 		if(reason)
764933707f3Ssthen 			q->res->why_bogus = strdup(reason);
7652308e98cSsthen 		q->res->was_ratelimited = was_ratelimited;
766933707f3Ssthen 		msg = context_serialize_answer(q, err, pkt, &len);
767933707f3Ssthen 		(void)rbtree_delete(&w->ctx->queries, q->node.key);
768933707f3Ssthen 		w->ctx->num_async--;
769933707f3Ssthen 		context_query_delete(q);
770933707f3Ssthen 	}
771933707f3Ssthen 
772933707f3Ssthen 	if(!msg) {
773933707f3Ssthen 		log_err("out of memory for async answer");
774933707f3Ssthen 		return;
775933707f3Ssthen 	}
776933707f3Ssthen 	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
777933707f3Ssthen 		log_err("out of memory for async answer");
778933707f3Ssthen 		return;
779933707f3Ssthen 	}
780933707f3Ssthen }
781933707f3Ssthen 
782933707f3Ssthen void
7830b68ff31Ssthen libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
7842308e98cSsthen 	char* why_bogus, int was_ratelimited)
785933707f3Ssthen {
786933707f3Ssthen 	struct ctx_query* q = (struct ctx_query*)arg;
787933707f3Ssthen 
7887191de28Ssthen 	if(q->cancelled || q->w->back->want_to_quit) {
789933707f3Ssthen 		if(q->w->is_bg_thread) {
790933707f3Ssthen 			/* delete it now */
791933707f3Ssthen 			struct ub_ctx* ctx = q->w->ctx;
792933707f3Ssthen 			lock_basic_lock(&ctx->cfglock);
793933707f3Ssthen 			(void)rbtree_delete(&ctx->queries, q->node.key);
794933707f3Ssthen 			ctx->num_async--;
795933707f3Ssthen 			context_query_delete(q);
796933707f3Ssthen 			lock_basic_unlock(&ctx->cfglock);
797933707f3Ssthen 		}
798933707f3Ssthen 		/* cancelled, do not give answer */
799933707f3Ssthen 		return;
800933707f3Ssthen 	}
801933707f3Ssthen 	q->msg_security = s;
8022308e98cSsthen 	if(!buf) {
803cebdf579Ssthen 		buf = q->w->env->scratch_buffer;
8042308e98cSsthen 	}
805933707f3Ssthen 	if(rcode != 0) {
806933707f3Ssthen 		error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
807933707f3Ssthen 	}
8082308e98cSsthen 	add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus, was_ratelimited);
809933707f3Ssthen }
810933707f3Ssthen 
811933707f3Ssthen 
812933707f3Ssthen /** handle new query command for bg worker */
813933707f3Ssthen static void
814933707f3Ssthen handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
815933707f3Ssthen {
816933707f3Ssthen 	uint16_t qflags, qid;
817933707f3Ssthen 	struct query_info qinfo;
818933707f3Ssthen 	struct edns_data edns;
819933707f3Ssthen 	struct ctx_query* q;
820933707f3Ssthen 	if(w->is_bg_thread) {
821933707f3Ssthen 		lock_basic_lock(&w->ctx->cfglock);
822933707f3Ssthen 		q = context_lookup_new_query(w->ctx, buf, len);
823933707f3Ssthen 		lock_basic_unlock(&w->ctx->cfglock);
824933707f3Ssthen 	} else {
825933707f3Ssthen 		q = context_deserialize_new_query(w->ctx, buf, len);
826933707f3Ssthen 	}
827933707f3Ssthen 	free(buf);
828933707f3Ssthen 	if(!q) {
829933707f3Ssthen 		log_err("failed to deserialize newq");
830933707f3Ssthen 		return;
831933707f3Ssthen 	}
832933707f3Ssthen 	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
8332308e98cSsthen 		add_bg_result(w, q, NULL, UB_SYNTAX, NULL, 0);
834933707f3Ssthen 		return;
835933707f3Ssthen 	}
836933707f3Ssthen 	qid = 0;
837933707f3Ssthen 	qflags = BIT_RD;
838933707f3Ssthen 	/* see if there is a fixed answer */
8390b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
8400b68ff31Ssthen 	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
84177079be7Ssthen 	if(local_zones_answer(w->ctx->local_zones, w->env, &qinfo, &edns,
84277079be7Ssthen 		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
84377079be7Ssthen 		NULL, 0, NULL, 0, NULL)) {
844933707f3Ssthen 		regional_free_all(w->env->scratch);
845933707f3Ssthen 		q->msg_security = sec_status_insecure;
8462308e98cSsthen 		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
847933707f3Ssthen 		free(qinfo.qname);
848933707f3Ssthen 		return;
849933707f3Ssthen 	}
850938a3a5eSflorian 	if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
8512308e98cSsthen 		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
852938a3a5eSflorian 		regional_free_all(w->env->scratch);
853938a3a5eSflorian 		q->msg_security = sec_status_insecure;
8542308e98cSsthen 		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
855938a3a5eSflorian 		free(qinfo.qname);
856938a3a5eSflorian 		return;
857938a3a5eSflorian 	}
858933707f3Ssthen 	q->w = w;
859933707f3Ssthen 	/* process new query */
860933707f3Ssthen 	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
8610bdb4f62Ssthen 		w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
8622308e98cSsthen 		add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
863933707f3Ssthen 	}
864933707f3Ssthen 	free(qinfo.qname);
865933707f3Ssthen }
866933707f3Ssthen 
867933707f3Ssthen void libworker_alloc_cleanup(void* arg)
868933707f3Ssthen {
869933707f3Ssthen 	struct libworker* w = (struct libworker*)arg;
870933707f3Ssthen 	slabhash_clear(&w->env->rrset_cache->table);
871933707f3Ssthen         slabhash_clear(w->env->msg_cache);
872933707f3Ssthen }
873933707f3Ssthen 
87477079be7Ssthen struct outbound_entry* libworker_send_query(struct query_info* qinfo,
87577079be7Ssthen 	uint16_t flags, int dnssec, int want_dnssec, int nocaps,
876e21c60efSsthen 	int check_ratelimit,
8772ee382b6Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
878e21c60efSsthen 	size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
879e21c60efSsthen 	struct module_qstate* q, int* was_ratelimited)
880933707f3Ssthen {
881933707f3Ssthen 	struct libworker* w = (struct libworker*)q->env->worker;
882933707f3Ssthen 	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
883933707f3Ssthen 		q->region, sizeof(*e));
884933707f3Ssthen 	if(!e)
885933707f3Ssthen 		return NULL;
886933707f3Ssthen 	e->qstate = q;
88777079be7Ssthen 	e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
888e21c60efSsthen 		want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream,
88920237c55Ssthen 		tls_auth_name, addr, addrlen, zone, zonelen, q,
890e21c60efSsthen 		libworker_handle_service_reply, e, w->back->udp_buff, q->env,
891e21c60efSsthen 		was_ratelimited);
892933707f3Ssthen 	if(!e->qsent) {
893933707f3Ssthen 		return NULL;
894933707f3Ssthen 	}
895933707f3Ssthen 	return e;
896933707f3Ssthen }
897933707f3Ssthen 
898933707f3Ssthen int
899933707f3Ssthen libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
900933707f3Ssthen         struct comm_reply* reply_info)
901933707f3Ssthen {
902933707f3Ssthen 	struct outbound_entry* e = (struct outbound_entry*)arg;
903933707f3Ssthen 	struct libworker* lw = (struct libworker*)e->qstate->env->worker;
904933707f3Ssthen 
905933707f3Ssthen 	if(error != 0) {
906933707f3Ssthen 		mesh_report_reply(lw->env->mesh, e, reply_info, error);
907933707f3Ssthen 		return 0;
908933707f3Ssthen 	}
909933707f3Ssthen 	/* sanity check. */
9100b68ff31Ssthen 	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
9110b68ff31Ssthen 		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
912933707f3Ssthen 			LDNS_PACKET_QUERY
9130b68ff31Ssthen 		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
914933707f3Ssthen 		/* error becomes timeout for the module as if this reply
915933707f3Ssthen 		 * never arrived. */
916933707f3Ssthen 		mesh_report_reply(lw->env->mesh, e, reply_info,
917933707f3Ssthen 			NETEVENT_TIMEOUT);
918933707f3Ssthen 		return 0;
919933707f3Ssthen 	}
920933707f3Ssthen 	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
921933707f3Ssthen 	return 0;
922933707f3Ssthen }
923933707f3Ssthen 
924933707f3Ssthen /* --- fake callbacks for fptr_wlist to work --- */
925933707f3Ssthen void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
926933707f3Ssthen 	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
927933707f3Ssthen 	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
928933707f3Ssthen {
929933707f3Ssthen 	log_assert(0);
930933707f3Ssthen }
931933707f3Ssthen 
932933707f3Ssthen int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
933933707f3Ssthen 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
934933707f3Ssthen         struct comm_reply* ATTR_UNUSED(repinfo))
935933707f3Ssthen {
936933707f3Ssthen 	log_assert(0);
937933707f3Ssthen 	return 0;
938933707f3Ssthen }
939933707f3Ssthen 
940933707f3Ssthen int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
941933707f3Ssthen 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
942933707f3Ssthen         struct comm_reply* ATTR_UNUSED(reply_info))
943933707f3Ssthen {
944933707f3Ssthen 	log_assert(0);
945933707f3Ssthen 	return 0;
946933707f3Ssthen }
947933707f3Ssthen 
948933707f3Ssthen int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
949933707f3Ssthen 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
950933707f3Ssthen         struct comm_reply* ATTR_UNUSED(repinfo))
951933707f3Ssthen {
952933707f3Ssthen 	log_assert(0);
953933707f3Ssthen 	return 0;
954933707f3Ssthen }
955933707f3Ssthen 
956933707f3Ssthen int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
957933707f3Ssthen 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
958933707f3Ssthen         struct comm_reply* ATTR_UNUSED(repinfo))
959933707f3Ssthen {
960933707f3Ssthen 	log_assert(0);
961933707f3Ssthen 	return 0;
962933707f3Ssthen }
963933707f3Ssthen 
964933707f3Ssthen void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
965933707f3Ssthen {
966933707f3Ssthen 	log_assert(0);
967933707f3Ssthen }
968933707f3Ssthen 
96977079be7Ssthen struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
97077079be7Ssthen 	uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
97177079be7Ssthen 	int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
972e21c60efSsthen 	int ATTR_UNUSED(check_ratelimit),
97377079be7Ssthen 	struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
974e21c60efSsthen 	uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
97520237c55Ssthen 	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
976e21c60efSsthen 	struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
977933707f3Ssthen {
978933707f3Ssthen 	log_assert(0);
979933707f3Ssthen 	return 0;
980933707f3Ssthen }
981933707f3Ssthen 
982933707f3Ssthen void
983933707f3Ssthen worker_alloc_cleanup(void* ATTR_UNUSED(arg))
984933707f3Ssthen {
985933707f3Ssthen 	log_assert(0);
986933707f3Ssthen }
987933707f3Ssthen 
988933707f3Ssthen void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
989933707f3Ssthen {
990933707f3Ssthen 	log_assert(0);
991933707f3Ssthen }
992933707f3Ssthen 
993933707f3Ssthen void worker_probe_timer_cb(void* ATTR_UNUSED(arg))
994933707f3Ssthen {
995933707f3Ssthen 	log_assert(0);
996933707f3Ssthen }
997933707f3Ssthen 
998af4988b1Ssthen void worker_start_accept(void* ATTR_UNUSED(arg))
999af4988b1Ssthen {
1000af4988b1Ssthen 	log_assert(0);
1001af4988b1Ssthen }
1002af4988b1Ssthen 
1003af4988b1Ssthen void worker_stop_accept(void* ATTR_UNUSED(arg))
1004af4988b1Ssthen {
1005af4988b1Ssthen 	log_assert(0);
1006af4988b1Ssthen }
1007af4988b1Ssthen 
1008933707f3Ssthen int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
1009933707f3Ssthen {
1010933707f3Ssthen 	log_assert(0);
1011933707f3Ssthen 	return 0;
1012933707f3Ssthen }
1013933707f3Ssthen 
1014933707f3Ssthen int
1015933707f3Ssthen codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1016933707f3Ssthen {
1017933707f3Ssthen 	log_assert(0);
1018933707f3Ssthen 	return 0;
1019933707f3Ssthen }
1020933707f3Ssthen 
1021933707f3Ssthen int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1022933707f3Ssthen {
1023933707f3Ssthen         log_assert(0);
1024933707f3Ssthen         return 0;
1025933707f3Ssthen }
1026933707f3Ssthen 
1027933707f3Ssthen void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
1028933707f3Ssthen {
1029933707f3Ssthen         log_assert(0);
1030933707f3Ssthen }
1031933707f3Ssthen 
1032933707f3Ssthen #ifdef UB_ON_WINDOWS
1033933707f3Ssthen void
1034933707f3Ssthen worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
1035933707f3Ssthen         ATTR_UNUSED(arg)) {
1036933707f3Ssthen         log_assert(0);
1037933707f3Ssthen }
1038933707f3Ssthen 
1039933707f3Ssthen void
1040933707f3Ssthen wsvc_cron_cb(void* ATTR_UNUSED(arg))
1041933707f3Ssthen {
1042933707f3Ssthen         log_assert(0);
1043933707f3Ssthen }
1044933707f3Ssthen #endif /* UB_ON_WINDOWS */
1045a3167c07Ssthen 
1046a3167c07Ssthen #ifdef USE_DNSTAP
1047a3167c07Ssthen void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1048a3167c07Ssthen 	void* ATTR_UNUSED(arg))
1049a3167c07Ssthen {
1050a3167c07Ssthen 	log_assert(0);
1051a3167c07Ssthen }
1052a3167c07Ssthen #endif
1053a3167c07Ssthen 
1054a3167c07Ssthen #ifdef USE_DNSTAP
1055a3167c07Ssthen void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1056a3167c07Ssthen 	void* ATTR_UNUSED(arg))
1057a3167c07Ssthen {
1058a3167c07Ssthen 	log_assert(0);
1059a3167c07Ssthen }
1060a3167c07Ssthen #endif
1061