1238106Sdes/* 2238106Sdes * unbound.c - unbound validating resolver public API implementation 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains functions to resolve DNS queries and 40238106Sdes * validate the answers. Synchonously and asynchronously. 41238106Sdes * 42238106Sdes */ 43238106Sdes 44238106Sdes/* include the public api first, it should be able to stand alone */ 45238106Sdes#include "libunbound/unbound.h" 46269257Sdes#include "libunbound/unbound-event.h" 47238106Sdes#include "config.h" 48238106Sdes#include <ctype.h> 49238106Sdes#include "libunbound/context.h" 50238106Sdes#include "libunbound/libworker.h" 51238106Sdes#include "util/locks.h" 52238106Sdes#include "util/config_file.h" 53238106Sdes#include "util/alloc.h" 54238106Sdes#include "util/module.h" 55238106Sdes#include "util/regional.h" 56238106Sdes#include "util/log.h" 57238106Sdes#include "util/random.h" 58238106Sdes#include "util/net_help.h" 59238106Sdes#include "util/tube.h" 60238106Sdes#include "services/modstack.h" 61238106Sdes#include "services/localzone.h" 62238106Sdes#include "services/cache/infra.h" 63238106Sdes#include "services/cache/rrset.h" 64269257Sdes#include "ldns/sbuffer.h" 65269257Sdes#ifdef HAVE_PTHREAD 66269257Sdes#include <signal.h> 67269257Sdes#endif 68238106Sdes 69238106Sdes#if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H) 70238106Sdes#include <windows.h> 71238106Sdes#include <iphlpapi.h> 72238106Sdes#endif /* UB_ON_WINDOWS */ 73238106Sdes 74269257Sdes/** create context functionality, but no pipes */ 75269257Sdesstatic struct ub_ctx* ub_ctx_create_nopipe(void) 76238106Sdes{ 77238106Sdes struct ub_ctx* ctx; 78238106Sdes unsigned int seed; 79238106Sdes#ifdef USE_WINSOCK 80238106Sdes int r; 81238106Sdes WSADATA wsa_data; 82238106Sdes#endif 83238106Sdes 84238106Sdes log_init(NULL, 0, NULL); /* logs to stderr */ 85238106Sdes log_ident_set("libunbound"); 86238106Sdes#ifdef USE_WINSOCK 87238106Sdes if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { 88238106Sdes log_err("could not init winsock. WSAStartup: %s", 89238106Sdes wsa_strerror(r)); 90238106Sdes return NULL; 91238106Sdes } 92238106Sdes#endif 93238106Sdes verbosity = 0; /* errors only */ 94238106Sdes checklock_start(); 95238106Sdes ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx)); 96238106Sdes if(!ctx) { 97238106Sdes errno = ENOMEM; 98238106Sdes return NULL; 99238106Sdes } 100238106Sdes alloc_init(&ctx->superalloc, NULL, 0); 101238106Sdes seed = (unsigned int)time(NULL) ^ (unsigned int)getpid(); 102238106Sdes if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) { 103238106Sdes seed = 0; 104238106Sdes ub_randfree(ctx->seed_rnd); 105238106Sdes free(ctx); 106238106Sdes errno = ENOMEM; 107238106Sdes return NULL; 108238106Sdes } 109238106Sdes seed = 0; 110238106Sdes lock_basic_init(&ctx->qqpipe_lock); 111238106Sdes lock_basic_init(&ctx->rrpipe_lock); 112238106Sdes lock_basic_init(&ctx->cfglock); 113238106Sdes ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env)); 114238106Sdes if(!ctx->env) { 115238106Sdes ub_randfree(ctx->seed_rnd); 116238106Sdes free(ctx); 117238106Sdes errno = ENOMEM; 118238106Sdes return NULL; 119238106Sdes } 120238106Sdes ctx->env->cfg = config_create_forlib(); 121238106Sdes if(!ctx->env->cfg) { 122238106Sdes free(ctx->env); 123238106Sdes ub_randfree(ctx->seed_rnd); 124238106Sdes free(ctx); 125238106Sdes errno = ENOMEM; 126238106Sdes return NULL; 127238106Sdes } 128238106Sdes ctx->env->alloc = &ctx->superalloc; 129238106Sdes ctx->env->worker = NULL; 130238106Sdes ctx->env->need_to_validate = 0; 131238106Sdes modstack_init(&ctx->mods); 132238106Sdes rbtree_init(&ctx->queries, &context_query_cmp); 133238106Sdes return ctx; 134238106Sdes} 135238106Sdes 136269257Sdesstruct ub_ctx* 137269257Sdesub_ctx_create(void) 138269257Sdes{ 139269257Sdes struct ub_ctx* ctx = ub_ctx_create_nopipe(); 140269257Sdes if(!ctx) 141269257Sdes return NULL; 142269257Sdes if((ctx->qq_pipe = tube_create()) == NULL) { 143269257Sdes int e = errno; 144269257Sdes ub_randfree(ctx->seed_rnd); 145269257Sdes config_delete(ctx->env->cfg); 146269257Sdes modstack_desetup(&ctx->mods, ctx->env); 147269257Sdes free(ctx->env); 148269257Sdes free(ctx); 149269257Sdes errno = e; 150269257Sdes return NULL; 151269257Sdes } 152269257Sdes if((ctx->rr_pipe = tube_create()) == NULL) { 153269257Sdes int e = errno; 154269257Sdes tube_delete(ctx->qq_pipe); 155269257Sdes ub_randfree(ctx->seed_rnd); 156269257Sdes config_delete(ctx->env->cfg); 157269257Sdes modstack_desetup(&ctx->mods, ctx->env); 158269257Sdes free(ctx->env); 159269257Sdes free(ctx); 160269257Sdes errno = e; 161269257Sdes return NULL; 162269257Sdes } 163269257Sdes return ctx; 164269257Sdes} 165269257Sdes 166269257Sdesstruct ub_ctx* 167269257Sdesub_ctx_create_event(struct event_base* eb) 168269257Sdes{ 169269257Sdes struct ub_ctx* ctx = ub_ctx_create_nopipe(); 170269257Sdes if(!ctx) 171269257Sdes return NULL; 172269257Sdes /* no pipes, but we have the locks to make sure everything works */ 173269257Sdes ctx->created_bg = 0; 174269257Sdes ctx->dothread = 1; /* the processing is in the same process, 175269257Sdes makes ub_cancel and ub_ctx_delete do the right thing */ 176269257Sdes ctx->event_base = eb; 177269257Sdes return ctx; 178269257Sdes} 179269257Sdes 180238106Sdes/** delete q */ 181238106Sdesstatic void 182238106Sdesdelq(rbnode_t* n, void* ATTR_UNUSED(arg)) 183238106Sdes{ 184238106Sdes struct ctx_query* q = (struct ctx_query*)n; 185238106Sdes context_query_delete(q); 186238106Sdes} 187238106Sdes 188269257Sdes/** stop the bg thread */ 189269257Sdesstatic void ub_stop_bg(struct ub_ctx* ctx) 190238106Sdes{ 191238106Sdes /* stop the bg thread */ 192238106Sdes lock_basic_lock(&ctx->cfglock); 193238106Sdes if(ctx->created_bg) { 194238106Sdes uint8_t* msg; 195238106Sdes uint32_t len; 196238106Sdes uint32_t cmd = UB_LIBCMD_QUIT; 197238106Sdes lock_basic_unlock(&ctx->cfglock); 198238106Sdes lock_basic_lock(&ctx->qqpipe_lock); 199238106Sdes (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, 200238106Sdes (uint32_t)sizeof(cmd), 0); 201238106Sdes lock_basic_unlock(&ctx->qqpipe_lock); 202238106Sdes lock_basic_lock(&ctx->rrpipe_lock); 203238106Sdes while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) { 204238106Sdes /* discard all results except a quit confirm */ 205238106Sdes if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) { 206238106Sdes free(msg); 207238106Sdes break; 208238106Sdes } 209238106Sdes free(msg); 210238106Sdes } 211238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 212238106Sdes 213238106Sdes /* if bg worker is a thread, wait for it to exit, so that all 214238106Sdes * resources are really gone. */ 215238106Sdes lock_basic_lock(&ctx->cfglock); 216238106Sdes if(ctx->dothread) { 217238106Sdes lock_basic_unlock(&ctx->cfglock); 218238106Sdes ub_thread_join(ctx->bg_tid); 219238106Sdes } else { 220238106Sdes lock_basic_unlock(&ctx->cfglock); 221238106Sdes } 222238106Sdes } 223238106Sdes else { 224238106Sdes lock_basic_unlock(&ctx->cfglock); 225238106Sdes } 226269257Sdes} 227238106Sdes 228269257Sdesvoid 229269257Sdesub_ctx_delete(struct ub_ctx* ctx) 230269257Sdes{ 231269257Sdes struct alloc_cache* a, *na; 232269257Sdes int do_stop = 1; 233269257Sdes if(!ctx) return; 234238106Sdes 235269257Sdes /* see if bg thread is created and if threads have been killed */ 236269257Sdes /* no locks, because those may be held by terminated threads */ 237269257Sdes /* for processes the read pipe is closed and we see that on read */ 238269257Sdes#ifdef HAVE_PTHREAD 239269257Sdes if(ctx->created_bg && ctx->dothread) { 240269257Sdes if(pthread_kill(ctx->bg_tid, 0) == ESRCH) { 241269257Sdes /* thread has been killed */ 242269257Sdes do_stop = 0; 243269257Sdes } 244269257Sdes } 245269257Sdes#endif /* HAVE_PTHREAD */ 246269257Sdes if(do_stop) 247269257Sdes ub_stop_bg(ctx); 248269257Sdes libworker_delete_event(ctx->event_worker); 249269257Sdes 250238106Sdes modstack_desetup(&ctx->mods, ctx->env); 251238106Sdes a = ctx->alloc_list; 252238106Sdes while(a) { 253238106Sdes na = a->super; 254238106Sdes a->super = &ctx->superalloc; 255238106Sdes alloc_clear(a); 256238106Sdes free(a); 257238106Sdes a = na; 258238106Sdes } 259238106Sdes local_zones_delete(ctx->local_zones); 260238106Sdes lock_basic_destroy(&ctx->qqpipe_lock); 261238106Sdes lock_basic_destroy(&ctx->rrpipe_lock); 262238106Sdes lock_basic_destroy(&ctx->cfglock); 263238106Sdes tube_delete(ctx->qq_pipe); 264238106Sdes tube_delete(ctx->rr_pipe); 265238106Sdes if(ctx->env) { 266238106Sdes slabhash_delete(ctx->env->msg_cache); 267238106Sdes rrset_cache_delete(ctx->env->rrset_cache); 268238106Sdes infra_delete(ctx->env->infra_cache); 269238106Sdes config_delete(ctx->env->cfg); 270238106Sdes free(ctx->env); 271238106Sdes } 272238106Sdes ub_randfree(ctx->seed_rnd); 273238106Sdes alloc_clear(&ctx->superalloc); 274238106Sdes traverse_postorder(&ctx->queries, delq, NULL); 275238106Sdes free(ctx); 276238106Sdes#ifdef USE_WINSOCK 277238106Sdes WSACleanup(); 278238106Sdes#endif 279238106Sdes} 280238106Sdes 281238106Sdesint 282255584Sdesub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val) 283238106Sdes{ 284238106Sdes lock_basic_lock(&ctx->cfglock); 285238106Sdes if(ctx->finalized) { 286238106Sdes lock_basic_unlock(&ctx->cfglock); 287238106Sdes return UB_AFTERFINAL; 288238106Sdes } 289238106Sdes if(!config_set_option(ctx->env->cfg, opt, val)) { 290238106Sdes lock_basic_unlock(&ctx->cfglock); 291238106Sdes return UB_SYNTAX; 292238106Sdes } 293238106Sdes lock_basic_unlock(&ctx->cfglock); 294238106Sdes return UB_NOERROR; 295238106Sdes} 296238106Sdes 297238106Sdesint 298255584Sdesub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str) 299238106Sdes{ 300238106Sdes int r; 301238106Sdes lock_basic_lock(&ctx->cfglock); 302238106Sdes r = config_get_option_collate(ctx->env->cfg, opt, str); 303238106Sdes lock_basic_unlock(&ctx->cfglock); 304238106Sdes if(r == 0) r = UB_NOERROR; 305238106Sdes else if(r == 1) r = UB_SYNTAX; 306238106Sdes else if(r == 2) r = UB_NOMEM; 307238106Sdes return r; 308238106Sdes} 309238106Sdes 310238106Sdesint 311255584Sdesub_ctx_config(struct ub_ctx* ctx, const char* fname) 312238106Sdes{ 313238106Sdes lock_basic_lock(&ctx->cfglock); 314238106Sdes if(ctx->finalized) { 315238106Sdes lock_basic_unlock(&ctx->cfglock); 316238106Sdes return UB_AFTERFINAL; 317238106Sdes } 318238106Sdes if(!config_read(ctx->env->cfg, fname, NULL)) { 319238106Sdes lock_basic_unlock(&ctx->cfglock); 320238106Sdes return UB_SYNTAX; 321238106Sdes } 322238106Sdes lock_basic_unlock(&ctx->cfglock); 323238106Sdes return UB_NOERROR; 324238106Sdes} 325238106Sdes 326238106Sdesint 327255584Sdesub_ctx_add_ta(struct ub_ctx* ctx, const char* ta) 328238106Sdes{ 329238106Sdes char* dup = strdup(ta); 330238106Sdes if(!dup) return UB_NOMEM; 331238106Sdes lock_basic_lock(&ctx->cfglock); 332238106Sdes if(ctx->finalized) { 333238106Sdes lock_basic_unlock(&ctx->cfglock); 334238106Sdes free(dup); 335238106Sdes return UB_AFTERFINAL; 336238106Sdes } 337238106Sdes if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { 338238106Sdes lock_basic_unlock(&ctx->cfglock); 339238106Sdes free(dup); 340238106Sdes return UB_NOMEM; 341238106Sdes } 342238106Sdes lock_basic_unlock(&ctx->cfglock); 343238106Sdes return UB_NOERROR; 344238106Sdes} 345238106Sdes 346238106Sdesint 347255584Sdesub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname) 348238106Sdes{ 349238106Sdes char* dup = strdup(fname); 350238106Sdes if(!dup) return UB_NOMEM; 351238106Sdes lock_basic_lock(&ctx->cfglock); 352238106Sdes if(ctx->finalized) { 353238106Sdes lock_basic_unlock(&ctx->cfglock); 354238106Sdes free(dup); 355238106Sdes return UB_AFTERFINAL; 356238106Sdes } 357238106Sdes if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) { 358238106Sdes lock_basic_unlock(&ctx->cfglock); 359238106Sdes free(dup); 360238106Sdes return UB_NOMEM; 361238106Sdes } 362238106Sdes lock_basic_unlock(&ctx->cfglock); 363238106Sdes return UB_NOERROR; 364238106Sdes} 365238106Sdes 366238106Sdesint 367255584Sdesub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname) 368238106Sdes{ 369238106Sdes char* dup = strdup(fname); 370238106Sdes if(!dup) return UB_NOMEM; 371238106Sdes lock_basic_lock(&ctx->cfglock); 372238106Sdes if(ctx->finalized) { 373238106Sdes lock_basic_unlock(&ctx->cfglock); 374238106Sdes free(dup); 375238106Sdes return UB_AFTERFINAL; 376238106Sdes } 377238106Sdes if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) { 378238106Sdes lock_basic_unlock(&ctx->cfglock); 379238106Sdes free(dup); 380238106Sdes return UB_NOMEM; 381238106Sdes } 382238106Sdes lock_basic_unlock(&ctx->cfglock); 383238106Sdes return UB_NOERROR; 384238106Sdes} 385238106Sdes 386238106Sdesint 387238106Sdesub_ctx_debuglevel(struct ub_ctx* ctx, int d) 388238106Sdes{ 389238106Sdes lock_basic_lock(&ctx->cfglock); 390238106Sdes verbosity = d; 391238106Sdes ctx->env->cfg->verbosity = d; 392238106Sdes lock_basic_unlock(&ctx->cfglock); 393238106Sdes return UB_NOERROR; 394238106Sdes} 395238106Sdes 396238106Sdesint ub_ctx_debugout(struct ub_ctx* ctx, void* out) 397238106Sdes{ 398238106Sdes lock_basic_lock(&ctx->cfglock); 399238106Sdes log_file((FILE*)out); 400238106Sdes ctx->logfile_override = 1; 401238106Sdes ctx->log_out = out; 402238106Sdes lock_basic_unlock(&ctx->cfglock); 403238106Sdes return UB_NOERROR; 404238106Sdes} 405238106Sdes 406238106Sdesint 407238106Sdesub_ctx_async(struct ub_ctx* ctx, int dothread) 408238106Sdes{ 409238106Sdes#ifdef THREADS_DISABLED 410238106Sdes if(dothread) /* cannot do threading */ 411238106Sdes return UB_NOERROR; 412238106Sdes#endif 413238106Sdes lock_basic_lock(&ctx->cfglock); 414238106Sdes if(ctx->finalized) { 415238106Sdes lock_basic_unlock(&ctx->cfglock); 416238106Sdes return UB_AFTERFINAL; 417238106Sdes } 418238106Sdes ctx->dothread = dothread; 419238106Sdes lock_basic_unlock(&ctx->cfglock); 420238106Sdes return UB_NOERROR; 421238106Sdes} 422238106Sdes 423238106Sdesint 424238106Sdesub_poll(struct ub_ctx* ctx) 425238106Sdes{ 426238106Sdes /* no need to hold lock while testing for readability. */ 427238106Sdes return tube_poll(ctx->rr_pipe); 428238106Sdes} 429238106Sdes 430238106Sdesint 431238106Sdesub_fd(struct ub_ctx* ctx) 432238106Sdes{ 433238106Sdes return tube_read_fd(ctx->rr_pipe); 434238106Sdes} 435238106Sdes 436238106Sdes/** process answer from bg worker */ 437238106Sdesstatic int 438238106Sdesprocess_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, 439238106Sdes ub_callback_t* cb, void** cbarg, int* err, 440238106Sdes struct ub_result** res) 441238106Sdes{ 442238106Sdes struct ctx_query* q; 443238106Sdes if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { 444238106Sdes log_err("error: bad data from bg worker %d", 445238106Sdes (int)context_serial_getcmd(msg, len)); 446238106Sdes return 0; 447238106Sdes } 448238106Sdes 449238106Sdes lock_basic_lock(&ctx->cfglock); 450238106Sdes q = context_deserialize_answer(ctx, msg, len, err); 451238106Sdes if(!q) { 452238106Sdes lock_basic_unlock(&ctx->cfglock); 453238106Sdes /* probably simply the lookup that failed, i.e. 454238106Sdes * response returned before cancel was sent out, so noerror */ 455238106Sdes return 1; 456238106Sdes } 457238106Sdes log_assert(q->async); 458238106Sdes 459238106Sdes /* grab cb while locked */ 460238106Sdes if(q->cancelled) { 461238106Sdes *cb = NULL; 462238106Sdes *cbarg = NULL; 463238106Sdes } else { 464238106Sdes *cb = q->cb; 465238106Sdes *cbarg = q->cb_arg; 466238106Sdes } 467238106Sdes if(*err) { 468238106Sdes *res = NULL; 469238106Sdes ub_resolve_free(q->res); 470238106Sdes } else { 471238106Sdes /* parse the message, extract rcode, fill result */ 472269257Sdes sldns_buffer* buf = sldns_buffer_new(q->msg_len); 473238106Sdes struct regional* region = regional_create(); 474238106Sdes *res = q->res; 475238106Sdes (*res)->rcode = LDNS_RCODE_SERVFAIL; 476238106Sdes if(region && buf) { 477269257Sdes sldns_buffer_clear(buf); 478269257Sdes sldns_buffer_write(buf, q->msg, q->msg_len); 479269257Sdes sldns_buffer_flip(buf); 480238106Sdes libworker_enter_result(*res, buf, region, 481238106Sdes q->msg_security); 482238106Sdes } 483238106Sdes (*res)->answer_packet = q->msg; 484238106Sdes (*res)->answer_len = (int)q->msg_len; 485238106Sdes q->msg = NULL; 486269257Sdes sldns_buffer_free(buf); 487238106Sdes regional_destroy(region); 488238106Sdes } 489238106Sdes q->res = NULL; 490238106Sdes /* delete the q from list */ 491238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 492238106Sdes ctx->num_async--; 493238106Sdes context_query_delete(q); 494238106Sdes lock_basic_unlock(&ctx->cfglock); 495238106Sdes 496238106Sdes if(*cb) return 2; 497238106Sdes ub_resolve_free(*res); 498238106Sdes return 1; 499238106Sdes} 500238106Sdes 501238106Sdes/** process answer from bg worker */ 502238106Sdesstatic int 503238106Sdesprocess_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len) 504238106Sdes{ 505238106Sdes int err; 506238106Sdes ub_callback_t cb; 507238106Sdes void* cbarg; 508238106Sdes struct ub_result* res; 509238106Sdes int r; 510238106Sdes 511238106Sdes r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); 512238106Sdes 513238106Sdes /* no locks held while calling callback, so that library is 514238106Sdes * re-entrant. */ 515238106Sdes if(r == 2) 516238106Sdes (*cb)(cbarg, err, res); 517238106Sdes 518238106Sdes return r; 519238106Sdes} 520238106Sdes 521238106Sdesint 522238106Sdesub_process(struct ub_ctx* ctx) 523238106Sdes{ 524238106Sdes int r; 525238106Sdes uint8_t* msg; 526238106Sdes uint32_t len; 527238106Sdes while(1) { 528238106Sdes msg = NULL; 529238106Sdes lock_basic_lock(&ctx->rrpipe_lock); 530238106Sdes r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 531238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 532238106Sdes if(r == 0) 533238106Sdes return UB_PIPE; 534238106Sdes else if(r == -1) 535238106Sdes break; 536238106Sdes if(!process_answer(ctx, msg, len)) { 537238106Sdes free(msg); 538238106Sdes return UB_PIPE; 539238106Sdes } 540238106Sdes free(msg); 541238106Sdes } 542238106Sdes return UB_NOERROR; 543238106Sdes} 544238106Sdes 545238106Sdesint 546238106Sdesub_wait(struct ub_ctx* ctx) 547238106Sdes{ 548238106Sdes int err; 549238106Sdes ub_callback_t cb; 550238106Sdes void* cbarg; 551238106Sdes struct ub_result* res; 552238106Sdes int r; 553238106Sdes uint8_t* msg; 554238106Sdes uint32_t len; 555238106Sdes /* this is basically the same loop as _process(), but with changes. 556238106Sdes * holds the rrpipe lock and waits with tube_wait */ 557238106Sdes while(1) { 558238106Sdes lock_basic_lock(&ctx->rrpipe_lock); 559238106Sdes lock_basic_lock(&ctx->cfglock); 560238106Sdes if(ctx->num_async == 0) { 561238106Sdes lock_basic_unlock(&ctx->cfglock); 562238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 563238106Sdes break; 564238106Sdes } 565238106Sdes lock_basic_unlock(&ctx->cfglock); 566238106Sdes 567238106Sdes /* keep rrpipe locked, while 568238106Sdes * o waiting for pipe readable 569238106Sdes * o parsing message 570238106Sdes * o possibly decrementing num_async 571238106Sdes * do callback without lock 572238106Sdes */ 573238106Sdes r = tube_wait(ctx->rr_pipe); 574238106Sdes if(r) { 575238106Sdes r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 576238106Sdes if(r == 0) { 577238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 578238106Sdes return UB_PIPE; 579238106Sdes } 580238106Sdes if(r == -1) { 581238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 582238106Sdes continue; 583238106Sdes } 584238106Sdes r = process_answer_detail(ctx, msg, len, 585238106Sdes &cb, &cbarg, &err, &res); 586238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 587238106Sdes free(msg); 588238106Sdes if(r == 0) 589238106Sdes return UB_PIPE; 590238106Sdes if(r == 2) 591238106Sdes (*cb)(cbarg, err, res); 592238106Sdes } else { 593238106Sdes lock_basic_unlock(&ctx->rrpipe_lock); 594238106Sdes } 595238106Sdes } 596238106Sdes return UB_NOERROR; 597238106Sdes} 598238106Sdes 599238106Sdesint 600255584Sdesub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, 601238106Sdes int rrclass, struct ub_result** result) 602238106Sdes{ 603238106Sdes struct ctx_query* q; 604238106Sdes int r; 605238106Sdes *result = NULL; 606238106Sdes 607238106Sdes lock_basic_lock(&ctx->cfglock); 608238106Sdes if(!ctx->finalized) { 609238106Sdes r = context_finalize(ctx); 610238106Sdes if(r) { 611238106Sdes lock_basic_unlock(&ctx->cfglock); 612238106Sdes return r; 613238106Sdes } 614238106Sdes } 615238106Sdes /* create new ctx_query and attempt to add to the list */ 616238106Sdes lock_basic_unlock(&ctx->cfglock); 617238106Sdes q = context_new(ctx, name, rrtype, rrclass, NULL, NULL); 618238106Sdes if(!q) 619238106Sdes return UB_NOMEM; 620238106Sdes /* become a resolver thread for a bit */ 621238106Sdes 622238106Sdes r = libworker_fg(ctx, q); 623238106Sdes if(r) { 624238106Sdes lock_basic_lock(&ctx->cfglock); 625238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 626238106Sdes context_query_delete(q); 627238106Sdes lock_basic_unlock(&ctx->cfglock); 628238106Sdes return r; 629238106Sdes } 630238106Sdes q->res->answer_packet = q->msg; 631238106Sdes q->res->answer_len = (int)q->msg_len; 632238106Sdes q->msg = NULL; 633238106Sdes *result = q->res; 634238106Sdes q->res = NULL; 635238106Sdes 636238106Sdes lock_basic_lock(&ctx->cfglock); 637238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 638238106Sdes context_query_delete(q); 639238106Sdes lock_basic_unlock(&ctx->cfglock); 640238106Sdes return UB_NOERROR; 641238106Sdes} 642238106Sdes 643238106Sdesint 644269257Sdesub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, 645269257Sdes int rrclass, void* mydata, ub_event_callback_t callback, int* async_id) 646269257Sdes{ 647269257Sdes struct ctx_query* q; 648269257Sdes int r; 649269257Sdes 650269257Sdes if(async_id) 651269257Sdes *async_id = 0; 652269257Sdes lock_basic_lock(&ctx->cfglock); 653269257Sdes if(!ctx->finalized) { 654269257Sdes int r = context_finalize(ctx); 655269257Sdes if(r) { 656269257Sdes lock_basic_unlock(&ctx->cfglock); 657269257Sdes return r; 658269257Sdes } 659269257Sdes } 660269257Sdes lock_basic_unlock(&ctx->cfglock); 661269257Sdes if(!ctx->event_worker) { 662269257Sdes ctx->event_worker = libworker_create_event(ctx, 663269257Sdes ctx->event_base); 664269257Sdes if(!ctx->event_worker) { 665269257Sdes return UB_INITFAIL; 666269257Sdes } 667269257Sdes } 668269257Sdes 669269257Sdes /* create new ctx_query and attempt to add to the list */ 670269257Sdes q = context_new(ctx, name, rrtype, rrclass, (ub_callback_t)callback, 671269257Sdes mydata); 672269257Sdes if(!q) 673269257Sdes return UB_NOMEM; 674269257Sdes 675269257Sdes /* attach to mesh */ 676269257Sdes if((r=libworker_attach_mesh(ctx, q, async_id)) != 0) 677269257Sdes return r; 678269257Sdes return UB_NOERROR; 679269257Sdes} 680269257Sdes 681269257Sdes 682269257Sdesint 683255584Sdesub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, 684238106Sdes int rrclass, void* mydata, ub_callback_t callback, int* async_id) 685238106Sdes{ 686238106Sdes struct ctx_query* q; 687238106Sdes uint8_t* msg = NULL; 688238106Sdes uint32_t len = 0; 689238106Sdes 690238106Sdes if(async_id) 691238106Sdes *async_id = 0; 692238106Sdes lock_basic_lock(&ctx->cfglock); 693238106Sdes if(!ctx->finalized) { 694238106Sdes int r = context_finalize(ctx); 695238106Sdes if(r) { 696238106Sdes lock_basic_unlock(&ctx->cfglock); 697238106Sdes return r; 698238106Sdes } 699238106Sdes } 700238106Sdes if(!ctx->created_bg) { 701238106Sdes int r; 702238106Sdes ctx->created_bg = 1; 703238106Sdes lock_basic_unlock(&ctx->cfglock); 704238106Sdes r = libworker_bg(ctx); 705238106Sdes if(r) { 706238106Sdes lock_basic_lock(&ctx->cfglock); 707238106Sdes ctx->created_bg = 0; 708238106Sdes lock_basic_unlock(&ctx->cfglock); 709238106Sdes return r; 710238106Sdes } 711238106Sdes } else { 712238106Sdes lock_basic_unlock(&ctx->cfglock); 713238106Sdes } 714238106Sdes 715238106Sdes /* create new ctx_query and attempt to add to the list */ 716238106Sdes q = context_new(ctx, name, rrtype, rrclass, callback, mydata); 717238106Sdes if(!q) 718238106Sdes return UB_NOMEM; 719238106Sdes 720238106Sdes /* write over pipe to background worker */ 721238106Sdes lock_basic_lock(&ctx->cfglock); 722238106Sdes msg = context_serialize_new_query(q, &len); 723238106Sdes if(!msg) { 724238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 725238106Sdes ctx->num_async--; 726238106Sdes context_query_delete(q); 727238106Sdes lock_basic_unlock(&ctx->cfglock); 728238106Sdes return UB_NOMEM; 729238106Sdes } 730238106Sdes if(async_id) 731238106Sdes *async_id = q->querynum; 732238106Sdes lock_basic_unlock(&ctx->cfglock); 733238106Sdes 734238106Sdes lock_basic_lock(&ctx->qqpipe_lock); 735238106Sdes if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 736238106Sdes lock_basic_unlock(&ctx->qqpipe_lock); 737238106Sdes free(msg); 738238106Sdes return UB_PIPE; 739238106Sdes } 740238106Sdes lock_basic_unlock(&ctx->qqpipe_lock); 741238106Sdes free(msg); 742238106Sdes return UB_NOERROR; 743238106Sdes} 744238106Sdes 745238106Sdesint 746238106Sdesub_cancel(struct ub_ctx* ctx, int async_id) 747238106Sdes{ 748238106Sdes struct ctx_query* q; 749238106Sdes uint8_t* msg = NULL; 750238106Sdes uint32_t len = 0; 751238106Sdes lock_basic_lock(&ctx->cfglock); 752238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id); 753238106Sdes if(!q || !q->async) { 754238106Sdes /* it is not there, so nothing to do */ 755238106Sdes lock_basic_unlock(&ctx->cfglock); 756238106Sdes return UB_NOID; 757238106Sdes } 758238106Sdes log_assert(q->async); 759238106Sdes q->cancelled = 1; 760238106Sdes 761238106Sdes /* delete it */ 762238106Sdes if(!ctx->dothread) { /* if forked */ 763238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 764238106Sdes ctx->num_async--; 765238106Sdes msg = context_serialize_cancel(q, &len); 766238106Sdes context_query_delete(q); 767238106Sdes lock_basic_unlock(&ctx->cfglock); 768238106Sdes if(!msg) { 769238106Sdes return UB_NOMEM; 770238106Sdes } 771238106Sdes /* send cancel to background worker */ 772238106Sdes lock_basic_lock(&ctx->qqpipe_lock); 773238106Sdes if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 774238106Sdes lock_basic_unlock(&ctx->qqpipe_lock); 775238106Sdes free(msg); 776238106Sdes return UB_PIPE; 777238106Sdes } 778238106Sdes lock_basic_unlock(&ctx->qqpipe_lock); 779238106Sdes free(msg); 780238106Sdes } else { 781238106Sdes lock_basic_unlock(&ctx->cfglock); 782238106Sdes } 783238106Sdes return UB_NOERROR; 784238106Sdes} 785238106Sdes 786238106Sdesvoid 787238106Sdesub_resolve_free(struct ub_result* result) 788238106Sdes{ 789238106Sdes char** p; 790238106Sdes if(!result) return; 791238106Sdes free(result->qname); 792238106Sdes if(result->canonname != result->qname) 793238106Sdes free(result->canonname); 794238106Sdes if(result->data) 795238106Sdes for(p = result->data; *p; p++) 796238106Sdes free(*p); 797238106Sdes free(result->data); 798238106Sdes free(result->len); 799238106Sdes free(result->answer_packet); 800238106Sdes free(result->why_bogus); 801238106Sdes free(result); 802238106Sdes} 803238106Sdes 804238106Sdesconst char* 805238106Sdesub_strerror(int err) 806238106Sdes{ 807238106Sdes switch(err) { 808238106Sdes case UB_NOERROR: return "no error"; 809238106Sdes case UB_SOCKET: return "socket io error"; 810238106Sdes case UB_NOMEM: return "out of memory"; 811238106Sdes case UB_SYNTAX: return "syntax error"; 812238106Sdes case UB_SERVFAIL: return "server failure"; 813238106Sdes case UB_FORKFAIL: return "could not fork"; 814238106Sdes case UB_INITFAIL: return "initialization failure"; 815238106Sdes case UB_AFTERFINAL: return "setting change after finalize"; 816238106Sdes case UB_PIPE: return "error in pipe communication with async"; 817238106Sdes case UB_READFILE: return "error reading file"; 818238106Sdes case UB_NOID: return "error async_id does not exist"; 819238106Sdes default: return "unknown error"; 820238106Sdes } 821238106Sdes} 822238106Sdes 823238106Sdesint 824255584Sdesub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr) 825238106Sdes{ 826238106Sdes struct sockaddr_storage storage; 827238106Sdes socklen_t stlen; 828238106Sdes struct config_stub* s; 829238106Sdes char* dupl; 830238106Sdes lock_basic_lock(&ctx->cfglock); 831238106Sdes if(ctx->finalized) { 832238106Sdes lock_basic_unlock(&ctx->cfglock); 833238106Sdes errno=EINVAL; 834238106Sdes return UB_AFTERFINAL; 835238106Sdes } 836238106Sdes if(!addr) { 837238106Sdes /* disable fwd mode - the root stub should be first. */ 838238106Sdes if(ctx->env->cfg->forwards && 839238106Sdes strcmp(ctx->env->cfg->forwards->name, ".") == 0) { 840238106Sdes s = ctx->env->cfg->forwards; 841238106Sdes ctx->env->cfg->forwards = s->next; 842238106Sdes s->next = NULL; 843238106Sdes config_delstubs(s); 844238106Sdes } 845238106Sdes lock_basic_unlock(&ctx->cfglock); 846238106Sdes return UB_NOERROR; 847238106Sdes } 848238106Sdes lock_basic_unlock(&ctx->cfglock); 849238106Sdes 850238106Sdes /* check syntax for addr */ 851238106Sdes if(!extstrtoaddr(addr, &storage, &stlen)) { 852238106Sdes errno=EINVAL; 853238106Sdes return UB_SYNTAX; 854238106Sdes } 855238106Sdes 856238106Sdes /* it parses, add root stub in front of list */ 857238106Sdes lock_basic_lock(&ctx->cfglock); 858238106Sdes if(!ctx->env->cfg->forwards || 859238106Sdes strcmp(ctx->env->cfg->forwards->name, ".") != 0) { 860238106Sdes s = calloc(1, sizeof(*s)); 861238106Sdes if(!s) { 862238106Sdes lock_basic_unlock(&ctx->cfglock); 863238106Sdes errno=ENOMEM; 864238106Sdes return UB_NOMEM; 865238106Sdes } 866238106Sdes s->name = strdup("."); 867238106Sdes if(!s->name) { 868238106Sdes free(s); 869238106Sdes lock_basic_unlock(&ctx->cfglock); 870238106Sdes errno=ENOMEM; 871238106Sdes return UB_NOMEM; 872238106Sdes } 873238106Sdes s->next = ctx->env->cfg->forwards; 874238106Sdes ctx->env->cfg->forwards = s; 875238106Sdes } else { 876238106Sdes log_assert(ctx->env->cfg->forwards); 877238106Sdes s = ctx->env->cfg->forwards; 878238106Sdes } 879238106Sdes dupl = strdup(addr); 880238106Sdes if(!dupl) { 881238106Sdes lock_basic_unlock(&ctx->cfglock); 882238106Sdes errno=ENOMEM; 883238106Sdes return UB_NOMEM; 884238106Sdes } 885238106Sdes if(!cfg_strlist_insert(&s->addrs, dupl)) { 886238106Sdes free(dupl); 887238106Sdes lock_basic_unlock(&ctx->cfglock); 888238106Sdes errno=ENOMEM; 889238106Sdes return UB_NOMEM; 890238106Sdes } 891238106Sdes lock_basic_unlock(&ctx->cfglock); 892238106Sdes return UB_NOERROR; 893238106Sdes} 894238106Sdes 895238106Sdesint 896255584Sdesub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname) 897238106Sdes{ 898238106Sdes FILE* in; 899238106Sdes int numserv = 0; 900238106Sdes char buf[1024]; 901238106Sdes char* parse, *addr; 902238106Sdes int r; 903238106Sdes 904238106Sdes if(fname == NULL) { 905238106Sdes#if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H) 906238106Sdes fname = "/etc/resolv.conf"; 907238106Sdes#else 908238106Sdes FIXED_INFO *info; 909238106Sdes ULONG buflen = sizeof(*info); 910238106Sdes IP_ADDR_STRING *ptr; 911238106Sdes 912238106Sdes info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO)); 913238106Sdes if (info == NULL) 914238106Sdes return UB_READFILE; 915238106Sdes 916238106Sdes if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { 917238106Sdes free(info); 918238106Sdes info = (FIXED_INFO *) malloc(buflen); 919238106Sdes if (info == NULL) 920238106Sdes return UB_READFILE; 921238106Sdes } 922238106Sdes 923238106Sdes if (GetNetworkParams(info, &buflen) == NO_ERROR) { 924238106Sdes int retval=0; 925238106Sdes ptr = &(info->DnsServerList); 926238106Sdes while (ptr) { 927238106Sdes numserv++; 928238106Sdes if((retval=ub_ctx_set_fwd(ctx, 929238106Sdes ptr->IpAddress.String)!=0)) { 930238106Sdes free(info); 931238106Sdes return retval; 932238106Sdes } 933238106Sdes ptr = ptr->Next; 934238106Sdes } 935238106Sdes free(info); 936238106Sdes if (numserv==0) 937238106Sdes return UB_READFILE; 938238106Sdes return UB_NOERROR; 939238106Sdes } 940238106Sdes free(info); 941238106Sdes return UB_READFILE; 942238106Sdes#endif /* WINDOWS */ 943238106Sdes } 944238106Sdes in = fopen(fname, "r"); 945238106Sdes if(!in) { 946238106Sdes /* error in errno! perror(fname) */ 947238106Sdes return UB_READFILE; 948238106Sdes } 949238106Sdes while(fgets(buf, (int)sizeof(buf), in)) { 950238106Sdes buf[sizeof(buf)-1] = 0; 951238106Sdes parse=buf; 952238106Sdes while(*parse == ' ' || *parse == '\t') 953238106Sdes parse++; 954238106Sdes if(strncmp(parse, "nameserver", 10) == 0) { 955238106Sdes numserv++; 956238106Sdes parse += 10; /* skip 'nameserver' */ 957238106Sdes /* skip whitespace */ 958238106Sdes while(*parse == ' ' || *parse == '\t') 959238106Sdes parse++; 960238106Sdes addr = parse; 961238106Sdes /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */ 962238106Sdes while(isxdigit(*parse) || *parse=='.' || *parse==':') 963238106Sdes parse++; 964238106Sdes /* terminate after the address, remove newline */ 965238106Sdes *parse = 0; 966238106Sdes 967238106Sdes if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) { 968238106Sdes fclose(in); 969238106Sdes return r; 970238106Sdes } 971238106Sdes } 972238106Sdes } 973238106Sdes fclose(in); 974238106Sdes if(numserv == 0) { 975238106Sdes /* from resolv.conf(5) if none given, use localhost */ 976238106Sdes return ub_ctx_set_fwd(ctx, "127.0.0.1"); 977238106Sdes } 978238106Sdes return UB_NOERROR; 979238106Sdes} 980238106Sdes 981238106Sdesint 982255584Sdesub_ctx_hosts(struct ub_ctx* ctx, const char* fname) 983238106Sdes{ 984238106Sdes FILE* in; 985238106Sdes char buf[1024], ldata[1024]; 986238106Sdes char* parse, *addr, *name, *ins; 987238106Sdes lock_basic_lock(&ctx->cfglock); 988238106Sdes if(ctx->finalized) { 989238106Sdes lock_basic_unlock(&ctx->cfglock); 990238106Sdes errno=EINVAL; 991238106Sdes return UB_AFTERFINAL; 992238106Sdes } 993238106Sdes lock_basic_unlock(&ctx->cfglock); 994238106Sdes if(fname == NULL) { 995238106Sdes#if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H) 996238106Sdes /* 997238106Sdes * If this is Windows NT/XP/2K it's in 998238106Sdes * %WINDIR%\system32\drivers\etc\hosts. 999238106Sdes * If this is Windows 95/98/Me it's in %WINDIR%\hosts. 1000238106Sdes */ 1001238106Sdes name = getenv("WINDIR"); 1002238106Sdes if (name != NULL) { 1003238106Sdes int retval=0; 1004238106Sdes snprintf(buf, sizeof(buf), "%s%s", name, 1005238106Sdes "\\system32\\drivers\\etc\\hosts"); 1006238106Sdes if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) { 1007238106Sdes snprintf(buf, sizeof(buf), "%s%s", name, 1008238106Sdes "\\hosts"); 1009238106Sdes retval=ub_ctx_hosts(ctx, buf); 1010238106Sdes } 1011238106Sdes free(name); 1012238106Sdes return retval; 1013238106Sdes } 1014238106Sdes return UB_READFILE; 1015238106Sdes#else 1016238106Sdes fname = "/etc/hosts"; 1017238106Sdes#endif /* WIN32 */ 1018238106Sdes } 1019238106Sdes in = fopen(fname, "r"); 1020238106Sdes if(!in) { 1021238106Sdes /* error in errno! perror(fname) */ 1022238106Sdes return UB_READFILE; 1023238106Sdes } 1024238106Sdes while(fgets(buf, (int)sizeof(buf), in)) { 1025238106Sdes buf[sizeof(buf)-1] = 0; 1026238106Sdes parse=buf; 1027238106Sdes while(*parse == ' ' || *parse == '\t') 1028238106Sdes parse++; 1029238106Sdes if(*parse == '#') 1030238106Sdes continue; /* skip comment */ 1031238106Sdes /* format: <addr> spaces <name> spaces <name> ... */ 1032238106Sdes addr = parse; 1033238106Sdes /* skip addr */ 1034238106Sdes while(isxdigit(*parse) || *parse == '.' || *parse == ':') 1035238106Sdes parse++; 1036238106Sdes if(*parse == '\n' || *parse == 0) 1037238106Sdes continue; 1038238106Sdes if(*parse == '%') 1039238106Sdes continue; /* ignore macOSX fe80::1%lo0 localhost */ 1040238106Sdes if(*parse != ' ' && *parse != '\t') { 1041238106Sdes /* must have whitespace after address */ 1042238106Sdes fclose(in); 1043238106Sdes errno=EINVAL; 1044238106Sdes return UB_SYNTAX; 1045238106Sdes } 1046238106Sdes *parse++ = 0; /* end delimiter for addr ... */ 1047238106Sdes /* go to names and add them */ 1048238106Sdes while(*parse) { 1049238106Sdes while(*parse == ' ' || *parse == '\t' || *parse=='\n') 1050238106Sdes parse++; 1051238106Sdes if(*parse == 0 || *parse == '#') 1052238106Sdes break; 1053238106Sdes /* skip name, allows (too) many printable characters */ 1054238106Sdes name = parse; 1055238106Sdes while('!' <= *parse && *parse <= '~') 1056238106Sdes parse++; 1057238106Sdes if(*parse) 1058238106Sdes *parse++ = 0; /* end delimiter for name */ 1059238106Sdes snprintf(ldata, sizeof(ldata), "%s %s %s", 1060238106Sdes name, str_is_ip6(addr)?"AAAA":"A", addr); 1061238106Sdes ins = strdup(ldata); 1062238106Sdes if(!ins) { 1063238106Sdes /* out of memory */ 1064238106Sdes fclose(in); 1065238106Sdes errno=ENOMEM; 1066238106Sdes return UB_NOMEM; 1067238106Sdes } 1068238106Sdes lock_basic_lock(&ctx->cfglock); 1069238106Sdes if(!cfg_strlist_insert(&ctx->env->cfg->local_data, 1070238106Sdes ins)) { 1071238106Sdes lock_basic_unlock(&ctx->cfglock); 1072238106Sdes fclose(in); 1073238106Sdes free(ins); 1074238106Sdes errno=ENOMEM; 1075238106Sdes return UB_NOMEM; 1076238106Sdes } 1077238106Sdes lock_basic_unlock(&ctx->cfglock); 1078238106Sdes } 1079238106Sdes } 1080238106Sdes fclose(in); 1081238106Sdes return UB_NOERROR; 1082238106Sdes} 1083238106Sdes 1084238106Sdes/** finalize the context, if not already finalized */ 1085238106Sdesstatic int ub_ctx_finalize(struct ub_ctx* ctx) 1086238106Sdes{ 1087238106Sdes int res = 0; 1088238106Sdes lock_basic_lock(&ctx->cfglock); 1089238106Sdes if (!ctx->finalized) { 1090238106Sdes res = context_finalize(ctx); 1091238106Sdes } 1092238106Sdes lock_basic_unlock(&ctx->cfglock); 1093238106Sdes return res; 1094238106Sdes} 1095238106Sdes 1096238106Sdes/* Print local zones and RR data */ 1097238106Sdesint ub_ctx_print_local_zones(struct ub_ctx* ctx) 1098238106Sdes{ 1099238106Sdes int res = ub_ctx_finalize(ctx); 1100238106Sdes if (res) return res; 1101238106Sdes 1102238106Sdes local_zones_print(ctx->local_zones); 1103238106Sdes 1104238106Sdes return UB_NOERROR; 1105238106Sdes} 1106238106Sdes 1107238106Sdes/* Add a new zone */ 1108269257Sdesint ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, 1109269257Sdes const char *zone_type) 1110238106Sdes{ 1111238106Sdes enum localzone_type t; 1112238106Sdes struct local_zone* z; 1113238106Sdes uint8_t* nm; 1114238106Sdes int nmlabs; 1115238106Sdes size_t nmlen; 1116238106Sdes 1117238106Sdes int res = ub_ctx_finalize(ctx); 1118238106Sdes if (res) return res; 1119238106Sdes 1120238106Sdes if(!local_zone_str2type(zone_type, &t)) { 1121238106Sdes return UB_SYNTAX; 1122238106Sdes } 1123238106Sdes 1124238106Sdes if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1125238106Sdes return UB_SYNTAX; 1126238106Sdes } 1127238106Sdes 1128269257Sdes lock_rw_wrlock(&ctx->local_zones->lock); 1129238106Sdes if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1130238106Sdes LDNS_RR_CLASS_IN))) { 1131238106Sdes /* already present in tree */ 1132238106Sdes lock_rw_wrlock(&z->lock); 1133238106Sdes z->type = t; /* update type anyway */ 1134238106Sdes lock_rw_unlock(&z->lock); 1135269257Sdes lock_rw_unlock(&ctx->local_zones->lock); 1136238106Sdes free(nm); 1137238106Sdes return UB_NOERROR; 1138238106Sdes } 1139238106Sdes if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, 1140238106Sdes LDNS_RR_CLASS_IN, t)) { 1141269257Sdes lock_rw_unlock(&ctx->local_zones->lock); 1142238106Sdes return UB_NOMEM; 1143238106Sdes } 1144269257Sdes lock_rw_unlock(&ctx->local_zones->lock); 1145238106Sdes return UB_NOERROR; 1146238106Sdes} 1147238106Sdes 1148238106Sdes/* Remove zone */ 1149269257Sdesint ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name) 1150238106Sdes{ 1151238106Sdes struct local_zone* z; 1152238106Sdes uint8_t* nm; 1153238106Sdes int nmlabs; 1154238106Sdes size_t nmlen; 1155238106Sdes 1156238106Sdes int res = ub_ctx_finalize(ctx); 1157238106Sdes if (res) return res; 1158238106Sdes 1159238106Sdes if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1160238106Sdes return UB_SYNTAX; 1161238106Sdes } 1162238106Sdes 1163269257Sdes lock_rw_wrlock(&ctx->local_zones->lock); 1164238106Sdes if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1165238106Sdes LDNS_RR_CLASS_IN))) { 1166238106Sdes /* present in tree */ 1167238106Sdes local_zones_del_zone(ctx->local_zones, z); 1168238106Sdes } 1169269257Sdes lock_rw_unlock(&ctx->local_zones->lock); 1170238106Sdes free(nm); 1171238106Sdes return UB_NOERROR; 1172238106Sdes} 1173238106Sdes 1174238106Sdes/* Add new RR data */ 1175269257Sdesint ub_ctx_data_add(struct ub_ctx* ctx, const char *data) 1176238106Sdes{ 1177238106Sdes int res = ub_ctx_finalize(ctx); 1178238106Sdes if (res) return res; 1179238106Sdes 1180269257Sdes res = local_zones_add_RR(ctx->local_zones, data); 1181238106Sdes return (!res) ? UB_NOMEM : UB_NOERROR; 1182238106Sdes} 1183238106Sdes 1184238106Sdes/* Remove RR data */ 1185269257Sdesint ub_ctx_data_remove(struct ub_ctx* ctx, const char *data) 1186238106Sdes{ 1187238106Sdes uint8_t* nm; 1188238106Sdes int nmlabs; 1189238106Sdes size_t nmlen; 1190238106Sdes int res = ub_ctx_finalize(ctx); 1191238106Sdes if (res) return res; 1192238106Sdes 1193238106Sdes if(!parse_dname(data, &nm, &nmlen, &nmlabs)) 1194238106Sdes return UB_SYNTAX; 1195238106Sdes 1196238106Sdes local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs, 1197238106Sdes LDNS_RR_CLASS_IN); 1198238106Sdes 1199238106Sdes free(nm); 1200238106Sdes return UB_NOERROR; 1201238106Sdes} 1202238106Sdes 1203238106Sdesconst char* ub_version(void) 1204238106Sdes{ 1205238106Sdes return PACKAGE_VERSION; 1206238106Sdes} 1207269257Sdes 1208269257Sdesint 1209269257Sdesub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) { 1210269257Sdes if (!ctx || !ctx->event_base || !base) { 1211269257Sdes return UB_INITFAIL; 1212269257Sdes } 1213269257Sdes if (ctx->event_base == base) { 1214269257Sdes /* already set */ 1215269257Sdes return UB_NOERROR; 1216269257Sdes } 1217269257Sdes 1218269257Sdes lock_basic_lock(&ctx->cfglock); 1219269257Sdes /* destroy the current worker - safe to pass in NULL */ 1220269257Sdes libworker_delete_event(ctx->event_worker); 1221269257Sdes ctx->event_worker = NULL; 1222269257Sdes ctx->event_base = base; 1223269257Sdes ctx->created_bg = 0; 1224269257Sdes ctx->dothread = 1; 1225269257Sdes lock_basic_unlock(&ctx->cfglock); 1226269257Sdes return UB_NOERROR; 1227269257Sdes} 1228