libworker.c revision 249141
1238106Sdes/* 2238106Sdes * libunbound/worker.c - worker thread or process that resolves 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 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains the worker process or thread that performs 40238106Sdes * the DNS resolving and validation. The worker is called by a procedure 41238106Sdes * and if in the background continues until exit, if in the foreground 42238106Sdes * returns from the procedure when done. 43238106Sdes */ 44238106Sdes#include "config.h" 45238106Sdes#include <ldns/dname.h> 46238106Sdes#include <ldns/wire2host.h> 47249141Sdes#ifdef HAVE_SSL 48238106Sdes#include <openssl/ssl.h> 49249141Sdes#endif 50238106Sdes#include "libunbound/libworker.h" 51238106Sdes#include "libunbound/context.h" 52238106Sdes#include "libunbound/unbound.h" 53238106Sdes#include "services/outside_network.h" 54238106Sdes#include "services/mesh.h" 55238106Sdes#include "services/localzone.h" 56238106Sdes#include "services/cache/rrset.h" 57238106Sdes#include "services/outbound_list.h" 58238106Sdes#include "util/module.h" 59238106Sdes#include "util/regional.h" 60238106Sdes#include "util/random.h" 61238106Sdes#include "util/config_file.h" 62238106Sdes#include "util/netevent.h" 63238106Sdes#include "util/storage/lookup3.h" 64238106Sdes#include "util/storage/slabhash.h" 65238106Sdes#include "util/net_help.h" 66238106Sdes#include "util/data/dname.h" 67238106Sdes#include "util/data/msgreply.h" 68238106Sdes#include "util/data/msgencode.h" 69238106Sdes#include "util/tube.h" 70238106Sdes#include "iterator/iter_fwd.h" 71238106Sdes#include "iterator/iter_hints.h" 72238106Sdes 73238106Sdes/** handle new query command for bg worker */ 74238106Sdesstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len); 75238106Sdes 76238106Sdes/** delete libworker struct */ 77238106Sdesstatic void 78238106Sdeslibworker_delete(struct libworker* w) 79238106Sdes{ 80238106Sdes if(!w) return; 81238106Sdes if(w->env) { 82238106Sdes outside_network_quit_prepare(w->back); 83238106Sdes mesh_delete(w->env->mesh); 84238106Sdes context_release_alloc(w->ctx, w->env->alloc, 85238106Sdes !w->is_bg || w->is_bg_thread); 86238106Sdes ldns_buffer_free(w->env->scratch_buffer); 87238106Sdes regional_destroy(w->env->scratch); 88238106Sdes forwards_delete(w->env->fwds); 89238106Sdes hints_delete(w->env->hints); 90238106Sdes ub_randfree(w->env->rnd); 91238106Sdes free(w->env); 92238106Sdes } 93249141Sdes#ifdef HAVE_SSL 94238106Sdes SSL_CTX_free(w->sslctx); 95249141Sdes#endif 96238106Sdes outside_network_delete(w->back); 97238106Sdes comm_base_delete(w->base); 98238106Sdes free(w); 99238106Sdes} 100238106Sdes 101238106Sdes/** setup fresh libworker struct */ 102238106Sdesstatic struct libworker* 103238106Sdeslibworker_setup(struct ub_ctx* ctx, int is_bg) 104238106Sdes{ 105238106Sdes unsigned int seed; 106238106Sdes struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); 107238106Sdes struct config_file* cfg = ctx->env->cfg; 108238106Sdes int* ports; 109238106Sdes int numports; 110238106Sdes if(!w) return NULL; 111238106Sdes w->is_bg = is_bg; 112238106Sdes w->ctx = ctx; 113238106Sdes w->env = (struct module_env*)malloc(sizeof(*w->env)); 114238106Sdes if(!w->env) { 115238106Sdes free(w); 116238106Sdes return NULL; 117238106Sdes } 118238106Sdes *w->env = *ctx->env; 119238106Sdes w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread); 120238106Sdes if(!w->env->alloc) { 121238106Sdes libworker_delete(w); 122238106Sdes return NULL; 123238106Sdes } 124238106Sdes w->thread_num = w->env->alloc->thread_num; 125238106Sdes alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w); 126238106Sdes if(!w->is_bg || w->is_bg_thread) { 127238106Sdes lock_basic_lock(&ctx->cfglock); 128238106Sdes } 129238106Sdes w->env->scratch = regional_create_custom(cfg->msg_buffer_size); 130238106Sdes w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size); 131238106Sdes w->env->fwds = forwards_create(); 132238106Sdes if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { 133238106Sdes forwards_delete(w->env->fwds); 134238106Sdes w->env->fwds = NULL; 135238106Sdes } 136238106Sdes w->env->hints = hints_create(); 137238106Sdes if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { 138238106Sdes hints_delete(w->env->hints); 139238106Sdes w->env->hints = NULL; 140238106Sdes } 141238106Sdes if(cfg->ssl_upstream) { 142238106Sdes w->sslctx = connect_sslctx_create(NULL, NULL, NULL); 143238106Sdes if(!w->sslctx) { 144238106Sdes /* to make the setup fail after unlock */ 145238106Sdes hints_delete(w->env->hints); 146238106Sdes w->env->hints = NULL; 147238106Sdes } 148238106Sdes } 149238106Sdes if(!w->is_bg || w->is_bg_thread) { 150238106Sdes lock_basic_unlock(&ctx->cfglock); 151238106Sdes } 152238106Sdes if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds || 153238106Sdes !w->env->hints) { 154238106Sdes libworker_delete(w); 155238106Sdes return NULL; 156238106Sdes } 157238106Sdes w->env->worker = (struct worker*)w; 158238106Sdes w->env->probe_timer = NULL; 159238106Sdes seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ 160238106Sdes (((unsigned int)w->thread_num)<<17); 161238106Sdes seed ^= (unsigned int)w->env->alloc->next_id; 162238106Sdes if(!w->is_bg || w->is_bg_thread) { 163238106Sdes lock_basic_lock(&ctx->cfglock); 164238106Sdes } 165238106Sdes if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) { 166238106Sdes if(!w->is_bg || w->is_bg_thread) { 167238106Sdes lock_basic_unlock(&ctx->cfglock); 168238106Sdes } 169238106Sdes seed = 0; 170238106Sdes libworker_delete(w); 171238106Sdes return NULL; 172238106Sdes } 173238106Sdes if(!w->is_bg || w->is_bg_thread) { 174238106Sdes lock_basic_unlock(&ctx->cfglock); 175238106Sdes } 176238106Sdes if(1) { 177238106Sdes /* primitive lockout for threading: if it overwrites another 178238106Sdes * thread it is like wiping the cache (which is likely empty 179238106Sdes * at the start) */ 180238106Sdes /* note we are holding the ctx lock in normal threaded 181238106Sdes * cases so that is solved properly, it is only for many ctx 182238106Sdes * in different threads that this may clash */ 183238106Sdes static int done_raninit = 0; 184238106Sdes if(!done_raninit) { 185238106Sdes done_raninit = 1; 186238106Sdes hash_set_raninit((uint32_t)ub_random(w->env->rnd)); 187238106Sdes } 188238106Sdes } 189238106Sdes seed = 0; 190238106Sdes 191238106Sdes w->base = comm_base_create(0); 192238106Sdes if(!w->base) { 193238106Sdes libworker_delete(w); 194238106Sdes return NULL; 195238106Sdes } 196238106Sdes if(!w->is_bg || w->is_bg_thread) { 197238106Sdes lock_basic_lock(&ctx->cfglock); 198238106Sdes } 199238106Sdes numports = cfg_condense_ports(cfg, &ports); 200238106Sdes if(numports == 0) { 201238106Sdes libworker_delete(w); 202238106Sdes return NULL; 203238106Sdes } 204238106Sdes w->back = outside_network_create(w->base, cfg->msg_buffer_size, 205238106Sdes (size_t)cfg->outgoing_num_ports, cfg->out_ifs, 206238106Sdes cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 207238106Sdes cfg->do_tcp?cfg->outgoing_num_tcp:0, 208238106Sdes w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, 209238106Sdes ports, numports, cfg->unwanted_threshold, 210238106Sdes &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx); 211238106Sdes if(!w->is_bg || w->is_bg_thread) { 212238106Sdes lock_basic_unlock(&ctx->cfglock); 213238106Sdes } 214238106Sdes free(ports); 215238106Sdes if(!w->back) { 216238106Sdes libworker_delete(w); 217238106Sdes return NULL; 218238106Sdes } 219238106Sdes w->env->mesh = mesh_create(&ctx->mods, w->env); 220238106Sdes if(!w->env->mesh) { 221238106Sdes libworker_delete(w); 222238106Sdes return NULL; 223238106Sdes } 224238106Sdes w->env->send_query = &libworker_send_query; 225238106Sdes w->env->detach_subs = &mesh_detach_subs; 226238106Sdes w->env->attach_sub = &mesh_attach_sub; 227238106Sdes w->env->kill_sub = &mesh_state_delete; 228238106Sdes w->env->detect_cycle = &mesh_detect_cycle; 229238106Sdes comm_base_timept(w->base, &w->env->now, &w->env->now_tv); 230238106Sdes return w; 231238106Sdes} 232238106Sdes 233238106Sdes/** handle cancel command for bg worker */ 234238106Sdesstatic void 235238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len) 236238106Sdes{ 237238106Sdes struct ctx_query* q; 238238106Sdes if(w->is_bg_thread) { 239238106Sdes lock_basic_lock(&w->ctx->cfglock); 240238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 241238106Sdes lock_basic_unlock(&w->ctx->cfglock); 242238106Sdes } else { 243238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 244238106Sdes } 245238106Sdes if(!q) { 246238106Sdes /* probably simply lookup failed, i.e. the message had been 247238106Sdes * processed and answered before the cancel arrived */ 248238106Sdes return; 249238106Sdes } 250238106Sdes q->cancelled = 1; 251238106Sdes free(buf); 252238106Sdes} 253238106Sdes 254238106Sdes/** do control command coming into bg server */ 255238106Sdesstatic void 256238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len) 257238106Sdes{ 258238106Sdes switch(context_serial_getcmd(msg, len)) { 259238106Sdes default: 260238106Sdes case UB_LIBCMD_ANSWER: 261238106Sdes log_err("unknown command for bg worker %d", 262238106Sdes (int)context_serial_getcmd(msg, len)); 263238106Sdes /* and fall through to quit */ 264238106Sdes case UB_LIBCMD_QUIT: 265238106Sdes free(msg); 266238106Sdes comm_base_exit(w->base); 267238106Sdes break; 268238106Sdes case UB_LIBCMD_NEWQUERY: 269238106Sdes handle_newq(w, msg, len); 270238106Sdes break; 271238106Sdes case UB_LIBCMD_CANCEL: 272238106Sdes handle_cancel(w, msg, len); 273238106Sdes break; 274238106Sdes } 275238106Sdes} 276238106Sdes 277238106Sdes/** handle control command coming into server */ 278238106Sdesvoid 279238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 280238106Sdes uint8_t* msg, size_t len, int err, void* arg) 281238106Sdes{ 282238106Sdes struct libworker* w = (struct libworker*)arg; 283238106Sdes 284238106Sdes if(err != 0) { 285238106Sdes free(msg); 286238106Sdes /* it is of no use to go on, exit */ 287238106Sdes comm_base_exit(w->base); 288238106Sdes return; 289238106Sdes } 290238106Sdes libworker_do_cmd(w, msg, len); /* also frees the buf */ 291238106Sdes} 292238106Sdes 293238106Sdes/** the background thread func */ 294238106Sdesstatic void* 295238106Sdeslibworker_dobg(void* arg) 296238106Sdes{ 297238106Sdes /* setup */ 298238106Sdes uint32_t m; 299238106Sdes struct libworker* w = (struct libworker*)arg; 300238106Sdes struct ub_ctx* ctx; 301238106Sdes if(!w) { 302238106Sdes log_err("libunbound bg worker init failed, nomem"); 303238106Sdes return NULL; 304238106Sdes } 305238106Sdes ctx = w->ctx; 306238106Sdes log_thread_set(&w->thread_num); 307238106Sdes#ifdef THREADS_DISABLED 308238106Sdes /* we are forked */ 309238106Sdes w->is_bg_thread = 0; 310238106Sdes /* close non-used parts of the pipes */ 311238106Sdes tube_close_write(ctx->qq_pipe); 312238106Sdes tube_close_read(ctx->rr_pipe); 313238106Sdes#endif 314238106Sdes if(!tube_setup_bg_listen(ctx->qq_pipe, w->base, 315238106Sdes libworker_handle_control_cmd, w)) { 316238106Sdes log_err("libunbound bg worker init failed, no bglisten"); 317238106Sdes return NULL; 318238106Sdes } 319238106Sdes if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) { 320238106Sdes log_err("libunbound bg worker init failed, no bgwrite"); 321238106Sdes return NULL; 322238106Sdes } 323238106Sdes 324238106Sdes /* do the work */ 325238106Sdes comm_base_dispatch(w->base); 326238106Sdes 327238106Sdes /* cleanup */ 328238106Sdes m = UB_LIBCMD_QUIT; 329238106Sdes tube_remove_bg_listen(w->ctx->qq_pipe); 330238106Sdes tube_remove_bg_write(w->ctx->rr_pipe); 331238106Sdes libworker_delete(w); 332238106Sdes (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m, 333238106Sdes (uint32_t)sizeof(m), 0); 334238106Sdes#ifdef THREADS_DISABLED 335238106Sdes /* close pipes from forked process before exit */ 336238106Sdes tube_close_read(ctx->qq_pipe); 337238106Sdes tube_close_write(ctx->rr_pipe); 338238106Sdes#endif 339238106Sdes return NULL; 340238106Sdes} 341238106Sdes 342238106Sdesint libworker_bg(struct ub_ctx* ctx) 343238106Sdes{ 344238106Sdes struct libworker* w; 345238106Sdes /* fork or threadcreate */ 346238106Sdes lock_basic_lock(&ctx->cfglock); 347238106Sdes if(ctx->dothread) { 348238106Sdes lock_basic_unlock(&ctx->cfglock); 349238106Sdes w = libworker_setup(ctx, 1); 350238106Sdes if(!w) return UB_NOMEM; 351238106Sdes w->is_bg_thread = 1; 352238106Sdes#ifdef ENABLE_LOCK_CHECKS 353238106Sdes w->thread_num = 1; /* for nicer DEBUG checklocks */ 354238106Sdes#endif 355238106Sdes ub_thread_create(&ctx->bg_tid, libworker_dobg, w); 356238106Sdes } else { 357238106Sdes lock_basic_unlock(&ctx->cfglock); 358238106Sdes#ifndef HAVE_FORK 359238106Sdes /* no fork on windows */ 360238106Sdes return UB_FORKFAIL; 361238106Sdes#else /* HAVE_FORK */ 362238106Sdes switch((ctx->bg_pid=fork())) { 363238106Sdes case 0: 364238106Sdes w = libworker_setup(ctx, 1); 365238106Sdes if(!w) fatal_exit("out of memory"); 366238106Sdes /* close non-used parts of the pipes */ 367238106Sdes tube_close_write(ctx->qq_pipe); 368238106Sdes tube_close_read(ctx->rr_pipe); 369238106Sdes (void)libworker_dobg(w); 370238106Sdes exit(0); 371238106Sdes break; 372238106Sdes case -1: 373238106Sdes return UB_FORKFAIL; 374238106Sdes default: 375238106Sdes break; 376238106Sdes } 377238106Sdes#endif /* HAVE_FORK */ 378238106Sdes } 379238106Sdes return UB_NOERROR; 380238106Sdes} 381238106Sdes 382238106Sdes/** get msg reply struct (in temp region) */ 383238106Sdesstatic struct reply_info* 384238106Sdesparse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) 385238106Sdes{ 386238106Sdes struct reply_info* rep; 387238106Sdes struct msg_parse* msg; 388238106Sdes if(!(msg = regional_alloc(region, sizeof(*msg)))) { 389238106Sdes return NULL; 390238106Sdes } 391238106Sdes memset(msg, 0, sizeof(*msg)); 392238106Sdes ldns_buffer_set_position(pkt, 0); 393238106Sdes if(parse_packet(pkt, msg, region) != 0) 394238106Sdes return 0; 395238106Sdes if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { 396238106Sdes return 0; 397238106Sdes } 398238106Sdes return rep; 399238106Sdes} 400238106Sdes 401238106Sdes/** insert canonname */ 402238106Sdesstatic int 403238106Sdesfill_canon(struct ub_result* res, uint8_t* s) 404238106Sdes{ 405238106Sdes char buf[255+2]; 406238106Sdes dname_str(s, buf); 407238106Sdes res->canonname = strdup(buf); 408238106Sdes return res->canonname != 0; 409238106Sdes} 410238106Sdes 411238106Sdes/** fill data into result */ 412238106Sdesstatic int 413238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, 414249141Sdes uint8_t* finalcname, struct query_info* rq, struct reply_info* rep) 415238106Sdes{ 416238106Sdes size_t i; 417238106Sdes struct packed_rrset_data* data; 418249141Sdes res->ttl = 0; 419238106Sdes if(!answer) { 420238106Sdes if(finalcname) { 421238106Sdes if(!fill_canon(res, finalcname)) 422238106Sdes return 0; /* out of memory */ 423238106Sdes } 424249141Sdes if(rep->rrset_count != 0) 425249141Sdes res->ttl = (int)rep->ttl; 426238106Sdes res->data = (char**)calloc(1, sizeof(char*)); 427238106Sdes res->len = (int*)calloc(1, sizeof(int)); 428238106Sdes return (res->data && res->len); 429238106Sdes } 430238106Sdes data = (struct packed_rrset_data*)answer->entry.data; 431238106Sdes if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { 432238106Sdes if(!fill_canon(res, answer->rk.dname)) 433238106Sdes return 0; /* out of memory */ 434238106Sdes } else res->canonname = NULL; 435238106Sdes res->data = (char**)calloc(data->count+1, sizeof(char*)); 436238106Sdes res->len = (int*)calloc(data->count+1, sizeof(int)); 437238106Sdes if(!res->data || !res->len) 438238106Sdes return 0; /* out of memory */ 439238106Sdes for(i=0; i<data->count; i++) { 440238106Sdes /* remove rdlength from rdata */ 441238106Sdes res->len[i] = (int)(data->rr_len[i] - 2); 442238106Sdes res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]); 443238106Sdes if(!res->data[i]) 444238106Sdes return 0; /* out of memory */ 445238106Sdes } 446249141Sdes /* ttl for positive answers, from CNAME and answer RRs */ 447249141Sdes if(data->count != 0) { 448249141Sdes size_t j; 449249141Sdes res->ttl = (int)data->ttl; 450249141Sdes for(j=0; j<rep->an_numrrsets; j++) { 451249141Sdes struct packed_rrset_data* d = 452249141Sdes (struct packed_rrset_data*)rep->rrsets[j]-> 453249141Sdes entry.data; 454249141Sdes if((int)d->ttl < res->ttl) 455249141Sdes res->ttl = (int)d->ttl; 456249141Sdes } 457249141Sdes } 458249141Sdes /* ttl for negative answers */ 459249141Sdes if(data->count == 0 && rep->rrset_count != 0) 460249141Sdes res->ttl = (int)rep->ttl; 461238106Sdes res->data[data->count] = NULL; 462238106Sdes res->len[data->count] = 0; 463238106Sdes return 1; 464238106Sdes} 465238106Sdes 466238106Sdes/** fill result from parsed message, on error fills servfail */ 467238106Sdesvoid 468238106Sdeslibworker_enter_result(struct ub_result* res, ldns_buffer* buf, 469238106Sdes struct regional* temp, enum sec_status msg_security) 470238106Sdes{ 471238106Sdes struct query_info rq; 472238106Sdes struct reply_info* rep; 473238106Sdes res->rcode = LDNS_RCODE_SERVFAIL; 474238106Sdes rep = parse_reply(buf, temp, &rq); 475238106Sdes if(!rep) { 476238106Sdes log_err("cannot parse buf"); 477238106Sdes return; /* error parsing buf, or out of memory */ 478238106Sdes } 479238106Sdes if(!fill_res(res, reply_find_answer_rrset(&rq, rep), 480249141Sdes reply_find_final_cname_target(&rq, rep), &rq, rep)) 481238106Sdes return; /* out of memory */ 482238106Sdes /* rcode, havedata, nxdomain, secure, bogus */ 483238106Sdes res->rcode = (int)FLAGS_GET_RCODE(rep->flags); 484238106Sdes if(res->data && res->data[0]) 485238106Sdes res->havedata = 1; 486238106Sdes if(res->rcode == LDNS_RCODE_NXDOMAIN) 487238106Sdes res->nxdomain = 1; 488238106Sdes if(msg_security == sec_status_secure) 489238106Sdes res->secure = 1; 490238106Sdes if(msg_security == sec_status_bogus) 491238106Sdes res->bogus = 1; 492238106Sdes} 493238106Sdes 494238106Sdes/** fillup fg results */ 495238106Sdesstatic void 496238106Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf, 497238106Sdes enum sec_status s, char* why_bogus) 498238106Sdes{ 499238106Sdes if(why_bogus) 500238106Sdes q->res->why_bogus = strdup(why_bogus); 501238106Sdes if(rcode != 0) { 502238106Sdes q->res->rcode = rcode; 503238106Sdes q->msg_security = s; 504238106Sdes return; 505238106Sdes } 506238106Sdes 507238106Sdes q->res->rcode = LDNS_RCODE_SERVFAIL; 508238106Sdes q->msg_security = 0; 509238106Sdes q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf)); 510238106Sdes q->msg_len = ldns_buffer_limit(buf); 511238106Sdes if(!q->msg) { 512238106Sdes return; /* the error is in the rcode */ 513238106Sdes } 514238106Sdes 515238106Sdes /* canonname and results */ 516238106Sdes q->msg_security = s; 517238106Sdes libworker_enter_result(q->res, buf, q->w->env->scratch, s); 518238106Sdes} 519238106Sdes 520238106Sdesvoid 521238106Sdeslibworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s, 522238106Sdes char* why_bogus) 523238106Sdes{ 524238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 525238106Sdes /* fg query is done; exit comm base */ 526238106Sdes comm_base_exit(q->w->base); 527238106Sdes 528238106Sdes libworker_fillup_fg(q, rcode, buf, s, why_bogus); 529238106Sdes} 530238106Sdes 531238106Sdes/** setup qinfo and edns */ 532238106Sdesstatic int 533238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q, 534238106Sdes struct query_info* qinfo, struct edns_data* edns) 535238106Sdes{ 536238106Sdes ldns_rdf* rdf; 537238106Sdes qinfo->qtype = (uint16_t)q->res->qtype; 538238106Sdes qinfo->qclass = (uint16_t)q->res->qclass; 539238106Sdes rdf = ldns_dname_new_frm_str(q->res->qname); 540238106Sdes if(!rdf) { 541238106Sdes return 0; 542238106Sdes } 543238106Sdes#ifdef UNBOUND_ALLOC_LITE 544238106Sdes qinfo->qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf)); 545238106Sdes qinfo->qname_len = ldns_rdf_size(rdf); 546238106Sdes ldns_rdf_deep_free(rdf); 547238106Sdes rdf = 0; 548238106Sdes#else 549238106Sdes qinfo->qname = ldns_rdf_data(rdf); 550238106Sdes qinfo->qname_len = ldns_rdf_size(rdf); 551238106Sdes#endif 552238106Sdes edns->edns_present = 1; 553238106Sdes edns->ext_rcode = 0; 554238106Sdes edns->edns_version = 0; 555238106Sdes edns->bits = EDNS_DO; 556238106Sdes if(ldns_buffer_capacity(w->back->udp_buff) < 65535) 557238106Sdes edns->udp_size = (uint16_t)ldns_buffer_capacity( 558238106Sdes w->back->udp_buff); 559238106Sdes else edns->udp_size = 65535; 560238106Sdes ldns_rdf_free(rdf); 561238106Sdes return 1; 562238106Sdes} 563238106Sdes 564238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) 565238106Sdes{ 566238106Sdes struct libworker* w = libworker_setup(ctx, 0); 567238106Sdes uint16_t qflags, qid; 568238106Sdes struct query_info qinfo; 569238106Sdes struct edns_data edns; 570238106Sdes if(!w) 571238106Sdes return UB_INITFAIL; 572238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 573238106Sdes libworker_delete(w); 574238106Sdes return UB_SYNTAX; 575238106Sdes } 576238106Sdes qid = 0; 577238106Sdes qflags = BIT_RD; 578238106Sdes q->w = w; 579238106Sdes /* see if there is a fixed answer */ 580238106Sdes ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 581238106Sdes ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 582238106Sdes if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 583238106Sdes w->back->udp_buff, w->env->scratch)) { 584238106Sdes regional_free_all(w->env->scratch); 585238106Sdes libworker_fillup_fg(q, LDNS_RCODE_NOERROR, 586238106Sdes w->back->udp_buff, sec_status_insecure, NULL); 587238106Sdes libworker_delete(w); 588238106Sdes free(qinfo.qname); 589238106Sdes return UB_NOERROR; 590238106Sdes } 591238106Sdes /* process new query */ 592238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 593238106Sdes w->back->udp_buff, qid, libworker_fg_done_cb, q)) { 594238106Sdes free(qinfo.qname); 595238106Sdes return UB_NOMEM; 596238106Sdes } 597238106Sdes free(qinfo.qname); 598238106Sdes 599238106Sdes /* wait for reply */ 600238106Sdes comm_base_dispatch(w->base); 601238106Sdes 602238106Sdes libworker_delete(w); 603238106Sdes return UB_NOERROR; 604238106Sdes} 605238106Sdes 606238106Sdes/** add result to the bg worker result queue */ 607238106Sdesstatic void 608238106Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt, 609238106Sdes int err, char* reason) 610238106Sdes{ 611238106Sdes uint8_t* msg = NULL; 612238106Sdes uint32_t len = 0; 613238106Sdes 614238106Sdes /* serialize and delete unneeded q */ 615238106Sdes if(w->is_bg_thread) { 616238106Sdes lock_basic_lock(&w->ctx->cfglock); 617238106Sdes if(reason) 618238106Sdes q->res->why_bogus = strdup(reason); 619238106Sdes if(pkt) { 620238106Sdes q->msg_len = ldns_buffer_remaining(pkt); 621238106Sdes q->msg = memdup(ldns_buffer_begin(pkt), q->msg_len); 622238106Sdes if(!q->msg) 623238106Sdes msg = context_serialize_answer(q, UB_NOMEM, 624238106Sdes NULL, &len); 625238106Sdes else msg = context_serialize_answer(q, err, 626238106Sdes NULL, &len); 627238106Sdes } else msg = context_serialize_answer(q, err, NULL, &len); 628238106Sdes lock_basic_unlock(&w->ctx->cfglock); 629238106Sdes } else { 630238106Sdes if(reason) 631238106Sdes q->res->why_bogus = strdup(reason); 632238106Sdes msg = context_serialize_answer(q, err, pkt, &len); 633238106Sdes (void)rbtree_delete(&w->ctx->queries, q->node.key); 634238106Sdes w->ctx->num_async--; 635238106Sdes context_query_delete(q); 636238106Sdes } 637238106Sdes 638238106Sdes if(!msg) { 639238106Sdes log_err("out of memory for async answer"); 640238106Sdes return; 641238106Sdes } 642238106Sdes if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) { 643238106Sdes log_err("out of memory for async answer"); 644238106Sdes return; 645238106Sdes } 646238106Sdes} 647238106Sdes 648238106Sdesvoid 649238106Sdeslibworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s, 650238106Sdes char* why_bogus) 651238106Sdes{ 652238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 653238106Sdes 654238106Sdes if(q->cancelled) { 655238106Sdes if(q->w->is_bg_thread) { 656238106Sdes /* delete it now */ 657238106Sdes struct ub_ctx* ctx = q->w->ctx; 658238106Sdes lock_basic_lock(&ctx->cfglock); 659238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 660238106Sdes ctx->num_async--; 661238106Sdes context_query_delete(q); 662238106Sdes lock_basic_unlock(&ctx->cfglock); 663238106Sdes } 664238106Sdes /* cancelled, do not give answer */ 665238106Sdes return; 666238106Sdes } 667238106Sdes q->msg_security = s; 668249141Sdes if(!buf) 669249141Sdes buf = q->w->env->scratch_buffer; 670238106Sdes if(rcode != 0) { 671238106Sdes error_encode(buf, rcode, NULL, 0, BIT_RD, NULL); 672238106Sdes } 673238106Sdes add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus); 674238106Sdes} 675238106Sdes 676238106Sdes 677238106Sdes/** handle new query command for bg worker */ 678238106Sdesstatic void 679238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len) 680238106Sdes{ 681238106Sdes uint16_t qflags, qid; 682238106Sdes struct query_info qinfo; 683238106Sdes struct edns_data edns; 684238106Sdes struct ctx_query* q; 685238106Sdes if(w->is_bg_thread) { 686238106Sdes lock_basic_lock(&w->ctx->cfglock); 687238106Sdes q = context_lookup_new_query(w->ctx, buf, len); 688238106Sdes lock_basic_unlock(&w->ctx->cfglock); 689238106Sdes } else { 690238106Sdes q = context_deserialize_new_query(w->ctx, buf, len); 691238106Sdes } 692238106Sdes free(buf); 693238106Sdes if(!q) { 694238106Sdes log_err("failed to deserialize newq"); 695238106Sdes return; 696238106Sdes } 697238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 698238106Sdes add_bg_result(w, q, NULL, UB_SYNTAX, NULL); 699238106Sdes return; 700238106Sdes } 701238106Sdes qid = 0; 702238106Sdes qflags = BIT_RD; 703238106Sdes /* see if there is a fixed answer */ 704238106Sdes ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 705238106Sdes ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 706238106Sdes if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, 707238106Sdes w->back->udp_buff, w->env->scratch)) { 708238106Sdes regional_free_all(w->env->scratch); 709238106Sdes q->msg_security = sec_status_insecure; 710238106Sdes add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL); 711238106Sdes free(qinfo.qname); 712238106Sdes return; 713238106Sdes } 714238106Sdes q->w = w; 715238106Sdes /* process new query */ 716238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 717238106Sdes w->back->udp_buff, qid, libworker_bg_done_cb, q)) { 718238106Sdes add_bg_result(w, q, NULL, UB_NOMEM, NULL); 719238106Sdes } 720238106Sdes free(qinfo.qname); 721238106Sdes} 722238106Sdes 723238106Sdesvoid libworker_alloc_cleanup(void* arg) 724238106Sdes{ 725238106Sdes struct libworker* w = (struct libworker*)arg; 726238106Sdes slabhash_clear(&w->env->rrset_cache->table); 727238106Sdes slabhash_clear(w->env->msg_cache); 728238106Sdes} 729238106Sdes 730238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, 731238106Sdes uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 732238106Sdes int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen, 733238106Sdes uint8_t* zone, size_t zonelen, struct module_qstate* q) 734238106Sdes{ 735238106Sdes struct libworker* w = (struct libworker*)q->env->worker; 736238106Sdes struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 737238106Sdes q->region, sizeof(*e)); 738238106Sdes if(!e) 739238106Sdes return NULL; 740238106Sdes e->qstate = q; 741238106Sdes e->qsent = outnet_serviced_query(w->back, qname, 742238106Sdes qnamelen, qtype, qclass, flags, dnssec, want_dnssec, 743238106Sdes q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, 744238106Sdes addrlen, zone, zonelen, libworker_handle_service_reply, e, 745249141Sdes w->back->udp_buff); 746238106Sdes if(!e->qsent) { 747238106Sdes return NULL; 748238106Sdes } 749238106Sdes return e; 750238106Sdes} 751238106Sdes 752238106Sdesint 753238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error, 754238106Sdes struct comm_reply* reply_info) 755238106Sdes{ 756238106Sdes struct module_qstate* q = (struct module_qstate*)arg; 757238106Sdes struct libworker* lw = (struct libworker*)q->env->worker; 758238106Sdes struct outbound_entry e; 759238106Sdes e.qstate = q; 760238106Sdes e.qsent = NULL; 761238106Sdes 762238106Sdes if(error != 0) { 763238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, error); 764238106Sdes return 0; 765238106Sdes } 766238106Sdes /* sanity check. */ 767238106Sdes if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) 768238106Sdes || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != 769238106Sdes LDNS_PACKET_QUERY 770238106Sdes || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { 771238106Sdes /* error becomes timeout for the module as if this reply 772238106Sdes * never arrived. */ 773238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, 774238106Sdes NETEVENT_TIMEOUT); 775238106Sdes return 0; 776238106Sdes } 777238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR); 778238106Sdes return 0; 779238106Sdes} 780238106Sdes 781238106Sdesint 782238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error, 783238106Sdes struct comm_reply* reply_info) 784238106Sdes{ 785238106Sdes struct outbound_entry* e = (struct outbound_entry*)arg; 786238106Sdes struct libworker* lw = (struct libworker*)e->qstate->env->worker; 787238106Sdes 788238106Sdes if(error != 0) { 789238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, error); 790238106Sdes return 0; 791238106Sdes } 792238106Sdes /* sanity check. */ 793238106Sdes if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) 794238106Sdes || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != 795238106Sdes LDNS_PACKET_QUERY 796238106Sdes || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { 797238106Sdes /* error becomes timeout for the module as if this reply 798238106Sdes * never arrived. */ 799238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, 800238106Sdes NETEVENT_TIMEOUT); 801238106Sdes return 0; 802238106Sdes } 803238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR); 804238106Sdes return 0; 805238106Sdes} 806238106Sdes 807238106Sdes/* --- fake callbacks for fptr_wlist to work --- */ 808238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 809238106Sdes uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 810238106Sdes int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 811238106Sdes{ 812238106Sdes log_assert(0); 813238106Sdes} 814238106Sdes 815238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c), 816238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 817238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 818238106Sdes{ 819238106Sdes log_assert(0); 820238106Sdes return 0; 821238106Sdes} 822238106Sdes 823238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c), 824238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 825238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 826238106Sdes{ 827238106Sdes log_assert(0); 828238106Sdes return 0; 829238106Sdes} 830238106Sdes 831238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 832238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 833238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 834238106Sdes{ 835238106Sdes log_assert(0); 836238106Sdes return 0; 837238106Sdes} 838238106Sdes 839238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c), 840238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 841238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 842238106Sdes{ 843238106Sdes log_assert(0); 844238106Sdes return 0; 845238106Sdes} 846238106Sdes 847238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c), 848238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 849238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 850238106Sdes{ 851238106Sdes log_assert(0); 852238106Sdes return 0; 853238106Sdes} 854238106Sdes 855238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) 856238106Sdes{ 857238106Sdes log_assert(0); 858238106Sdes} 859238106Sdes 860238106Sdesstruct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), 861238106Sdes size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 862238106Sdes uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 863238106Sdes int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 864238106Sdes struct sockaddr_storage* ATTR_UNUSED(addr), 865238106Sdes socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) 866238106Sdes{ 867238106Sdes log_assert(0); 868238106Sdes return 0; 869238106Sdes} 870238106Sdes 871238106Sdesvoid 872238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg)) 873238106Sdes{ 874238106Sdes log_assert(0); 875238106Sdes} 876238106Sdes 877238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg)) 878238106Sdes{ 879238106Sdes log_assert(0); 880238106Sdes} 881238106Sdes 882238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg)) 883238106Sdes{ 884238106Sdes log_assert(0); 885238106Sdes} 886238106Sdes 887238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg)) 888238106Sdes{ 889238106Sdes log_assert(0); 890238106Sdes} 891238106Sdes 892238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg)) 893238106Sdes{ 894238106Sdes log_assert(0); 895238106Sdes} 896238106Sdes 897238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 898238106Sdes{ 899238106Sdes log_assert(0); 900238106Sdes return 0; 901238106Sdes} 902238106Sdes 903238106Sdesint 904238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 905238106Sdes{ 906238106Sdes log_assert(0); 907238106Sdes return 0; 908238106Sdes} 909238106Sdes 910238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 911238106Sdes{ 912238106Sdes log_assert(0); 913238106Sdes return 0; 914238106Sdes} 915238106Sdes 916238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) 917238106Sdes{ 918238106Sdes log_assert(0); 919238106Sdes} 920238106Sdes 921238106Sdes#ifdef UB_ON_WINDOWS 922238106Sdesvoid 923238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* 924238106Sdes ATTR_UNUSED(arg)) { 925238106Sdes log_assert(0); 926238106Sdes} 927238106Sdes 928238106Sdesvoid 929238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg)) 930238106Sdes{ 931238106Sdes log_assert(0); 932238106Sdes} 933238106Sdes#endif /* UB_ON_WINDOWS */ 934