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"
76369939Sgit2svn#ifdef USE_DNSTAP
77369939Sgit2svn#include "dnstap/dtstream.h"
78369939Sgit2svn#endif
79238106Sdes
80366095Scy#ifdef HAVE_TARGETCONDITIONALS_H
81366095Scy#include <TargetConditionals.h>
82366095Scy#endif
83366095Scy
84368129Scy#if (defined(TARGET_OS_TV) && TARGET_OS_TV) || (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH)
85366095Scy#undef HAVE_FORK
86366095Scy#endif
87366095Scy
88238106Sdes/** handle new query command for bg worker */
89238106Sdesstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
90238106Sdes
91266114Sdes/** delete libworker env */
92238106Sdesstatic void
93266114Sdeslibworker_delete_env(struct libworker* w)
94238106Sdes{
95238106Sdes	if(w->env) {
96238106Sdes		outside_network_quit_prepare(w->back);
97238106Sdes		mesh_delete(w->env->mesh);
98238106Sdes		context_release_alloc(w->ctx, w->env->alloc,
99238106Sdes			!w->is_bg || w->is_bg_thread);
100266114Sdes		sldns_buffer_free(w->env->scratch_buffer);
101238106Sdes		regional_destroy(w->env->scratch);
102238106Sdes		forwards_delete(w->env->fwds);
103238106Sdes		hints_delete(w->env->hints);
104238106Sdes		ub_randfree(w->env->rnd);
105238106Sdes		free(w->env);
106238106Sdes	}
107249141Sdes#ifdef HAVE_SSL
108238106Sdes	SSL_CTX_free(w->sslctx);
109249141Sdes#endif
110238106Sdes	outside_network_delete(w->back);
111266114Sdes}
112266114Sdes
113266114Sdes/** delete libworker struct */
114266114Sdesstatic void
115266114Sdeslibworker_delete(struct libworker* w)
116266114Sdes{
117266114Sdes	if(!w) return;
118266114Sdes	libworker_delete_env(w);
119238106Sdes	comm_base_delete(w->base);
120238106Sdes	free(w);
121238106Sdes}
122238106Sdes
123266114Sdesvoid
124266114Sdeslibworker_delete_event(struct libworker* w)
125266114Sdes{
126266114Sdes	if(!w) return;
127266114Sdes	libworker_delete_env(w);
128266114Sdes	comm_base_delete_no_base(w->base);
129266114Sdes	free(w);
130266114Sdes}
131266114Sdes
132238106Sdes/** setup fresh libworker struct */
133238106Sdesstatic struct libworker*
134307729Sdeslibworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
135238106Sdes{
136238106Sdes	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
137238106Sdes	struct config_file* cfg = ctx->env->cfg;
138238106Sdes	int* ports;
139238106Sdes	int numports;
140238106Sdes	if(!w) return NULL;
141238106Sdes	w->is_bg = is_bg;
142238106Sdes	w->ctx = ctx;
143238106Sdes	w->env = (struct module_env*)malloc(sizeof(*w->env));
144238106Sdes	if(!w->env) {
145238106Sdes		free(w);
146238106Sdes		return NULL;
147238106Sdes	}
148238106Sdes	*w->env = *ctx->env;
149238106Sdes	w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
150238106Sdes	if(!w->env->alloc) {
151238106Sdes		libworker_delete(w);
152238106Sdes		return NULL;
153238106Sdes	}
154238106Sdes	w->thread_num = w->env->alloc->thread_num;
155238106Sdes	alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
156238106Sdes	if(!w->is_bg || w->is_bg_thread) {
157238106Sdes		lock_basic_lock(&ctx->cfglock);
158238106Sdes	}
159238106Sdes	w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
160266114Sdes	w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
161238106Sdes	w->env->fwds = forwards_create();
162238106Sdes	if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
163238106Sdes		forwards_delete(w->env->fwds);
164238106Sdes		w->env->fwds = NULL;
165238106Sdes	}
166238106Sdes	w->env->hints = hints_create();
167238106Sdes	if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
168238106Sdes		hints_delete(w->env->hints);
169238106Sdes		w->env->hints = NULL;
170238106Sdes	}
171356345Scy	if(cfg->ssl_upstream || (cfg->tls_cert_bundle && cfg->tls_cert_bundle[0]) || cfg->tls_win_cert) {
172356345Scy		w->sslctx = connect_sslctx_create(NULL, NULL,
173356345Scy			cfg->tls_cert_bundle, cfg->tls_win_cert);
174238106Sdes		if(!w->sslctx) {
175238106Sdes			/* to make the setup fail after unlock */
176238106Sdes			hints_delete(w->env->hints);
177238106Sdes			w->env->hints = NULL;
178238106Sdes		}
179238106Sdes	}
180238106Sdes	if(!w->is_bg || w->is_bg_thread) {
181238106Sdes		lock_basic_unlock(&ctx->cfglock);
182238106Sdes	}
183238106Sdes	if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
184238106Sdes		!w->env->hints) {
185238106Sdes		libworker_delete(w);
186238106Sdes		return NULL;
187238106Sdes	}
188238106Sdes	w->env->worker = (struct worker*)w;
189238106Sdes	w->env->probe_timer = NULL;
190238106Sdes	if(!w->is_bg || w->is_bg_thread) {
191238106Sdes		lock_basic_lock(&ctx->cfglock);
192238106Sdes	}
193356345Scy	if(!(w->env->rnd = ub_initstate(ctx->seed_rnd))) {
194238106Sdes		if(!w->is_bg || w->is_bg_thread) {
195238106Sdes			lock_basic_unlock(&ctx->cfglock);
196238106Sdes		}
197238106Sdes		libworker_delete(w);
198238106Sdes		return NULL;
199238106Sdes	}
200238106Sdes	if(!w->is_bg || w->is_bg_thread) {
201238106Sdes		lock_basic_unlock(&ctx->cfglock);
202238106Sdes	}
203238106Sdes	if(1) {
204238106Sdes		/* primitive lockout for threading: if it overwrites another
205238106Sdes		 * thread it is like wiping the cache (which is likely empty
206238106Sdes		 * at the start) */
207238106Sdes		/* note we are holding the ctx lock in normal threaded
208238106Sdes		 * cases so that is solved properly, it is only for many ctx
209238106Sdes		 * in different threads that this may clash */
210238106Sdes		static int done_raninit = 0;
211238106Sdes		if(!done_raninit) {
212238106Sdes			done_raninit = 1;
213238106Sdes			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
214238106Sdes		}
215238106Sdes	}
216238106Sdes
217266114Sdes	if(eb)
218266114Sdes		w->base = comm_base_create_event(eb);
219266114Sdes	else	w->base = comm_base_create(0);
220238106Sdes	if(!w->base) {
221238106Sdes		libworker_delete(w);
222238106Sdes		return NULL;
223238106Sdes	}
224356345Scy	w->env->worker_base = w->base;
225238106Sdes	if(!w->is_bg || w->is_bg_thread) {
226238106Sdes		lock_basic_lock(&ctx->cfglock);
227238106Sdes	}
228238106Sdes	numports = cfg_condense_ports(cfg, &ports);
229238106Sdes	if(numports == 0) {
230356345Scy		if(!w->is_bg || w->is_bg_thread) {
231266114Sdes			lock_basic_unlock(&ctx->cfglock);
232266114Sdes		}
233356345Scy		libworker_delete(w);
234238106Sdes		return NULL;
235238106Sdes	}
236238106Sdes	w->back = outside_network_create(w->base, cfg->msg_buffer_size,
237238106Sdes		(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
238238106Sdes		cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
239366095Scy		cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
240238106Sdes		w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
241238106Sdes		ports, numports, cfg->unwanted_threshold,
242356345Scy		cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
243356345Scy		cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
244368693Scy		cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect);
245356345Scy	w->env->outnet = w->back;
246238106Sdes	if(!w->is_bg || w->is_bg_thread) {
247238106Sdes		lock_basic_unlock(&ctx->cfglock);
248238106Sdes	}
249238106Sdes	free(ports);
250238106Sdes	if(!w->back) {
251238106Sdes		libworker_delete(w);
252238106Sdes		return NULL;
253238106Sdes	}
254238106Sdes	w->env->mesh = mesh_create(&ctx->mods, w->env);
255238106Sdes	if(!w->env->mesh) {
256238106Sdes		libworker_delete(w);
257238106Sdes		return NULL;
258238106Sdes	}
259238106Sdes	w->env->send_query = &libworker_send_query;
260238106Sdes	w->env->detach_subs = &mesh_detach_subs;
261238106Sdes	w->env->attach_sub = &mesh_attach_sub;
262356345Scy	w->env->add_sub = &mesh_add_sub;
263238106Sdes	w->env->kill_sub = &mesh_state_delete;
264238106Sdes	w->env->detect_cycle = &mesh_detect_cycle;
265238106Sdes	comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
266238106Sdes	return w;
267238106Sdes}
268238106Sdes
269266114Sdesstruct libworker* libworker_create_event(struct ub_ctx* ctx,
270307729Sdes	struct ub_event_base* eb)
271266114Sdes{
272266114Sdes	return libworker_setup(ctx, 0, eb);
273266114Sdes}
274266114Sdes
275238106Sdes/** handle cancel command for bg worker */
276238106Sdesstatic void
277238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
278238106Sdes{
279238106Sdes	struct ctx_query* q;
280238106Sdes	if(w->is_bg_thread) {
281238106Sdes		lock_basic_lock(&w->ctx->cfglock);
282238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
283238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
284238106Sdes	} else {
285238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
286238106Sdes	}
287238106Sdes	if(!q) {
288238106Sdes		/* probably simply lookup failed, i.e. the message had been
289238106Sdes		 * processed and answered before the cancel arrived */
290238106Sdes		return;
291238106Sdes	}
292238106Sdes	q->cancelled = 1;
293238106Sdes	free(buf);
294238106Sdes}
295238106Sdes
296238106Sdes/** do control command coming into bg server */
297238106Sdesstatic void
298238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
299238106Sdes{
300238106Sdes	switch(context_serial_getcmd(msg, len)) {
301238106Sdes		default:
302238106Sdes		case UB_LIBCMD_ANSWER:
303238106Sdes			log_err("unknown command for bg worker %d",
304238106Sdes				(int)context_serial_getcmd(msg, len));
305238106Sdes			/* and fall through to quit */
306356345Scy			/* fallthrough */
307238106Sdes		case UB_LIBCMD_QUIT:
308238106Sdes			free(msg);
309238106Sdes			comm_base_exit(w->base);
310238106Sdes			break;
311238106Sdes		case UB_LIBCMD_NEWQUERY:
312238106Sdes			handle_newq(w, msg, len);
313238106Sdes			break;
314238106Sdes		case UB_LIBCMD_CANCEL:
315238106Sdes			handle_cancel(w, msg, len);
316238106Sdes			break;
317238106Sdes	}
318238106Sdes}
319238106Sdes
320238106Sdes/** handle control command coming into server */
321238106Sdesvoid
322238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
323238106Sdes	uint8_t* msg, size_t len, int err, void* arg)
324238106Sdes{
325238106Sdes	struct libworker* w = (struct libworker*)arg;
326238106Sdes
327238106Sdes	if(err != 0) {
328238106Sdes		free(msg);
329238106Sdes		/* it is of no use to go on, exit */
330238106Sdes		comm_base_exit(w->base);
331238106Sdes		return;
332238106Sdes	}
333238106Sdes	libworker_do_cmd(w, msg, len); /* also frees the buf */
334238106Sdes}
335238106Sdes
336238106Sdes/** the background thread func */
337238106Sdesstatic void*
338238106Sdeslibworker_dobg(void* arg)
339238106Sdes{
340238106Sdes	/* setup */
341238106Sdes	uint32_t m;
342238106Sdes	struct libworker* w = (struct libworker*)arg;
343238106Sdes	struct ub_ctx* ctx;
344238106Sdes	if(!w) {
345238106Sdes		log_err("libunbound bg worker init failed, nomem");
346238106Sdes		return NULL;
347238106Sdes	}
348238106Sdes	ctx = w->ctx;
349238106Sdes	log_thread_set(&w->thread_num);
350238106Sdes#ifdef THREADS_DISABLED
351238106Sdes	/* we are forked */
352238106Sdes	w->is_bg_thread = 0;
353238106Sdes	/* close non-used parts of the pipes */
354238106Sdes	tube_close_write(ctx->qq_pipe);
355238106Sdes	tube_close_read(ctx->rr_pipe);
356238106Sdes#endif
357238106Sdes	if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
358238106Sdes		libworker_handle_control_cmd, w)) {
359238106Sdes		log_err("libunbound bg worker init failed, no bglisten");
360238106Sdes		return NULL;
361238106Sdes	}
362238106Sdes	if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
363238106Sdes		log_err("libunbound bg worker init failed, no bgwrite");
364238106Sdes		return NULL;
365238106Sdes	}
366238106Sdes
367238106Sdes	/* do the work */
368238106Sdes	comm_base_dispatch(w->base);
369238106Sdes
370238106Sdes	/* cleanup */
371238106Sdes	m = UB_LIBCMD_QUIT;
372356345Scy	w->want_quit = 1;
373238106Sdes	tube_remove_bg_listen(w->ctx->qq_pipe);
374238106Sdes	tube_remove_bg_write(w->ctx->rr_pipe);
375238106Sdes	libworker_delete(w);
376238106Sdes	(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
377238106Sdes		(uint32_t)sizeof(m), 0);
378238106Sdes#ifdef THREADS_DISABLED
379238106Sdes	/* close pipes from forked process before exit */
380238106Sdes	tube_close_read(ctx->qq_pipe);
381238106Sdes	tube_close_write(ctx->rr_pipe);
382238106Sdes#endif
383238106Sdes	return NULL;
384238106Sdes}
385238106Sdes
386238106Sdesint libworker_bg(struct ub_ctx* ctx)
387238106Sdes{
388238106Sdes	struct libworker* w;
389238106Sdes	/* fork or threadcreate */
390238106Sdes	lock_basic_lock(&ctx->cfglock);
391238106Sdes	if(ctx->dothread) {
392238106Sdes		lock_basic_unlock(&ctx->cfglock);
393266114Sdes		w = libworker_setup(ctx, 1, NULL);
394238106Sdes		if(!w) return UB_NOMEM;
395238106Sdes		w->is_bg_thread = 1;
396238106Sdes#ifdef ENABLE_LOCK_CHECKS
397238106Sdes		w->thread_num = 1; /* for nicer DEBUG checklocks */
398238106Sdes#endif
399238106Sdes		ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
400238106Sdes	} else {
401238106Sdes		lock_basic_unlock(&ctx->cfglock);
402238106Sdes#ifndef HAVE_FORK
403238106Sdes		/* no fork on windows */
404238106Sdes		return UB_FORKFAIL;
405238106Sdes#else /* HAVE_FORK */
406238106Sdes		switch((ctx->bg_pid=fork())) {
407238106Sdes			case 0:
408266114Sdes				w = libworker_setup(ctx, 1, NULL);
409238106Sdes				if(!w) fatal_exit("out of memory");
410238106Sdes				/* close non-used parts of the pipes */
411238106Sdes				tube_close_write(ctx->qq_pipe);
412238106Sdes				tube_close_read(ctx->rr_pipe);
413238106Sdes				(void)libworker_dobg(w);
414238106Sdes				exit(0);
415238106Sdes				break;
416238106Sdes			case -1:
417238106Sdes				return UB_FORKFAIL;
418238106Sdes			default:
419266114Sdes				/* close non-used parts, so that the worker
420266114Sdes				 * bgprocess gets 'pipe closed' when the
421266114Sdes				 * main process exits */
422266114Sdes				tube_close_read(ctx->qq_pipe);
423266114Sdes				tube_close_write(ctx->rr_pipe);
424238106Sdes				break;
425238106Sdes		}
426238106Sdes#endif /* HAVE_FORK */
427238106Sdes	}
428238106Sdes	return UB_NOERROR;
429238106Sdes}
430238106Sdes
431238106Sdes/** insert canonname */
432238106Sdesstatic int
433238106Sdesfill_canon(struct ub_result* res, uint8_t* s)
434238106Sdes{
435238106Sdes	char buf[255+2];
436238106Sdes	dname_str(s, buf);
437238106Sdes	res->canonname = strdup(buf);
438238106Sdes	return res->canonname != 0;
439238106Sdes}
440238106Sdes
441238106Sdes/** fill data into result */
442238106Sdesstatic int
443238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
444249141Sdes	uint8_t* finalcname, struct query_info* rq, struct reply_info* rep)
445238106Sdes{
446238106Sdes	size_t i;
447238106Sdes	struct packed_rrset_data* data;
448249141Sdes	res->ttl = 0;
449238106Sdes	if(!answer) {
450238106Sdes		if(finalcname) {
451238106Sdes			if(!fill_canon(res, finalcname))
452238106Sdes				return 0; /* out of memory */
453238106Sdes		}
454249141Sdes		if(rep->rrset_count != 0)
455249141Sdes			res->ttl = (int)rep->ttl;
456238106Sdes		res->data = (char**)calloc(1, sizeof(char*));
457238106Sdes		res->len = (int*)calloc(1, sizeof(int));
458238106Sdes		return (res->data && res->len);
459238106Sdes	}
460238106Sdes	data = (struct packed_rrset_data*)answer->entry.data;
461238106Sdes	if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
462238106Sdes		if(!fill_canon(res, answer->rk.dname))
463238106Sdes			return 0; /* out of memory */
464238106Sdes	} else	res->canonname = NULL;
465238106Sdes	res->data = (char**)calloc(data->count+1, sizeof(char*));
466238106Sdes	res->len = (int*)calloc(data->count+1, sizeof(int));
467238106Sdes	if(!res->data || !res->len)
468238106Sdes		return 0; /* out of memory */
469238106Sdes	for(i=0; i<data->count; i++) {
470238106Sdes		/* remove rdlength from rdata */
471238106Sdes		res->len[i] = (int)(data->rr_len[i] - 2);
472238106Sdes		res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
473238106Sdes		if(!res->data[i])
474238106Sdes			return 0; /* out of memory */
475238106Sdes	}
476249141Sdes	/* ttl for positive answers, from CNAME and answer RRs */
477249141Sdes	if(data->count != 0) {
478249141Sdes		size_t j;
479249141Sdes		res->ttl = (int)data->ttl;
480249141Sdes		for(j=0; j<rep->an_numrrsets; j++) {
481249141Sdes			struct packed_rrset_data* d =
482249141Sdes				(struct packed_rrset_data*)rep->rrsets[j]->
483249141Sdes				entry.data;
484249141Sdes			if((int)d->ttl < res->ttl)
485249141Sdes				res->ttl = (int)d->ttl;
486249141Sdes		}
487249141Sdes	}
488249141Sdes	/* ttl for negative answers */
489249141Sdes	if(data->count == 0 && rep->rrset_count != 0)
490249141Sdes		res->ttl = (int)rep->ttl;
491238106Sdes	res->data[data->count] = NULL;
492238106Sdes	res->len[data->count] = 0;
493238106Sdes	return 1;
494238106Sdes}
495238106Sdes
496238106Sdes/** fill result from parsed message, on error fills servfail */
497238106Sdesvoid
498266114Sdeslibworker_enter_result(struct ub_result* res, sldns_buffer* buf,
499238106Sdes	struct regional* temp, enum sec_status msg_security)
500238106Sdes{
501238106Sdes	struct query_info rq;
502238106Sdes	struct reply_info* rep;
503238106Sdes	res->rcode = LDNS_RCODE_SERVFAIL;
504356345Scy	rep = parse_reply_in_temp_region(buf, temp, &rq);
505238106Sdes	if(!rep) {
506238106Sdes		log_err("cannot parse buf");
507238106Sdes		return; /* error parsing buf, or out of memory */
508238106Sdes	}
509238106Sdes	if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
510249141Sdes		reply_find_final_cname_target(&rq, rep), &rq, rep))
511238106Sdes		return; /* out of memory */
512238106Sdes	/* rcode, havedata, nxdomain, secure, bogus */
513238106Sdes	res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
514238106Sdes	if(res->data && res->data[0])
515238106Sdes		res->havedata = 1;
516238106Sdes	if(res->rcode == LDNS_RCODE_NXDOMAIN)
517238106Sdes		res->nxdomain = 1;
518238106Sdes	if(msg_security == sec_status_secure)
519238106Sdes		res->secure = 1;
520356345Scy	if(msg_security == sec_status_bogus ||
521356345Scy		msg_security == sec_status_secure_sentinel_fail)
522238106Sdes		res->bogus = 1;
523238106Sdes}
524238106Sdes
525238106Sdes/** fillup fg results */
526238106Sdesstatic void
527266114Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
528356345Scy	enum sec_status s, char* why_bogus, int was_ratelimited)
529238106Sdes{
530356345Scy	q->res->was_ratelimited = was_ratelimited;
531238106Sdes	if(why_bogus)
532238106Sdes		q->res->why_bogus = strdup(why_bogus);
533238106Sdes	if(rcode != 0) {
534238106Sdes		q->res->rcode = rcode;
535238106Sdes		q->msg_security = s;
536238106Sdes		return;
537238106Sdes	}
538238106Sdes
539238106Sdes	q->res->rcode = LDNS_RCODE_SERVFAIL;
540356345Scy	q->msg_security = sec_status_unchecked;
541266114Sdes	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
542266114Sdes	q->msg_len = sldns_buffer_limit(buf);
543238106Sdes	if(!q->msg) {
544238106Sdes		return; /* the error is in the rcode */
545238106Sdes	}
546238106Sdes
547238106Sdes	/* canonname and results */
548238106Sdes	q->msg_security = s;
549238106Sdes	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
550238106Sdes}
551238106Sdes
552238106Sdesvoid
553266114Sdeslibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
554356345Scy	char* why_bogus, int was_ratelimited)
555238106Sdes{
556238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
557238106Sdes	/* fg query is done; exit comm base */
558238106Sdes	comm_base_exit(q->w->base);
559238106Sdes
560356345Scy	libworker_fillup_fg(q, rcode, buf, s, why_bogus, was_ratelimited);
561238106Sdes}
562238106Sdes
563238106Sdes/** setup qinfo and edns */
564238106Sdesstatic int
565238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q,
566238106Sdes	struct query_info* qinfo, struct edns_data* edns)
567238106Sdes{
568238106Sdes	qinfo->qtype = (uint16_t)q->res->qtype;
569238106Sdes	qinfo->qclass = (uint16_t)q->res->qclass;
570356345Scy	qinfo->local_alias = NULL;
571266114Sdes	qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len);
572266114Sdes	if(!qinfo->qname) {
573238106Sdes		return 0;
574238106Sdes	}
575238106Sdes	edns->edns_present = 1;
576238106Sdes	edns->ext_rcode = 0;
577238106Sdes	edns->edns_version = 0;
578238106Sdes	edns->bits = EDNS_DO;
579307729Sdes	edns->opt_list = NULL;
580369939Sgit2svn	edns->padding_block_size = 0;
581266114Sdes	if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
582266114Sdes		edns->udp_size = (uint16_t)sldns_buffer_capacity(
583238106Sdes			w->back->udp_buff);
584238106Sdes	else	edns->udp_size = 65535;
585238106Sdes	return 1;
586238106Sdes}
587238106Sdes
588238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
589238106Sdes{
590266114Sdes	struct libworker* w = libworker_setup(ctx, 0, NULL);
591238106Sdes	uint16_t qflags, qid;
592238106Sdes	struct query_info qinfo;
593238106Sdes	struct edns_data edns;
594238106Sdes	if(!w)
595238106Sdes		return UB_INITFAIL;
596238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
597238106Sdes		libworker_delete(w);
598238106Sdes		return UB_SYNTAX;
599238106Sdes	}
600238106Sdes	qid = 0;
601238106Sdes	qflags = BIT_RD;
602238106Sdes	q->w = w;
603238106Sdes	/* see if there is a fixed answer */
604266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
605266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
606356345Scy	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
607307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
608356345Scy		NULL, 0, NULL, 0, NULL)) {
609238106Sdes		regional_free_all(w->env->scratch);
610238106Sdes		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
611356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
612238106Sdes		libworker_delete(w);
613238106Sdes		free(qinfo.qname);
614238106Sdes		return UB_NOERROR;
615238106Sdes	}
616356345Scy	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
617356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
618356345Scy		regional_free_all(w->env->scratch);
619356345Scy		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
620356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
621356345Scy		libworker_delete(w);
622356345Scy		free(qinfo.qname);
623356345Scy		return UB_NOERROR;
624356345Scy	}
625238106Sdes	/* process new query */
626238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
627238106Sdes		w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
628238106Sdes		free(qinfo.qname);
629238106Sdes		return UB_NOMEM;
630238106Sdes	}
631238106Sdes	free(qinfo.qname);
632238106Sdes
633238106Sdes	/* wait for reply */
634238106Sdes	comm_base_dispatch(w->base);
635238106Sdes
636238106Sdes	libworker_delete(w);
637238106Sdes	return UB_NOERROR;
638238106Sdes}
639238106Sdes
640266114Sdesvoid
641266114Sdeslibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
642356345Scy	enum sec_status s, char* why_bogus, int was_ratelimited)
643266114Sdes{
644266114Sdes	struct ctx_query* q = (struct ctx_query*)arg;
645356345Scy	ub_event_callback_type cb = q->cb_event;
646266114Sdes	void* cb_arg = q->cb_arg;
647266114Sdes	int cancelled = q->cancelled;
648266114Sdes
649266114Sdes	/* delete it now */
650266114Sdes	struct ub_ctx* ctx = q->w->ctx;
651266114Sdes	lock_basic_lock(&ctx->cfglock);
652266114Sdes	(void)rbtree_delete(&ctx->queries, q->node.key);
653266114Sdes	ctx->num_async--;
654266114Sdes	context_query_delete(q);
655266114Sdes	lock_basic_unlock(&ctx->cfglock);
656266114Sdes
657266114Sdes	if(!cancelled) {
658266114Sdes		/* call callback */
659266114Sdes		int sec = 0;
660266114Sdes		if(s == sec_status_bogus)
661266114Sdes			sec = 1;
662266114Sdes		else if(s == sec_status_secure)
663266114Sdes			sec = 2;
664356345Scy		(*cb)(cb_arg, rcode, (buf?(void*)sldns_buffer_begin(buf):NULL),
665356345Scy			(buf?(int)sldns_buffer_limit(buf):0), sec, why_bogus, was_ratelimited);
666266114Sdes	}
667266114Sdes}
668266114Sdes
669266114Sdesint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
670266114Sdes	int* async_id)
671266114Sdes{
672266114Sdes	struct libworker* w = ctx->event_worker;
673266114Sdes	uint16_t qflags, qid;
674266114Sdes	struct query_info qinfo;
675266114Sdes	struct edns_data edns;
676266114Sdes	if(!w)
677266114Sdes		return UB_INITFAIL;
678266114Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns))
679266114Sdes		return UB_SYNTAX;
680266114Sdes	qid = 0;
681266114Sdes	qflags = BIT_RD;
682266114Sdes	q->w = w;
683266114Sdes	/* see if there is a fixed answer */
684266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
685266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
686356345Scy	if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns,
687307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
688356345Scy		NULL, 0, NULL, 0, NULL)) {
689266114Sdes		regional_free_all(w->env->scratch);
690266114Sdes		free(qinfo.qname);
691266114Sdes		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
692356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
693266114Sdes		return UB_NOERROR;
694266114Sdes	}
695356345Scy	if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
696356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
697356345Scy		regional_free_all(w->env->scratch);
698356345Scy		free(qinfo.qname);
699356345Scy		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
700356345Scy			w->back->udp_buff, sec_status_insecure, NULL, 0);
701356345Scy		return UB_NOERROR;
702356345Scy	}
703266114Sdes	/* process new query */
704266114Sdes	if(async_id)
705266114Sdes		*async_id = q->querynum;
706266114Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
707266114Sdes		w->back->udp_buff, qid, libworker_event_done_cb, q)) {
708266114Sdes		free(qinfo.qname);
709266114Sdes		return UB_NOMEM;
710266114Sdes	}
711266114Sdes	free(qinfo.qname);
712266114Sdes	return UB_NOERROR;
713266114Sdes}
714266114Sdes
715238106Sdes/** add result to the bg worker result queue */
716238106Sdesstatic void
717266114Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
718356345Scy	int err, char* reason, int was_ratelimited)
719238106Sdes{
720238106Sdes	uint8_t* msg = NULL;
721238106Sdes	uint32_t len = 0;
722238106Sdes
723356345Scy	if(w->want_quit) {
724356345Scy		context_query_delete(q);
725356345Scy		return;
726356345Scy	}
727238106Sdes	/* serialize and delete unneeded q */
728238106Sdes	if(w->is_bg_thread) {
729238106Sdes		lock_basic_lock(&w->ctx->cfglock);
730238106Sdes		if(reason)
731238106Sdes			q->res->why_bogus = strdup(reason);
732356345Scy		q->res->was_ratelimited = was_ratelimited;
733238106Sdes		if(pkt) {
734266114Sdes			q->msg_len = sldns_buffer_remaining(pkt);
735266114Sdes			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
736356345Scy			if(!q->msg) {
737356345Scy				msg = context_serialize_answer(q, UB_NOMEM, NULL, &len);
738356345Scy			} else {
739356345Scy				msg = context_serialize_answer(q, err, NULL, &len);
740356345Scy			}
741356345Scy		} else {
742356345Scy			msg = context_serialize_answer(q, err, NULL, &len);
743356345Scy		}
744238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
745238106Sdes	} else {
746238106Sdes		if(reason)
747238106Sdes			q->res->why_bogus = strdup(reason);
748356345Scy		q->res->was_ratelimited = was_ratelimited;
749238106Sdes		msg = context_serialize_answer(q, err, pkt, &len);
750238106Sdes		(void)rbtree_delete(&w->ctx->queries, q->node.key);
751238106Sdes		w->ctx->num_async--;
752238106Sdes		context_query_delete(q);
753238106Sdes	}
754238106Sdes
755238106Sdes	if(!msg) {
756238106Sdes		log_err("out of memory for async answer");
757238106Sdes		return;
758238106Sdes	}
759238106Sdes	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
760238106Sdes		log_err("out of memory for async answer");
761238106Sdes		return;
762238106Sdes	}
763238106Sdes}
764238106Sdes
765238106Sdesvoid
766266114Sdeslibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
767356345Scy	char* why_bogus, int was_ratelimited)
768238106Sdes{
769238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
770238106Sdes
771356345Scy	if(q->cancelled || q->w->back->want_to_quit) {
772238106Sdes		if(q->w->is_bg_thread) {
773238106Sdes			/* delete it now */
774238106Sdes			struct ub_ctx* ctx = q->w->ctx;
775238106Sdes			lock_basic_lock(&ctx->cfglock);
776238106Sdes			(void)rbtree_delete(&ctx->queries, q->node.key);
777238106Sdes			ctx->num_async--;
778238106Sdes			context_query_delete(q);
779238106Sdes			lock_basic_unlock(&ctx->cfglock);
780238106Sdes		}
781238106Sdes		/* cancelled, do not give answer */
782238106Sdes		return;
783238106Sdes	}
784238106Sdes	q->msg_security = s;
785356345Scy	if(!buf) {
786249141Sdes		buf = q->w->env->scratch_buffer;
787356345Scy	}
788238106Sdes	if(rcode != 0) {
789238106Sdes		error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
790238106Sdes	}
791356345Scy	add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus, was_ratelimited);
792238106Sdes}
793238106Sdes
794238106Sdes
795238106Sdes/** handle new query command for bg worker */
796238106Sdesstatic void
797238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
798238106Sdes{
799238106Sdes	uint16_t qflags, qid;
800238106Sdes	struct query_info qinfo;
801238106Sdes	struct edns_data edns;
802238106Sdes	struct ctx_query* q;
803238106Sdes	if(w->is_bg_thread) {
804238106Sdes		lock_basic_lock(&w->ctx->cfglock);
805238106Sdes		q = context_lookup_new_query(w->ctx, buf, len);
806238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
807238106Sdes	} else {
808238106Sdes		q = context_deserialize_new_query(w->ctx, buf, len);
809238106Sdes	}
810238106Sdes	free(buf);
811238106Sdes	if(!q) {
812238106Sdes		log_err("failed to deserialize newq");
813238106Sdes		return;
814238106Sdes	}
815238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
816356345Scy		add_bg_result(w, q, NULL, UB_SYNTAX, NULL, 0);
817238106Sdes		return;
818238106Sdes	}
819238106Sdes	qid = 0;
820238106Sdes	qflags = BIT_RD;
821238106Sdes	/* see if there is a fixed answer */
822266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
823266114Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
824356345Scy	if(local_zones_answer(w->ctx->local_zones, w->env, &qinfo, &edns,
825307729Sdes		w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
826356345Scy		NULL, 0, NULL, 0, NULL)) {
827238106Sdes		regional_free_all(w->env->scratch);
828238106Sdes		q->msg_security = sec_status_insecure;
829356345Scy		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
830238106Sdes		free(qinfo.qname);
831238106Sdes		return;
832238106Sdes	}
833356345Scy	if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
834356345Scy		w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
835356345Scy		regional_free_all(w->env->scratch);
836356345Scy		q->msg_security = sec_status_insecure;
837356345Scy		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
838356345Scy		free(qinfo.qname);
839356345Scy		return;
840356345Scy	}
841238106Sdes	q->w = w;
842238106Sdes	/* process new query */
843238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
844238106Sdes		w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
845356345Scy		add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
846238106Sdes	}
847238106Sdes	free(qinfo.qname);
848238106Sdes}
849238106Sdes
850238106Sdesvoid libworker_alloc_cleanup(void* arg)
851238106Sdes{
852238106Sdes	struct libworker* w = (struct libworker*)arg;
853238106Sdes	slabhash_clear(&w->env->rrset_cache->table);
854238106Sdes        slabhash_clear(w->env->msg_cache);
855238106Sdes}
856238106Sdes
857356345Scystruct outbound_entry* libworker_send_query(struct query_info* qinfo,
858356345Scy	uint16_t flags, int dnssec, int want_dnssec, int nocaps,
859307729Sdes	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
860356345Scy	size_t zonelen, int ssl_upstream, char* tls_auth_name,
861356345Scy	struct module_qstate* q)
862238106Sdes{
863238106Sdes	struct libworker* w = (struct libworker*)q->env->worker;
864238106Sdes	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
865238106Sdes		q->region, sizeof(*e));
866238106Sdes	if(!e)
867238106Sdes		return NULL;
868238106Sdes	e->qstate = q;
869356345Scy	e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
870356345Scy		want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream,
871356345Scy		tls_auth_name, addr, addrlen, zone, zonelen, q,
872356345Scy		libworker_handle_service_reply, e, w->back->udp_buff, q->env);
873238106Sdes	if(!e->qsent) {
874238106Sdes		return NULL;
875238106Sdes	}
876238106Sdes	return e;
877238106Sdes}
878238106Sdes
879238106Sdesint
880238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error,
881238106Sdes        struct comm_reply* reply_info)
882238106Sdes{
883238106Sdes	struct module_qstate* q = (struct module_qstate*)arg;
884238106Sdes	struct libworker* lw = (struct libworker*)q->env->worker;
885238106Sdes	struct outbound_entry e;
886238106Sdes	e.qstate = q;
887238106Sdes	e.qsent = NULL;
888238106Sdes
889238106Sdes	if(error != 0) {
890238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info, error);
891238106Sdes		return 0;
892238106Sdes	}
893238106Sdes	/* sanity check. */
894266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
895266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
896238106Sdes			LDNS_PACKET_QUERY
897266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
898238106Sdes		/* error becomes timeout for the module as if this reply
899238106Sdes		 * never arrived. */
900238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info,
901238106Sdes			NETEVENT_TIMEOUT);
902238106Sdes		return 0;
903238106Sdes	}
904238106Sdes	mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
905238106Sdes	return 0;
906238106Sdes}
907238106Sdes
908238106Sdesint
909238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error,
910238106Sdes        struct comm_reply* reply_info)
911238106Sdes{
912238106Sdes	struct outbound_entry* e = (struct outbound_entry*)arg;
913238106Sdes	struct libworker* lw = (struct libworker*)e->qstate->env->worker;
914238106Sdes
915238106Sdes	if(error != 0) {
916238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info, error);
917238106Sdes		return 0;
918238106Sdes	}
919238106Sdes	/* sanity check. */
920266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
921266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
922238106Sdes			LDNS_PACKET_QUERY
923266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
924238106Sdes		/* error becomes timeout for the module as if this reply
925238106Sdes		 * never arrived. */
926238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info,
927238106Sdes			NETEVENT_TIMEOUT);
928238106Sdes		return 0;
929238106Sdes	}
930238106Sdes	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
931238106Sdes	return 0;
932238106Sdes}
933238106Sdes
934238106Sdes/* --- fake callbacks for fptr_wlist to work --- */
935238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
936238106Sdes	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
937238106Sdes	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
938238106Sdes{
939238106Sdes	log_assert(0);
940238106Sdes}
941238106Sdes
942238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c),
943238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
944238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
945238106Sdes{
946238106Sdes	log_assert(0);
947238106Sdes	return 0;
948238106Sdes}
949238106Sdes
950238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
951238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
952238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
953238106Sdes{
954238106Sdes	log_assert(0);
955238106Sdes	return 0;
956238106Sdes}
957238106Sdes
958238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
959238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
960238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
961238106Sdes{
962238106Sdes	log_assert(0);
963238106Sdes	return 0;
964238106Sdes}
965238106Sdes
966238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
967238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
968238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
969238106Sdes{
970238106Sdes	log_assert(0);
971238106Sdes	return 0;
972238106Sdes}
973238106Sdes
974238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c),
975238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
976238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
977238106Sdes{
978238106Sdes	log_assert(0);
979238106Sdes	return 0;
980238106Sdes}
981238106Sdes
982238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
983238106Sdes{
984238106Sdes	log_assert(0);
985238106Sdes}
986238106Sdes
987356345Scystruct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
988356345Scy	uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
989356345Scy	int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
990356345Scy	struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
991356345Scy	uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
992356345Scy	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
993356345Scy	struct module_qstate* ATTR_UNUSED(q))
994238106Sdes{
995238106Sdes	log_assert(0);
996238106Sdes	return 0;
997238106Sdes}
998238106Sdes
999238106Sdesvoid
1000238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg))
1001238106Sdes{
1002238106Sdes	log_assert(0);
1003238106Sdes}
1004238106Sdes
1005238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg))
1006238106Sdes{
1007238106Sdes	log_assert(0);
1008238106Sdes}
1009238106Sdes
1010238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg))
1011238106Sdes{
1012238106Sdes	log_assert(0);
1013238106Sdes}
1014238106Sdes
1015238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg))
1016238106Sdes{
1017238106Sdes	log_assert(0);
1018238106Sdes}
1019238106Sdes
1020238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg))
1021238106Sdes{
1022238106Sdes	log_assert(0);
1023238106Sdes}
1024238106Sdes
1025238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
1026238106Sdes{
1027238106Sdes	log_assert(0);
1028238106Sdes	return 0;
1029238106Sdes}
1030238106Sdes
1031238106Sdesint
1032238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1033238106Sdes{
1034238106Sdes	log_assert(0);
1035238106Sdes	return 0;
1036238106Sdes}
1037238106Sdes
1038238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1039238106Sdes{
1040238106Sdes        log_assert(0);
1041238106Sdes        return 0;
1042238106Sdes}
1043238106Sdes
1044238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
1045238106Sdes{
1046238106Sdes        log_assert(0);
1047238106Sdes}
1048238106Sdes
1049238106Sdes#ifdef UB_ON_WINDOWS
1050238106Sdesvoid
1051238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
1052238106Sdes        ATTR_UNUSED(arg)) {
1053238106Sdes        log_assert(0);
1054238106Sdes}
1055238106Sdes
1056238106Sdesvoid
1057238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg))
1058238106Sdes{
1059238106Sdes        log_assert(0);
1060238106Sdes}
1061238106Sdes#endif /* UB_ON_WINDOWS */
1062366095Scy
1063366095Scy#ifdef USE_DNSTAP
1064366095Scyvoid dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1065366095Scy	void* ATTR_UNUSED(arg))
1066366095Scy{
1067366095Scy	log_assert(0);
1068366095Scy}
1069366095Scy#endif
1070366095Scy
1071366095Scy#ifdef USE_DNSTAP
1072366095Scyvoid dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
1073366095Scy	void* ATTR_UNUSED(arg))
1074366095Scy{
1075366095Scy	log_assert(0);
1076366095Scy}
1077366095Scy#endif
1078