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