libworker.c revision 366095
1238106Sdes/*
2238106Sdes * libunbound/worker.c - worker thread or process that resolves
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains the worker process or thread that performs
40238106Sdes * the DNS resolving and validation. The worker is called by a procedure
41238106Sdes * and if in the background continues until exit, if in the foreground
42238106Sdes * returns from the procedure when done.
43238106Sdes */
44238106Sdes#include "config.h"
45249141Sdes#ifdef HAVE_SSL
46238106Sdes#include <openssl/ssl.h>
47249141Sdes#endif
48238106Sdes#include "libunbound/libworker.h"
49238106Sdes#include "libunbound/context.h"
50238106Sdes#include "libunbound/unbound.h"
51255579Sdes#include "libunbound/worker.h"
52266114Sdes#include "libunbound/unbound-event.h"
53238106Sdes#include "services/outside_network.h"
54238106Sdes#include "services/mesh.h"
55238106Sdes#include "services/localzone.h"
56238106Sdes#include "services/cache/rrset.h"
57238106Sdes#include "services/outbound_list.h"
58356345Scy#include "services/authzone.h"
59255579Sdes#include "util/fptr_wlist.h"
60238106Sdes#include "util/module.h"
61238106Sdes#include "util/regional.h"
62238106Sdes#include "util/random.h"
63238106Sdes#include "util/config_file.h"
64238106Sdes#include "util/netevent.h"
65238106Sdes#include "util/storage/lookup3.h"
66238106Sdes#include "util/storage/slabhash.h"
67238106Sdes#include "util/net_help.h"
68238106Sdes#include "util/data/dname.h"
69238106Sdes#include "util/data/msgreply.h"
70238106Sdes#include "util/data/msgencode.h"
71238106Sdes#include "util/tube.h"
72238106Sdes#include "iterator/iter_fwd.h"
73238106Sdes#include "iterator/iter_hints.h"
74287917Sdes#include "sldns/sbuffer.h"
75287917Sdes#include "sldns/str2wire.h"
76238106Sdes
77366095Scy#ifdef HAVE_TARGETCONDITIONALS_H
78366095Scy#include <TargetConditionals.h>
79366095Scy#endif
80366095Scy
81366095Scy#if defined(TARGET_OS_TV) || defined(TARGET_OS_WATCH)
82366095Scy#undef HAVE_FORK
83366095Scy#endif
84366095Scy
85238106Sdes/** handle new query command for bg worker */
86238106Sdesstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
87238106Sdes
88266114Sdes/** delete libworker env */
89238106Sdesstatic void
90266114Sdeslibworker_delete_env(struct libworker* w)
91238106Sdes{
92238106Sdes	if(w->env) {
93238106Sdes		outside_network_quit_prepare(w->back);
94238106Sdes		mesh_delete(w->env->mesh);
95238106Sdes		context_release_alloc(w->ctx, w->env->alloc,
96238106Sdes			!w->is_bg || w->is_bg_thread);
97266114Sdes		sldns_buffer_free(w->env->scratch_buffer);
98238106Sdes		regional_destroy(w->env->scratch);
99238106Sdes		forwards_delete(w->env->fwds);
100238106Sdes		hints_delete(w->env->hints);
101238106Sdes		ub_randfree(w->env->rnd);
102238106Sdes		free(w->env);
103238106Sdes	}
104249141Sdes#ifdef HAVE_SSL
105238106Sdes	SSL_CTX_free(w->sslctx);
106249141Sdes#endif
107238106Sdes	outside_network_delete(w->back);
108266114Sdes}
109266114Sdes
110266114Sdes/** delete libworker struct */
111266114Sdesstatic void
112266114Sdeslibworker_delete(struct libworker* w)
113266114Sdes{
114266114Sdes	if(!w) return;
115266114Sdes	libworker_delete_env(w);
116238106Sdes	comm_base_delete(w->base);
117238106Sdes	free(w);
118238106Sdes}
119238106Sdes
120266114Sdesvoid
121266114Sdeslibworker_delete_event(struct libworker* w)
122266114Sdes{
123266114Sdes	if(!w) return;
124266114Sdes	libworker_delete_env(w);
125266114Sdes	comm_base_delete_no_base(w->base);
126266114Sdes	free(w);
127266114Sdes}
128266114Sdes
129238106Sdes/** setup fresh libworker struct */
130238106Sdesstatic struct libworker*
131307729Sdeslibworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
132238106Sdes{
133238106Sdes	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
134238106Sdes	struct config_file* cfg = ctx->env->cfg;
135238106Sdes	int* ports;
136238106Sdes	int numports;
137238106Sdes	if(!w) return NULL;
138238106Sdes	w->is_bg = is_bg;
139238106Sdes	w->ctx = ctx;
140238106Sdes	w->env = (struct module_env*)malloc(sizeof(*w->env));
141238106Sdes	if(!w->env) {
142238106Sdes		free(w);
143238106Sdes		return NULL;
144238106Sdes	}
145238106Sdes	*w->env = *ctx->env;
146238106Sdes	w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
147238106Sdes	if(!w->env->alloc) {
148238106Sdes		libworker_delete(w);
149238106Sdes		return NULL;
150238106Sdes	}
151238106Sdes	w->thread_num = w->env->alloc->thread_num;
152238106Sdes	alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
153238106Sdes	if(!w->is_bg || w->is_bg_thread) {
154238106Sdes		lock_basic_lock(&ctx->cfglock);
155238106Sdes	}
156238106Sdes	w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
157266114Sdes	w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
158238106Sdes	w->env->fwds = forwards_create();
159238106Sdes	if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
160238106Sdes		forwards_delete(w->env->fwds);
161238106Sdes		w->env->fwds = NULL;
162238106Sdes	}
163238106Sdes	w->env->hints = hints_create();
164238106Sdes	if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
165238106Sdes		hints_delete(w->env->hints);
166238106Sdes		w->env->hints = NULL;
167238106Sdes	}
168356345Scy	if(cfg->ssl_upstream || (cfg->tls_cert_bundle && cfg->tls_cert_bundle[0]) || cfg->tls_win_cert) {
169356345Scy		w->sslctx = connect_sslctx_create(NULL, NULL,
170356345Scy			cfg->tls_cert_bundle, cfg->tls_win_cert);
171238106Sdes		if(!w->sslctx) {
172238106Sdes			/* to make the setup fail after unlock */
173238106Sdes			hints_delete(w->env->hints);
174238106Sdes			w->env->hints = NULL;
175238106Sdes		}
176238106Sdes	}
177238106Sdes	if(!w->is_bg || w->is_bg_thread) {
178238106Sdes		lock_basic_unlock(&ctx->cfglock);
179238106Sdes	}
180238106Sdes	if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
181238106Sdes		!w->env->hints) {
182238106Sdes		libworker_delete(w);
183238106Sdes		return NULL;
184238106Sdes	}
185238106Sdes	w->env->worker = (struct worker*)w;
186238106Sdes	w->env->probe_timer = NULL;
187238106Sdes	if(!w->is_bg || w->is_bg_thread) {
188238106Sdes		lock_basic_lock(&ctx->cfglock);
189238106Sdes	}
190356345Scy	if(!(w->env->rnd = ub_initstate(ctx->seed_rnd))) {
191238106Sdes		if(!w->is_bg || w->is_bg_thread) {
192238106Sdes			lock_basic_unlock(&ctx->cfglock);
193238106Sdes		}
194238106Sdes		libworker_delete(w);
195238106Sdes		return NULL;
196238106Sdes	}
197238106Sdes	if(!w->is_bg || w->is_bg_thread) {
198238106Sdes		lock_basic_unlock(&ctx->cfglock);
199238106Sdes	}
200238106Sdes	if(1) {
201238106Sdes		/* primitive lockout for threading: if it overwrites another
202238106Sdes		 * thread it is like wiping the cache (which is likely empty
203238106Sdes		 * at the start) */
204238106Sdes		/* note we are holding the ctx lock in normal threaded
205238106Sdes		 * cases so that is solved properly, it is only for many ctx
206238106Sdes		 * in different threads that this may clash */
207238106Sdes		static int done_raninit = 0;
208238106Sdes		if(!done_raninit) {
209238106Sdes			done_raninit = 1;
210238106Sdes			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
211238106Sdes		}
212238106Sdes	}
213238106Sdes
214266114Sdes	if(eb)
215266114Sdes		w->base = comm_base_create_event(eb);
216266114Sdes	else	w->base = comm_base_create(0);
217238106Sdes	if(!w->base) {
218238106Sdes		libworker_delete(w);
219238106Sdes		return NULL;
220238106Sdes	}
221356345Scy	w->env->worker_base = w->base;
222238106Sdes	if(!w->is_bg || w->is_bg_thread) {
223238106Sdes		lock_basic_lock(&ctx->cfglock);
224238106Sdes	}
225238106Sdes	numports = cfg_condense_ports(cfg, &ports);
226238106Sdes	if(numports == 0) {
227356345Scy		if(!w->is_bg || w->is_bg_thread) {
228266114Sdes			lock_basic_unlock(&ctx->cfglock);
229266114Sdes		}
230356345Scy		libworker_delete(w);
231238106Sdes		return NULL;
232238106Sdes	}
233238106Sdes	w->back = outside_network_create(w->base, cfg->msg_buffer_size,
234238106Sdes		(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
235238106Sdes		cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
236366095Scy		cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
237238106Sdes		w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
238238106Sdes		ports, numports, cfg->unwanted_threshold,
239356345Scy		cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
240356345Scy		cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
241366095Scy		cfg->delay_close, cfg->tls_use_sni, NULL);
242356345Scy	w->env->outnet = w->back;
243238106Sdes	if(!w->is_bg || w->is_bg_thread) {
244238106Sdes		lock_basic_unlock(&ctx->cfglock);
245238106Sdes	}
246238106Sdes	free(ports);
247238106Sdes	if(!w->back) {
248238106Sdes		libworker_delete(w);
249238106Sdes		return NULL;
250238106Sdes	}
251238106Sdes	w->env->mesh = mesh_create(&ctx->mods, w->env);
252238106Sdes	if(!w->env->mesh) {
253238106Sdes		libworker_delete(w);
254238106Sdes		return NULL;
255238106Sdes	}
256238106Sdes	w->env->send_query = &libworker_send_query;
257238106Sdes	w->env->detach_subs = &mesh_detach_subs;
258238106Sdes	w->env->attach_sub = &mesh_attach_sub;
259356345Scy	w->env->add_sub = &mesh_add_sub;
260238106Sdes	w->env->kill_sub = &mesh_state_delete;
261238106Sdes	w->env->detect_cycle = &mesh_detect_cycle;
262238106Sdes	comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
263238106Sdes	return w;
264238106Sdes}
265238106Sdes
266266114Sdesstruct libworker* libworker_create_event(struct ub_ctx* ctx,
267307729Sdes	struct ub_event_base* eb)
268266114Sdes{
269266114Sdes	return libworker_setup(ctx, 0, eb);
270266114Sdes}
271266114Sdes
272238106Sdes/** handle cancel command for bg worker */
273238106Sdesstatic void
274238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
275238106Sdes{
276238106Sdes	struct ctx_query* q;
277238106Sdes	if(w->is_bg_thread) {
278238106Sdes		lock_basic_lock(&w->ctx->cfglock);
279238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
280238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
281238106Sdes	} else {
282238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
283238106Sdes	}
284238106Sdes	if(!q) {
285238106Sdes		/* probably simply lookup failed, i.e. the message had been
286238106Sdes		 * processed and answered before the cancel arrived */
287238106Sdes		return;
288238106Sdes	}
289238106Sdes	q->cancelled = 1;
290238106Sdes	free(buf);
291238106Sdes}
292238106Sdes
293238106Sdes/** do control command coming into bg server */
294238106Sdesstatic void
295238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
296238106Sdes{
297238106Sdes	switch(context_serial_getcmd(msg, len)) {
298238106Sdes		default:
299238106Sdes		case UB_LIBCMD_ANSWER:
300238106Sdes			log_err("unknown command for bg worker %d",
301238106Sdes				(int)context_serial_getcmd(msg, len));
302238106Sdes			/* and fall through to quit */
303356345Scy			/* fallthrough */
304238106Sdes		case UB_LIBCMD_QUIT:
305238106Sdes			free(msg);
306238106Sdes			comm_base_exit(w->base);
307238106Sdes			break;
308238106Sdes		case UB_LIBCMD_NEWQUERY:
309238106Sdes			handle_newq(w, msg, len);
310238106Sdes			break;
311238106Sdes		case UB_LIBCMD_CANCEL:
312238106Sdes			handle_cancel(w, msg, len);
313238106Sdes			break;
314238106Sdes	}
315238106Sdes}
316238106Sdes
317238106Sdes/** handle control command coming into server */
318238106Sdesvoid
319238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
320238106Sdes	uint8_t* msg, size_t len, int err, void* arg)
321238106Sdes{
322238106Sdes	struct libworker* w = (struct libworker*)arg;
323238106Sdes
324238106Sdes	if(err != 0) {
325238106Sdes		free(msg);
326238106Sdes		/* it is of no use to go on, exit */
327238106Sdes		comm_base_exit(w->base);
328238106Sdes		return;
329238106Sdes	}
330238106Sdes	libworker_do_cmd(w, msg, len); /* also frees the buf */
331238106Sdes}
332238106Sdes
333238106Sdes/** the background thread func */
334238106Sdesstatic void*
335238106Sdeslibworker_dobg(void* arg)
336238106Sdes{
337238106Sdes	/* setup */
338238106Sdes	uint32_t m;
339238106Sdes	struct libworker* w = (struct libworker*)arg;
340238106Sdes	struct ub_ctx* ctx;
341238106Sdes	if(!w) {
342238106Sdes		log_err("libunbound bg worker init failed, nomem");
343238106Sdes		return NULL;
344238106Sdes	}
345238106Sdes	ctx = w->ctx;
346238106Sdes	log_thread_set(&w->thread_num);
347238106Sdes#ifdef THREADS_DISABLED
348238106Sdes	/* we are forked */
349238106Sdes	w->is_bg_thread = 0;
350238106Sdes	/* close non-used parts of the pipes */
351238106Sdes	tube_close_write(ctx->qq_pipe);
352238106Sdes	tube_close_read(ctx->rr_pipe);
353238106Sdes#endif
354238106Sdes	if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
355238106Sdes		libworker_handle_control_cmd, w)) {
356238106Sdes		log_err("libunbound bg worker init failed, no bglisten");
357238106Sdes		return NULL;
358238106Sdes	}
359238106Sdes	if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
360238106Sdes		log_err("libunbound bg worker init failed, no bgwrite");
361238106Sdes		return NULL;
362238106Sdes	}
363238106Sdes
364238106Sdes	/* do the work */
365238106Sdes	comm_base_dispatch(w->base);
366238106Sdes
367238106Sdes	/* cleanup */
368238106Sdes	m = UB_LIBCMD_QUIT;
369356345Scy	w->want_quit = 1;
370238106Sdes	tube_remove_bg_listen(w->ctx->qq_pipe);
371238106Sdes	tube_remove_bg_write(w->ctx->rr_pipe);
372238106Sdes	libworker_delete(w);
373238106Sdes	(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
374238106Sdes		(uint32_t)sizeof(m), 0);
375238106Sdes#ifdef THREADS_DISABLED
376238106Sdes	/* close pipes from forked process before exit */
377238106Sdes	tube_close_read(ctx->qq_pipe);
378238106Sdes	tube_close_write(ctx->rr_pipe);
379238106Sdes#endif
380238106Sdes	return NULL;
381238106Sdes}
382238106Sdes
383238106Sdesint libworker_bg(struct ub_ctx* ctx)
384238106Sdes{
385238106Sdes	struct libworker* w;
386238106Sdes	/* fork or threadcreate */
387238106Sdes	lock_basic_lock(&ctx->cfglock);
388238106Sdes	if(ctx->dothread) {
389238106Sdes		lock_basic_unlock(&ctx->cfglock);
390266114Sdes		w = libworker_setup(ctx, 1, NULL);
391238106Sdes		if(!w) return UB_NOMEM;
392238106Sdes		w->is_bg_thread = 1;
393238106Sdes#ifdef ENABLE_LOCK_CHECKS
394238106Sdes		w->thread_num = 1; /* for nicer DEBUG checklocks */
395238106Sdes#endif
396238106Sdes		ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
397238106Sdes	} else {
398238106Sdes		lock_basic_unlock(&ctx->cfglock);
399238106Sdes#ifndef HAVE_FORK
400238106Sdes		/* no fork on windows */
401238106Sdes		return UB_FORKFAIL;
402238106Sdes#else /* HAVE_FORK */
403238106Sdes		switch((ctx->bg_pid=fork())) {
404238106Sdes			case 0:
405266114Sdes				w = libworker_setup(ctx, 1, NULL);
406238106Sdes				if(!w) fatal_exit("out of memory");
407238106Sdes				/* close non-used parts of the pipes */
408238106Sdes				tube_close_write(ctx->qq_pipe);
409238106Sdes				tube_close_read(ctx->rr_pipe);
410238106Sdes				(void)libworker_dobg(w);
411238106Sdes				exit(0);
412238106Sdes				break;
413238106Sdes			case -1:
414238106Sdes				return UB_FORKFAIL;
415238106Sdes			default:
416266114Sdes				/* close non-used parts, so that the worker
417266114Sdes				 * bgprocess gets 'pipe closed' when the
418266114Sdes				 * main process exits */
419266114Sdes				tube_close_read(ctx->qq_pipe);
420266114Sdes				tube_close_write(ctx->rr_pipe);
421238106Sdes				break;
422238106Sdes		}
423238106Sdes#endif /* HAVE_FORK */
424238106Sdes	}
425238106Sdes	return UB_NOERROR;
426238106Sdes}
427238106Sdes
428238106Sdes/** insert canonname */
429238106Sdesstatic int
430238106Sdesfill_canon(struct ub_result* res, uint8_t* s)
431238106Sdes{
432238106Sdes	char buf[255+2];
433238106Sdes	dname_str(s, buf);
434238106Sdes	res->canonname = strdup(buf);
435238106Sdes	return res->canonname != 0;
436238106Sdes}
437238106Sdes
438238106Sdes/** fill data into result */
439238106Sdesstatic int
440238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
441249141Sdes	uint8_t* finalcname, struct query_info* rq, struct reply_info* rep)
442238106Sdes{
443238106Sdes	size_t i;
444238106Sdes	struct packed_rrset_data* data;
445249141Sdes	res->ttl = 0;
446238106Sdes	if(!answer) {
447238106Sdes		if(finalcname) {
448238106Sdes			if(!fill_canon(res, finalcname))
449238106Sdes				return 0; /* out of memory */
450238106Sdes		}
451249141Sdes		if(rep->rrset_count != 0)
452249141Sdes			res->ttl = (int)rep->ttl;
453238106Sdes		res->data = (char**)calloc(1, sizeof(char*));
454238106Sdes		res->len = (int*)calloc(1, sizeof(int));
455238106Sdes		return (res->data && res->len);
456238106Sdes	}
457238106Sdes	data = (struct packed_rrset_data*)answer->entry.data;
458238106Sdes	if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
459238106Sdes		if(!fill_canon(res, answer->rk.dname))
460238106Sdes			return 0; /* out of memory */
461238106Sdes	} else	res->canonname = NULL;
462238106Sdes	res->data = (char**)calloc(data->count+1, sizeof(char*));
463238106Sdes	res->len = (int*)calloc(data->count+1, sizeof(int));
464238106Sdes	if(!res->data || !res->len)
465238106Sdes		return 0; /* out of memory */
466238106Sdes	for(i=0; i<data->count; i++) {
467238106Sdes		/* remove rdlength from rdata */
468238106Sdes		res->len[i] = (int)(data->rr_len[i] - 2);
469238106Sdes		res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
470238106Sdes		if(!res->data[i])
471238106Sdes			return 0; /* out of memory */
472238106Sdes	}
473249141Sdes	/* ttl for positive answers, from CNAME and answer RRs */
474249141Sdes	if(data->count != 0) {
475249141Sdes		size_t j;
476249141Sdes		res->ttl = (int)data->ttl;
477249141Sdes		for(j=0; j<rep->an_numrrsets; j++) {
478249141Sdes			struct packed_rrset_data* d =
479249141Sdes				(struct packed_rrset_data*)rep->rrsets[j]->
480249141Sdes				entry.data;
481249141Sdes			if((int)d->ttl < res->ttl)
482249141Sdes				res->ttl = (int)d->ttl;
483249141Sdes		}
484249141Sdes	}
485249141Sdes	/* ttl for negative answers */
486249141Sdes	if(data->count == 0 && rep->rrset_count != 0)
487249141Sdes		res->ttl = (int)rep->ttl;
488238106Sdes	res->data[data->count] = NULL;
489238106Sdes	res->len[data->count] = 0;
490238106Sdes	return 1;
491238106Sdes}
492238106Sdes
493238106Sdes/** fill result from parsed message, on error fills servfail */
494238106Sdesvoid
495266114Sdeslibworker_enter_result(struct ub_result* res, sldns_buffer* buf,
496238106Sdes	struct regional* temp, enum sec_status msg_security)
497238106Sdes{
498238106Sdes	struct query_info rq;
499238106Sdes	struct reply_info* rep;
500238106Sdes	res->rcode = LDNS_RCODE_SERVFAIL;
501356345Scy	rep = parse_reply_in_temp_region(buf, temp, &rq);
502238106Sdes	if(!rep) {
503238106Sdes		log_err("cannot parse buf");
504238106Sdes		return; /* error parsing buf, or out of memory */
505238106Sdes	}
506238106Sdes	if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
507249141Sdes		reply_find_final_cname_target(&rq, rep), &rq, rep))
508238106Sdes		return; /* out of memory */
509238106Sdes	/* rcode, havedata, nxdomain, secure, bogus */
510238106Sdes	res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
511238106Sdes	if(res->data && res->data[0])
512238106Sdes		res->havedata = 1;
513238106Sdes	if(res->rcode == LDNS_RCODE_NXDOMAIN)
514238106Sdes		res->nxdomain = 1;
515238106Sdes	if(msg_security == sec_status_secure)
516238106Sdes		res->secure = 1;
517356345Scy	if(msg_security == sec_status_bogus ||
518356345Scy		msg_security == sec_status_secure_sentinel_fail)
519238106Sdes		res->bogus = 1;
520238106Sdes}
521238106Sdes
522238106Sdes/** fillup fg results */
523238106Sdesstatic void
524266114Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
525356345Scy	enum sec_status s, char* why_bogus, int was_ratelimited)
526238106Sdes{
527356345Scy	q->res->was_ratelimited = was_ratelimited;
528238106Sdes	if(why_bogus)
529238106Sdes		q->res->why_bogus = strdup(why_bogus);
530238106Sdes	if(rcode != 0) {
531238106Sdes		q->res->rcode = rcode;
532238106Sdes		q->msg_security = s;
533238106Sdes		return;
534238106Sdes	}
535238106Sdes
536238106Sdes	q->res->rcode = LDNS_RCODE_SERVFAIL;
537356345Scy	q->msg_security = sec_status_unchecked;
538266114Sdes	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
539266114Sdes	q->msg_len = sldns_buffer_limit(buf);
540238106Sdes	if(!q->msg) {
541238106Sdes		return; /* the error is in the rcode */
542238106Sdes	}
543238106Sdes
544238106Sdes	/* canonname and results */
545238106Sdes	q->msg_security = s;
546238106Sdes	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
547238106Sdes}
548238106Sdes
549238106Sdesvoid
550266114Sdeslibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
551356345Scy	char* why_bogus, int was_ratelimited)
552238106Sdes{
553238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
554238106Sdes	/* fg query is done; exit comm base */
555238106Sdes	comm_base_exit(q->w->base);
556238106Sdes
557356345Scy	libworker_fillup_fg(q, rcode, buf, s, why_bogus, was_ratelimited);
558238106Sdes}
559238106Sdes
560238106Sdes/** setup qinfo and edns */
561238106Sdesstatic int
562238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q,
563238106Sdes	struct query_info* qinfo, struct edns_data* edns)
564238106Sdes{
565238106Sdes	qinfo->qtype = (uint16_t)q->res->qtype;
566238106Sdes	qinfo->qclass = (uint16_t)q->res->qclass;
567356345Scy	qinfo->local_alias = NULL;
568266114Sdes	qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len);
569266114Sdes	if(!qinfo->qname) {
570238106Sdes		return 0;
571238106Sdes	}
572238106Sdes	edns->edns_present = 1;
573238106Sdes	edns->ext_rcode = 0;
574238106Sdes	edns->edns_version = 0;
575238106Sdes	edns->bits = EDNS_DO;
576307729Sdes	edns->opt_list = NULL;
577266114Sdes	if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
578266114Sdes		edns->udp_size = (uint16_t)sldns_buffer_capacity(
579238106Sdes			w->back->udp_buff);
580238106Sdes	else	edns->udp_size = 65535;
581238106Sdes	return 1;
582238106Sdes}
583238106Sdes
584238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
585238106Sdes{
586266114Sdes	struct libworker* w = libworker_setup(ctx, 0, NULL);
587238106Sdes	uint16_t qflags, qid;
588238106Sdes	struct query_info qinfo;
589238106Sdes	struct edns_data edns;
590238106Sdes	if(!w)
591238106Sdes		return UB_INITFAIL;
592238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
593238106Sdes		libworker_delete(w);
594238106Sdes		return UB_SYNTAX;
595238106Sdes	}
596238106Sdes	qid = 0;
597238106Sdes	qflags = BIT_RD;
598238106Sdes	q->w = w;
599238106Sdes	/* see if there is a fixed answer */
600266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
601266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
602356345Scy	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
603307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
604356345Scy		NULL, 0, NULL, 0, NULL)) {
605238106Sdes		regional_free_all(w->env->scratch);
606238106Sdes		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
607356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
608238106Sdes		libworker_delete(w);
609238106Sdes		free(qinfo.qname);
610238106Sdes		return UB_NOERROR;
611238106Sdes	}
612356345Scy	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
613356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
614356345Scy		regional_free_all(w->env->scratch);
615356345Scy		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
616356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
617356345Scy		libworker_delete(w);
618356345Scy		free(qinfo.qname);
619356345Scy		return UB_NOERROR;
620356345Scy	}
621238106Sdes	/* process new query */
622238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
623238106Sdes		w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
624238106Sdes		free(qinfo.qname);
625238106Sdes		return UB_NOMEM;
626238106Sdes	}
627238106Sdes	free(qinfo.qname);
628238106Sdes
629238106Sdes	/* wait for reply */
630238106Sdes	comm_base_dispatch(w->base);
631238106Sdes
632238106Sdes	libworker_delete(w);
633238106Sdes	return UB_NOERROR;
634238106Sdes}
635238106Sdes
636266114Sdesvoid
637266114Sdeslibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
638356345Scy	enum sec_status s, char* why_bogus, int was_ratelimited)
639266114Sdes{
640266114Sdes	struct ctx_query* q = (struct ctx_query*)arg;
641356345Scy	ub_event_callback_type cb = q->cb_event;
642266114Sdes	void* cb_arg = q->cb_arg;
643266114Sdes	int cancelled = q->cancelled;
644266114Sdes
645266114Sdes	/* delete it now */
646266114Sdes	struct ub_ctx* ctx = q->w->ctx;
647266114Sdes	lock_basic_lock(&ctx->cfglock);
648266114Sdes	(void)rbtree_delete(&ctx->queries, q->node.key);
649266114Sdes	ctx->num_async--;
650266114Sdes	context_query_delete(q);
651266114Sdes	lock_basic_unlock(&ctx->cfglock);
652266114Sdes
653266114Sdes	if(!cancelled) {
654266114Sdes		/* call callback */
655266114Sdes		int sec = 0;
656266114Sdes		if(s == sec_status_bogus)
657266114Sdes			sec = 1;
658266114Sdes		else if(s == sec_status_secure)
659266114Sdes			sec = 2;
660356345Scy		(*cb)(cb_arg, rcode, (buf?(void*)sldns_buffer_begin(buf):NULL),
661356345Scy			(buf?(int)sldns_buffer_limit(buf):0), sec, why_bogus, was_ratelimited);
662266114Sdes	}
663266114Sdes}
664266114Sdes
665266114Sdesint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
666266114Sdes	int* async_id)
667266114Sdes{
668266114Sdes	struct libworker* w = ctx->event_worker;
669266114Sdes	uint16_t qflags, qid;
670266114Sdes	struct query_info qinfo;
671266114Sdes	struct edns_data edns;
672266114Sdes	if(!w)
673266114Sdes		return UB_INITFAIL;
674266114Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns))
675266114Sdes		return UB_SYNTAX;
676266114Sdes	qid = 0;
677266114Sdes	qflags = BIT_RD;
678266114Sdes	q->w = w;
679266114Sdes	/* see if there is a fixed answer */
680266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
681266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
682356345Scy	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
683307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
684356345Scy		NULL, 0, NULL, 0, NULL)) {
685266114Sdes		regional_free_all(w->env->scratch);
686266114Sdes		free(qinfo.qname);
687266114Sdes		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
688356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
689266114Sdes		return UB_NOERROR;
690266114Sdes	}
691356345Scy	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
692356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
693356345Scy		regional_free_all(w->env->scratch);
694356345Scy		free(qinfo.qname);
695356345Scy		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
696356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
697356345Scy		return UB_NOERROR;
698356345Scy	}
699266114Sdes	/* process new query */
700266114Sdes	if(async_id)
701266114Sdes		*async_id = q->querynum;
702266114Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
703266114Sdes		w->back->udp_buff, qid, libworker_event_done_cb, q)) {
704266114Sdes		free(qinfo.qname);
705266114Sdes		return UB_NOMEM;
706266114Sdes	}
707266114Sdes	free(qinfo.qname);
708266114Sdes	return UB_NOERROR;
709266114Sdes}
710266114Sdes
711238106Sdes/** add result to the bg worker result queue */
712238106Sdesstatic void
713266114Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
714356345Scy	int err, char* reason, int was_ratelimited)
715238106Sdes{
716238106Sdes	uint8_t* msg = NULL;
717238106Sdes	uint32_t len = 0;
718238106Sdes
719356345Scy	if(w->want_quit) {
720356345Scy		context_query_delete(q);
721356345Scy		return;
722356345Scy	}
723238106Sdes	/* serialize and delete unneeded q */
724238106Sdes	if(w->is_bg_thread) {
725238106Sdes		lock_basic_lock(&w->ctx->cfglock);
726238106Sdes		if(reason)
727238106Sdes			q->res->why_bogus = strdup(reason);
728356345Scy		q->res->was_ratelimited = was_ratelimited;
729238106Sdes		if(pkt) {
730266114Sdes			q->msg_len = sldns_buffer_remaining(pkt);
731266114Sdes			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
732356345Scy			if(!q->msg) {
733356345Scy				msg = context_serialize_answer(q, UB_NOMEM, NULL, &len);
734356345Scy			} else {
735356345Scy				msg = context_serialize_answer(q, err, NULL, &len);
736356345Scy			}
737356345Scy		} else {
738356345Scy			msg = context_serialize_answer(q, err, NULL, &len);
739356345Scy		}
740238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
741238106Sdes	} else {
742238106Sdes		if(reason)
743238106Sdes			q->res->why_bogus = strdup(reason);
744356345Scy		q->res->was_ratelimited = was_ratelimited;
745238106Sdes		msg = context_serialize_answer(q, err, pkt, &len);
746238106Sdes		(void)rbtree_delete(&w->ctx->queries, q->node.key);
747238106Sdes		w->ctx->num_async--;
748238106Sdes		context_query_delete(q);
749238106Sdes	}
750238106Sdes
751238106Sdes	if(!msg) {
752238106Sdes		log_err("out of memory for async answer");
753238106Sdes		return;
754238106Sdes	}
755238106Sdes	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
756238106Sdes		log_err("out of memory for async answer");
757238106Sdes		return;
758238106Sdes	}
759238106Sdes}
760238106Sdes
761238106Sdesvoid
762266114Sdeslibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
763356345Scy	char* why_bogus, int was_ratelimited)
764238106Sdes{
765238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
766238106Sdes
767356345Scy	if(q->cancelled || q->w->back->want_to_quit) {
768238106Sdes		if(q->w->is_bg_thread) {
769238106Sdes			/* delete it now */
770238106Sdes			struct ub_ctx* ctx = q->w->ctx;
771238106Sdes			lock_basic_lock(&ctx->cfglock);
772238106Sdes			(void)rbtree_delete(&ctx->queries, q->node.key);
773238106Sdes			ctx->num_async--;
774238106Sdes			context_query_delete(q);
775238106Sdes			lock_basic_unlock(&ctx->cfglock);
776238106Sdes		}
777238106Sdes		/* cancelled, do not give answer */
778238106Sdes		return;
779238106Sdes	}
780238106Sdes	q->msg_security = s;
781356345Scy	if(!buf) {
782249141Sdes		buf = q->w->env->scratch_buffer;
783356345Scy	}
784238106Sdes	if(rcode != 0) {
785238106Sdes		error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
786238106Sdes	}
787356345Scy	add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus, was_ratelimited);
788238106Sdes}
789238106Sdes
790238106Sdes
791238106Sdes/** handle new query command for bg worker */
792238106Sdesstatic void
793238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
794238106Sdes{
795238106Sdes	uint16_t qflags, qid;
796238106Sdes	struct query_info qinfo;
797238106Sdes	struct edns_data edns;
798238106Sdes	struct ctx_query* q;
799238106Sdes	if(w->is_bg_thread) {
800238106Sdes		lock_basic_lock(&w->ctx->cfglock);
801238106Sdes		q = context_lookup_new_query(w->ctx, buf, len);
802238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
803238106Sdes	} else {
804238106Sdes		q = context_deserialize_new_query(w->ctx, buf, len);
805238106Sdes	}
806238106Sdes	free(buf);
807238106Sdes	if(!q) {
808238106Sdes		log_err("failed to deserialize newq");
809238106Sdes		return;
810238106Sdes	}
811238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
812356345Scy		add_bg_result(w, q, NULL, UB_SYNTAX, NULL, 0);
813238106Sdes		return;
814238106Sdes	}
815238106Sdes	qid = 0;
816238106Sdes	qflags = BIT_RD;
817238106Sdes	/* see if there is a fixed answer */
818266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
819266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
820356345Scy	if(local_zones_answer(w->ctx->local_zones, w->env, &qinfo, &edns,
821307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
822356345Scy		NULL, 0, NULL, 0, NULL)) {
823238106Sdes		regional_free_all(w->env->scratch);
824238106Sdes		q->msg_security = sec_status_insecure;
825356345Scy		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
826238106Sdes		free(qinfo.qname);
827238106Sdes		return;
828238106Sdes	}
829356345Scy	if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
830356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
831356345Scy		regional_free_all(w->env->scratch);
832356345Scy		q->msg_security = sec_status_insecure;
833356345Scy		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
834356345Scy		free(qinfo.qname);
835356345Scy		return;
836356345Scy	}
837238106Sdes	q->w = w;
838238106Sdes	/* process new query */
839238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
840238106Sdes		w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
841356345Scy		add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
842238106Sdes	}
843238106Sdes	free(qinfo.qname);
844238106Sdes}
845238106Sdes
846238106Sdesvoid libworker_alloc_cleanup(void* arg)
847238106Sdes{
848238106Sdes	struct libworker* w = (struct libworker*)arg;
849238106Sdes	slabhash_clear(&w->env->rrset_cache->table);
850238106Sdes        slabhash_clear(w->env->msg_cache);
851238106Sdes}
852238106Sdes
853356345Scystruct outbound_entry* libworker_send_query(struct query_info* qinfo,
854356345Scy	uint16_t flags, int dnssec, int want_dnssec, int nocaps,
855307729Sdes	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
856356345Scy	size_t zonelen, int ssl_upstream, char* tls_auth_name,
857356345Scy	struct module_qstate* q)
858238106Sdes{
859238106Sdes	struct libworker* w = (struct libworker*)q->env->worker;
860238106Sdes	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
861238106Sdes		q->region, sizeof(*e));
862238106Sdes	if(!e)
863238106Sdes		return NULL;
864238106Sdes	e->qstate = q;
865356345Scy	e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
866356345Scy		want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream,
867356345Scy		tls_auth_name, addr, addrlen, zone, zonelen, q,
868356345Scy		libworker_handle_service_reply, e, w->back->udp_buff, q->env);
869238106Sdes	if(!e->qsent) {
870238106Sdes		return NULL;
871238106Sdes	}
872238106Sdes	return e;
873238106Sdes}
874238106Sdes
875238106Sdesint
876238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error,
877238106Sdes        struct comm_reply* reply_info)
878238106Sdes{
879238106Sdes	struct module_qstate* q = (struct module_qstate*)arg;
880238106Sdes	struct libworker* lw = (struct libworker*)q->env->worker;
881238106Sdes	struct outbound_entry e;
882238106Sdes	e.qstate = q;
883238106Sdes	e.qsent = NULL;
884238106Sdes
885238106Sdes	if(error != 0) {
886238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info, error);
887238106Sdes		return 0;
888238106Sdes	}
889238106Sdes	/* sanity check. */
890266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
891266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
892238106Sdes			LDNS_PACKET_QUERY
893266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
894238106Sdes		/* error becomes timeout for the module as if this reply
895238106Sdes		 * never arrived. */
896238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info,
897238106Sdes			NETEVENT_TIMEOUT);
898238106Sdes		return 0;
899238106Sdes	}
900238106Sdes	mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
901238106Sdes	return 0;
902238106Sdes}
903238106Sdes
904238106Sdesint
905238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error,
906238106Sdes        struct comm_reply* reply_info)
907238106Sdes{
908238106Sdes	struct outbound_entry* e = (struct outbound_entry*)arg;
909238106Sdes	struct libworker* lw = (struct libworker*)e->qstate->env->worker;
910238106Sdes
911238106Sdes	if(error != 0) {
912238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info, error);
913238106Sdes		return 0;
914238106Sdes	}
915238106Sdes	/* sanity check. */
916266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
917266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
918238106Sdes			LDNS_PACKET_QUERY
919266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
920238106Sdes		/* error becomes timeout for the module as if this reply
921238106Sdes		 * never arrived. */
922238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info,
923238106Sdes			NETEVENT_TIMEOUT);
924238106Sdes		return 0;
925238106Sdes	}
926238106Sdes	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
927238106Sdes	return 0;
928238106Sdes}
929238106Sdes
930238106Sdes/* --- fake callbacks for fptr_wlist to work --- */
931238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
932238106Sdes	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
933238106Sdes	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
934238106Sdes{
935238106Sdes	log_assert(0);
936238106Sdes}
937238106Sdes
938238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c),
939238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
940238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
941238106Sdes{
942238106Sdes	log_assert(0);
943238106Sdes	return 0;
944238106Sdes}
945238106Sdes
946238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
947238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
948238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
949238106Sdes{
950238106Sdes	log_assert(0);
951238106Sdes	return 0;
952238106Sdes}
953238106Sdes
954238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
955238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
956238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
957238106Sdes{
958238106Sdes	log_assert(0);
959238106Sdes	return 0;
960238106Sdes}
961238106Sdes
962238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
963238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
964238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
965238106Sdes{
966238106Sdes	log_assert(0);
967238106Sdes	return 0;
968238106Sdes}
969238106Sdes
970238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c),
971238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
972238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
973238106Sdes{
974238106Sdes	log_assert(0);
975238106Sdes	return 0;
976238106Sdes}
977238106Sdes
978238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
979238106Sdes{
980238106Sdes	log_assert(0);
981238106Sdes}
982238106Sdes
983356345Scystruct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
984356345Scy	uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
985356345Scy	int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
986356345Scy	struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
987356345Scy	uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
988356345Scy	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
989356345Scy	struct module_qstate* ATTR_UNUSED(q))
990238106Sdes{
991238106Sdes	log_assert(0);
992238106Sdes	return 0;
993238106Sdes}
994238106Sdes
995238106Sdesvoid
996238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg))
997238106Sdes{
998238106Sdes	log_assert(0);
999238106Sdes}
1000238106Sdes
1001238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg))
1002238106Sdes{
1003238106Sdes	log_assert(0);
1004238106Sdes}
1005238106Sdes
1006238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg))
1007238106Sdes{
1008238106Sdes	log_assert(0);
1009238106Sdes}
1010238106Sdes
1011238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg))
1012238106Sdes{
1013238106Sdes	log_assert(0);
1014238106Sdes}
1015238106Sdes
1016238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg))
1017238106Sdes{
1018238106Sdes	log_assert(0);
1019238106Sdes}
1020238106Sdes
1021238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
1022238106Sdes{
1023238106Sdes	log_assert(0);
1024238106Sdes	return 0;
1025238106Sdes}
1026238106Sdes
1027238106Sdesint
1028238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1029238106Sdes{
1030238106Sdes	log_assert(0);
1031238106Sdes	return 0;
1032238106Sdes}
1033238106Sdes
1034238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1035238106Sdes{
1036238106Sdes        log_assert(0);
1037238106Sdes        return 0;
1038238106Sdes}
1039238106Sdes
1040238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
1041238106Sdes{
1042238106Sdes        log_assert(0);
1043238106Sdes}
1044238106Sdes
1045238106Sdes#ifdef UB_ON_WINDOWS
1046238106Sdesvoid
1047238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
1048238106Sdes        ATTR_UNUSED(arg)) {
1049238106Sdes        log_assert(0);
1050238106Sdes}
1051238106Sdes
1052238106Sdesvoid
1053238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg))
1054238106Sdes{
1055238106Sdes        log_assert(0);
1056238106Sdes}
1057238106Sdes#endif /* UB_ON_WINDOWS */
1058366095Scy
1059366095Scy#ifdef USE_DNSTAP
1060366095Scyvoid dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1061366095Scy	void* ATTR_UNUSED(arg))
1062366095Scy{
1063366095Scy	log_assert(0);
1064366095Scy}
1065366095Scy#endif
1066366095Scy
1067366095Scy#ifdef USE_DNSTAP
1068366095Scyvoid dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1069366095Scy	void* ATTR_UNUSED(arg))
1070366095Scy{
1071366095Scy	log_assert(0);
1072366095Scy}
1073366095Scy#endif
1074