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