1933707f3Ssthen /* 2933707f3Ssthen * unbound.c - unbound validating resolver public API implementation 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains functions to resolve DNS queries and 40bdfc4d55Sflorian * validate the answers. Synchronously and asynchronously. 41933707f3Ssthen * 42933707f3Ssthen */ 43933707f3Ssthen 44933707f3Ssthen /* include the public api first, it should be able to stand alone */ 45933707f3Ssthen #include "libunbound/unbound.h" 465d76a658Ssthen #include "libunbound/unbound-event.h" 47933707f3Ssthen #include "config.h" 48933707f3Ssthen #include <ctype.h> 49933707f3Ssthen #include "libunbound/context.h" 50933707f3Ssthen #include "libunbound/libworker.h" 51933707f3Ssthen #include "util/locks.h" 52933707f3Ssthen #include "util/config_file.h" 53933707f3Ssthen #include "util/alloc.h" 54933707f3Ssthen #include "util/module.h" 55933707f3Ssthen #include "util/regional.h" 56933707f3Ssthen #include "util/log.h" 57933707f3Ssthen #include "util/random.h" 58933707f3Ssthen #include "util/net_help.h" 59933707f3Ssthen #include "util/tube.h" 602ee382b6Ssthen #include "util/ub_event.h" 612c144df0Ssthen #include "util/edns.h" 62933707f3Ssthen #include "services/modstack.h" 63933707f3Ssthen #include "services/localzone.h" 64933707f3Ssthen #include "services/cache/infra.h" 65933707f3Ssthen #include "services/cache/rrset.h" 66938a3a5eSflorian #include "services/authzone.h" 67e21c60efSsthen #include "services/listen_dnsport.h" 68fdfb4ba6Ssthen #include "sldns/sbuffer.h" 692bdc0ed1Ssthen #include "iterator/iter_fwd.h" 702bdc0ed1Ssthen #include "iterator/iter_hints.h" 71229e174cSsthen #ifdef HAVE_PTHREAD 72229e174cSsthen #include <signal.h> 73229e174cSsthen #endif 74a961b961Ssthen #ifdef HAVE_SYS_WAIT_H 75a961b961Ssthen #include <sys/wait.h> 76a961b961Ssthen #endif 7724893edcSsthen #ifdef HAVE_TIME_H 7824893edcSsthen #include <time.h> 7924893edcSsthen #endif 80933707f3Ssthen 81933707f3Ssthen #if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H) 82933707f3Ssthen #include <windows.h> 83933707f3Ssthen #include <iphlpapi.h> 84933707f3Ssthen #endif /* UB_ON_WINDOWS */ 85933707f3Ssthen 868240c1b9Ssthen /** store that the logfile has a debug override */ 878240c1b9Ssthen int ctx_logfile_overridden = 0; 888240c1b9Ssthen 895d76a658Ssthen /** create context functionality, but no pipes */ 905d76a658Ssthen static struct ub_ctx* ub_ctx_create_nopipe(void) 91933707f3Ssthen { 92933707f3Ssthen struct ub_ctx* ctx; 93933707f3Ssthen #ifdef USE_WINSOCK 94933707f3Ssthen int r; 95933707f3Ssthen WSADATA wsa_data; 96933707f3Ssthen #endif 97933707f3Ssthen 98938a3a5eSflorian checklock_start(); 998240c1b9Ssthen if(!ctx_logfile_overridden) 100933707f3Ssthen log_init(NULL, 0, NULL); /* logs to stderr */ 101933707f3Ssthen log_ident_set("libunbound"); 102933707f3Ssthen #ifdef USE_WINSOCK 103933707f3Ssthen if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { 104933707f3Ssthen log_err("could not init winsock. WSAStartup: %s", 105933707f3Ssthen wsa_strerror(r)); 106933707f3Ssthen return NULL; 107933707f3Ssthen } 108933707f3Ssthen #endif 109ebf5bb73Ssthen verbosity = NO_VERBOSE; /* errors only */ 110933707f3Ssthen checklock_start(); 111933707f3Ssthen ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx)); 112933707f3Ssthen if(!ctx) { 113933707f3Ssthen errno = ENOMEM; 114933707f3Ssthen return NULL; 115933707f3Ssthen } 116933707f3Ssthen alloc_init(&ctx->superalloc, NULL, 0); 117ebf5bb73Ssthen if(!(ctx->seed_rnd = ub_initstate(NULL))) { 118933707f3Ssthen ub_randfree(ctx->seed_rnd); 119933707f3Ssthen free(ctx); 120933707f3Ssthen errno = ENOMEM; 121933707f3Ssthen return NULL; 122933707f3Ssthen } 123933707f3Ssthen lock_basic_init(&ctx->qqpipe_lock); 124933707f3Ssthen lock_basic_init(&ctx->rrpipe_lock); 125933707f3Ssthen lock_basic_init(&ctx->cfglock); 126933707f3Ssthen ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env)); 127933707f3Ssthen if(!ctx->env) { 128933707f3Ssthen ub_randfree(ctx->seed_rnd); 129933707f3Ssthen free(ctx); 130933707f3Ssthen errno = ENOMEM; 131933707f3Ssthen return NULL; 132933707f3Ssthen } 133933707f3Ssthen ctx->env->cfg = config_create_forlib(); 134933707f3Ssthen if(!ctx->env->cfg) { 135933707f3Ssthen free(ctx->env); 136933707f3Ssthen ub_randfree(ctx->seed_rnd); 137933707f3Ssthen free(ctx); 138933707f3Ssthen errno = ENOMEM; 139933707f3Ssthen return NULL; 140933707f3Ssthen } 14177079be7Ssthen /* init edns_known_options */ 14277079be7Ssthen if(!edns_known_options_init(ctx->env)) { 14377079be7Ssthen config_delete(ctx->env->cfg); 14477079be7Ssthen free(ctx->env); 14577079be7Ssthen ub_randfree(ctx->seed_rnd); 14677079be7Ssthen free(ctx); 14777079be7Ssthen errno = ENOMEM; 14877079be7Ssthen return NULL; 14977079be7Ssthen } 150938a3a5eSflorian ctx->env->auth_zones = auth_zones_create(); 151938a3a5eSflorian if(!ctx->env->auth_zones) { 152938a3a5eSflorian edns_known_options_delete(ctx->env); 153938a3a5eSflorian config_delete(ctx->env->cfg); 154938a3a5eSflorian free(ctx->env); 155938a3a5eSflorian ub_randfree(ctx->seed_rnd); 156938a3a5eSflorian free(ctx); 157938a3a5eSflorian errno = ENOMEM; 158938a3a5eSflorian return NULL; 159938a3a5eSflorian } 160eba819a2Ssthen ctx->env->edns_strings = edns_strings_create(); 161eba819a2Ssthen if(!ctx->env->edns_strings) { 1622c144df0Ssthen auth_zones_delete(ctx->env->auth_zones); 1632c144df0Ssthen edns_known_options_delete(ctx->env); 1642c144df0Ssthen config_delete(ctx->env->cfg); 1652c144df0Ssthen free(ctx->env); 1662c144df0Ssthen ub_randfree(ctx->seed_rnd); 1672c144df0Ssthen free(ctx); 1682c144df0Ssthen errno = ENOMEM; 1692c144df0Ssthen return NULL; 1702c144df0Ssthen } 1712c144df0Ssthen 172933707f3Ssthen ctx->env->alloc = &ctx->superalloc; 173933707f3Ssthen ctx->env->worker = NULL; 174933707f3Ssthen ctx->env->need_to_validate = 0; 175933707f3Ssthen modstack_init(&ctx->mods); 1762bdc0ed1Ssthen ctx->env->modstack = &ctx->mods; 177933707f3Ssthen rbtree_init(&ctx->queries, &context_query_cmp); 178933707f3Ssthen return ctx; 179933707f3Ssthen } 180933707f3Ssthen 1815d76a658Ssthen struct ub_ctx* 1825d76a658Ssthen ub_ctx_create(void) 1835d76a658Ssthen { 1845d76a658Ssthen struct ub_ctx* ctx = ub_ctx_create_nopipe(); 1855d76a658Ssthen if(!ctx) 1865d76a658Ssthen return NULL; 1875d76a658Ssthen if((ctx->qq_pipe = tube_create()) == NULL) { 1885d76a658Ssthen int e = errno; 1895d76a658Ssthen ub_randfree(ctx->seed_rnd); 1905d76a658Ssthen config_delete(ctx->env->cfg); 191*98bc733bSsthen modstack_call_deinit(&ctx->mods, ctx->env); 192*98bc733bSsthen modstack_call_destartup(&ctx->mods, ctx->env); 193*98bc733bSsthen modstack_free(&ctx->mods); 194e21c60efSsthen listen_desetup_locks(); 19577079be7Ssthen edns_known_options_delete(ctx->env); 196eba819a2Ssthen edns_strings_delete(ctx->env->edns_strings); 1975d76a658Ssthen free(ctx->env); 1985d76a658Ssthen free(ctx); 1995d76a658Ssthen errno = e; 2005d76a658Ssthen return NULL; 2015d76a658Ssthen } 2025d76a658Ssthen if((ctx->rr_pipe = tube_create()) == NULL) { 2035d76a658Ssthen int e = errno; 2045d76a658Ssthen tube_delete(ctx->qq_pipe); 2055d76a658Ssthen ub_randfree(ctx->seed_rnd); 2065d76a658Ssthen config_delete(ctx->env->cfg); 207*98bc733bSsthen modstack_call_deinit(&ctx->mods, ctx->env); 208*98bc733bSsthen modstack_call_destartup(&ctx->mods, ctx->env); 209*98bc733bSsthen modstack_free(&ctx->mods); 210e21c60efSsthen listen_desetup_locks(); 21177079be7Ssthen edns_known_options_delete(ctx->env); 212eba819a2Ssthen edns_strings_delete(ctx->env->edns_strings); 2135d76a658Ssthen free(ctx->env); 2145d76a658Ssthen free(ctx); 2155d76a658Ssthen errno = e; 2165d76a658Ssthen return NULL; 2175d76a658Ssthen } 2185d76a658Ssthen return ctx; 2195d76a658Ssthen } 2205d76a658Ssthen 2215d76a658Ssthen struct ub_ctx* 2222ee382b6Ssthen ub_ctx_create_ub_event(struct ub_event_base* ueb) 2232ee382b6Ssthen { 2242ee382b6Ssthen struct ub_ctx* ctx = ub_ctx_create_nopipe(); 2252ee382b6Ssthen if(!ctx) 2262ee382b6Ssthen return NULL; 2272ee382b6Ssthen /* no pipes, but we have the locks to make sure everything works */ 2282ee382b6Ssthen ctx->created_bg = 0; 2292ee382b6Ssthen ctx->dothread = 1; /* the processing is in the same process, 2302ee382b6Ssthen makes ub_cancel and ub_ctx_delete do the right thing */ 2312ee382b6Ssthen ctx->event_base = ueb; 2322ee382b6Ssthen return ctx; 2332ee382b6Ssthen } 2342ee382b6Ssthen 2352ee382b6Ssthen struct ub_ctx* 2365d76a658Ssthen ub_ctx_create_event(struct event_base* eb) 2375d76a658Ssthen { 2385d76a658Ssthen struct ub_ctx* ctx = ub_ctx_create_nopipe(); 2395d76a658Ssthen if(!ctx) 2405d76a658Ssthen return NULL; 2415d76a658Ssthen /* no pipes, but we have the locks to make sure everything works */ 2425d76a658Ssthen ctx->created_bg = 0; 2435d76a658Ssthen ctx->dothread = 1; /* the processing is in the same process, 2445d76a658Ssthen makes ub_cancel and ub_ctx_delete do the right thing */ 2452ee382b6Ssthen ctx->event_base = ub_libevent_event_base(eb); 2462ee382b6Ssthen if (!ctx->event_base) { 2472ee382b6Ssthen ub_ctx_delete(ctx); 2482ee382b6Ssthen return NULL; 2492ee382b6Ssthen } 250ebf5bb73Ssthen ctx->event_base_malloced = 1; 2515d76a658Ssthen return ctx; 2525d76a658Ssthen } 2535d76a658Ssthen 254933707f3Ssthen /** delete q */ 255933707f3Ssthen static void 25677079be7Ssthen delq(rbnode_type* n, void* ATTR_UNUSED(arg)) 257933707f3Ssthen { 258933707f3Ssthen struct ctx_query* q = (struct ctx_query*)n; 259933707f3Ssthen context_query_delete(q); 260933707f3Ssthen } 261933707f3Ssthen 262229e174cSsthen /** stop the bg thread */ 263229e174cSsthen static void ub_stop_bg(struct ub_ctx* ctx) 264933707f3Ssthen { 265933707f3Ssthen /* stop the bg thread */ 266933707f3Ssthen lock_basic_lock(&ctx->cfglock); 267933707f3Ssthen if(ctx->created_bg) { 268933707f3Ssthen uint8_t* msg; 269933707f3Ssthen uint32_t len; 270933707f3Ssthen uint32_t cmd = UB_LIBCMD_QUIT; 271933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 272933707f3Ssthen lock_basic_lock(&ctx->qqpipe_lock); 273933707f3Ssthen (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd, 274933707f3Ssthen (uint32_t)sizeof(cmd), 0); 275933707f3Ssthen lock_basic_unlock(&ctx->qqpipe_lock); 276933707f3Ssthen lock_basic_lock(&ctx->rrpipe_lock); 277933707f3Ssthen while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) { 278933707f3Ssthen /* discard all results except a quit confirm */ 279933707f3Ssthen if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) { 280933707f3Ssthen free(msg); 281933707f3Ssthen break; 282933707f3Ssthen } 283933707f3Ssthen free(msg); 284933707f3Ssthen } 285933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 286933707f3Ssthen 287933707f3Ssthen /* if bg worker is a thread, wait for it to exit, so that all 288933707f3Ssthen * resources are really gone. */ 289933707f3Ssthen lock_basic_lock(&ctx->cfglock); 290933707f3Ssthen if(ctx->dothread) { 291933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 292933707f3Ssthen ub_thread_join(ctx->bg_tid); 293933707f3Ssthen } else { 294933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 295a961b961Ssthen #ifndef UB_ON_WINDOWS 296a961b961Ssthen if(waitpid(ctx->bg_pid, NULL, 0) == -1) { 297a961b961Ssthen if(verbosity > 2) 298a961b961Ssthen log_err("waitpid: %s", strerror(errno)); 299a961b961Ssthen } 300a961b961Ssthen #endif 301933707f3Ssthen } 302933707f3Ssthen } 303933707f3Ssthen else { 304933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 305933707f3Ssthen } 306229e174cSsthen } 307933707f3Ssthen 308229e174cSsthen void 309229e174cSsthen ub_ctx_delete(struct ub_ctx* ctx) 310229e174cSsthen { 311229e174cSsthen struct alloc_cache* a, *na; 312229e174cSsthen int do_stop = 1; 313229e174cSsthen if(!ctx) return; 314229e174cSsthen 3158b7325afSsthen /* if the delete is called but it has forked, and before the fork 3168b7325afSsthen * the context was finalized, then the bg worker is not stopped 3178b7325afSsthen * from here. There is one worker, but two contexts that refer to 3188b7325afSsthen * it and only one should clean up, the one with getpid == pipe_pid.*/ 3198b7325afSsthen if(ctx->created_bg && ctx->pipe_pid != getpid()) { 3208b7325afSsthen do_stop = 0; 3218b7325afSsthen #ifndef USE_WINSOCK 3228b7325afSsthen /* Stop events from getting deregistered, if the backend is 3238b7325afSsthen * epoll, the epoll fd is the same as the other process. 3248b7325afSsthen * That process should deregister them. */ 3258b7325afSsthen if(ctx->qq_pipe->listen_com) 3268b7325afSsthen ctx->qq_pipe->listen_com->event_added = 0; 3278b7325afSsthen if(ctx->qq_pipe->res_com) 3288b7325afSsthen ctx->qq_pipe->res_com->event_added = 0; 3298b7325afSsthen if(ctx->rr_pipe->listen_com) 3308b7325afSsthen ctx->rr_pipe->listen_com->event_added = 0; 3318b7325afSsthen if(ctx->rr_pipe->res_com) 3328b7325afSsthen ctx->rr_pipe->res_com->event_added = 0; 3338b7325afSsthen #endif 3348b7325afSsthen } 335229e174cSsthen /* see if bg thread is created and if threads have been killed */ 336229e174cSsthen /* no locks, because those may be held by terminated threads */ 337229e174cSsthen /* for processes the read pipe is closed and we see that on read */ 338229e174cSsthen #ifdef HAVE_PTHREAD 3398b7325afSsthen if(ctx->created_bg && ctx->dothread && do_stop) { 340229e174cSsthen if(pthread_kill(ctx->bg_tid, 0) == ESRCH) { 341229e174cSsthen /* thread has been killed */ 342229e174cSsthen do_stop = 0; 343229e174cSsthen } 344229e174cSsthen } 345229e174cSsthen #endif /* HAVE_PTHREAD */ 346229e174cSsthen if(do_stop) 347229e174cSsthen ub_stop_bg(ctx); 3488b7325afSsthen if(ctx->created_bg && ctx->pipe_pid != getpid() && ctx->thread_worker) { 3498b7325afSsthen /* This delete is happening from a different process. Delete 3508b7325afSsthen * the thread worker from this process memory space. The 3518b7325afSsthen * thread is not there to do so, so it is freed here. */ 3528b7325afSsthen struct ub_event_base* evbase = comm_base_internal( 3538b7325afSsthen ctx->thread_worker->base); 3548b7325afSsthen libworker_delete_event(ctx->thread_worker); 3558b7325afSsthen ctx->thread_worker = NULL; 3568b7325afSsthen #ifdef USE_MINI_EVENT 3578b7325afSsthen ub_event_base_free(evbase); 3588b7325afSsthen #else 3598b7325afSsthen /* cannot event_base_free, because the epoll_fd cleanup 3608b7325afSsthen * in libevent could stop the original event_base in the 3618b7325afSsthen * other process from working. */ 3628b7325afSsthen free(evbase); 3638b7325afSsthen #endif 3648b7325afSsthen } 3655d76a658Ssthen libworker_delete_event(ctx->event_worker); 366933707f3Ssthen 367*98bc733bSsthen modstack_call_deinit(&ctx->mods, ctx->env); 368*98bc733bSsthen modstack_call_destartup(&ctx->mods, ctx->env); 369*98bc733bSsthen modstack_free(&ctx->mods); 370933707f3Ssthen a = ctx->alloc_list; 371933707f3Ssthen while(a) { 372933707f3Ssthen na = a->super; 373933707f3Ssthen a->super = &ctx->superalloc; 374933707f3Ssthen alloc_clear(a); 375933707f3Ssthen free(a); 376933707f3Ssthen a = na; 377933707f3Ssthen } 378933707f3Ssthen local_zones_delete(ctx->local_zones); 379933707f3Ssthen lock_basic_destroy(&ctx->qqpipe_lock); 380933707f3Ssthen lock_basic_destroy(&ctx->rrpipe_lock); 381933707f3Ssthen lock_basic_destroy(&ctx->cfglock); 382933707f3Ssthen tube_delete(ctx->qq_pipe); 383933707f3Ssthen tube_delete(ctx->rr_pipe); 384933707f3Ssthen if(ctx->env) { 385933707f3Ssthen slabhash_delete(ctx->env->msg_cache); 386933707f3Ssthen rrset_cache_delete(ctx->env->rrset_cache); 387933707f3Ssthen infra_delete(ctx->env->infra_cache); 388933707f3Ssthen config_delete(ctx->env->cfg); 38977079be7Ssthen edns_known_options_delete(ctx->env); 390eba819a2Ssthen edns_strings_delete(ctx->env->edns_strings); 3912bdc0ed1Ssthen forwards_delete(ctx->env->fwds); 3922bdc0ed1Ssthen hints_delete(ctx->env->hints); 393938a3a5eSflorian auth_zones_delete(ctx->env->auth_zones); 394933707f3Ssthen free(ctx->env); 395933707f3Ssthen } 396933707f3Ssthen ub_randfree(ctx->seed_rnd); 397933707f3Ssthen alloc_clear(&ctx->superalloc); 398e21c60efSsthen listen_desetup_locks(); 399933707f3Ssthen traverse_postorder(&ctx->queries, delq, NULL); 4008240c1b9Ssthen if(ctx_logfile_overridden) { 4018240c1b9Ssthen log_file(NULL); 4028240c1b9Ssthen ctx_logfile_overridden = 0; 4038240c1b9Ssthen } 404ebf5bb73Ssthen if(ctx->event_base_malloced) 405ebf5bb73Ssthen free(ctx->event_base); 406933707f3Ssthen free(ctx); 407933707f3Ssthen #ifdef USE_WINSOCK 408933707f3Ssthen WSACleanup(); 409933707f3Ssthen #endif 410933707f3Ssthen } 411933707f3Ssthen 412933707f3Ssthen int 413229e174cSsthen ub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val) 414933707f3Ssthen { 415933707f3Ssthen lock_basic_lock(&ctx->cfglock); 416933707f3Ssthen if(ctx->finalized) { 417933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 418933707f3Ssthen return UB_AFTERFINAL; 419933707f3Ssthen } 420933707f3Ssthen if(!config_set_option(ctx->env->cfg, opt, val)) { 421933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 422933707f3Ssthen return UB_SYNTAX; 423933707f3Ssthen } 424933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 425933707f3Ssthen return UB_NOERROR; 426933707f3Ssthen } 427933707f3Ssthen 428933707f3Ssthen int 429229e174cSsthen ub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str) 430933707f3Ssthen { 431933707f3Ssthen int r; 432933707f3Ssthen lock_basic_lock(&ctx->cfglock); 433933707f3Ssthen r = config_get_option_collate(ctx->env->cfg, opt, str); 434933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 435933707f3Ssthen if(r == 0) r = UB_NOERROR; 436933707f3Ssthen else if(r == 1) r = UB_SYNTAX; 437933707f3Ssthen else if(r == 2) r = UB_NOMEM; 438933707f3Ssthen return r; 439933707f3Ssthen } 440933707f3Ssthen 441933707f3Ssthen int 442229e174cSsthen ub_ctx_config(struct ub_ctx* ctx, const char* fname) 443933707f3Ssthen { 444933707f3Ssthen lock_basic_lock(&ctx->cfglock); 445933707f3Ssthen if(ctx->finalized) { 446933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 447933707f3Ssthen return UB_AFTERFINAL; 448933707f3Ssthen } 449933707f3Ssthen if(!config_read(ctx->env->cfg, fname, NULL)) { 450933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 451933707f3Ssthen return UB_SYNTAX; 452933707f3Ssthen } 453933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 454933707f3Ssthen return UB_NOERROR; 455933707f3Ssthen } 456933707f3Ssthen 457933707f3Ssthen int 458229e174cSsthen ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta) 459933707f3Ssthen { 460933707f3Ssthen char* dup = strdup(ta); 461933707f3Ssthen if(!dup) return UB_NOMEM; 462933707f3Ssthen lock_basic_lock(&ctx->cfglock); 463933707f3Ssthen if(ctx->finalized) { 464933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 465933707f3Ssthen free(dup); 466933707f3Ssthen return UB_AFTERFINAL; 467933707f3Ssthen } 468933707f3Ssthen if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { 469933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 470933707f3Ssthen return UB_NOMEM; 471933707f3Ssthen } 472933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 473933707f3Ssthen return UB_NOERROR; 474933707f3Ssthen } 475933707f3Ssthen 476933707f3Ssthen int 477229e174cSsthen ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname) 478933707f3Ssthen { 479933707f3Ssthen char* dup = strdup(fname); 480933707f3Ssthen if(!dup) return UB_NOMEM; 481933707f3Ssthen lock_basic_lock(&ctx->cfglock); 482933707f3Ssthen if(ctx->finalized) { 483933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 484933707f3Ssthen free(dup); 485933707f3Ssthen return UB_AFTERFINAL; 486933707f3Ssthen } 487933707f3Ssthen if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) { 488933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 489933707f3Ssthen return UB_NOMEM; 490933707f3Ssthen } 491933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 492933707f3Ssthen return UB_NOERROR; 493933707f3Ssthen } 494933707f3Ssthen 49598f3ca02Sbrad int ub_ctx_add_ta_autr(struct ub_ctx* ctx, const char* fname) 49698f3ca02Sbrad { 49798f3ca02Sbrad char* dup = strdup(fname); 49898f3ca02Sbrad if(!dup) return UB_NOMEM; 49998f3ca02Sbrad lock_basic_lock(&ctx->cfglock); 50098f3ca02Sbrad if(ctx->finalized) { 50198f3ca02Sbrad lock_basic_unlock(&ctx->cfglock); 50298f3ca02Sbrad free(dup); 50398f3ca02Sbrad return UB_AFTERFINAL; 50498f3ca02Sbrad } 50598f3ca02Sbrad if(!cfg_strlist_insert(&ctx->env->cfg->auto_trust_anchor_file_list, 50698f3ca02Sbrad dup)) { 50798f3ca02Sbrad lock_basic_unlock(&ctx->cfglock); 50898f3ca02Sbrad return UB_NOMEM; 50998f3ca02Sbrad } 51098f3ca02Sbrad lock_basic_unlock(&ctx->cfglock); 51198f3ca02Sbrad return UB_NOERROR; 51298f3ca02Sbrad } 51398f3ca02Sbrad 514933707f3Ssthen int 515229e174cSsthen ub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname) 516933707f3Ssthen { 517933707f3Ssthen char* dup = strdup(fname); 518933707f3Ssthen if(!dup) return UB_NOMEM; 519933707f3Ssthen lock_basic_lock(&ctx->cfglock); 520933707f3Ssthen if(ctx->finalized) { 521933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 522933707f3Ssthen free(dup); 523933707f3Ssthen return UB_AFTERFINAL; 524933707f3Ssthen } 525933707f3Ssthen if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) { 526933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 527933707f3Ssthen return UB_NOMEM; 528933707f3Ssthen } 529933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 530933707f3Ssthen return UB_NOERROR; 531933707f3Ssthen } 532933707f3Ssthen 533933707f3Ssthen int 534933707f3Ssthen ub_ctx_debuglevel(struct ub_ctx* ctx, int d) 535933707f3Ssthen { 536933707f3Ssthen lock_basic_lock(&ctx->cfglock); 537933707f3Ssthen verbosity = d; 538933707f3Ssthen ctx->env->cfg->verbosity = d; 539933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 540933707f3Ssthen return UB_NOERROR; 541933707f3Ssthen } 542933707f3Ssthen 543933707f3Ssthen int ub_ctx_debugout(struct ub_ctx* ctx, void* out) 544933707f3Ssthen { 545933707f3Ssthen lock_basic_lock(&ctx->cfglock); 546933707f3Ssthen log_file((FILE*)out); 5478240c1b9Ssthen ctx_logfile_overridden = 1; 548933707f3Ssthen ctx->logfile_override = 1; 549933707f3Ssthen ctx->log_out = out; 550933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 551933707f3Ssthen return UB_NOERROR; 552933707f3Ssthen } 553933707f3Ssthen 554933707f3Ssthen int 555933707f3Ssthen ub_ctx_async(struct ub_ctx* ctx, int dothread) 556933707f3Ssthen { 557933707f3Ssthen #ifdef THREADS_DISABLED 558933707f3Ssthen if(dothread) /* cannot do threading */ 559933707f3Ssthen return UB_NOERROR; 560933707f3Ssthen #endif 561933707f3Ssthen lock_basic_lock(&ctx->cfglock); 562933707f3Ssthen if(ctx->finalized) { 563933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 564933707f3Ssthen return UB_AFTERFINAL; 565933707f3Ssthen } 566933707f3Ssthen ctx->dothread = dothread; 567933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 568933707f3Ssthen return UB_NOERROR; 569933707f3Ssthen } 570933707f3Ssthen 571933707f3Ssthen int 572933707f3Ssthen ub_poll(struct ub_ctx* ctx) 573933707f3Ssthen { 574933707f3Ssthen /* no need to hold lock while testing for readability. */ 575933707f3Ssthen return tube_poll(ctx->rr_pipe); 576933707f3Ssthen } 577933707f3Ssthen 578933707f3Ssthen int 579933707f3Ssthen ub_fd(struct ub_ctx* ctx) 580933707f3Ssthen { 581933707f3Ssthen return tube_read_fd(ctx->rr_pipe); 582933707f3Ssthen } 583933707f3Ssthen 584933707f3Ssthen /** process answer from bg worker */ 585933707f3Ssthen static int 586933707f3Ssthen process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, 58777079be7Ssthen ub_callback_type* cb, void** cbarg, int* err, 588933707f3Ssthen struct ub_result** res) 589933707f3Ssthen { 590933707f3Ssthen struct ctx_query* q; 591933707f3Ssthen if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) { 592933707f3Ssthen log_err("error: bad data from bg worker %d", 593933707f3Ssthen (int)context_serial_getcmd(msg, len)); 594933707f3Ssthen return 0; 595933707f3Ssthen } 596933707f3Ssthen 597933707f3Ssthen lock_basic_lock(&ctx->cfglock); 598933707f3Ssthen q = context_deserialize_answer(ctx, msg, len, err); 599933707f3Ssthen if(!q) { 600933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 601933707f3Ssthen /* probably simply the lookup that failed, i.e. 602933707f3Ssthen * response returned before cancel was sent out, so noerror */ 603933707f3Ssthen return 1; 604933707f3Ssthen } 605933707f3Ssthen log_assert(q->async); 606933707f3Ssthen 607933707f3Ssthen /* grab cb while locked */ 608933707f3Ssthen if(q->cancelled) { 609933707f3Ssthen *cb = NULL; 610933707f3Ssthen *cbarg = NULL; 611933707f3Ssthen } else { 612933707f3Ssthen *cb = q->cb; 613933707f3Ssthen *cbarg = q->cb_arg; 614933707f3Ssthen } 615933707f3Ssthen if(*err) { 616933707f3Ssthen *res = NULL; 617933707f3Ssthen ub_resolve_free(q->res); 618933707f3Ssthen } else { 619933707f3Ssthen /* parse the message, extract rcode, fill result */ 6205d76a658Ssthen sldns_buffer* buf = sldns_buffer_new(q->msg_len); 621933707f3Ssthen struct regional* region = regional_create(); 622933707f3Ssthen *res = q->res; 623933707f3Ssthen (*res)->rcode = LDNS_RCODE_SERVFAIL; 624933707f3Ssthen if(region && buf) { 6255d76a658Ssthen sldns_buffer_clear(buf); 6265d76a658Ssthen sldns_buffer_write(buf, q->msg, q->msg_len); 6275d76a658Ssthen sldns_buffer_flip(buf); 628933707f3Ssthen libworker_enter_result(*res, buf, region, 629933707f3Ssthen q->msg_security); 630933707f3Ssthen } 631933707f3Ssthen (*res)->answer_packet = q->msg; 632933707f3Ssthen (*res)->answer_len = (int)q->msg_len; 633933707f3Ssthen q->msg = NULL; 6345d76a658Ssthen sldns_buffer_free(buf); 635933707f3Ssthen regional_destroy(region); 636933707f3Ssthen } 637933707f3Ssthen q->res = NULL; 638933707f3Ssthen /* delete the q from list */ 639933707f3Ssthen (void)rbtree_delete(&ctx->queries, q->node.key); 640933707f3Ssthen ctx->num_async--; 641933707f3Ssthen context_query_delete(q); 642933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 643933707f3Ssthen 644933707f3Ssthen if(*cb) return 2; 645933707f3Ssthen ub_resolve_free(*res); 646933707f3Ssthen return 1; 647933707f3Ssthen } 648933707f3Ssthen 649933707f3Ssthen /** process answer from bg worker */ 650933707f3Ssthen static int 651933707f3Ssthen process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len) 652933707f3Ssthen { 653933707f3Ssthen int err; 65477079be7Ssthen ub_callback_type cb; 655933707f3Ssthen void* cbarg; 656933707f3Ssthen struct ub_result* res; 657933707f3Ssthen int r; 658933707f3Ssthen 659933707f3Ssthen r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); 660933707f3Ssthen 661933707f3Ssthen /* no locks held while calling callback, so that library is 662933707f3Ssthen * re-entrant. */ 663933707f3Ssthen if(r == 2) 664933707f3Ssthen (*cb)(cbarg, err, res); 665933707f3Ssthen 666933707f3Ssthen return r; 667933707f3Ssthen } 668933707f3Ssthen 669933707f3Ssthen int 670933707f3Ssthen ub_process(struct ub_ctx* ctx) 671933707f3Ssthen { 672933707f3Ssthen int r; 673933707f3Ssthen uint8_t* msg; 674933707f3Ssthen uint32_t len; 675933707f3Ssthen while(1) { 676933707f3Ssthen msg = NULL; 677933707f3Ssthen lock_basic_lock(&ctx->rrpipe_lock); 678933707f3Ssthen r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 679933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 680933707f3Ssthen if(r == 0) 681933707f3Ssthen return UB_PIPE; 682933707f3Ssthen else if(r == -1) 683933707f3Ssthen break; 684933707f3Ssthen if(!process_answer(ctx, msg, len)) { 685933707f3Ssthen free(msg); 686933707f3Ssthen return UB_PIPE; 687933707f3Ssthen } 688933707f3Ssthen free(msg); 689933707f3Ssthen } 690933707f3Ssthen return UB_NOERROR; 691933707f3Ssthen } 692933707f3Ssthen 693933707f3Ssthen int 694933707f3Ssthen ub_wait(struct ub_ctx* ctx) 695933707f3Ssthen { 696933707f3Ssthen int err; 69777079be7Ssthen ub_callback_type cb; 698933707f3Ssthen void* cbarg; 699933707f3Ssthen struct ub_result* res; 700933707f3Ssthen int r; 701933707f3Ssthen uint8_t* msg; 702933707f3Ssthen uint32_t len; 703933707f3Ssthen /* this is basically the same loop as _process(), but with changes. 704933707f3Ssthen * holds the rrpipe lock and waits with tube_wait */ 705933707f3Ssthen while(1) { 706933707f3Ssthen lock_basic_lock(&ctx->rrpipe_lock); 707933707f3Ssthen lock_basic_lock(&ctx->cfglock); 708933707f3Ssthen if(ctx->num_async == 0) { 709933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 710933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 711933707f3Ssthen break; 712933707f3Ssthen } 713933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 714933707f3Ssthen 715933707f3Ssthen /* keep rrpipe locked, while 716933707f3Ssthen * o waiting for pipe readable 717933707f3Ssthen * o parsing message 718933707f3Ssthen * o possibly decrementing num_async 719933707f3Ssthen * do callback without lock 720933707f3Ssthen */ 721933707f3Ssthen r = tube_wait(ctx->rr_pipe); 722933707f3Ssthen if(r) { 723933707f3Ssthen r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); 724933707f3Ssthen if(r == 0) { 725933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 726933707f3Ssthen return UB_PIPE; 727933707f3Ssthen } 728933707f3Ssthen if(r == -1) { 729933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 730933707f3Ssthen continue; 731933707f3Ssthen } 732933707f3Ssthen r = process_answer_detail(ctx, msg, len, 733933707f3Ssthen &cb, &cbarg, &err, &res); 734933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 735933707f3Ssthen free(msg); 736933707f3Ssthen if(r == 0) 737933707f3Ssthen return UB_PIPE; 738933707f3Ssthen if(r == 2) 739933707f3Ssthen (*cb)(cbarg, err, res); 740933707f3Ssthen } else { 741933707f3Ssthen lock_basic_unlock(&ctx->rrpipe_lock); 742933707f3Ssthen } 743933707f3Ssthen } 744933707f3Ssthen return UB_NOERROR; 745933707f3Ssthen } 746933707f3Ssthen 747933707f3Ssthen int 748229e174cSsthen ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, 749933707f3Ssthen int rrclass, struct ub_result** result) 750933707f3Ssthen { 751933707f3Ssthen struct ctx_query* q; 752933707f3Ssthen int r; 753933707f3Ssthen *result = NULL; 754933707f3Ssthen 755933707f3Ssthen lock_basic_lock(&ctx->cfglock); 756933707f3Ssthen if(!ctx->finalized) { 757933707f3Ssthen r = context_finalize(ctx); 758933707f3Ssthen if(r) { 759933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 760933707f3Ssthen return r; 761933707f3Ssthen } 762933707f3Ssthen } 763933707f3Ssthen /* create new ctx_query and attempt to add to the list */ 764933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 76520237c55Ssthen q = context_new(ctx, name, rrtype, rrclass, NULL, NULL, NULL); 766933707f3Ssthen if(!q) 767933707f3Ssthen return UB_NOMEM; 768933707f3Ssthen /* become a resolver thread for a bit */ 769933707f3Ssthen 770933707f3Ssthen r = libworker_fg(ctx, q); 771933707f3Ssthen if(r) { 772933707f3Ssthen lock_basic_lock(&ctx->cfglock); 773933707f3Ssthen (void)rbtree_delete(&ctx->queries, q->node.key); 774933707f3Ssthen context_query_delete(q); 775933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 776933707f3Ssthen return r; 777933707f3Ssthen } 778933707f3Ssthen q->res->answer_packet = q->msg; 779933707f3Ssthen q->res->answer_len = (int)q->msg_len; 780933707f3Ssthen q->msg = NULL; 781933707f3Ssthen *result = q->res; 782933707f3Ssthen q->res = NULL; 783933707f3Ssthen 784933707f3Ssthen lock_basic_lock(&ctx->cfglock); 785933707f3Ssthen (void)rbtree_delete(&ctx->queries, q->node.key); 786933707f3Ssthen context_query_delete(q); 787933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 788933707f3Ssthen return UB_NOERROR; 789933707f3Ssthen } 790933707f3Ssthen 791933707f3Ssthen int 7925d76a658Ssthen ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, 79377079be7Ssthen int rrclass, void* mydata, ub_event_callback_type callback, 79477079be7Ssthen int* async_id) 7955d76a658Ssthen { 7965d76a658Ssthen struct ctx_query* q; 7975d76a658Ssthen int r; 7985d76a658Ssthen 7995d76a658Ssthen if(async_id) 8005d76a658Ssthen *async_id = 0; 8015d76a658Ssthen lock_basic_lock(&ctx->cfglock); 8025d76a658Ssthen if(!ctx->finalized) { 803f6b99bafSsthen r = context_finalize(ctx); 8045d76a658Ssthen if(r) { 8055d76a658Ssthen lock_basic_unlock(&ctx->cfglock); 8065d76a658Ssthen return r; 8075d76a658Ssthen } 8085d76a658Ssthen } 8095d76a658Ssthen lock_basic_unlock(&ctx->cfglock); 8105d76a658Ssthen if(!ctx->event_worker) { 8115d76a658Ssthen ctx->event_worker = libworker_create_event(ctx, 8125d76a658Ssthen ctx->event_base); 8135d76a658Ssthen if(!ctx->event_worker) { 8145d76a658Ssthen return UB_INITFAIL; 8155d76a658Ssthen } 8165d76a658Ssthen } 8175d76a658Ssthen 8182ee382b6Ssthen /* set time in case answer comes from cache */ 8192ee382b6Ssthen ub_comm_base_now(ctx->event_worker->base); 8202ee382b6Ssthen 8215d76a658Ssthen /* create new ctx_query and attempt to add to the list */ 82220237c55Ssthen q = context_new(ctx, name, rrtype, rrclass, NULL, callback, mydata); 8235d76a658Ssthen if(!q) 8245d76a658Ssthen return UB_NOMEM; 8255d76a658Ssthen 8265d76a658Ssthen /* attach to mesh */ 8275d76a658Ssthen if((r=libworker_attach_mesh(ctx, q, async_id)) != 0) 8285d76a658Ssthen return r; 8295d76a658Ssthen return UB_NOERROR; 8305d76a658Ssthen } 8315d76a658Ssthen 8325d76a658Ssthen 8335d76a658Ssthen int 834229e174cSsthen ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, 83577079be7Ssthen int rrclass, void* mydata, ub_callback_type callback, int* async_id) 836933707f3Ssthen { 837933707f3Ssthen struct ctx_query* q; 838933707f3Ssthen uint8_t* msg = NULL; 839933707f3Ssthen uint32_t len = 0; 840933707f3Ssthen 841933707f3Ssthen if(async_id) 842933707f3Ssthen *async_id = 0; 843933707f3Ssthen lock_basic_lock(&ctx->cfglock); 844933707f3Ssthen if(!ctx->finalized) { 845933707f3Ssthen int r = context_finalize(ctx); 846933707f3Ssthen if(r) { 847933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 848933707f3Ssthen return r; 849933707f3Ssthen } 850933707f3Ssthen } 851933707f3Ssthen if(!ctx->created_bg) { 852933707f3Ssthen int r; 853933707f3Ssthen ctx->created_bg = 1; 854933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 855933707f3Ssthen r = libworker_bg(ctx); 856933707f3Ssthen if(r) { 857933707f3Ssthen lock_basic_lock(&ctx->cfglock); 858933707f3Ssthen ctx->created_bg = 0; 859933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 860933707f3Ssthen return r; 861933707f3Ssthen } 862933707f3Ssthen } else { 863933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 864933707f3Ssthen } 865933707f3Ssthen 866933707f3Ssthen /* create new ctx_query and attempt to add to the list */ 86720237c55Ssthen q = context_new(ctx, name, rrtype, rrclass, callback, NULL, mydata); 868933707f3Ssthen if(!q) 869933707f3Ssthen return UB_NOMEM; 870933707f3Ssthen 871933707f3Ssthen /* write over pipe to background worker */ 872933707f3Ssthen lock_basic_lock(&ctx->cfglock); 873933707f3Ssthen msg = context_serialize_new_query(q, &len); 874933707f3Ssthen if(!msg) { 875933707f3Ssthen (void)rbtree_delete(&ctx->queries, q->node.key); 876933707f3Ssthen ctx->num_async--; 877933707f3Ssthen context_query_delete(q); 878933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 879933707f3Ssthen return UB_NOMEM; 880933707f3Ssthen } 881933707f3Ssthen if(async_id) 882933707f3Ssthen *async_id = q->querynum; 883933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 884933707f3Ssthen 885933707f3Ssthen lock_basic_lock(&ctx->qqpipe_lock); 886933707f3Ssthen if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 887933707f3Ssthen lock_basic_unlock(&ctx->qqpipe_lock); 888933707f3Ssthen free(msg); 889933707f3Ssthen return UB_PIPE; 890933707f3Ssthen } 891933707f3Ssthen lock_basic_unlock(&ctx->qqpipe_lock); 892933707f3Ssthen free(msg); 893933707f3Ssthen return UB_NOERROR; 894933707f3Ssthen } 895933707f3Ssthen 896933707f3Ssthen int 897933707f3Ssthen ub_cancel(struct ub_ctx* ctx, int async_id) 898933707f3Ssthen { 899933707f3Ssthen struct ctx_query* q; 900933707f3Ssthen uint8_t* msg = NULL; 901933707f3Ssthen uint32_t len = 0; 902933707f3Ssthen lock_basic_lock(&ctx->cfglock); 903933707f3Ssthen q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id); 904933707f3Ssthen if(!q || !q->async) { 905933707f3Ssthen /* it is not there, so nothing to do */ 906933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 907933707f3Ssthen return UB_NOID; 908933707f3Ssthen } 909933707f3Ssthen log_assert(q->async); 910933707f3Ssthen q->cancelled = 1; 911933707f3Ssthen 912933707f3Ssthen /* delete it */ 913933707f3Ssthen if(!ctx->dothread) { /* if forked */ 914933707f3Ssthen (void)rbtree_delete(&ctx->queries, q->node.key); 915933707f3Ssthen ctx->num_async--; 916933707f3Ssthen msg = context_serialize_cancel(q, &len); 917933707f3Ssthen context_query_delete(q); 918933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 919933707f3Ssthen if(!msg) { 920933707f3Ssthen return UB_NOMEM; 921933707f3Ssthen } 922933707f3Ssthen /* send cancel to background worker */ 923933707f3Ssthen lock_basic_lock(&ctx->qqpipe_lock); 924933707f3Ssthen if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) { 925933707f3Ssthen lock_basic_unlock(&ctx->qqpipe_lock); 926933707f3Ssthen free(msg); 927933707f3Ssthen return UB_PIPE; 928933707f3Ssthen } 929933707f3Ssthen lock_basic_unlock(&ctx->qqpipe_lock); 930933707f3Ssthen free(msg); 931933707f3Ssthen } else { 932933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 933933707f3Ssthen } 934933707f3Ssthen return UB_NOERROR; 935933707f3Ssthen } 936933707f3Ssthen 937933707f3Ssthen void 938933707f3Ssthen ub_resolve_free(struct ub_result* result) 939933707f3Ssthen { 940933707f3Ssthen char** p; 941933707f3Ssthen if(!result) return; 942933707f3Ssthen free(result->qname); 943933707f3Ssthen if(result->canonname != result->qname) 944933707f3Ssthen free(result->canonname); 945933707f3Ssthen if(result->data) 946933707f3Ssthen for(p = result->data; *p; p++) 947933707f3Ssthen free(*p); 948933707f3Ssthen free(result->data); 949933707f3Ssthen free(result->len); 950933707f3Ssthen free(result->answer_packet); 951933707f3Ssthen free(result->why_bogus); 952933707f3Ssthen free(result); 953933707f3Ssthen } 954933707f3Ssthen 955933707f3Ssthen const char* 956933707f3Ssthen ub_strerror(int err) 957933707f3Ssthen { 958933707f3Ssthen switch(err) { 959933707f3Ssthen case UB_NOERROR: return "no error"; 960933707f3Ssthen case UB_SOCKET: return "socket io error"; 961933707f3Ssthen case UB_NOMEM: return "out of memory"; 962933707f3Ssthen case UB_SYNTAX: return "syntax error"; 963933707f3Ssthen case UB_SERVFAIL: return "server failure"; 964933707f3Ssthen case UB_FORKFAIL: return "could not fork"; 965933707f3Ssthen case UB_INITFAIL: return "initialization failure"; 966933707f3Ssthen case UB_AFTERFINAL: return "setting change after finalize"; 967933707f3Ssthen case UB_PIPE: return "error in pipe communication with async"; 968933707f3Ssthen case UB_READFILE: return "error reading file"; 969933707f3Ssthen case UB_NOID: return "error async_id does not exist"; 970933707f3Ssthen default: return "unknown error"; 971933707f3Ssthen } 972933707f3Ssthen } 973933707f3Ssthen 974933707f3Ssthen int 975229e174cSsthen ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr) 976933707f3Ssthen { 977933707f3Ssthen struct sockaddr_storage storage; 978933707f3Ssthen socklen_t stlen; 979933707f3Ssthen struct config_stub* s; 980933707f3Ssthen char* dupl; 981933707f3Ssthen lock_basic_lock(&ctx->cfglock); 982933707f3Ssthen if(ctx->finalized) { 983933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 984933707f3Ssthen errno=EINVAL; 985933707f3Ssthen return UB_AFTERFINAL; 986933707f3Ssthen } 987933707f3Ssthen if(!addr) { 988933707f3Ssthen /* disable fwd mode - the root stub should be first. */ 989933707f3Ssthen if(ctx->env->cfg->forwards && 990*98bc733bSsthen (ctx->env->cfg->forwards->name && 991*98bc733bSsthen strcmp(ctx->env->cfg->forwards->name, ".") == 0)) { 992933707f3Ssthen s = ctx->env->cfg->forwards; 993933707f3Ssthen ctx->env->cfg->forwards = s->next; 994933707f3Ssthen s->next = NULL; 995933707f3Ssthen config_delstubs(s); 996933707f3Ssthen } 997933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 998933707f3Ssthen return UB_NOERROR; 999933707f3Ssthen } 1000933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1001933707f3Ssthen 1002933707f3Ssthen /* check syntax for addr */ 100345872187Ssthen if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) { 1004933707f3Ssthen errno=EINVAL; 1005933707f3Ssthen return UB_SYNTAX; 1006933707f3Ssthen } 1007933707f3Ssthen 1008933707f3Ssthen /* it parses, add root stub in front of list */ 1009933707f3Ssthen lock_basic_lock(&ctx->cfglock); 1010933707f3Ssthen if(!ctx->env->cfg->forwards || 1011*98bc733bSsthen (ctx->env->cfg->forwards->name && 1012*98bc733bSsthen strcmp(ctx->env->cfg->forwards->name, ".") != 0)) { 1013933707f3Ssthen s = calloc(1, sizeof(*s)); 1014933707f3Ssthen if(!s) { 1015933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1016933707f3Ssthen errno=ENOMEM; 1017933707f3Ssthen return UB_NOMEM; 1018933707f3Ssthen } 1019933707f3Ssthen s->name = strdup("."); 1020933707f3Ssthen if(!s->name) { 1021933707f3Ssthen free(s); 1022933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1023933707f3Ssthen errno=ENOMEM; 1024933707f3Ssthen return UB_NOMEM; 1025933707f3Ssthen } 1026933707f3Ssthen s->next = ctx->env->cfg->forwards; 1027933707f3Ssthen ctx->env->cfg->forwards = s; 1028933707f3Ssthen } else { 1029933707f3Ssthen log_assert(ctx->env->cfg->forwards); 1030*98bc733bSsthen log_assert(ctx->env->cfg->forwards->name); 1031933707f3Ssthen s = ctx->env->cfg->forwards; 1032933707f3Ssthen } 1033933707f3Ssthen dupl = strdup(addr); 1034933707f3Ssthen if(!dupl) { 1035933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1036933707f3Ssthen errno=ENOMEM; 1037933707f3Ssthen return UB_NOMEM; 1038933707f3Ssthen } 1039933707f3Ssthen if(!cfg_strlist_insert(&s->addrs, dupl)) { 1040933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1041933707f3Ssthen errno=ENOMEM; 1042933707f3Ssthen return UB_NOMEM; 1043933707f3Ssthen } 1044933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1045933707f3Ssthen return UB_NOERROR; 1046933707f3Ssthen } 1047933707f3Ssthen 1048f6b99bafSsthen int ub_ctx_set_tls(struct ub_ctx* ctx, int tls) 1049f6b99bafSsthen { 1050f6b99bafSsthen lock_basic_lock(&ctx->cfglock); 1051f6b99bafSsthen if(ctx->finalized) { 1052f6b99bafSsthen lock_basic_unlock(&ctx->cfglock); 1053f6b99bafSsthen errno=EINVAL; 1054f6b99bafSsthen return UB_AFTERFINAL; 1055f6b99bafSsthen } 1056f6b99bafSsthen ctx->env->cfg->ssl_upstream = tls; 1057f6b99bafSsthen lock_basic_unlock(&ctx->cfglock); 1058f6b99bafSsthen return UB_NOERROR; 1059f6b99bafSsthen } 1060f6b99bafSsthen 106132e31f52Ssthen int ub_ctx_set_stub(struct ub_ctx* ctx, const char* zone, const char* addr, 106232e31f52Ssthen int isprime) 106332e31f52Ssthen { 106432e31f52Ssthen char* a; 106532e31f52Ssthen struct config_stub **prev, *elem; 106632e31f52Ssthen 106732e31f52Ssthen /* check syntax for zone name */ 106832e31f52Ssthen if(zone) { 106932e31f52Ssthen uint8_t* nm; 107032e31f52Ssthen int nmlabs; 107132e31f52Ssthen size_t nmlen; 107232e31f52Ssthen if(!parse_dname(zone, &nm, &nmlen, &nmlabs)) { 107332e31f52Ssthen errno=EINVAL; 107432e31f52Ssthen return UB_SYNTAX; 107532e31f52Ssthen } 107632e31f52Ssthen free(nm); 107732e31f52Ssthen } else { 107832e31f52Ssthen zone = "."; 107932e31f52Ssthen } 108032e31f52Ssthen 108132e31f52Ssthen /* check syntax for addr (if not NULL) */ 108232e31f52Ssthen if(addr) { 108332e31f52Ssthen struct sockaddr_storage storage; 108432e31f52Ssthen socklen_t stlen; 108545872187Ssthen if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) { 108632e31f52Ssthen errno=EINVAL; 108732e31f52Ssthen return UB_SYNTAX; 108832e31f52Ssthen } 108932e31f52Ssthen } 109032e31f52Ssthen 109132e31f52Ssthen lock_basic_lock(&ctx->cfglock); 109232e31f52Ssthen if(ctx->finalized) { 109332e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 109432e31f52Ssthen errno=EINVAL; 109532e31f52Ssthen return UB_AFTERFINAL; 109632e31f52Ssthen } 109732e31f52Ssthen 109832e31f52Ssthen /* arguments all right, now find or add the stub */ 109932e31f52Ssthen prev = &ctx->env->cfg->stubs; 110032e31f52Ssthen elem = cfg_stub_find(&prev, zone); 110132e31f52Ssthen if(!elem && !addr) { 110232e31f52Ssthen /* not found and we want to delete, nothing to do */ 110332e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 110432e31f52Ssthen return UB_NOERROR; 110532e31f52Ssthen } else if(elem && !addr) { 110632e31f52Ssthen /* found, and we want to delete */ 110732e31f52Ssthen *prev = elem->next; 110832e31f52Ssthen config_delstub(elem); 110932e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 111032e31f52Ssthen return UB_NOERROR; 111132e31f52Ssthen } else if(!elem) { 111232e31f52Ssthen /* not found, create the stub entry */ 111332e31f52Ssthen elem=(struct config_stub*)calloc(1, sizeof(struct config_stub)); 111432e31f52Ssthen if(elem) elem->name = strdup(zone); 111532e31f52Ssthen if(!elem || !elem->name) { 111632e31f52Ssthen free(elem); 111732e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 111832e31f52Ssthen errno = ENOMEM; 111932e31f52Ssthen return UB_NOMEM; 112032e31f52Ssthen } 112132e31f52Ssthen elem->next = ctx->env->cfg->stubs; 112232e31f52Ssthen ctx->env->cfg->stubs = elem; 112332e31f52Ssthen } 112432e31f52Ssthen 112532e31f52Ssthen /* add the address to the list and set settings */ 112632e31f52Ssthen elem->isprime = isprime; 112732e31f52Ssthen a = strdup(addr); 112832e31f52Ssthen if(!a) { 112932e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 113032e31f52Ssthen errno = ENOMEM; 113132e31f52Ssthen return UB_NOMEM; 113232e31f52Ssthen } 113332e31f52Ssthen if(!cfg_strlist_insert(&elem->addrs, a)) { 113432e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 113532e31f52Ssthen errno = ENOMEM; 113632e31f52Ssthen return UB_NOMEM; 113732e31f52Ssthen } 113832e31f52Ssthen lock_basic_unlock(&ctx->cfglock); 113932e31f52Ssthen return UB_NOERROR; 114032e31f52Ssthen } 114132e31f52Ssthen 1142933707f3Ssthen int 1143229e174cSsthen ub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname) 1144933707f3Ssthen { 1145933707f3Ssthen FILE* in; 1146933707f3Ssthen int numserv = 0; 1147933707f3Ssthen char buf[1024]; 1148933707f3Ssthen char* parse, *addr; 1149933707f3Ssthen int r; 1150933707f3Ssthen 1151933707f3Ssthen if(fname == NULL) { 1152933707f3Ssthen #if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H) 1153933707f3Ssthen fname = "/etc/resolv.conf"; 1154933707f3Ssthen #else 1155933707f3Ssthen FIXED_INFO *info; 1156933707f3Ssthen ULONG buflen = sizeof(*info); 1157933707f3Ssthen IP_ADDR_STRING *ptr; 1158933707f3Ssthen 1159933707f3Ssthen info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO)); 1160933707f3Ssthen if (info == NULL) 1161933707f3Ssthen return UB_READFILE; 1162933707f3Ssthen 1163933707f3Ssthen if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) { 1164933707f3Ssthen free(info); 1165933707f3Ssthen info = (FIXED_INFO *) malloc(buflen); 1166933707f3Ssthen if (info == NULL) 1167933707f3Ssthen return UB_READFILE; 1168933707f3Ssthen } 1169933707f3Ssthen 1170933707f3Ssthen if (GetNetworkParams(info, &buflen) == NO_ERROR) { 1171933707f3Ssthen int retval=0; 1172933707f3Ssthen ptr = &(info->DnsServerList); 1173933707f3Ssthen while (ptr) { 1174933707f3Ssthen numserv++; 1175933707f3Ssthen if((retval=ub_ctx_set_fwd(ctx, 117654baf1aaSjsg ptr->IpAddress.String))!=0) { 1177933707f3Ssthen free(info); 1178933707f3Ssthen return retval; 1179933707f3Ssthen } 1180933707f3Ssthen ptr = ptr->Next; 1181933707f3Ssthen } 1182933707f3Ssthen free(info); 1183933707f3Ssthen if (numserv==0) 1184933707f3Ssthen return UB_READFILE; 1185933707f3Ssthen return UB_NOERROR; 1186933707f3Ssthen } 1187933707f3Ssthen free(info); 1188933707f3Ssthen return UB_READFILE; 1189933707f3Ssthen #endif /* WINDOWS */ 1190933707f3Ssthen } 1191933707f3Ssthen in = fopen(fname, "r"); 1192933707f3Ssthen if(!in) { 1193933707f3Ssthen /* error in errno! perror(fname) */ 1194933707f3Ssthen return UB_READFILE; 1195933707f3Ssthen } 1196933707f3Ssthen while(fgets(buf, (int)sizeof(buf), in)) { 1197933707f3Ssthen buf[sizeof(buf)-1] = 0; 1198933707f3Ssthen parse=buf; 1199933707f3Ssthen while(*parse == ' ' || *parse == '\t') 1200933707f3Ssthen parse++; 1201933707f3Ssthen if(strncmp(parse, "nameserver", 10) == 0) { 1202933707f3Ssthen numserv++; 1203933707f3Ssthen parse += 10; /* skip 'nameserver' */ 1204933707f3Ssthen /* skip whitespace */ 1205933707f3Ssthen while(*parse == ' ' || *parse == '\t') 1206933707f3Ssthen parse++; 1207933707f3Ssthen addr = parse; 1208933707f3Ssthen /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */ 120998f3ca02Sbrad while(isxdigit((unsigned char)*parse) || *parse=='.' || *parse==':') 1210933707f3Ssthen parse++; 1211933707f3Ssthen /* terminate after the address, remove newline */ 1212933707f3Ssthen *parse = 0; 1213933707f3Ssthen 1214933707f3Ssthen if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) { 1215933707f3Ssthen fclose(in); 1216933707f3Ssthen return r; 1217933707f3Ssthen } 1218933707f3Ssthen } 1219933707f3Ssthen } 1220933707f3Ssthen fclose(in); 1221933707f3Ssthen if(numserv == 0) { 1222933707f3Ssthen /* from resolv.conf(5) if none given, use localhost */ 1223933707f3Ssthen return ub_ctx_set_fwd(ctx, "127.0.0.1"); 1224933707f3Ssthen } 1225933707f3Ssthen return UB_NOERROR; 1226933707f3Ssthen } 1227933707f3Ssthen 1228933707f3Ssthen int 1229229e174cSsthen ub_ctx_hosts(struct ub_ctx* ctx, const char* fname) 1230933707f3Ssthen { 1231933707f3Ssthen FILE* in; 12328240c1b9Ssthen char buf[1024], ldata[2048]; 1233933707f3Ssthen char* parse, *addr, *name, *ins; 1234933707f3Ssthen lock_basic_lock(&ctx->cfglock); 1235933707f3Ssthen if(ctx->finalized) { 1236933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1237933707f3Ssthen errno=EINVAL; 1238933707f3Ssthen return UB_AFTERFINAL; 1239933707f3Ssthen } 1240933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1241933707f3Ssthen if(fname == NULL) { 1242933707f3Ssthen #if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H) 1243933707f3Ssthen /* 1244933707f3Ssthen * If this is Windows NT/XP/2K it's in 1245933707f3Ssthen * %WINDIR%\system32\drivers\etc\hosts. 1246933707f3Ssthen * If this is Windows 95/98/Me it's in %WINDIR%\hosts. 1247933707f3Ssthen */ 1248933707f3Ssthen name = getenv("WINDIR"); 1249933707f3Ssthen if (name != NULL) { 1250933707f3Ssthen int retval=0; 1251933707f3Ssthen snprintf(buf, sizeof(buf), "%s%s", name, 1252933707f3Ssthen "\\system32\\drivers\\etc\\hosts"); 1253933707f3Ssthen if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) { 1254933707f3Ssthen snprintf(buf, sizeof(buf), "%s%s", name, 1255933707f3Ssthen "\\hosts"); 1256933707f3Ssthen retval=ub_ctx_hosts(ctx, buf); 1257933707f3Ssthen } 1258933707f3Ssthen return retval; 1259933707f3Ssthen } 1260933707f3Ssthen return UB_READFILE; 1261933707f3Ssthen #else 1262933707f3Ssthen fname = "/etc/hosts"; 1263933707f3Ssthen #endif /* WIN32 */ 1264933707f3Ssthen } 1265933707f3Ssthen in = fopen(fname, "r"); 1266933707f3Ssthen if(!in) { 1267933707f3Ssthen /* error in errno! perror(fname) */ 1268933707f3Ssthen return UB_READFILE; 1269933707f3Ssthen } 1270933707f3Ssthen while(fgets(buf, (int)sizeof(buf), in)) { 1271933707f3Ssthen buf[sizeof(buf)-1] = 0; 1272933707f3Ssthen parse=buf; 1273933707f3Ssthen while(*parse == ' ' || *parse == '\t') 1274933707f3Ssthen parse++; 1275933707f3Ssthen if(*parse == '#') 1276933707f3Ssthen continue; /* skip comment */ 1277933707f3Ssthen /* format: <addr> spaces <name> spaces <name> ... */ 1278933707f3Ssthen addr = parse; 1279933707f3Ssthen /* skip addr */ 128098f3ca02Sbrad while(isxdigit((unsigned char)*parse) || *parse == '.' || *parse == ':') 1281933707f3Ssthen parse++; 1282fdfb4ba6Ssthen if(*parse == '\r') 1283fdfb4ba6Ssthen parse++; 1284933707f3Ssthen if(*parse == '\n' || *parse == 0) 1285933707f3Ssthen continue; 1286933707f3Ssthen if(*parse == '%') 1287933707f3Ssthen continue; /* ignore macOSX fe80::1%lo0 localhost */ 1288933707f3Ssthen if(*parse != ' ' && *parse != '\t') { 1289933707f3Ssthen /* must have whitespace after address */ 1290933707f3Ssthen fclose(in); 1291933707f3Ssthen errno=EINVAL; 1292933707f3Ssthen return UB_SYNTAX; 1293933707f3Ssthen } 1294933707f3Ssthen *parse++ = 0; /* end delimiter for addr ... */ 1295933707f3Ssthen /* go to names and add them */ 1296933707f3Ssthen while(*parse) { 1297fdfb4ba6Ssthen while(*parse == ' ' || *parse == '\t' || *parse=='\n' 1298fdfb4ba6Ssthen || *parse=='\r') 1299933707f3Ssthen parse++; 1300933707f3Ssthen if(*parse == 0 || *parse == '#') 1301933707f3Ssthen break; 1302933707f3Ssthen /* skip name, allows (too) many printable characters */ 1303933707f3Ssthen name = parse; 1304933707f3Ssthen while('!' <= *parse && *parse <= '~') 1305933707f3Ssthen parse++; 1306933707f3Ssthen if(*parse) 1307933707f3Ssthen *parse++ = 0; /* end delimiter for name */ 1308933707f3Ssthen snprintf(ldata, sizeof(ldata), "%s %s %s", 1309933707f3Ssthen name, str_is_ip6(addr)?"AAAA":"A", addr); 1310933707f3Ssthen ins = strdup(ldata); 1311933707f3Ssthen if(!ins) { 1312933707f3Ssthen /* out of memory */ 1313933707f3Ssthen fclose(in); 1314933707f3Ssthen errno=ENOMEM; 1315933707f3Ssthen return UB_NOMEM; 1316933707f3Ssthen } 1317933707f3Ssthen lock_basic_lock(&ctx->cfglock); 1318933707f3Ssthen if(!cfg_strlist_insert(&ctx->env->cfg->local_data, 1319933707f3Ssthen ins)) { 1320933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1321933707f3Ssthen fclose(in); 1322933707f3Ssthen errno=ENOMEM; 1323933707f3Ssthen return UB_NOMEM; 1324933707f3Ssthen } 1325933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1326933707f3Ssthen } 1327933707f3Ssthen } 1328933707f3Ssthen fclose(in); 1329933707f3Ssthen return UB_NOERROR; 1330933707f3Ssthen } 1331933707f3Ssthen 1332933707f3Ssthen /** finalize the context, if not already finalized */ 1333933707f3Ssthen static int ub_ctx_finalize(struct ub_ctx* ctx) 1334933707f3Ssthen { 1335933707f3Ssthen int res = 0; 1336933707f3Ssthen lock_basic_lock(&ctx->cfglock); 1337933707f3Ssthen if (!ctx->finalized) { 1338933707f3Ssthen res = context_finalize(ctx); 1339933707f3Ssthen } 1340933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 1341933707f3Ssthen return res; 1342933707f3Ssthen } 1343933707f3Ssthen 1344933707f3Ssthen /* Print local zones and RR data */ 1345933707f3Ssthen int ub_ctx_print_local_zones(struct ub_ctx* ctx) 1346933707f3Ssthen { 1347933707f3Ssthen int res = ub_ctx_finalize(ctx); 1348933707f3Ssthen if (res) return res; 1349933707f3Ssthen 1350933707f3Ssthen local_zones_print(ctx->local_zones); 1351933707f3Ssthen 1352933707f3Ssthen return UB_NOERROR; 1353933707f3Ssthen } 1354933707f3Ssthen 1355933707f3Ssthen /* Add a new zone */ 1356229e174cSsthen int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, 1357229e174cSsthen const char *zone_type) 1358933707f3Ssthen { 1359933707f3Ssthen enum localzone_type t; 1360933707f3Ssthen struct local_zone* z; 1361933707f3Ssthen uint8_t* nm; 1362933707f3Ssthen int nmlabs; 1363933707f3Ssthen size_t nmlen; 1364933707f3Ssthen 1365933707f3Ssthen int res = ub_ctx_finalize(ctx); 1366933707f3Ssthen if (res) return res; 1367933707f3Ssthen 1368933707f3Ssthen if(!local_zone_str2type(zone_type, &t)) { 1369933707f3Ssthen return UB_SYNTAX; 1370933707f3Ssthen } 1371933707f3Ssthen 1372933707f3Ssthen if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1373933707f3Ssthen return UB_SYNTAX; 1374933707f3Ssthen } 1375933707f3Ssthen 13765d76a658Ssthen lock_rw_wrlock(&ctx->local_zones->lock); 1377933707f3Ssthen if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1378933707f3Ssthen LDNS_RR_CLASS_IN))) { 1379933707f3Ssthen /* already present in tree */ 1380933707f3Ssthen lock_rw_wrlock(&z->lock); 1381933707f3Ssthen z->type = t; /* update type anyway */ 1382933707f3Ssthen lock_rw_unlock(&z->lock); 13835d76a658Ssthen lock_rw_unlock(&ctx->local_zones->lock); 1384933707f3Ssthen free(nm); 1385933707f3Ssthen return UB_NOERROR; 1386933707f3Ssthen } 1387933707f3Ssthen if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, 1388933707f3Ssthen LDNS_RR_CLASS_IN, t)) { 13895d76a658Ssthen lock_rw_unlock(&ctx->local_zones->lock); 1390933707f3Ssthen return UB_NOMEM; 1391933707f3Ssthen } 13925d76a658Ssthen lock_rw_unlock(&ctx->local_zones->lock); 1393933707f3Ssthen return UB_NOERROR; 1394933707f3Ssthen } 1395933707f3Ssthen 1396933707f3Ssthen /* Remove zone */ 1397229e174cSsthen int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name) 1398933707f3Ssthen { 1399933707f3Ssthen struct local_zone* z; 1400933707f3Ssthen uint8_t* nm; 1401933707f3Ssthen int nmlabs; 1402933707f3Ssthen size_t nmlen; 1403933707f3Ssthen 1404933707f3Ssthen int res = ub_ctx_finalize(ctx); 1405933707f3Ssthen if (res) return res; 1406933707f3Ssthen 1407933707f3Ssthen if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) { 1408933707f3Ssthen return UB_SYNTAX; 1409933707f3Ssthen } 1410933707f3Ssthen 14115d76a658Ssthen lock_rw_wrlock(&ctx->local_zones->lock); 1412933707f3Ssthen if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, 1413933707f3Ssthen LDNS_RR_CLASS_IN))) { 1414933707f3Ssthen /* present in tree */ 1415933707f3Ssthen local_zones_del_zone(ctx->local_zones, z); 1416933707f3Ssthen } 14175d76a658Ssthen lock_rw_unlock(&ctx->local_zones->lock); 1418933707f3Ssthen free(nm); 1419933707f3Ssthen return UB_NOERROR; 1420933707f3Ssthen } 1421933707f3Ssthen 1422933707f3Ssthen /* Add new RR data */ 1423229e174cSsthen int ub_ctx_data_add(struct ub_ctx* ctx, const char *data) 1424933707f3Ssthen { 1425933707f3Ssthen int res = ub_ctx_finalize(ctx); 1426933707f3Ssthen if (res) return res; 1427933707f3Ssthen 14285d76a658Ssthen res = local_zones_add_RR(ctx->local_zones, data); 1429933707f3Ssthen return (!res) ? UB_NOMEM : UB_NOERROR; 1430933707f3Ssthen } 1431933707f3Ssthen 1432933707f3Ssthen /* Remove RR data */ 1433229e174cSsthen int ub_ctx_data_remove(struct ub_ctx* ctx, const char *data) 1434933707f3Ssthen { 1435933707f3Ssthen uint8_t* nm; 1436933707f3Ssthen int nmlabs; 1437933707f3Ssthen size_t nmlen; 1438933707f3Ssthen int res = ub_ctx_finalize(ctx); 1439933707f3Ssthen if (res) return res; 1440933707f3Ssthen 1441933707f3Ssthen if(!parse_dname(data, &nm, &nmlen, &nmlabs)) 1442933707f3Ssthen return UB_SYNTAX; 1443933707f3Ssthen 1444933707f3Ssthen local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs, 1445933707f3Ssthen LDNS_RR_CLASS_IN); 1446933707f3Ssthen 1447933707f3Ssthen free(nm); 1448933707f3Ssthen return UB_NOERROR; 1449933707f3Ssthen } 1450933707f3Ssthen 1451933707f3Ssthen const char* ub_version(void) 1452933707f3Ssthen { 1453933707f3Ssthen return PACKAGE_VERSION; 1454933707f3Ssthen } 14555d76a658Ssthen 14565d76a658Ssthen int 14575d76a658Ssthen ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) { 14582ee382b6Ssthen struct ub_event_base* new_base; 14592ee382b6Ssthen 14605d76a658Ssthen if (!ctx || !ctx->event_base || !base) { 14615d76a658Ssthen return UB_INITFAIL; 14625d76a658Ssthen } 14632ee382b6Ssthen if (ub_libevent_get_event_base(ctx->event_base) == base) { 14645d76a658Ssthen /* already set */ 14655d76a658Ssthen return UB_NOERROR; 14665d76a658Ssthen } 14675d76a658Ssthen 14685d76a658Ssthen lock_basic_lock(&ctx->cfglock); 14695d76a658Ssthen /* destroy the current worker - safe to pass in NULL */ 14705d76a658Ssthen libworker_delete_event(ctx->event_worker); 14715d76a658Ssthen ctx->event_worker = NULL; 14722ee382b6Ssthen new_base = ub_libevent_event_base(base); 14732ee382b6Ssthen if (new_base) 14742ee382b6Ssthen ctx->event_base = new_base; 14755d76a658Ssthen ctx->created_bg = 0; 14765d76a658Ssthen ctx->dothread = 1; 14775d76a658Ssthen lock_basic_unlock(&ctx->cfglock); 14782ee382b6Ssthen return new_base ? UB_NOERROR : UB_INITFAIL; 14795d76a658Ssthen } 1480