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 LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains functions to resolve DNS queries and 40 * validate the answers. Synchonously 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 "config.h" 47 #include <ctype.h> 48 #include "libunbound/context.h" 49 #include "libunbound/libworker.h" 50 #include "util/locks.h" 51 #include "util/config_file.h" 52 #include "util/alloc.h" 53 #include "util/module.h" 54 #include "util/regional.h" 55 #include "util/log.h" 56 #include "util/random.h" 57 #include "util/net_help.h" 58 #include "util/tube.h" 59 #include "services/modstack.h" 60 #include "services/localzone.h" 61 #include "services/cache/infra.h" 62 #include "services/cache/rrset.h" 63 64 #if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H) 65 #include <windows.h> 66 #include <iphlpapi.h> 67 #endif /* UB_ON_WINDOWS */ 68 69 struct ub_ctx* 70 ub_ctx_create(void) 71 { 72 struct ub_ctx* ctx; 73 unsigned int seed; 74 #ifdef USE_WINSOCK 75 int r; 76 WSADATA wsa_data; 77 #endif 78 79 log_init(NULL, 0, NULL); /* logs to stderr */ 80 log_ident_set("libunbound"); 81 #ifdef USE_WINSOCK 82 if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { 83 log_err("could not init winsock. WSAStartup: %s", 84 wsa_strerror(r)); 85 return NULL; 86 } 87 #endif 88 verbosity = 0; /* errors only */ 89 checklock_start(); 90 ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx)); 91 if(!ctx) { 92 errno = ENOMEM; 93 return NULL; 94 } 95 alloc_init(&ctx->superalloc, NULL, 0); 96 seed = (unsigned int)time(NULL) ^ (unsigned int)getpid(); 97 if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) { 98 seed = 0; 99 ub_randfree(ctx->seed_rnd); 100 free(ctx); 101 errno = ENOMEM; 102 return NULL; 103 } 104 seed = 0; 105 if((ctx->qq_pipe = tube_create()) == NULL) { 106 int e = errno; 107 ub_randfree(ctx->seed_rnd); 108 free(ctx); 109 errno = e; 110 return NULL; 111 } 112 if((ctx->rr_pipe = tube_create()) == NULL) { 113 int e = errno; 114 tube_delete(ctx->qq_pipe); 115 ub_randfree(ctx->seed_rnd); 116 free(ctx); 117 errno = e; 118 return NULL; 119 } 120 lock_basic_init(&ctx->qqpipe_lock); 121 lock_basic_init(&ctx->rrpipe_lock); 122 lock_basic_init(&ctx->cfglock); 123 ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env)); 124 if(!ctx->env) { 125 tube_delete(ctx->qq_pipe); 126 tube_delete(ctx->rr_pipe); 127 ub_randfree(ctx->seed_rnd); 128 free(ctx); 129 errno = ENOMEM; 130 return NULL; 131 } 132 ctx->env->cfg = config_create_forlib(); 133 if(!ctx->env->cfg) { 134 tube_delete(ctx->qq_pipe); 135 tube_delete(ctx->rr_pipe); 136 free(ctx->env); 137 ub_randfree(ctx->seed_rnd); 138 free(ctx); 139 errno = ENOMEM; 140 return NULL; 141 } 142 ctx->env->alloc = &ctx->superalloc; 143 ctx->env->worker = NULL; 144 ctx->env->need_to_validate = 0; 145 modstack_init(&ctx->mods); 146 rbtree_init(&ctx->queries, &context_query_cmp); 147 return ctx; 148 } 149 150 /** delete q */ 151 static void 152 delq(rbnode_t* n, void* ATTR_UNUSED(arg)) 153 { 154 struct ctx_query* q = (struct ctx_query*)n; 155 context_query_delete(q); 156 } 157 158 void 159 ub_ctx_delete(struct ub_ctx* ctx) 160 { 161 struct alloc_cache* a, *na; 162 if(!ctx) return; 163 /* stop the bg thread */ 164 lock_basic_lock(&ctx->cfglock); 165 if(ctx->created_bg) { 166 uint8_t* msg; 167 uint32_t len; 168 uint32_t cmd = UB_LIBCMD_QUIT; 169 lock_basic_unlock(&ctx->cfglock); 170 lock_basic_lock(&ctx->qqpipe_lock); 171 (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, 172 (uint32_t)sizeof(cmd), 0); 173 lock_basic_unlock(&ctx->qqpipe_lock); 174 lock_basic_lock(&ctx->rrpipe_lock); 175 while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) { 176 /* discard all results except a quit confirm */ 177 if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) { 178 free(msg); 179 break; 180 } 181 free(msg); 182 } 183 lock_basic_unlock(&ctx->rrpipe_lock); 184 185 /* if bg worker is a thread, wait for it to exit, so that all 186 * resources are really gone. */ 187 lock_basic_lock(&ctx->cfglock); 188 if(ctx->dothread) { 189 lock_basic_unlock(&ctx->cfglock); 190 ub_thread_join(ctx->bg_tid); 191 } else { 192 lock_basic_unlock(&ctx->cfglock); 193 } 194 } 195 else { 196 lock_basic_unlock(&ctx->cfglock); 197 } 198 199 200 modstack_desetup(&ctx->mods, ctx->env); 201 a = ctx->alloc_list; 202 while(a) { 203 na = a->super; 204 a->super = &ctx->superalloc; 205 alloc_clear(a); 206 free(a); 207 a = na; 208 } 209 local_zones_delete(ctx->local_zones); 210 lock_basic_destroy(&ctx->qqpipe_lock); 211 lock_basic_destroy(&ctx->rrpipe_lock); 212 lock_basic_destroy(&ctx->cfglock); 213 tube_delete(ctx->qq_pipe); 214 tube_delete(ctx->rr_pipe); 215 if(ctx->env) { 216 slabhash_delete(ctx->env->msg_cache); 217 rrset_cache_delete(ctx->env->rrset_cache); 218 infra_delete(ctx->env->infra_cache); 219 config_delete(ctx->env->cfg); 220 free(ctx->env); 221 } 222 ub_randfree(ctx->seed_rnd); 223 alloc_clear(&ctx->superalloc); 224 traverse_postorder(&ctx->queries, delq, NULL); 225 free(ctx); 226 #ifdef USE_WINSOCK 227 WSACleanup(); 228 #endif 229 } 230 231 int 232 ub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val) 233 { 234 lock_basic_lock(&ctx->cfglock); 235 if(ctx->finalized) { 236 lock_basic_unlock(&ctx->cfglock); 237 return UB_AFTERFINAL; 238 } 239 if(!config_set_option(ctx->env->cfg, opt, val)) { 240 lock_basic_unlock(&ctx->cfglock); 241 return UB_SYNTAX; 242 } 243 lock_basic_unlock(&ctx->cfglock); 244 return UB_NOERROR; 245 } 246 247 int 248 ub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str) 249 { 250 int r; 251 lock_basic_lock(&ctx->cfglock); 252 r = config_get_option_collate(ctx->env->cfg, opt, str); 253 lock_basic_unlock(&ctx->cfglock); 254 if(r == 0) r = UB_NOERROR; 255 else if(r == 1) r = UB_SYNTAX; 256 else if(r == 2) r = UB_NOMEM; 257 return r; 258 } 259 260 int 261 ub_ctx_config(struct ub_ctx* ctx, const char* fname) 262 { 263 lock_basic_lock(&ctx->cfglock); 264 if(ctx->finalized) { 265 lock_basic_unlock(&ctx->cfglock); 266 return UB_AFTERFINAL; 267 } 268 if(!config_read(ctx->env->cfg, fname, NULL)) { 269 lock_basic_unlock(&ctx->cfglock); 270 return UB_SYNTAX; 271 } 272 lock_basic_unlock(&ctx->cfglock); 273 return UB_NOERROR; 274 } 275 276 int 277 ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta) 278 { 279 char* dup = strdup(ta); 280 if(!dup) return UB_NOMEM; 281 lock_basic_lock(&ctx->cfglock); 282 if(ctx->finalized) { 283 lock_basic_unlock(&ctx->cfglock); 284 free(dup); 285 return UB_AFTERFINAL; 286 } 287 if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { 288 lock_basic_unlock(&ctx->cfglock); 289 free(dup); 290 return UB_NOMEM; 291 } 292 lock_basic_unlock(&ctx->cfglock); 293 return UB_NOERROR; 294 } 295 296 int 297 ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname) 298 { 299 char* dup = strdup(fname); 300 if(!dup) return UB_NOMEM; 301 lock_basic_lock(&ctx->cfglock); 302 if(ctx->finalized) { 303 lock_basic_unlock(&ctx->cfglock); 304 free(dup); 305 return UB_AFTERFINAL; 306 } 307 if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) { 308 lock_basic_unlock(&ctx->cfglock); 309 free(dup); 310 return UB_NOMEM; 311 } 312 lock_basic_unlock(&ctx->cfglock); 313 return UB_NOERROR; 314 } 315 316 int 317 ub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname) 318 { 319 char* dup = strdup(fname); 320 if(!dup) return UB_NOMEM; 321 lock_basic_lock(&ctx->cfglock); 322 if(ctx->finalized) { 323 lock_basic_unlock(&ctx->cfglock); 324 free(dup); 325 return UB_AFTERFINAL; 326 } 327 if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) { 328 lock_basic_unlock(&ctx->cfglock); 329 free(dup); 330 return UB_NOMEM; 331 } 332 lock_basic_unlock(&ctx->cfglock); 333 return UB_NOERROR; 334 } 335 336 int 337 ub_ctx_debuglevel(struct ub_ctx* ctx, int d) 338 { 339 lock_basic_lock(&ctx->cfglock); 340 verbosity = d; 341 ctx->env->cfg->verbosity = d; 342 lock_basic_unlock(&ctx->cfglock); 343 return UB_NOERROR; 344 } 345 346 int ub_ctx_debugout(struct ub_ctx* ctx, void* out) 347 { 348 lock_basic_lock(&ctx->cfglock); 349 log_file((FILE*)out); 350 ctx->logfile_override = 1; 351 ctx->log_out = out; 352 lock_basic_unlock(&ctx->cfglock); 353 return UB_NOERROR; 354 } 355 356 int 357 ub_ctx_async(struct ub_ctx* ctx, int dothread) 358 { 359 #ifdef THREADS_DISABLED 360 if(dothread) /* cannot do threading */ 361 return UB_NOERROR; 362 #endif 363 lock_basic_lock(&ctx->cfglock); 364 if(ctx->finalized) { 365 lock_basic_unlock(&ctx->cfglock); 366 return UB_AFTERFINAL; 367 } 368 ctx->dothread = dothread; 369 lock_basic_unlock(&ctx->cfglock); 370 return UB_NOERROR; 371 } 372 373 int 374 ub_poll(struct ub_ctx* ctx) 375 { 376 /* no need to hold lock while testing for readability. */ 377 return tube_poll(ctx->rr_pipe); 378 } 379 380 int 381 ub_fd(struct ub_ctx* ctx) 382 { 383 return tube_read_fd(ctx->rr_pipe); 384 } 385 386 /** process answer from bg worker */ 387 static int 388 process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, 389 ub_callback_t* cb, void** cbarg, int* err, 390 struct ub_result** res) 391 { 392 struct ctx_query* q; 393 if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { 394 log_err("error: bad data from bg worker %d", 395 (int)context_serial_getcmd(msg, len)); 396 return 0; 397 } 398 399 lock_basic_lock(&ctx->cfglock); 400 q = context_deserialize_answer(ctx, msg, len, err); 401 if(!q) { 402 lock_basic_unlock(&ctx->cfglock); 403 /* probably simply the lookup that failed, i.e. 404 * response returned before cancel was sent out, so noerror */ 405 return 1; 406 } 407 log_assert(q->async); 408 409 /* grab cb while locked */ 410 if(q->cancelled) { 411 *cb = NULL; 412 *cbarg = NULL; 413 } else { 414 *cb = q->cb; 415 *cbarg = q->cb_arg; 416 } 417 if(*err) { 418 *res = NULL; 419 ub_resolve_free(q->res); 420 } else { 421 /* parse the message, extract rcode, fill result */ 422 ldns_buffer* buf = ldns_buffer_new(q->msg_len); 423 struct regional* region = regional_create(); 424 *res = q->res; 425 (*res)->rcode = LDNS_RCODE_SERVFAIL; 426 if(region && buf) { 427 ldns_buffer_clear(buf); 428 ldns_buffer_write(buf, q->msg, q->msg_len); 429 ldns_buffer_flip(buf); 430 libworker_enter_result(*res, buf, region, 431 q->msg_security); 432 } 433 (*res)->answer_packet = q->msg; 434 (*res)->answer_len = (int)q->msg_len; 435 q->msg = NULL; 436 ldns_buffer_free(buf); 437 regional_destroy(region); 438 } 439 q->res = NULL; 440 /* delete the q from list */ 441 (void)rbtree_delete(&ctx->queries, q->node.key); 442 ctx->num_async--; 443 context_query_delete(q); 444 lock_basic_unlock(&ctx->cfglock); 445 446 if(*cb) return 2; 447 ub_resolve_free(*res); 448 return 1; 449 } 450 451 /** process answer from bg worker */ 452 static int 453 process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len) 454 { 455 int err; 456 ub_callback_t cb; 457 void* cbarg; 458 struct ub_result* res; 459 int r; 460 461 r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); 462 463 /* no locks held while calling callback, so that library is 464 * re-entrant. */ 465 if(r == 2) 466 (*cb)(cbarg, err, res); 467 468 return r; 469 } 470 471 int 472 ub_process(struct ub_ctx* ctx) 473 { 474 int r; 475 uint8_t* msg; 476 uint32_t len; 477 while(1) { 478 msg = NULL; 479 lock_basic_lock(&ctx->rrpipe_lock); 480 r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 481 lock_basic_unlock(&ctx->rrpipe_lock); 482 if(r == 0) 483 return UB_PIPE; 484 else if(r == -1) 485 break; 486 if(!process_answer(ctx, msg, len)) { 487 free(msg); 488 return UB_PIPE; 489 } 490 free(msg); 491 } 492 return UB_NOERROR; 493 } 494 495 int 496 ub_wait(struct ub_ctx* ctx) 497 { 498 int err; 499 ub_callback_t cb; 500 void* cbarg; 501 struct ub_result* res; 502 int r; 503 uint8_t* msg; 504 uint32_t len; 505 /* this is basically the same loop as _process(), but with changes. 506 * holds the rrpipe lock and waits with tube_wait */ 507 while(1) { 508 lock_basic_lock(&ctx->rrpipe_lock); 509 lock_basic_lock(&ctx->cfglock); 510 if(ctx->num_async == 0) { 511 lock_basic_unlock(&ctx->cfglock); 512 lock_basic_unlock(&ctx->rrpipe_lock); 513 break; 514 } 515 lock_basic_unlock(&ctx->cfglock); 516 517 /* keep rrpipe locked, while 518 * o waiting for pipe readable 519 * o parsing message 520 * o possibly decrementing num_async 521 * do callback without lock 522 */ 523 r = tube_wait(ctx->rr_pipe); 524 if(r) { 525 r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 526 if(r == 0) { 527 lock_basic_unlock(&ctx->rrpipe_lock); 528 return UB_PIPE; 529 } 530 if(r == -1) { 531 lock_basic_unlock(&ctx->rrpipe_lock); 532 continue; 533 } 534 r = process_answer_detail(ctx, msg, len, 535 &cb, &cbarg, &err, &res); 536 lock_basic_unlock(&ctx->rrpipe_lock); 537 free(msg); 538 if(r == 0) 539 return UB_PIPE; 540 if(r == 2) 541 (*cb)(cbarg, err, res); 542 } else { 543 lock_basic_unlock(&ctx->rrpipe_lock); 544 } 545 } 546 return UB_NOERROR; 547 } 548 549 int 550 ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, 551 int rrclass, struct ub_result** result) 552 { 553 struct ctx_query* q; 554 int r; 555 *result = NULL; 556 557 lock_basic_lock(&ctx->cfglock); 558 if(!ctx->finalized) { 559 r = context_finalize(ctx); 560 if(r) { 561 lock_basic_unlock(&ctx->cfglock); 562 return r; 563 } 564 } 565 /* create new ctx_query and attempt to add to the list */ 566 lock_basic_unlock(&ctx->cfglock); 567 q = context_new(ctx, name, rrtype, rrclass, NULL, NULL); 568 if(!q) 569 return UB_NOMEM; 570 /* become a resolver thread for a bit */ 571 572 r = libworker_fg(ctx, q); 573 if(r) { 574 lock_basic_lock(&ctx->cfglock); 575 (void)rbtree_delete(&ctx->queries, q->node.key); 576 context_query_delete(q); 577 lock_basic_unlock(&ctx->cfglock); 578 return r; 579 } 580 q->res->answer_packet = q->msg; 581 q->res->answer_len = (int)q->msg_len; 582 q->msg = NULL; 583 *result = q->res; 584 q->res = NULL; 585 586 lock_basic_lock(&ctx->cfglock); 587 (void)rbtree_delete(&ctx->queries, q->node.key); 588 context_query_delete(q); 589 lock_basic_unlock(&ctx->cfglock); 590 return UB_NOERROR; 591 } 592 593 int 594 ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, 595 int rrclass, void* mydata, ub_callback_t callback, int* async_id) 596 { 597 struct ctx_query* q; 598 uint8_t* msg = NULL; 599 uint32_t len = 0; 600 601 if(async_id) 602 *async_id = 0; 603 lock_basic_lock(&ctx->cfglock); 604 if(!ctx->finalized) { 605 int r = context_finalize(ctx); 606 if(r) { 607 lock_basic_unlock(&ctx->cfglock); 608 return r; 609 } 610 } 611 if(!ctx->created_bg) { 612 int r; 613 ctx->created_bg = 1; 614 lock_basic_unlock(&ctx->cfglock); 615 r = libworker_bg(ctx); 616 if(r) { 617 lock_basic_lock(&ctx->cfglock); 618 ctx->created_bg = 0; 619 lock_basic_unlock(&ctx->cfglock); 620 return r; 621 } 622 } else { 623 lock_basic_unlock(&ctx->cfglock); 624 } 625 626 /* create new ctx_query and attempt to add to the list */ 627 q = context_new(ctx, name, rrtype, rrclass, callback, mydata); 628 if(!q) 629 return UB_NOMEM; 630 631 /* write over pipe to background worker */ 632 lock_basic_lock(&ctx->cfglock); 633 msg = context_serialize_new_query(q, &len); 634 if(!msg) { 635 (void)rbtree_delete(&ctx->queries, q->node.key); 636 ctx->num_async--; 637 context_query_delete(q); 638 lock_basic_unlock(&ctx->cfglock); 639 return UB_NOMEM; 640 } 641 if(async_id) 642 *async_id = q->querynum; 643 lock_basic_unlock(&ctx->cfglock); 644 645 lock_basic_lock(&ctx->qqpipe_lock); 646 if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 647 lock_basic_unlock(&ctx->qqpipe_lock); 648 free(msg); 649 return UB_PIPE; 650 } 651 lock_basic_unlock(&ctx->qqpipe_lock); 652 free(msg); 653 return UB_NOERROR; 654 } 655 656 int 657 ub_cancel(struct ub_ctx* ctx, int async_id) 658 { 659 struct ctx_query* q; 660 uint8_t* msg = NULL; 661 uint32_t len = 0; 662 lock_basic_lock(&ctx->cfglock); 663 q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id); 664 if(!q || !q->async) { 665 /* it is not there, so nothing to do */ 666 lock_basic_unlock(&ctx->cfglock); 667 return UB_NOID; 668 } 669 log_assert(q->async); 670 q->cancelled = 1; 671 672 /* delete it */ 673 if(!ctx->dothread) { /* if forked */ 674 (void)rbtree_delete(&ctx->queries, q->node.key); 675 ctx->num_async--; 676 msg = context_serialize_cancel(q, &len); 677 context_query_delete(q); 678 lock_basic_unlock(&ctx->cfglock); 679 if(!msg) { 680 return UB_NOMEM; 681 } 682 /* send cancel to background worker */ 683 lock_basic_lock(&ctx->qqpipe_lock); 684 if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 685 lock_basic_unlock(&ctx->qqpipe_lock); 686 free(msg); 687 return UB_PIPE; 688 } 689 lock_basic_unlock(&ctx->qqpipe_lock); 690 free(msg); 691 } else { 692 lock_basic_unlock(&ctx->cfglock); 693 } 694 return UB_NOERROR; 695 } 696 697 void 698 ub_resolve_free(struct ub_result* result) 699 { 700 char** p; 701 if(!result) return; 702 free(result->qname); 703 if(result->canonname != result->qname) 704 free(result->canonname); 705 if(result->data) 706 for(p = result->data; *p; p++) 707 free(*p); 708 free(result->data); 709 free(result->len); 710 free(result->answer_packet); 711 free(result->why_bogus); 712 free(result); 713 } 714 715 const char* 716 ub_strerror(int err) 717 { 718 switch(err) { 719 case UB_NOERROR: return "no error"; 720 case UB_SOCKET: return "socket io error"; 721 case UB_NOMEM: return "out of memory"; 722 case UB_SYNTAX: return "syntax error"; 723 case UB_SERVFAIL: return "server failure"; 724 case UB_FORKFAIL: return "could not fork"; 725 case UB_INITFAIL: return "initialization failure"; 726 case UB_AFTERFINAL: return "setting change after finalize"; 727 case UB_PIPE: return "error in pipe communication with async"; 728 case UB_READFILE: return "error reading file"; 729 case UB_NOID: return "error async_id does not exist"; 730 default: return "unknown error"; 731 } 732 } 733 734 int 735 ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr) 736 { 737 struct sockaddr_storage storage; 738 socklen_t stlen; 739 struct config_stub* s; 740 char* dupl; 741 lock_basic_lock(&ctx->cfglock); 742 if(ctx->finalized) { 743 lock_basic_unlock(&ctx->cfglock); 744 errno=EINVAL; 745 return UB_AFTERFINAL; 746 } 747 if(!addr) { 748 /* disable fwd mode - the root stub should be first. */ 749 if(ctx->env->cfg->forwards && 750 strcmp(ctx->env->cfg->forwards->name, ".") == 0) { 751 s = ctx->env->cfg->forwards; 752 ctx->env->cfg->forwards = s->next; 753 s->next = NULL; 754 config_delstubs(s); 755 } 756 lock_basic_unlock(&ctx->cfglock); 757 return UB_NOERROR; 758 } 759 lock_basic_unlock(&ctx->cfglock); 760 761 /* check syntax for addr */ 762 if(!extstrtoaddr(addr, &storage, &stlen)) { 763 errno=EINVAL; 764 return UB_SYNTAX; 765 } 766 767 /* it parses, add root stub in front of list */ 768 lock_basic_lock(&ctx->cfglock); 769 if(!ctx->env->cfg->forwards || 770 strcmp(ctx->env->cfg->forwards->name, ".") != 0) { 771 s = calloc(1, sizeof(*s)); 772 if(!s) { 773 lock_basic_unlock(&ctx->cfglock); 774 errno=ENOMEM; 775 return UB_NOMEM; 776 } 777 s->name = strdup("."); 778 if(!s->name) { 779 free(s); 780 lock_basic_unlock(&ctx->cfglock); 781 errno=ENOMEM; 782 return UB_NOMEM; 783 } 784 s->next = ctx->env->cfg->forwards; 785 ctx->env->cfg->forwards = s; 786 } else { 787 log_assert(ctx->env->cfg->forwards); 788 s = ctx->env->cfg->forwards; 789 } 790 dupl = strdup(addr); 791 if(!dupl) { 792 lock_basic_unlock(&ctx->cfglock); 793 errno=ENOMEM; 794 return UB_NOMEM; 795 } 796 if(!cfg_strlist_insert(&s->addrs, dupl)) { 797 free(dupl); 798 lock_basic_unlock(&ctx->cfglock); 799 errno=ENOMEM; 800 return UB_NOMEM; 801 } 802 lock_basic_unlock(&ctx->cfglock); 803 return UB_NOERROR; 804 } 805 806 int 807 ub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname) 808 { 809 FILE* in; 810 int numserv = 0; 811 char buf[1024]; 812 char* parse, *addr; 813 int r; 814 815 if(fname == NULL) { 816 #if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H) 817 fname = "/etc/resolv.conf"; 818 #else 819 FIXED_INFO *info; 820 ULONG buflen = sizeof(*info); 821 IP_ADDR_STRING *ptr; 822 823 info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO)); 824 if (info == NULL) 825 return UB_READFILE; 826 827 if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { 828 free(info); 829 info = (FIXED_INFO *) malloc(buflen); 830 if (info == NULL) 831 return UB_READFILE; 832 } 833 834 if (GetNetworkParams(info, &buflen) == NO_ERROR) { 835 int retval=0; 836 ptr = &(info->DnsServerList); 837 while (ptr) { 838 numserv++; 839 if((retval=ub_ctx_set_fwd(ctx, 840 ptr->IpAddress.String)!=0)) { 841 free(info); 842 return retval; 843 } 844 ptr = ptr->Next; 845 } 846 free(info); 847 if (numserv==0) 848 return UB_READFILE; 849 return UB_NOERROR; 850 } 851 free(info); 852 return UB_READFILE; 853 #endif /* WINDOWS */ 854 } 855 in = fopen(fname, "r"); 856 if(!in) { 857 /* error in errno! perror(fname) */ 858 return UB_READFILE; 859 } 860 while(fgets(buf, (int)sizeof(buf), in)) { 861 buf[sizeof(buf)-1] = 0; 862 parse=buf; 863 while(*parse == ' ' || *parse == '\t') 864 parse++; 865 if(strncmp(parse, "nameserver", 10) == 0) { 866 numserv++; 867 parse += 10; /* skip 'nameserver' */ 868 /* skip whitespace */ 869 while(*parse == ' ' || *parse == '\t') 870 parse++; 871 addr = parse; 872 /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */ 873 while(isxdigit(*parse) || *parse=='.' || *parse==':') 874 parse++; 875 /* terminate after the address, remove newline */ 876 *parse = 0; 877 878 if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) { 879 fclose(in); 880 return r; 881 } 882 } 883 } 884 fclose(in); 885 if(numserv == 0) { 886 /* from resolv.conf(5) if none given, use localhost */ 887 return ub_ctx_set_fwd(ctx, "127.0.0.1"); 888 } 889 return UB_NOERROR; 890 } 891 892 int 893 ub_ctx_hosts(struct ub_ctx* ctx, const char* fname) 894 { 895 FILE* in; 896 char buf[1024], ldata[1024]; 897 char* parse, *addr, *name, *ins; 898 lock_basic_lock(&ctx->cfglock); 899 if(ctx->finalized) { 900 lock_basic_unlock(&ctx->cfglock); 901 errno=EINVAL; 902 return UB_AFTERFINAL; 903 } 904 lock_basic_unlock(&ctx->cfglock); 905 if(fname == NULL) { 906 #if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H) 907 /* 908 * If this is Windows NT/XP/2K it's in 909 * %WINDIR%\system32\drivers\etc\hosts. 910 * If this is Windows 95/98/Me it's in %WINDIR%\hosts. 911 */ 912 name = getenv("WINDIR"); 913 if (name != NULL) { 914 int retval=0; 915 snprintf(buf, sizeof(buf), "%s%s", name, 916 "\\system32\\drivers\\etc\\hosts"); 917 if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) { 918 snprintf(buf, sizeof(buf), "%s%s", name, 919 "\\hosts"); 920 retval=ub_ctx_hosts(ctx, buf); 921 } 922 free(name); 923 return retval; 924 } 925 return UB_READFILE; 926 #else 927 fname = "/etc/hosts"; 928 #endif /* WIN32 */ 929 } 930 in = fopen(fname, "r"); 931 if(!in) { 932 /* error in errno! perror(fname) */ 933 return UB_READFILE; 934 } 935 while(fgets(buf, (int)sizeof(buf), in)) { 936 buf[sizeof(buf)-1] = 0; 937 parse=buf; 938 while(*parse == ' ' || *parse == '\t') 939 parse++; 940 if(*parse == '#') 941 continue; /* skip comment */ 942 /* format: <addr> spaces <name> spaces <name> ... */ 943 addr = parse; 944 /* skip addr */ 945 while(isxdigit(*parse) || *parse == '.' || *parse == ':') 946 parse++; 947 if(*parse == '\n' || *parse == 0) 948 continue; 949 if(*parse == '%') 950 continue; /* ignore macOSX fe80::1%lo0 localhost */ 951 if(*parse != ' ' && *parse != '\t') { 952 /* must have whitespace after address */ 953 fclose(in); 954 errno=EINVAL; 955 return UB_SYNTAX; 956 } 957 *parse++ = 0; /* end delimiter for addr ... */ 958 /* go to names and add them */ 959 while(*parse) { 960 while(*parse == ' ' || *parse == '\t' || *parse=='\n') 961 parse++; 962 if(*parse == 0 || *parse == '#') 963 break; 964 /* skip name, allows (too) many printable characters */ 965 name = parse; 966 while('!' <= *parse && *parse <= '~') 967 parse++; 968 if(*parse) 969 *parse++ = 0; /* end delimiter for name */ 970 snprintf(ldata, sizeof(ldata), "%s %s %s", 971 name, str_is_ip6(addr)?"AAAA":"A", addr); 972 ins = strdup(ldata); 973 if(!ins) { 974 /* out of memory */ 975 fclose(in); 976 errno=ENOMEM; 977 return UB_NOMEM; 978 } 979 lock_basic_lock(&ctx->cfglock); 980 if(!cfg_strlist_insert(&ctx->env->cfg->local_data, 981 ins)) { 982 lock_basic_unlock(&ctx->cfglock); 983 fclose(in); 984 free(ins); 985 errno=ENOMEM; 986 return UB_NOMEM; 987 } 988 lock_basic_unlock(&ctx->cfglock); 989 } 990 } 991 fclose(in); 992 return UB_NOERROR; 993 } 994 995 /** finalize the context, if not already finalized */ 996 static int ub_ctx_finalize(struct ub_ctx* ctx) 997 { 998 int res = 0; 999 lock_basic_lock(&ctx->cfglock); 1000 if (!ctx->finalized) { 1001 res = context_finalize(ctx); 1002 } 1003 lock_basic_unlock(&ctx->cfglock); 1004 return res; 1005 } 1006 1007 /* Print local zones and RR data */ 1008 int ub_ctx_print_local_zones(struct ub_ctx* ctx) 1009 { 1010 int res = ub_ctx_finalize(ctx); 1011 if (res) return res; 1012 1013 local_zones_print(ctx->local_zones); 1014 1015 return UB_NOERROR; 1016 } 1017 1018 /* Add a new zone */ 1019 int ub_ctx_zone_add(struct ub_ctx* ctx, char *zone_name, char *zone_type) 1020 { 1021 enum localzone_type t; 1022 struct local_zone* z; 1023 uint8_t* nm; 1024 int nmlabs; 1025 size_t nmlen; 1026 1027 int res = ub_ctx_finalize(ctx); 1028 if (res) return res; 1029 1030 if(!local_zone_str2type(zone_type, &t)) { 1031 return UB_SYNTAX; 1032 } 1033 1034 if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1035 return UB_SYNTAX; 1036 } 1037 1038 lock_quick_lock(&ctx->local_zones->lock); 1039 if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1040 LDNS_RR_CLASS_IN))) { 1041 /* already present in tree */ 1042 lock_rw_wrlock(&z->lock); 1043 z->type = t; /* update type anyway */ 1044 lock_rw_unlock(&z->lock); 1045 lock_quick_unlock(&ctx->local_zones->lock); 1046 free(nm); 1047 return UB_NOERROR; 1048 } 1049 if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, 1050 LDNS_RR_CLASS_IN, t)) { 1051 lock_quick_unlock(&ctx->local_zones->lock); 1052 return UB_NOMEM; 1053 } 1054 lock_quick_unlock(&ctx->local_zones->lock); 1055 return UB_NOERROR; 1056 } 1057 1058 /* Remove zone */ 1059 int ub_ctx_zone_remove(struct ub_ctx* ctx, char *zone_name) 1060 { 1061 struct local_zone* z; 1062 uint8_t* nm; 1063 int nmlabs; 1064 size_t nmlen; 1065 1066 int res = ub_ctx_finalize(ctx); 1067 if (res) return res; 1068 1069 if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1070 return UB_SYNTAX; 1071 } 1072 1073 lock_quick_lock(&ctx->local_zones->lock); 1074 if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1075 LDNS_RR_CLASS_IN))) { 1076 /* present in tree */ 1077 local_zones_del_zone(ctx->local_zones, z); 1078 } 1079 lock_quick_unlock(&ctx->local_zones->lock); 1080 free(nm); 1081 return UB_NOERROR; 1082 } 1083 1084 /* Add new RR data */ 1085 int ub_ctx_data_add(struct ub_ctx* ctx, char *data) 1086 { 1087 ldns_buffer* buf; 1088 int res = ub_ctx_finalize(ctx); 1089 if (res) return res; 1090 1091 lock_basic_lock(&ctx->cfglock); 1092 buf = ldns_buffer_new(ctx->env->cfg->msg_buffer_size); 1093 lock_basic_unlock(&ctx->cfglock); 1094 if(!buf) return UB_NOMEM; 1095 1096 res = local_zones_add_RR(ctx->local_zones, data, buf); 1097 1098 ldns_buffer_free(buf); 1099 return (!res) ? UB_NOMEM : UB_NOERROR; 1100 } 1101 1102 /* Remove RR data */ 1103 int ub_ctx_data_remove(struct ub_ctx* ctx, char *data) 1104 { 1105 uint8_t* nm; 1106 int nmlabs; 1107 size_t nmlen; 1108 int res = ub_ctx_finalize(ctx); 1109 if (res) return res; 1110 1111 if(!parse_dname(data, &nm, &nmlen, &nmlabs)) 1112 return UB_SYNTAX; 1113 1114 local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs, 1115 LDNS_RR_CLASS_IN); 1116 1117 free(nm); 1118 return UB_NOERROR; 1119 } 1120 1121 const char* ub_version(void) 1122 { 1123 return PACKAGE_VERSION; 1124 } 1125