1 /*
2 * unbound.c - unbound validating resolver public API implementation
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
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /**
37 * \file
38 *
39 * This file contains functions to resolve DNS queries and
40 * validate the answers. Synchronously and asynchronously.
41 *
42 */
43
44 /* include the public api first, it should be able to stand alone */
45 #include "libunbound/unbound.h"
46 #include "libunbound/unbound-event.h"
47 #include "config.h"
48 #include <ctype.h>
49 #include "libunbound/context.h"
50 #include "libunbound/libworker.h"
51 #include "util/locks.h"
52 #include "util/config_file.h"
53 #include "util/alloc.h"
54 #include "util/module.h"
55 #include "util/regional.h"
56 #include "util/log.h"
57 #include "util/random.h"
58 #include "util/net_help.h"
59 #include "util/tube.h"
60 #include "util/ub_event.h"
61 #include "services/modstack.h"
62 #include "services/localzone.h"
63 #include "services/cache/infra.h"
64 #include "services/cache/rrset.h"
65 #include "services/authzone.h"
66 #include "sldns/sbuffer.h"
67 #ifdef HAVE_PTHREAD
68 #include <signal.h>
69 #endif
70 #ifdef HAVE_SYS_WAIT_H
71 #include <sys/wait.h>
72 #endif
73 #ifdef HAVE_TIME_H
74 #include <time.h>
75 #endif
76
77 #if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H)
78 #include <windows.h>
79 #include <iphlpapi.h>
80 #endif /* UB_ON_WINDOWS */
81
82 /** store that the logfile has a debug override */
83 int ctx_logfile_overridden = 0;
84
85 /** create context functionality, but no pipes */
ub_ctx_create_nopipe(void)86 static struct ub_ctx* ub_ctx_create_nopipe(void)
87 {
88 struct ub_ctx* ctx;
89 #ifdef USE_WINSOCK
90 int r;
91 WSADATA wsa_data;
92 #endif
93
94 checklock_start();
95 if(!ctx_logfile_overridden)
96 log_init(NULL, 0, NULL); /* logs to stderr */
97 log_ident_set("libunbound");
98 #ifdef USE_WINSOCK
99 if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
100 log_err("could not init winsock. WSAStartup: %s",
101 wsa_strerror(r));
102 return NULL;
103 }
104 #endif
105 verbosity = NO_VERBOSE; /* errors only */
106 checklock_start();
107 ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
108 if(!ctx) {
109 errno = ENOMEM;
110 return NULL;
111 }
112 alloc_init(&ctx->superalloc, NULL, 0);
113 if(!(ctx->seed_rnd = ub_initstate(NULL))) {
114 ub_randfree(ctx->seed_rnd);
115 free(ctx);
116 errno = ENOMEM;
117 return NULL;
118 }
119 lock_basic_init(&ctx->qqpipe_lock);
120 lock_basic_init(&ctx->rrpipe_lock);
121 lock_basic_init(&ctx->cfglock);
122 ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
123 if(!ctx->env) {
124 ub_randfree(ctx->seed_rnd);
125 free(ctx);
126 errno = ENOMEM;
127 return NULL;
128 }
129 ctx->env->cfg = config_create_forlib();
130 if(!ctx->env->cfg) {
131 free(ctx->env);
132 ub_randfree(ctx->seed_rnd);
133 free(ctx);
134 errno = ENOMEM;
135 return NULL;
136 }
137 /* init edns_known_options */
138 if(!edns_known_options_init(ctx->env)) {
139 config_delete(ctx->env->cfg);
140 free(ctx->env);
141 ub_randfree(ctx->seed_rnd);
142 free(ctx);
143 errno = ENOMEM;
144 return NULL;
145 }
146 ctx->env->auth_zones = auth_zones_create();
147 if(!ctx->env->auth_zones) {
148 edns_known_options_delete(ctx->env);
149 config_delete(ctx->env->cfg);
150 free(ctx->env);
151 ub_randfree(ctx->seed_rnd);
152 free(ctx);
153 errno = ENOMEM;
154 return NULL;
155 }
156 ctx->env->alloc = &ctx->superalloc;
157 ctx->env->worker = NULL;
158 ctx->env->need_to_validate = 0;
159 modstack_init(&ctx->mods);
160 rbtree_init(&ctx->queries, &context_query_cmp);
161 return ctx;
162 }
163
164 struct ub_ctx*
ub_ctx_create(void)165 ub_ctx_create(void)
166 {
167 struct ub_ctx* ctx = ub_ctx_create_nopipe();
168 if(!ctx)
169 return NULL;
170 if((ctx->qq_pipe = tube_create()) == NULL) {
171 int e = errno;
172 ub_randfree(ctx->seed_rnd);
173 config_delete(ctx->env->cfg);
174 modstack_desetup(&ctx->mods, ctx->env);
175 edns_known_options_delete(ctx->env);
176 free(ctx->env);
177 free(ctx);
178 errno = e;
179 return NULL;
180 }
181 if((ctx->rr_pipe = tube_create()) == NULL) {
182 int e = errno;
183 tube_delete(ctx->qq_pipe);
184 ub_randfree(ctx->seed_rnd);
185 config_delete(ctx->env->cfg);
186 modstack_desetup(&ctx->mods, ctx->env);
187 edns_known_options_delete(ctx->env);
188 free(ctx->env);
189 free(ctx);
190 errno = e;
191 return NULL;
192 }
193 return ctx;
194 }
195
196 struct ub_ctx*
ub_ctx_create_ub_event(struct ub_event_base * ueb)197 ub_ctx_create_ub_event(struct ub_event_base* ueb)
198 {
199 struct ub_ctx* ctx = ub_ctx_create_nopipe();
200 if(!ctx)
201 return NULL;
202 /* no pipes, but we have the locks to make sure everything works */
203 ctx->created_bg = 0;
204 ctx->dothread = 1; /* the processing is in the same process,
205 makes ub_cancel and ub_ctx_delete do the right thing */
206 ctx->event_base = ueb;
207 return ctx;
208 }
209
210 struct ub_ctx*
ub_ctx_create_event(struct event_base * eb)211 ub_ctx_create_event(struct event_base* eb)
212 {
213 struct ub_ctx* ctx = ub_ctx_create_nopipe();
214 if(!ctx)
215 return NULL;
216 /* no pipes, but we have the locks to make sure everything works */
217 ctx->created_bg = 0;
218 ctx->dothread = 1; /* the processing is in the same process,
219 makes ub_cancel and ub_ctx_delete do the right thing */
220 ctx->event_base = ub_libevent_event_base(eb);
221 if (!ctx->event_base) {
222 ub_ctx_delete(ctx);
223 return NULL;
224 }
225 ctx->event_base_malloced = 1;
226 return ctx;
227 }
228
229 /** delete q */
230 static void
delq(rbnode_type * n,void * ATTR_UNUSED (arg))231 delq(rbnode_type* n, void* ATTR_UNUSED(arg))
232 {
233 struct ctx_query* q = (struct ctx_query*)n;
234 context_query_delete(q);
235 }
236
237 /** stop the bg thread */
ub_stop_bg(struct ub_ctx * ctx)238 static void ub_stop_bg(struct ub_ctx* ctx)
239 {
240 /* stop the bg thread */
241 lock_basic_lock(&ctx->cfglock);
242 if(ctx->created_bg) {
243 uint8_t* msg;
244 uint32_t len;
245 uint32_t cmd = UB_LIBCMD_QUIT;
246 lock_basic_unlock(&ctx->cfglock);
247 lock_basic_lock(&ctx->qqpipe_lock);
248 (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd,
249 (uint32_t)sizeof(cmd), 0);
250 lock_basic_unlock(&ctx->qqpipe_lock);
251 lock_basic_lock(&ctx->rrpipe_lock);
252 while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) {
253 /* discard all results except a quit confirm */
254 if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
255 free(msg);
256 break;
257 }
258 free(msg);
259 }
260 lock_basic_unlock(&ctx->rrpipe_lock);
261
262 /* if bg worker is a thread, wait for it to exit, so that all
263 * resources are really gone. */
264 lock_basic_lock(&ctx->cfglock);
265 if(ctx->dothread) {
266 lock_basic_unlock(&ctx->cfglock);
267 ub_thread_join(ctx->bg_tid);
268 } else {
269 lock_basic_unlock(&ctx->cfglock);
270 #ifndef UB_ON_WINDOWS
271 if(waitpid(ctx->bg_pid, NULL, 0) == -1) {
272 if(verbosity > 2)
273 log_err("waitpid: %s", strerror(errno));
274 }
275 #endif
276 }
277 }
278 else {
279 lock_basic_unlock(&ctx->cfglock);
280 }
281 }
282
283 void
ub_ctx_delete(struct ub_ctx * ctx)284 ub_ctx_delete(struct ub_ctx* ctx)
285 {
286 struct alloc_cache* a, *na;
287 int do_stop = 1;
288 if(!ctx) return;
289
290 /* see if bg thread is created and if threads have been killed */
291 /* no locks, because those may be held by terminated threads */
292 /* for processes the read pipe is closed and we see that on read */
293 #ifdef HAVE_PTHREAD
294 if(ctx->created_bg && ctx->dothread) {
295 if(pthread_kill(ctx->bg_tid, 0) == ESRCH) {
296 /* thread has been killed */
297 do_stop = 0;
298 }
299 }
300 #endif /* HAVE_PTHREAD */
301 if(do_stop)
302 ub_stop_bg(ctx);
303 libworker_delete_event(ctx->event_worker);
304
305 modstack_desetup(&ctx->mods, ctx->env);
306 a = ctx->alloc_list;
307 while(a) {
308 na = a->super;
309 a->super = &ctx->superalloc;
310 alloc_clear(a);
311 free(a);
312 a = na;
313 }
314 local_zones_delete(ctx->local_zones);
315 lock_basic_destroy(&ctx->qqpipe_lock);
316 lock_basic_destroy(&ctx->rrpipe_lock);
317 lock_basic_destroy(&ctx->cfglock);
318 tube_delete(ctx->qq_pipe);
319 tube_delete(ctx->rr_pipe);
320 if(ctx->env) {
321 slabhash_delete(ctx->env->msg_cache);
322 rrset_cache_delete(ctx->env->rrset_cache);
323 infra_delete(ctx->env->infra_cache);
324 config_delete(ctx->env->cfg);
325 edns_known_options_delete(ctx->env);
326 auth_zones_delete(ctx->env->auth_zones);
327 free(ctx->env);
328 }
329 ub_randfree(ctx->seed_rnd);
330 alloc_clear(&ctx->superalloc);
331 traverse_postorder(&ctx->queries, delq, NULL);
332 if(ctx_logfile_overridden) {
333 log_file(NULL);
334 ctx_logfile_overridden = 0;
335 }
336 if(ctx->event_base_malloced)
337 free(ctx->event_base);
338 free(ctx);
339 #ifdef USE_WINSOCK
340 WSACleanup();
341 #endif
342 }
343
344 int
ub_ctx_set_option(struct ub_ctx * ctx,const char * opt,const char * val)345 ub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val)
346 {
347 lock_basic_lock(&ctx->cfglock);
348 if(ctx->finalized) {
349 lock_basic_unlock(&ctx->cfglock);
350 return UB_AFTERFINAL;
351 }
352 if(!config_set_option(ctx->env->cfg, opt, val)) {
353 lock_basic_unlock(&ctx->cfglock);
354 return UB_SYNTAX;
355 }
356 lock_basic_unlock(&ctx->cfglock);
357 return UB_NOERROR;
358 }
359
360 int
ub_ctx_get_option(struct ub_ctx * ctx,const char * opt,char ** str)361 ub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str)
362 {
363 int r;
364 lock_basic_lock(&ctx->cfglock);
365 r = config_get_option_collate(ctx->env->cfg, opt, str);
366 lock_basic_unlock(&ctx->cfglock);
367 if(r == 0) r = UB_NOERROR;
368 else if(r == 1) r = UB_SYNTAX;
369 else if(r == 2) r = UB_NOMEM;
370 return r;
371 }
372
373 int
ub_ctx_config(struct ub_ctx * ctx,const char * fname)374 ub_ctx_config(struct ub_ctx* ctx, const char* fname)
375 {
376 lock_basic_lock(&ctx->cfglock);
377 if(ctx->finalized) {
378 lock_basic_unlock(&ctx->cfglock);
379 return UB_AFTERFINAL;
380 }
381 if(!config_read(ctx->env->cfg, fname, NULL)) {
382 lock_basic_unlock(&ctx->cfglock);
383 return UB_SYNTAX;
384 }
385 lock_basic_unlock(&ctx->cfglock);
386 return UB_NOERROR;
387 }
388
389 int
ub_ctx_add_ta(struct ub_ctx * ctx,const char * ta)390 ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta)
391 {
392 char* dup = strdup(ta);
393 if(!dup) return UB_NOMEM;
394 lock_basic_lock(&ctx->cfglock);
395 if(ctx->finalized) {
396 lock_basic_unlock(&ctx->cfglock);
397 free(dup);
398 return UB_AFTERFINAL;
399 }
400 if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
401 lock_basic_unlock(&ctx->cfglock);
402 return UB_NOMEM;
403 }
404 lock_basic_unlock(&ctx->cfglock);
405 return UB_NOERROR;
406 }
407
408 int
ub_ctx_add_ta_file(struct ub_ctx * ctx,const char * fname)409 ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname)
410 {
411 char* dup = strdup(fname);
412 if(!dup) return UB_NOMEM;
413 lock_basic_lock(&ctx->cfglock);
414 if(ctx->finalized) {
415 lock_basic_unlock(&ctx->cfglock);
416 free(dup);
417 return UB_AFTERFINAL;
418 }
419 if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
420 lock_basic_unlock(&ctx->cfglock);
421 return UB_NOMEM;
422 }
423 lock_basic_unlock(&ctx->cfglock);
424 return UB_NOERROR;
425 }
426
ub_ctx_add_ta_autr(struct ub_ctx * ctx,const char * fname)427 int ub_ctx_add_ta_autr(struct ub_ctx* ctx, const char* fname)
428 {
429 char* dup = strdup(fname);
430 if(!dup) return UB_NOMEM;
431 lock_basic_lock(&ctx->cfglock);
432 if(ctx->finalized) {
433 lock_basic_unlock(&ctx->cfglock);
434 free(dup);
435 return UB_AFTERFINAL;
436 }
437 if(!cfg_strlist_insert(&ctx->env->cfg->auto_trust_anchor_file_list,
438 dup)) {
439 lock_basic_unlock(&ctx->cfglock);
440 return UB_NOMEM;
441 }
442 lock_basic_unlock(&ctx->cfglock);
443 return UB_NOERROR;
444 }
445
446 int
ub_ctx_trustedkeys(struct ub_ctx * ctx,const char * fname)447 ub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname)
448 {
449 char* dup = strdup(fname);
450 if(!dup) return UB_NOMEM;
451 lock_basic_lock(&ctx->cfglock);
452 if(ctx->finalized) {
453 lock_basic_unlock(&ctx->cfglock);
454 free(dup);
455 return UB_AFTERFINAL;
456 }
457 if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
458 lock_basic_unlock(&ctx->cfglock);
459 return UB_NOMEM;
460 }
461 lock_basic_unlock(&ctx->cfglock);
462 return UB_NOERROR;
463 }
464
465 int
ub_ctx_debuglevel(struct ub_ctx * ctx,int d)466 ub_ctx_debuglevel(struct ub_ctx* ctx, int d)
467 {
468 lock_basic_lock(&ctx->cfglock);
469 verbosity = d;
470 ctx->env->cfg->verbosity = d;
471 lock_basic_unlock(&ctx->cfglock);
472 return UB_NOERROR;
473 }
474
ub_ctx_debugout(struct ub_ctx * ctx,void * out)475 int ub_ctx_debugout(struct ub_ctx* ctx, void* out)
476 {
477 lock_basic_lock(&ctx->cfglock);
478 log_file((FILE*)out);
479 ctx_logfile_overridden = 1;
480 ctx->logfile_override = 1;
481 ctx->log_out = out;
482 lock_basic_unlock(&ctx->cfglock);
483 return UB_NOERROR;
484 }
485
486 int
ub_ctx_async(struct ub_ctx * ctx,int dothread)487 ub_ctx_async(struct ub_ctx* ctx, int dothread)
488 {
489 #ifdef THREADS_DISABLED
490 if(dothread) /* cannot do threading */
491 return UB_NOERROR;
492 #endif
493 lock_basic_lock(&ctx->cfglock);
494 if(ctx->finalized) {
495 lock_basic_unlock(&ctx->cfglock);
496 return UB_AFTERFINAL;
497 }
498 ctx->dothread = dothread;
499 lock_basic_unlock(&ctx->cfglock);
500 return UB_NOERROR;
501 }
502
503 int
ub_poll(struct ub_ctx * ctx)504 ub_poll(struct ub_ctx* ctx)
505 {
506 /* no need to hold lock while testing for readability. */
507 return tube_poll(ctx->rr_pipe);
508 }
509
510 int
ub_fd(struct ub_ctx * ctx)511 ub_fd(struct ub_ctx* ctx)
512 {
513 return tube_read_fd(ctx->rr_pipe);
514 }
515
516 /** process answer from bg worker */
517 static int
process_answer_detail(struct ub_ctx * ctx,uint8_t * msg,uint32_t len,ub_callback_type * cb,void ** cbarg,int * err,struct ub_result ** res)518 process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
519 ub_callback_type* cb, void** cbarg, int* err,
520 struct ub_result** res)
521 {
522 struct ctx_query* q;
523 if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
524 log_err("error: bad data from bg worker %d",
525 (int)context_serial_getcmd(msg, len));
526 return 0;
527 }
528
529 lock_basic_lock(&ctx->cfglock);
530 q = context_deserialize_answer(ctx, msg, len, err);
531 if(!q) {
532 lock_basic_unlock(&ctx->cfglock);
533 /* probably simply the lookup that failed, i.e.
534 * response returned before cancel was sent out, so noerror */
535 return 1;
536 }
537 log_assert(q->async);
538
539 /* grab cb while locked */
540 if(q->cancelled) {
541 *cb = NULL;
542 *cbarg = NULL;
543 } else {
544 *cb = q->cb;
545 *cbarg = q->cb_arg;
546 }
547 if(*err) {
548 *res = NULL;
549 ub_resolve_free(q->res);
550 } else {
551 /* parse the message, extract rcode, fill result */
552 sldns_buffer* buf = sldns_buffer_new(q->msg_len);
553 struct regional* region = regional_create();
554 *res = q->res;
555 (*res)->rcode = LDNS_RCODE_SERVFAIL;
556 if(region && buf) {
557 sldns_buffer_clear(buf);
558 sldns_buffer_write(buf, q->msg, q->msg_len);
559 sldns_buffer_flip(buf);
560 libworker_enter_result(*res, buf, region,
561 q->msg_security);
562 }
563 (*res)->answer_packet = q->msg;
564 (*res)->answer_len = (int)q->msg_len;
565 q->msg = NULL;
566 sldns_buffer_free(buf);
567 regional_destroy(region);
568 }
569 q->res = NULL;
570 /* delete the q from list */
571 (void)rbtree_delete(&ctx->queries, q->node.key);
572 ctx->num_async--;
573 context_query_delete(q);
574 lock_basic_unlock(&ctx->cfglock);
575
576 if(*cb) return 2;
577 ub_resolve_free(*res);
578 return 1;
579 }
580
581 /** process answer from bg worker */
582 static int
process_answer(struct ub_ctx * ctx,uint8_t * msg,uint32_t len)583 process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len)
584 {
585 int err;
586 ub_callback_type cb;
587 void* cbarg;
588 struct ub_result* res;
589 int r;
590
591 r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res);
592
593 /* no locks held while calling callback, so that library is
594 * re-entrant. */
595 if(r == 2)
596 (*cb)(cbarg, err, res);
597
598 return r;
599 }
600
601 int
ub_process(struct ub_ctx * ctx)602 ub_process(struct ub_ctx* ctx)
603 {
604 int r;
605 uint8_t* msg;
606 uint32_t len;
607 while(1) {
608 msg = NULL;
609 lock_basic_lock(&ctx->rrpipe_lock);
610 r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
611 lock_basic_unlock(&ctx->rrpipe_lock);
612 if(r == 0)
613 return UB_PIPE;
614 else if(r == -1)
615 break;
616 if(!process_answer(ctx, msg, len)) {
617 free(msg);
618 return UB_PIPE;
619 }
620 free(msg);
621 }
622 return UB_NOERROR;
623 }
624
625 int
ub_wait(struct ub_ctx * ctx)626 ub_wait(struct ub_ctx* ctx)
627 {
628 int err;
629 ub_callback_type cb;
630 void* cbarg;
631 struct ub_result* res;
632 int r;
633 uint8_t* msg;
634 uint32_t len;
635 /* this is basically the same loop as _process(), but with changes.
636 * holds the rrpipe lock and waits with tube_wait */
637 while(1) {
638 lock_basic_lock(&ctx->rrpipe_lock);
639 lock_basic_lock(&ctx->cfglock);
640 if(ctx->num_async == 0) {
641 lock_basic_unlock(&ctx->cfglock);
642 lock_basic_unlock(&ctx->rrpipe_lock);
643 break;
644 }
645 lock_basic_unlock(&ctx->cfglock);
646
647 /* keep rrpipe locked, while
648 * o waiting for pipe readable
649 * o parsing message
650 * o possibly decrementing num_async
651 * do callback without lock
652 */
653 r = tube_wait(ctx->rr_pipe);
654 if(r) {
655 r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
656 if(r == 0) {
657 lock_basic_unlock(&ctx->rrpipe_lock);
658 return UB_PIPE;
659 }
660 if(r == -1) {
661 lock_basic_unlock(&ctx->rrpipe_lock);
662 continue;
663 }
664 r = process_answer_detail(ctx, msg, len,
665 &cb, &cbarg, &err, &res);
666 lock_basic_unlock(&ctx->rrpipe_lock);
667 free(msg);
668 if(r == 0)
669 return UB_PIPE;
670 if(r == 2)
671 (*cb)(cbarg, err, res);
672 } else {
673 lock_basic_unlock(&ctx->rrpipe_lock);
674 }
675 }
676 return UB_NOERROR;
677 }
678
679 int
ub_resolve(struct ub_ctx * ctx,const char * name,int rrtype,int rrclass,struct ub_result ** result)680 ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
681 int rrclass, struct ub_result** result)
682 {
683 struct ctx_query* q;
684 int r;
685 *result = NULL;
686
687 lock_basic_lock(&ctx->cfglock);
688 if(!ctx->finalized) {
689 r = context_finalize(ctx);
690 if(r) {
691 lock_basic_unlock(&ctx->cfglock);
692 return r;
693 }
694 }
695 /* create new ctx_query and attempt to add to the list */
696 lock_basic_unlock(&ctx->cfglock);
697 q = context_new(ctx, name, rrtype, rrclass, NULL, NULL, NULL);
698 if(!q)
699 return UB_NOMEM;
700 /* become a resolver thread for a bit */
701
702 r = libworker_fg(ctx, q);
703 if(r) {
704 lock_basic_lock(&ctx->cfglock);
705 (void)rbtree_delete(&ctx->queries, q->node.key);
706 context_query_delete(q);
707 lock_basic_unlock(&ctx->cfglock);
708 return r;
709 }
710 q->res->answer_packet = q->msg;
711 q->res->answer_len = (int)q->msg_len;
712 q->msg = NULL;
713 *result = q->res;
714 q->res = NULL;
715
716 lock_basic_lock(&ctx->cfglock);
717 (void)rbtree_delete(&ctx->queries, q->node.key);
718 context_query_delete(q);
719 lock_basic_unlock(&ctx->cfglock);
720 return UB_NOERROR;
721 }
722
723 int
ub_resolve_event(struct ub_ctx * ctx,const char * name,int rrtype,int rrclass,void * mydata,ub_event_callback_type callback,int * async_id)724 ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
725 int rrclass, void* mydata, ub_event_callback_type callback,
726 int* async_id)
727 {
728 struct ctx_query* q;
729 int r;
730
731 if(async_id)
732 *async_id = 0;
733 lock_basic_lock(&ctx->cfglock);
734 if(!ctx->finalized) {
735 r = context_finalize(ctx);
736 if(r) {
737 lock_basic_unlock(&ctx->cfglock);
738 return r;
739 }
740 }
741 lock_basic_unlock(&ctx->cfglock);
742 if(!ctx->event_worker) {
743 ctx->event_worker = libworker_create_event(ctx,
744 ctx->event_base);
745 if(!ctx->event_worker) {
746 return UB_INITFAIL;
747 }
748 }
749
750 /* set time in case answer comes from cache */
751 ub_comm_base_now(ctx->event_worker->base);
752
753 /* create new ctx_query and attempt to add to the list */
754 q = context_new(ctx, name, rrtype, rrclass, NULL, callback, mydata);
755 if(!q)
756 return UB_NOMEM;
757
758 /* attach to mesh */
759 if((r=libworker_attach_mesh(ctx, q, async_id)) != 0)
760 return r;
761 return UB_NOERROR;
762 }
763
764
765 int
ub_resolve_async(struct ub_ctx * ctx,const char * name,int rrtype,int rrclass,void * mydata,ub_callback_type callback,int * async_id)766 ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
767 int rrclass, void* mydata, ub_callback_type callback, int* async_id)
768 {
769 struct ctx_query* q;
770 uint8_t* msg = NULL;
771 uint32_t len = 0;
772
773 if(async_id)
774 *async_id = 0;
775 lock_basic_lock(&ctx->cfglock);
776 if(!ctx->finalized) {
777 int r = context_finalize(ctx);
778 if(r) {
779 lock_basic_unlock(&ctx->cfglock);
780 return r;
781 }
782 }
783 if(!ctx->created_bg) {
784 int r;
785 ctx->created_bg = 1;
786 lock_basic_unlock(&ctx->cfglock);
787 r = libworker_bg(ctx);
788 if(r) {
789 lock_basic_lock(&ctx->cfglock);
790 ctx->created_bg = 0;
791 lock_basic_unlock(&ctx->cfglock);
792 return r;
793 }
794 } else {
795 lock_basic_unlock(&ctx->cfglock);
796 }
797
798 /* create new ctx_query and attempt to add to the list */
799 q = context_new(ctx, name, rrtype, rrclass, callback, NULL, mydata);
800 if(!q)
801 return UB_NOMEM;
802
803 /* write over pipe to background worker */
804 lock_basic_lock(&ctx->cfglock);
805 msg = context_serialize_new_query(q, &len);
806 if(!msg) {
807 (void)rbtree_delete(&ctx->queries, q->node.key);
808 ctx->num_async--;
809 context_query_delete(q);
810 lock_basic_unlock(&ctx->cfglock);
811 return UB_NOMEM;
812 }
813 if(async_id)
814 *async_id = q->querynum;
815 lock_basic_unlock(&ctx->cfglock);
816
817 lock_basic_lock(&ctx->qqpipe_lock);
818 if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
819 lock_basic_unlock(&ctx->qqpipe_lock);
820 free(msg);
821 return UB_PIPE;
822 }
823 lock_basic_unlock(&ctx->qqpipe_lock);
824 free(msg);
825 return UB_NOERROR;
826 }
827
828 int
ub_cancel(struct ub_ctx * ctx,int async_id)829 ub_cancel(struct ub_ctx* ctx, int async_id)
830 {
831 struct ctx_query* q;
832 uint8_t* msg = NULL;
833 uint32_t len = 0;
834 lock_basic_lock(&ctx->cfglock);
835 q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
836 if(!q || !q->async) {
837 /* it is not there, so nothing to do */
838 lock_basic_unlock(&ctx->cfglock);
839 return UB_NOID;
840 }
841 log_assert(q->async);
842 q->cancelled = 1;
843
844 /* delete it */
845 if(!ctx->dothread) { /* if forked */
846 (void)rbtree_delete(&ctx->queries, q->node.key);
847 ctx->num_async--;
848 msg = context_serialize_cancel(q, &len);
849 context_query_delete(q);
850 lock_basic_unlock(&ctx->cfglock);
851 if(!msg) {
852 return UB_NOMEM;
853 }
854 /* send cancel to background worker */
855 lock_basic_lock(&ctx->qqpipe_lock);
856 if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
857 lock_basic_unlock(&ctx->qqpipe_lock);
858 free(msg);
859 return UB_PIPE;
860 }
861 lock_basic_unlock(&ctx->qqpipe_lock);
862 free(msg);
863 } else {
864 lock_basic_unlock(&ctx->cfglock);
865 }
866 return UB_NOERROR;
867 }
868
869 void
ub_resolve_free(struct ub_result * result)870 ub_resolve_free(struct ub_result* result)
871 {
872 char** p;
873 if(!result) return;
874 free(result->qname);
875 if(result->canonname != result->qname)
876 free(result->canonname);
877 if(result->data)
878 for(p = result->data; *p; p++)
879 free(*p);
880 free(result->data);
881 free(result->len);
882 free(result->answer_packet);
883 free(result->why_bogus);
884 free(result);
885 }
886
887 const char*
ub_strerror(int err)888 ub_strerror(int err)
889 {
890 switch(err) {
891 case UB_NOERROR: return "no error";
892 case UB_SOCKET: return "socket io error";
893 case UB_NOMEM: return "out of memory";
894 case UB_SYNTAX: return "syntax error";
895 case UB_SERVFAIL: return "server failure";
896 case UB_FORKFAIL: return "could not fork";
897 case UB_INITFAIL: return "initialization failure";
898 case UB_AFTERFINAL: return "setting change after finalize";
899 case UB_PIPE: return "error in pipe communication with async";
900 case UB_READFILE: return "error reading file";
901 case UB_NOID: return "error async_id does not exist";
902 default: return "unknown error";
903 }
904 }
905
906 int
ub_ctx_set_fwd(struct ub_ctx * ctx,const char * addr)907 ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
908 {
909 struct sockaddr_storage storage;
910 socklen_t stlen;
911 struct config_stub* s;
912 char* dupl;
913 lock_basic_lock(&ctx->cfglock);
914 if(ctx->finalized) {
915 lock_basic_unlock(&ctx->cfglock);
916 errno=EINVAL;
917 return UB_AFTERFINAL;
918 }
919 if(!addr) {
920 /* disable fwd mode - the root stub should be first. */
921 if(ctx->env->cfg->forwards &&
922 strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
923 s = ctx->env->cfg->forwards;
924 ctx->env->cfg->forwards = s->next;
925 s->next = NULL;
926 config_delstubs(s);
927 }
928 lock_basic_unlock(&ctx->cfglock);
929 return UB_NOERROR;
930 }
931 lock_basic_unlock(&ctx->cfglock);
932
933 /* check syntax for addr */
934 if(!extstrtoaddr(addr, &storage, &stlen)) {
935 errno=EINVAL;
936 return UB_SYNTAX;
937 }
938
939 /* it parses, add root stub in front of list */
940 lock_basic_lock(&ctx->cfglock);
941 if(!ctx->env->cfg->forwards ||
942 strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
943 s = calloc(1, sizeof(*s));
944 if(!s) {
945 lock_basic_unlock(&ctx->cfglock);
946 errno=ENOMEM;
947 return UB_NOMEM;
948 }
949 s->name = strdup(".");
950 if(!s->name) {
951 free(s);
952 lock_basic_unlock(&ctx->cfglock);
953 errno=ENOMEM;
954 return UB_NOMEM;
955 }
956 s->next = ctx->env->cfg->forwards;
957 ctx->env->cfg->forwards = s;
958 } else {
959 log_assert(ctx->env->cfg->forwards);
960 s = ctx->env->cfg->forwards;
961 }
962 dupl = strdup(addr);
963 if(!dupl) {
964 lock_basic_unlock(&ctx->cfglock);
965 errno=ENOMEM;
966 return UB_NOMEM;
967 }
968 if(!cfg_strlist_insert(&s->addrs, dupl)) {
969 lock_basic_unlock(&ctx->cfglock);
970 errno=ENOMEM;
971 return UB_NOMEM;
972 }
973 lock_basic_unlock(&ctx->cfglock);
974 return UB_NOERROR;
975 }
976
ub_ctx_set_tls(struct ub_ctx * ctx,int tls)977 int ub_ctx_set_tls(struct ub_ctx* ctx, int tls)
978 {
979 lock_basic_lock(&ctx->cfglock);
980 if(ctx->finalized) {
981 lock_basic_unlock(&ctx->cfglock);
982 errno=EINVAL;
983 return UB_AFTERFINAL;
984 }
985 ctx->env->cfg->ssl_upstream = tls;
986 lock_basic_unlock(&ctx->cfglock);
987 return UB_NOERROR;
988 }
989
ub_ctx_set_stub(struct ub_ctx * ctx,const char * zone,const char * addr,int isprime)990 int ub_ctx_set_stub(struct ub_ctx* ctx, const char* zone, const char* addr,
991 int isprime)
992 {
993 char* a;
994 struct config_stub **prev, *elem;
995
996 /* check syntax for zone name */
997 if(zone) {
998 uint8_t* nm;
999 int nmlabs;
1000 size_t nmlen;
1001 if(!parse_dname(zone, &nm, &nmlen, &nmlabs)) {
1002 errno=EINVAL;
1003 return UB_SYNTAX;
1004 }
1005 free(nm);
1006 } else {
1007 zone = ".";
1008 }
1009
1010 /* check syntax for addr (if not NULL) */
1011 if(addr) {
1012 struct sockaddr_storage storage;
1013 socklen_t stlen;
1014 if(!extstrtoaddr(addr, &storage, &stlen)) {
1015 errno=EINVAL;
1016 return UB_SYNTAX;
1017 }
1018 }
1019
1020 lock_basic_lock(&ctx->cfglock);
1021 if(ctx->finalized) {
1022 lock_basic_unlock(&ctx->cfglock);
1023 errno=EINVAL;
1024 return UB_AFTERFINAL;
1025 }
1026
1027 /* arguments all right, now find or add the stub */
1028 prev = &ctx->env->cfg->stubs;
1029 elem = cfg_stub_find(&prev, zone);
1030 if(!elem && !addr) {
1031 /* not found and we want to delete, nothing to do */
1032 lock_basic_unlock(&ctx->cfglock);
1033 return UB_NOERROR;
1034 } else if(elem && !addr) {
1035 /* found, and we want to delete */
1036 *prev = elem->next;
1037 config_delstub(elem);
1038 lock_basic_unlock(&ctx->cfglock);
1039 return UB_NOERROR;
1040 } else if(!elem) {
1041 /* not found, create the stub entry */
1042 elem=(struct config_stub*)calloc(1, sizeof(struct config_stub));
1043 if(elem) elem->name = strdup(zone);
1044 if(!elem || !elem->name) {
1045 free(elem);
1046 lock_basic_unlock(&ctx->cfglock);
1047 errno = ENOMEM;
1048 return UB_NOMEM;
1049 }
1050 elem->next = ctx->env->cfg->stubs;
1051 ctx->env->cfg->stubs = elem;
1052 }
1053
1054 /* add the address to the list and set settings */
1055 elem->isprime = isprime;
1056 a = strdup(addr);
1057 if(!a) {
1058 lock_basic_unlock(&ctx->cfglock);
1059 errno = ENOMEM;
1060 return UB_NOMEM;
1061 }
1062 if(!cfg_strlist_insert(&elem->addrs, a)) {
1063 lock_basic_unlock(&ctx->cfglock);
1064 errno = ENOMEM;
1065 return UB_NOMEM;
1066 }
1067 lock_basic_unlock(&ctx->cfglock);
1068 return UB_NOERROR;
1069 }
1070
1071 int
ub_ctx_resolvconf(struct ub_ctx * ctx,const char * fname)1072 ub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname)
1073 {
1074 FILE* in;
1075 int numserv = 0;
1076 char buf[1024];
1077 char* parse, *addr;
1078 int r;
1079
1080 if(fname == NULL) {
1081 #if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H)
1082 fname = "/etc/resolv.conf";
1083 #else
1084 FIXED_INFO *info;
1085 ULONG buflen = sizeof(*info);
1086 IP_ADDR_STRING *ptr;
1087
1088 info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
1089 if (info == NULL)
1090 return UB_READFILE;
1091
1092 if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) {
1093 free(info);
1094 info = (FIXED_INFO *) malloc(buflen);
1095 if (info == NULL)
1096 return UB_READFILE;
1097 }
1098
1099 if (GetNetworkParams(info, &buflen) == NO_ERROR) {
1100 int retval=0;
1101 ptr = &(info->DnsServerList);
1102 while (ptr) {
1103 numserv++;
1104 if((retval=ub_ctx_set_fwd(ctx,
1105 ptr->IpAddress.String))!=0) {
1106 free(info);
1107 return retval;
1108 }
1109 ptr = ptr->Next;
1110 }
1111 free(info);
1112 if (numserv==0)
1113 return UB_READFILE;
1114 return UB_NOERROR;
1115 }
1116 free(info);
1117 return UB_READFILE;
1118 #endif /* WINDOWS */
1119 }
1120 in = fopen(fname, "r");
1121 if(!in) {
1122 /* error in errno! perror(fname) */
1123 return UB_READFILE;
1124 }
1125 while(fgets(buf, (int)sizeof(buf), in)) {
1126 buf[sizeof(buf)-1] = 0;
1127 parse=buf;
1128 while(*parse == ' ' || *parse == '\t')
1129 parse++;
1130 if(strncmp(parse, "nameserver", 10) == 0) {
1131 numserv++;
1132 parse += 10; /* skip 'nameserver' */
1133 /* skip whitespace */
1134 while(*parse == ' ' || *parse == '\t')
1135 parse++;
1136 addr = parse;
1137 /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
1138 while(isxdigit((unsigned char)*parse) || *parse=='.' || *parse==':')
1139 parse++;
1140 /* terminate after the address, remove newline */
1141 *parse = 0;
1142
1143 if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
1144 fclose(in);
1145 return r;
1146 }
1147 }
1148 }
1149 fclose(in);
1150 if(numserv == 0) {
1151 /* from resolv.conf(5) if none given, use localhost */
1152 return ub_ctx_set_fwd(ctx, "127.0.0.1");
1153 }
1154 return UB_NOERROR;
1155 }
1156
1157 int
ub_ctx_hosts(struct ub_ctx * ctx,const char * fname)1158 ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
1159 {
1160 FILE* in;
1161 char buf[1024], ldata[2048];
1162 char* parse, *addr, *name, *ins;
1163 lock_basic_lock(&ctx->cfglock);
1164 if(ctx->finalized) {
1165 lock_basic_unlock(&ctx->cfglock);
1166 errno=EINVAL;
1167 return UB_AFTERFINAL;
1168 }
1169 lock_basic_unlock(&ctx->cfglock);
1170 if(fname == NULL) {
1171 #if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H)
1172 /*
1173 * If this is Windows NT/XP/2K it's in
1174 * %WINDIR%\system32\drivers\etc\hosts.
1175 * If this is Windows 95/98/Me it's in %WINDIR%\hosts.
1176 */
1177 name = getenv("WINDIR");
1178 if (name != NULL) {
1179 int retval=0;
1180 snprintf(buf, sizeof(buf), "%s%s", name,
1181 "\\system32\\drivers\\etc\\hosts");
1182 if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) {
1183 snprintf(buf, sizeof(buf), "%s%s", name,
1184 "\\hosts");
1185 retval=ub_ctx_hosts(ctx, buf);
1186 }
1187 return retval;
1188 }
1189 return UB_READFILE;
1190 #else
1191 fname = "/etc/hosts";
1192 #endif /* WIN32 */
1193 }
1194 in = fopen(fname, "r");
1195 if(!in) {
1196 /* error in errno! perror(fname) */
1197 return UB_READFILE;
1198 }
1199 while(fgets(buf, (int)sizeof(buf), in)) {
1200 buf[sizeof(buf)-1] = 0;
1201 parse=buf;
1202 while(*parse == ' ' || *parse == '\t')
1203 parse++;
1204 if(*parse == '#')
1205 continue; /* skip comment */
1206 /* format: <addr> spaces <name> spaces <name> ... */
1207 addr = parse;
1208 /* skip addr */
1209 while(isxdigit((unsigned char)*parse) || *parse == '.' || *parse == ':')
1210 parse++;
1211 if(*parse == '\r')
1212 parse++;
1213 if(*parse == '\n' || *parse == 0)
1214 continue;
1215 if(*parse == '%')
1216 continue; /* ignore macOSX fe80::1%lo0 localhost */
1217 if(*parse != ' ' && *parse != '\t') {
1218 /* must have whitespace after address */
1219 fclose(in);
1220 errno=EINVAL;
1221 return UB_SYNTAX;
1222 }
1223 *parse++ = 0; /* end delimiter for addr ... */
1224 /* go to names and add them */
1225 while(*parse) {
1226 while(*parse == ' ' || *parse == '\t' || *parse=='\n'
1227 || *parse=='\r')
1228 parse++;
1229 if(*parse == 0 || *parse == '#')
1230 break;
1231 /* skip name, allows (too) many printable characters */
1232 name = parse;
1233 while('!' <= *parse && *parse <= '~')
1234 parse++;
1235 if(*parse)
1236 *parse++ = 0; /* end delimiter for name */
1237 snprintf(ldata, sizeof(ldata), "%s %s %s",
1238 name, str_is_ip6(addr)?"AAAA":"A", addr);
1239 ins = strdup(ldata);
1240 if(!ins) {
1241 /* out of memory */
1242 fclose(in);
1243 errno=ENOMEM;
1244 return UB_NOMEM;
1245 }
1246 lock_basic_lock(&ctx->cfglock);
1247 if(!cfg_strlist_insert(&ctx->env->cfg->local_data,
1248 ins)) {
1249 lock_basic_unlock(&ctx->cfglock);
1250 fclose(in);
1251 errno=ENOMEM;
1252 return UB_NOMEM;
1253 }
1254 lock_basic_unlock(&ctx->cfglock);
1255 }
1256 }
1257 fclose(in);
1258 return UB_NOERROR;
1259 }
1260
1261 /** finalize the context, if not already finalized */
ub_ctx_finalize(struct ub_ctx * ctx)1262 static int ub_ctx_finalize(struct ub_ctx* ctx)
1263 {
1264 int res = 0;
1265 lock_basic_lock(&ctx->cfglock);
1266 if (!ctx->finalized) {
1267 res = context_finalize(ctx);
1268 }
1269 lock_basic_unlock(&ctx->cfglock);
1270 return res;
1271 }
1272
1273 /* Print local zones and RR data */
ub_ctx_print_local_zones(struct ub_ctx * ctx)1274 int ub_ctx_print_local_zones(struct ub_ctx* ctx)
1275 {
1276 int res = ub_ctx_finalize(ctx);
1277 if (res) return res;
1278
1279 local_zones_print(ctx->local_zones);
1280
1281 return UB_NOERROR;
1282 }
1283
1284 /* Add a new zone */
ub_ctx_zone_add(struct ub_ctx * ctx,const char * zone_name,const char * zone_type)1285 int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name,
1286 const char *zone_type)
1287 {
1288 enum localzone_type t;
1289 struct local_zone* z;
1290 uint8_t* nm;
1291 int nmlabs;
1292 size_t nmlen;
1293
1294 int res = ub_ctx_finalize(ctx);
1295 if (res) return res;
1296
1297 if(!local_zone_str2type(zone_type, &t)) {
1298 return UB_SYNTAX;
1299 }
1300
1301 if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1302 return UB_SYNTAX;
1303 }
1304
1305 lock_rw_wrlock(&ctx->local_zones->lock);
1306 if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
1307 LDNS_RR_CLASS_IN))) {
1308 /* already present in tree */
1309 lock_rw_wrlock(&z->lock);
1310 z->type = t; /* update type anyway */
1311 lock_rw_unlock(&z->lock);
1312 lock_rw_unlock(&ctx->local_zones->lock);
1313 free(nm);
1314 return UB_NOERROR;
1315 }
1316 if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs,
1317 LDNS_RR_CLASS_IN, t)) {
1318 lock_rw_unlock(&ctx->local_zones->lock);
1319 return UB_NOMEM;
1320 }
1321 lock_rw_unlock(&ctx->local_zones->lock);
1322 return UB_NOERROR;
1323 }
1324
1325 /* Remove zone */
ub_ctx_zone_remove(struct ub_ctx * ctx,const char * zone_name)1326 int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name)
1327 {
1328 struct local_zone* z;
1329 uint8_t* nm;
1330 int nmlabs;
1331 size_t nmlen;
1332
1333 int res = ub_ctx_finalize(ctx);
1334 if (res) return res;
1335
1336 if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1337 return UB_SYNTAX;
1338 }
1339
1340 lock_rw_wrlock(&ctx->local_zones->lock);
1341 if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
1342 LDNS_RR_CLASS_IN))) {
1343 /* present in tree */
1344 local_zones_del_zone(ctx->local_zones, z);
1345 }
1346 lock_rw_unlock(&ctx->local_zones->lock);
1347 free(nm);
1348 return UB_NOERROR;
1349 }
1350
1351 /* Add new RR data */
ub_ctx_data_add(struct ub_ctx * ctx,const char * data)1352 int ub_ctx_data_add(struct ub_ctx* ctx, const char *data)
1353 {
1354 int res = ub_ctx_finalize(ctx);
1355 if (res) return res;
1356
1357 res = local_zones_add_RR(ctx->local_zones, data);
1358 return (!res) ? UB_NOMEM : UB_NOERROR;
1359 }
1360
1361 /* Remove RR data */
ub_ctx_data_remove(struct ub_ctx * ctx,const char * data)1362 int ub_ctx_data_remove(struct ub_ctx* ctx, const char *data)
1363 {
1364 uint8_t* nm;
1365 int nmlabs;
1366 size_t nmlen;
1367 int res = ub_ctx_finalize(ctx);
1368 if (res) return res;
1369
1370 if(!parse_dname(data, &nm, &nmlen, &nmlabs))
1371 return UB_SYNTAX;
1372
1373 local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs,
1374 LDNS_RR_CLASS_IN);
1375
1376 free(nm);
1377 return UB_NOERROR;
1378 }
1379
ub_version(void)1380 const char* ub_version(void)
1381 {
1382 return PACKAGE_VERSION;
1383 }
1384
1385 int
ub_ctx_set_event(struct ub_ctx * ctx,struct event_base * base)1386 ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
1387 struct ub_event_base* new_base;
1388
1389 if (!ctx || !ctx->event_base || !base) {
1390 return UB_INITFAIL;
1391 }
1392 if (ub_libevent_get_event_base(ctx->event_base) == base) {
1393 /* already set */
1394 return UB_NOERROR;
1395 }
1396
1397 lock_basic_lock(&ctx->cfglock);
1398 /* destroy the current worker - safe to pass in NULL */
1399 libworker_delete_event(ctx->event_worker);
1400 ctx->event_worker = NULL;
1401 new_base = ub_libevent_event_base(base);
1402 if (new_base)
1403 ctx->event_base = new_base;
1404 ctx->created_bg = 0;
1405 ctx->dothread = 1;
1406 lock_basic_unlock(&ctx->cfglock);
1407 return new_base ? UB_NOERROR : UB_INITFAIL;
1408 }
1409