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 */ 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* 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* 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* 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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* 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 1380 const char* ub_version(void) 1381 { 1382 return PACKAGE_VERSION; 1383 } 1384 1385 int 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