]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/libunbound/libworker.c
Minimal subset of the unbound sources.
[FreeBSD/FreeBSD.git] / contrib / unbound / libunbound / libworker.c
1 /*
2  * libunbound/worker.c - worker thread or process that resolves
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  * 
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * 
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 /**
37  * \file
38  *
39  * This file contains the worker process or thread that performs
40  * the DNS resolving and validation. The worker is called by a procedure
41  * and if in the background continues until exit, if in the foreground
42  * returns from the procedure when done.
43  */
44 #include "config.h"
45 #include <ldns/dname.h>
46 #include <ldns/wire2host.h>
47 #include <openssl/ssl.h>
48 #include "libunbound/libworker.h"
49 #include "libunbound/context.h"
50 #include "libunbound/unbound.h"
51 #include "services/outside_network.h"
52 #include "services/mesh.h"
53 #include "services/localzone.h"
54 #include "services/cache/rrset.h"
55 #include "services/outbound_list.h"
56 #include "util/module.h"
57 #include "util/regional.h"
58 #include "util/random.h"
59 #include "util/config_file.h"
60 #include "util/netevent.h"
61 #include "util/storage/lookup3.h"
62 #include "util/storage/slabhash.h"
63 #include "util/net_help.h"
64 #include "util/data/dname.h"
65 #include "util/data/msgreply.h"
66 #include "util/data/msgencode.h"
67 #include "util/tube.h"
68 #include "iterator/iter_fwd.h"
69 #include "iterator/iter_hints.h"
70
71 /** handle new query command for bg worker */
72 static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
73
74 /** delete libworker struct */
75 static void
76 libworker_delete(struct libworker* w)
77 {
78         if(!w) return;
79         if(w->env) {
80                 outside_network_quit_prepare(w->back);
81                 mesh_delete(w->env->mesh);
82                 context_release_alloc(w->ctx, w->env->alloc, 
83                         !w->is_bg || w->is_bg_thread);
84                 ldns_buffer_free(w->env->scratch_buffer);
85                 regional_destroy(w->env->scratch);
86                 forwards_delete(w->env->fwds);
87                 hints_delete(w->env->hints);
88                 ub_randfree(w->env->rnd);
89                 free(w->env);
90         }
91         SSL_CTX_free(w->sslctx);
92         outside_network_delete(w->back);
93         comm_base_delete(w->base);
94         free(w);
95 }
96
97 /** setup fresh libworker struct */
98 static struct libworker*
99 libworker_setup(struct ub_ctx* ctx, int is_bg)
100 {
101         unsigned int seed;
102         struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
103         struct config_file* cfg = ctx->env->cfg;
104         int* ports;
105         int numports;
106         if(!w) return NULL;
107         w->is_bg = is_bg;
108         w->ctx = ctx;
109         w->env = (struct module_env*)malloc(sizeof(*w->env));
110         if(!w->env) {
111                 free(w);
112                 return NULL;
113         }
114         *w->env = *ctx->env;
115         w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
116         if(!w->env->alloc) {
117                 libworker_delete(w);
118                 return NULL;
119         }
120         w->thread_num = w->env->alloc->thread_num;
121         alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
122         if(!w->is_bg || w->is_bg_thread) {
123                 lock_basic_lock(&ctx->cfglock);
124         }
125         w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
126         w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
127         w->env->fwds = forwards_create();
128         if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { 
129                 forwards_delete(w->env->fwds);
130                 w->env->fwds = NULL;
131         }
132         w->env->hints = hints_create();
133         if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { 
134                 hints_delete(w->env->hints);
135                 w->env->hints = NULL;
136         }
137         if(cfg->ssl_upstream) {
138                 w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
139                 if(!w->sslctx) {
140                         /* to make the setup fail after unlock */
141                         hints_delete(w->env->hints);
142                         w->env->hints = NULL;
143                 }
144         }
145         if(!w->is_bg || w->is_bg_thread) {
146                 lock_basic_unlock(&ctx->cfglock);
147         }
148         if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
149                 !w->env->hints) {
150                 libworker_delete(w);
151                 return NULL;
152         }
153         w->env->worker = (struct worker*)w;
154         w->env->probe_timer = NULL;
155         seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
156                 (((unsigned int)w->thread_num)<<17);
157         seed ^= (unsigned int)w->env->alloc->next_id;
158         if(!w->is_bg || w->is_bg_thread) {
159                 lock_basic_lock(&ctx->cfglock);
160         }
161         if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
162                 if(!w->is_bg || w->is_bg_thread) {
163                         lock_basic_unlock(&ctx->cfglock);
164                 }
165                 seed = 0;
166                 libworker_delete(w);
167                 return NULL;
168         }
169         if(!w->is_bg || w->is_bg_thread) {
170                 lock_basic_unlock(&ctx->cfglock);
171         }
172         if(1) {
173                 /* primitive lockout for threading: if it overwrites another
174                  * thread it is like wiping the cache (which is likely empty
175                  * at the start) */
176                 /* note we are holding the ctx lock in normal threaded
177                  * cases so that is solved properly, it is only for many ctx
178                  * in different threads that this may clash */
179                 static int done_raninit = 0;
180                 if(!done_raninit) {
181                         done_raninit = 1;
182                         hash_set_raninit((uint32_t)ub_random(w->env->rnd));
183                 }
184         }
185         seed = 0;
186
187         w->base = comm_base_create(0);
188         if(!w->base) {
189                 libworker_delete(w);
190                 return NULL;
191         }
192         if(!w->is_bg || w->is_bg_thread) {
193                 lock_basic_lock(&ctx->cfglock);
194         }
195         numports = cfg_condense_ports(cfg, &ports);
196         if(numports == 0) {
197                 libworker_delete(w);
198                 return NULL;
199         }
200         w->back = outside_network_create(w->base, cfg->msg_buffer_size,
201                 (size_t)cfg->outgoing_num_ports, cfg->out_ifs,
202                 cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 
203                 cfg->do_tcp?cfg->outgoing_num_tcp:0,
204                 w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
205                 ports, numports, cfg->unwanted_threshold,
206                 &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx);
207         if(!w->is_bg || w->is_bg_thread) {
208                 lock_basic_unlock(&ctx->cfglock);
209         }
210         free(ports);
211         if(!w->back) {
212                 libworker_delete(w);
213                 return NULL;
214         }
215         w->env->mesh = mesh_create(&ctx->mods, w->env);
216         if(!w->env->mesh) {
217                 libworker_delete(w);
218                 return NULL;
219         }
220         w->env->send_query = &libworker_send_query;
221         w->env->detach_subs = &mesh_detach_subs;
222         w->env->attach_sub = &mesh_attach_sub;
223         w->env->kill_sub = &mesh_state_delete;
224         w->env->detect_cycle = &mesh_detect_cycle;
225         comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
226         return w;
227 }
228
229 /** handle cancel command for bg worker */
230 static void
231 handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
232 {
233         struct ctx_query* q;
234         if(w->is_bg_thread) {
235                 lock_basic_lock(&w->ctx->cfglock);
236                 q = context_deserialize_cancel(w->ctx, buf, len);
237                 lock_basic_unlock(&w->ctx->cfglock);
238         } else {
239                 q = context_deserialize_cancel(w->ctx, buf, len);
240         }
241         if(!q) {
242                 /* probably simply lookup failed, i.e. the message had been
243                  * processed and answered before the cancel arrived */
244                 return;
245         }
246         q->cancelled = 1;
247         free(buf);
248 }
249
250 /** do control command coming into bg server */
251 static void
252 libworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
253 {
254         switch(context_serial_getcmd(msg, len)) {
255                 default:
256                 case UB_LIBCMD_ANSWER:
257                         log_err("unknown command for bg worker %d", 
258                                 (int)context_serial_getcmd(msg, len));
259                         /* and fall through to quit */
260                 case UB_LIBCMD_QUIT:
261                         free(msg);
262                         comm_base_exit(w->base);
263                         break;
264                 case UB_LIBCMD_NEWQUERY:
265                         handle_newq(w, msg, len);
266                         break;
267                 case UB_LIBCMD_CANCEL:
268                         handle_cancel(w, msg, len);
269                         break;
270         }
271 }
272
273 /** handle control command coming into server */
274 void 
275 libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 
276         uint8_t* msg, size_t len, int err, void* arg)
277 {
278         struct libworker* w = (struct libworker*)arg;
279
280         if(err != 0) {
281                 free(msg);
282                 /* it is of no use to go on, exit */
283                 comm_base_exit(w->base);
284                 return;
285         }
286         libworker_do_cmd(w, msg, len); /* also frees the buf */
287 }
288
289 /** the background thread func */
290 static void*
291 libworker_dobg(void* arg)
292 {
293         /* setup */
294         uint32_t m;
295         struct libworker* w = (struct libworker*)arg;
296         struct ub_ctx* ctx;
297         if(!w) {
298                 log_err("libunbound bg worker init failed, nomem");
299                 return NULL;
300         }
301         ctx = w->ctx;
302         log_thread_set(&w->thread_num);
303 #ifdef THREADS_DISABLED
304         /* we are forked */
305         w->is_bg_thread = 0;
306         /* close non-used parts of the pipes */
307         tube_close_write(ctx->qq_pipe);
308         tube_close_read(ctx->rr_pipe);
309 #endif
310         if(!tube_setup_bg_listen(ctx->qq_pipe, w->base, 
311                 libworker_handle_control_cmd, w)) {
312                 log_err("libunbound bg worker init failed, no bglisten");
313                 return NULL;
314         }
315         if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
316                 log_err("libunbound bg worker init failed, no bgwrite");
317                 return NULL;
318         }
319
320         /* do the work */
321         comm_base_dispatch(w->base);
322
323         /* cleanup */
324         m = UB_LIBCMD_QUIT;
325         tube_remove_bg_listen(w->ctx->qq_pipe);
326         tube_remove_bg_write(w->ctx->rr_pipe);
327         libworker_delete(w);
328         (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m, 
329                 (uint32_t)sizeof(m), 0);
330 #ifdef THREADS_DISABLED
331         /* close pipes from forked process before exit */
332         tube_close_read(ctx->qq_pipe);
333         tube_close_write(ctx->rr_pipe);
334 #endif
335         return NULL;
336 }
337
338 int libworker_bg(struct ub_ctx* ctx)
339 {
340         struct libworker* w;
341         /* fork or threadcreate */
342         lock_basic_lock(&ctx->cfglock);
343         if(ctx->dothread) {
344                 lock_basic_unlock(&ctx->cfglock);
345                 w = libworker_setup(ctx, 1);
346                 if(!w) return UB_NOMEM;
347                 w->is_bg_thread = 1;
348 #ifdef ENABLE_LOCK_CHECKS
349                 w->thread_num = 1; /* for nicer DEBUG checklocks */
350 #endif
351                 ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
352         } else {
353                 lock_basic_unlock(&ctx->cfglock);
354 #ifndef HAVE_FORK
355                 /* no fork on windows */
356                 return UB_FORKFAIL;
357 #else /* HAVE_FORK */
358                 switch((ctx->bg_pid=fork())) {
359                         case 0:
360                                 w = libworker_setup(ctx, 1);
361                                 if(!w) fatal_exit("out of memory");
362                                 /* close non-used parts of the pipes */
363                                 tube_close_write(ctx->qq_pipe);
364                                 tube_close_read(ctx->rr_pipe);
365                                 (void)libworker_dobg(w);
366                                 exit(0);
367                                 break;
368                         case -1:
369                                 return UB_FORKFAIL;
370                         default:
371                                 break;
372                 }
373 #endif /* HAVE_FORK */ 
374         }
375         return UB_NOERROR;
376 }
377
378 /** get msg reply struct (in temp region) */
379 static struct reply_info*
380 parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi)
381 {
382         struct reply_info* rep;
383         struct msg_parse* msg;
384         if(!(msg = regional_alloc(region, sizeof(*msg)))) {
385                 return NULL;
386         }
387         memset(msg, 0, sizeof(*msg));
388         ldns_buffer_set_position(pkt, 0);
389         if(parse_packet(pkt, msg, region) != 0)
390                 return 0;
391         if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
392                 return 0;
393         }
394         return rep;
395 }
396
397 /** insert canonname */
398 static int
399 fill_canon(struct ub_result* res, uint8_t* s)
400 {
401         char buf[255+2];
402         dname_str(s, buf);
403         res->canonname = strdup(buf);
404         return res->canonname != 0;
405 }
406
407 /** fill data into result */
408 static int
409 fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
410         uint8_t* finalcname, struct query_info* rq)
411 {
412         size_t i;
413         struct packed_rrset_data* data;
414         if(!answer) {
415                 if(finalcname) {
416                         if(!fill_canon(res, finalcname))
417                                 return 0; /* out of memory */
418                 }
419                 res->data = (char**)calloc(1, sizeof(char*));
420                 res->len = (int*)calloc(1, sizeof(int));
421                 return (res->data && res->len);
422         }
423         data = (struct packed_rrset_data*)answer->entry.data;
424         if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
425                 if(!fill_canon(res, answer->rk.dname))
426                         return 0; /* out of memory */
427         } else  res->canonname = NULL;
428         res->data = (char**)calloc(data->count+1, sizeof(char*));
429         res->len = (int*)calloc(data->count+1, sizeof(int));
430         if(!res->data || !res->len)
431                 return 0; /* out of memory */
432         for(i=0; i<data->count; i++) {
433                 /* remove rdlength from rdata */
434                 res->len[i] = (int)(data->rr_len[i] - 2);
435                 res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
436                 if(!res->data[i])
437                         return 0; /* out of memory */
438         }
439         res->data[data->count] = NULL;
440         res->len[data->count] = 0;
441         return 1;
442 }
443
444 /** fill result from parsed message, on error fills servfail */
445 void
446 libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
447         struct regional* temp, enum sec_status msg_security)
448 {
449         struct query_info rq;
450         struct reply_info* rep;
451         res->rcode = LDNS_RCODE_SERVFAIL;
452         rep = parse_reply(buf, temp, &rq);
453         if(!rep) {
454                 log_err("cannot parse buf");
455                 return; /* error parsing buf, or out of memory */
456         }
457         if(!fill_res(res, reply_find_answer_rrset(&rq, rep), 
458                 reply_find_final_cname_target(&rq, rep), &rq))
459                 return; /* out of memory */
460         /* rcode, havedata, nxdomain, secure, bogus */
461         res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
462         if(res->data && res->data[0])
463                 res->havedata = 1;
464         if(res->rcode == LDNS_RCODE_NXDOMAIN)
465                 res->nxdomain = 1;
466         if(msg_security == sec_status_secure)
467                 res->secure = 1;
468         if(msg_security == sec_status_bogus)
469                 res->bogus = 1;
470 }
471
472 /** fillup fg results */
473 static void
474 libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf, 
475         enum sec_status s, char* why_bogus)
476 {
477         if(why_bogus)
478                 q->res->why_bogus = strdup(why_bogus);
479         if(rcode != 0) {
480                 q->res->rcode = rcode;
481                 q->msg_security = s;
482                 return;
483         }
484
485         q->res->rcode = LDNS_RCODE_SERVFAIL;
486         q->msg_security = 0;
487         q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf));
488         q->msg_len = ldns_buffer_limit(buf);
489         if(!q->msg) {
490                 return; /* the error is in the rcode */
491         }
492
493         /* canonname and results */
494         q->msg_security = s;
495         libworker_enter_result(q->res, buf, q->w->env->scratch, s);
496 }
497
498 void
499 libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
500         char* why_bogus)
501 {
502         struct ctx_query* q = (struct ctx_query*)arg;
503         /* fg query is done; exit comm base */
504         comm_base_exit(q->w->base);
505
506         libworker_fillup_fg(q, rcode, buf, s, why_bogus);
507 }
508
509 /** setup qinfo and edns */
510 static int
511 setup_qinfo_edns(struct libworker* w, struct ctx_query* q, 
512         struct query_info* qinfo, struct edns_data* edns)
513 {
514         ldns_rdf* rdf;
515         qinfo->qtype = (uint16_t)q->res->qtype;
516         qinfo->qclass = (uint16_t)q->res->qclass;
517         rdf = ldns_dname_new_frm_str(q->res->qname);
518         if(!rdf) {
519                 return 0;
520         }
521 #ifdef UNBOUND_ALLOC_LITE
522         qinfo->qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
523         qinfo->qname_len = ldns_rdf_size(rdf);
524         ldns_rdf_deep_free(rdf);
525         rdf = 0;
526 #else
527         qinfo->qname = ldns_rdf_data(rdf);
528         qinfo->qname_len = ldns_rdf_size(rdf);
529 #endif
530         edns->edns_present = 1;
531         edns->ext_rcode = 0;
532         edns->edns_version = 0;
533         edns->bits = EDNS_DO;
534         if(ldns_buffer_capacity(w->back->udp_buff) < 65535)
535                 edns->udp_size = (uint16_t)ldns_buffer_capacity(
536                         w->back->udp_buff);
537         else    edns->udp_size = 65535;
538         ldns_rdf_free(rdf);
539         return 1;
540 }
541
542 int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
543 {
544         struct libworker* w = libworker_setup(ctx, 0);
545         uint16_t qflags, qid;
546         struct query_info qinfo;
547         struct edns_data edns;
548         if(!w)
549                 return UB_INITFAIL;
550         if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
551                 libworker_delete(w);
552                 return UB_SYNTAX;
553         }
554         qid = 0;
555         qflags = BIT_RD;
556         q->w = w;
557         /* see if there is a fixed answer */
558         ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
559         ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
560         if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 
561                 w->back->udp_buff, w->env->scratch)) {
562                 regional_free_all(w->env->scratch);
563                 libworker_fillup_fg(q, LDNS_RCODE_NOERROR, 
564                         w->back->udp_buff, sec_status_insecure, NULL);
565                 libworker_delete(w);
566                 free(qinfo.qname);
567                 return UB_NOERROR;
568         }
569         /* process new query */
570         if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
571                 w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
572                 free(qinfo.qname);
573                 return UB_NOMEM;
574         }
575         free(qinfo.qname);
576
577         /* wait for reply */
578         comm_base_dispatch(w->base);
579
580         libworker_delete(w);
581         return UB_NOERROR;
582 }
583
584 /** add result to the bg worker result queue */
585 static void
586 add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt, 
587         int err, char* reason)
588 {
589         uint8_t* msg = NULL;
590         uint32_t len = 0;
591
592         /* serialize and delete unneeded q */
593         if(w->is_bg_thread) {
594                 lock_basic_lock(&w->ctx->cfglock);
595                 if(reason)
596                         q->res->why_bogus = strdup(reason);
597                 if(pkt) {
598                         q->msg_len = ldns_buffer_remaining(pkt);
599                         q->msg = memdup(ldns_buffer_begin(pkt), q->msg_len);
600                         if(!q->msg)
601                                 msg = context_serialize_answer(q, UB_NOMEM, 
602                                 NULL, &len);
603                         else    msg = context_serialize_answer(q, err, 
604                                 NULL, &len);
605                 } else msg = context_serialize_answer(q, err, NULL, &len);
606                 lock_basic_unlock(&w->ctx->cfglock);
607         } else {
608                 if(reason)
609                         q->res->why_bogus = strdup(reason);
610                 msg = context_serialize_answer(q, err, pkt, &len);
611                 (void)rbtree_delete(&w->ctx->queries, q->node.key);
612                 w->ctx->num_async--;
613                 context_query_delete(q);
614         }
615
616         if(!msg) {
617                 log_err("out of memory for async answer");
618                 return;
619         }
620         if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
621                 log_err("out of memory for async answer");
622                 return;
623         }
624 }
625
626 void
627 libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
628         char* why_bogus)
629 {
630         struct ctx_query* q = (struct ctx_query*)arg;
631
632         if(q->cancelled) {
633                 if(q->w->is_bg_thread) {
634                         /* delete it now */
635                         struct ub_ctx* ctx = q->w->ctx;
636                         lock_basic_lock(&ctx->cfglock);
637                         (void)rbtree_delete(&ctx->queries, q->node.key);
638                         ctx->num_async--;
639                         context_query_delete(q);
640                         lock_basic_unlock(&ctx->cfglock);
641                 }
642                 /* cancelled, do not give answer */
643                 return;
644         }
645         q->msg_security = s;
646         if(rcode != 0) {
647                 error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
648         }
649         add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
650 }
651
652
653 /** handle new query command for bg worker */
654 static void
655 handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
656 {
657         uint16_t qflags, qid;
658         struct query_info qinfo;
659         struct edns_data edns;
660         struct ctx_query* q;
661         if(w->is_bg_thread) {
662                 lock_basic_lock(&w->ctx->cfglock);
663                 q = context_lookup_new_query(w->ctx, buf, len);
664                 lock_basic_unlock(&w->ctx->cfglock);
665         } else {
666                 q = context_deserialize_new_query(w->ctx, buf, len);
667         }
668         free(buf);
669         if(!q) {
670                 log_err("failed to deserialize newq");
671                 return;
672         }
673         if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
674                 add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
675                 return;
676         }
677         qid = 0;
678         qflags = BIT_RD;
679         /* see if there is a fixed answer */
680         ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
681         ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
682         if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, 
683                 w->back->udp_buff, w->env->scratch)) {
684                 regional_free_all(w->env->scratch);
685                 q->msg_security = sec_status_insecure;
686                 add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
687                 free(qinfo.qname);
688                 return;
689         }
690         q->w = w;
691         /* process new query */
692         if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
693                 w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
694                 add_bg_result(w, q, NULL, UB_NOMEM, NULL);
695         }
696         free(qinfo.qname);
697 }
698
699 void libworker_alloc_cleanup(void* arg)
700 {
701         struct libworker* w = (struct libworker*)arg;
702         slabhash_clear(&w->env->rrset_cache->table);
703         slabhash_clear(w->env->msg_cache);
704 }
705
706 /** compare outbound entry qstates */
707 static int
708 outbound_entry_compare(void* a, void* b)
709 {
710         struct outbound_entry* e1 = (struct outbound_entry*)a;
711         struct outbound_entry* e2 = (struct outbound_entry*)b;
712         if(e1->qstate == e2->qstate)
713                 return 1;
714         return 0;
715 }
716
717 struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
718         uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
719         int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
720         uint8_t* zone, size_t zonelen, struct module_qstate* q)
721 {
722         struct libworker* w = (struct libworker*)q->env->worker;
723         struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
724                 q->region, sizeof(*e));
725         if(!e)
726                 return NULL;
727         e->qstate = q;
728         e->qsent = outnet_serviced_query(w->back, qname,
729                 qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
730                 q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
731                 addrlen, zone, zonelen, libworker_handle_service_reply, e,
732                 w->back->udp_buff, &outbound_entry_compare);
733         if(!e->qsent) {
734                 return NULL;
735         }
736         return e;
737 }
738
739 int 
740 libworker_handle_reply(struct comm_point* c, void* arg, int error,
741         struct comm_reply* reply_info)
742 {
743         struct module_qstate* q = (struct module_qstate*)arg;
744         struct libworker* lw = (struct libworker*)q->env->worker;
745         struct outbound_entry e;
746         e.qstate = q;
747         e.qsent = NULL;
748
749         if(error != 0) {
750                 mesh_report_reply(lw->env->mesh, &e, reply_info, error);
751                 return 0;
752         }
753         /* sanity check. */
754         if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
755                 || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
756                         LDNS_PACKET_QUERY
757                 || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
758                 /* error becomes timeout for the module as if this reply
759                  * never arrived. */
760                 mesh_report_reply(lw->env->mesh, &e, reply_info, 
761                         NETEVENT_TIMEOUT);
762                 return 0;
763         }
764         mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
765         return 0;
766 }
767
768 int 
769 libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
770         struct comm_reply* reply_info)
771 {
772         struct outbound_entry* e = (struct outbound_entry*)arg;
773         struct libworker* lw = (struct libworker*)e->qstate->env->worker;
774
775         if(error != 0) {
776                 mesh_report_reply(lw->env->mesh, e, reply_info, error);
777                 return 0;
778         }
779         /* sanity check. */
780         if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
781                 || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
782                         LDNS_PACKET_QUERY
783                 || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
784                 /* error becomes timeout for the module as if this reply
785                  * never arrived. */
786                 mesh_report_reply(lw->env->mesh, e, reply_info, 
787                         NETEVENT_TIMEOUT);
788                 return 0;
789         }
790         mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
791         return 0;
792 }
793
794 /* --- fake callbacks for fptr_wlist to work --- */
795 void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 
796         uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
797         int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
798 {
799         log_assert(0);
800 }
801
802 int worker_handle_request(struct comm_point* ATTR_UNUSED(c), 
803         void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
804         struct comm_reply* ATTR_UNUSED(repinfo))
805 {
806         log_assert(0);
807         return 0;
808 }
809
810 int worker_handle_reply(struct comm_point* ATTR_UNUSED(c), 
811         void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
812         struct comm_reply* ATTR_UNUSED(reply_info))
813 {
814         log_assert(0);
815         return 0;
816 }
817
818 int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 
819         void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
820         struct comm_reply* ATTR_UNUSED(reply_info))
821 {
822         log_assert(0);
823         return 0;
824 }
825
826 int remote_accept_callback(struct comm_point* ATTR_UNUSED(c), 
827         void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
828         struct comm_reply* ATTR_UNUSED(repinfo))
829 {
830         log_assert(0);
831         return 0;
832 }
833
834 int remote_control_callback(struct comm_point* ATTR_UNUSED(c), 
835         void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
836         struct comm_reply* ATTR_UNUSED(repinfo))
837 {
838         log_assert(0);
839         return 0;
840 }
841
842 void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
843 {
844         log_assert(0);
845 }
846
847 struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), 
848         size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 
849         uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 
850         int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
851         struct sockaddr_storage* ATTR_UNUSED(addr), 
852         socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
853 {
854         log_assert(0);
855         return 0;
856 }
857
858 void 
859 worker_alloc_cleanup(void* ATTR_UNUSED(arg))
860 {
861         log_assert(0);
862 }
863
864 void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
865 {
866         log_assert(0);
867 }
868
869 void worker_probe_timer_cb(void* ATTR_UNUSED(arg))
870 {
871         log_assert(0);
872 }
873
874 void worker_start_accept(void* ATTR_UNUSED(arg))
875 {
876         log_assert(0);
877 }
878
879 void worker_stop_accept(void* ATTR_UNUSED(arg))
880 {
881         log_assert(0);
882 }
883
884 int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
885 {
886         log_assert(0);
887         return 0;
888 }
889
890 int
891 codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
892 {
893         log_assert(0);
894         return 0;
895 }
896
897 int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
898 {
899         log_assert(0);
900         return 0;
901 }
902
903 void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
904 {
905         log_assert(0);
906 }
907
908 #ifdef UB_ON_WINDOWS
909 void
910 worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* 
911         ATTR_UNUSED(arg)) {
912         log_assert(0);
913 }
914
915 void
916 wsvc_cron_cb(void* ATTR_UNUSED(arg))
917 {
918         log_assert(0);
919 }
920 #endif /* UB_ON_WINDOWS */