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 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains 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" 45249141Sdes#ifdef HAVE_SSL 46238106Sdes#include <openssl/ssl.h> 47249141Sdes#endif 48238106Sdes#include "libunbound/libworker.h" 49238106Sdes#include "libunbound/context.h" 50238106Sdes#include "libunbound/unbound.h" 51255579Sdes#include "libunbound/worker.h" 52269257Sdes#include "libunbound/unbound-event.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" 58255579Sdes#include "util/fptr_wlist.h" 59238106Sdes#include "util/module.h" 60238106Sdes#include "util/regional.h" 61238106Sdes#include "util/random.h" 62238106Sdes#include "util/config_file.h" 63238106Sdes#include "util/netevent.h" 64238106Sdes#include "util/storage/lookup3.h" 65238106Sdes#include "util/storage/slabhash.h" 66238106Sdes#include "util/net_help.h" 67238106Sdes#include "util/data/dname.h" 68238106Sdes#include "util/data/msgreply.h" 69238106Sdes#include "util/data/msgencode.h" 70238106Sdes#include "util/tube.h" 71238106Sdes#include "iterator/iter_fwd.h" 72238106Sdes#include "iterator/iter_hints.h" 73291767Sdes#include "sldns/sbuffer.h" 74291767Sdes#include "sldns/str2wire.h" 75238106Sdes 76238106Sdes/** handle new query command for bg worker */ 77238106Sdesstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len); 78238106Sdes 79269257Sdes/** delete libworker env */ 80238106Sdesstatic void 81269257Sdeslibworker_delete_env(struct libworker* w) 82238106Sdes{ 83238106Sdes if(w->env) { 84238106Sdes outside_network_quit_prepare(w->back); 85238106Sdes mesh_delete(w->env->mesh); 86238106Sdes context_release_alloc(w->ctx, w->env->alloc, 87238106Sdes !w->is_bg || w->is_bg_thread); 88269257Sdes sldns_buffer_free(w->env->scratch_buffer); 89238106Sdes regional_destroy(w->env->scratch); 90238106Sdes forwards_delete(w->env->fwds); 91238106Sdes hints_delete(w->env->hints); 92238106Sdes ub_randfree(w->env->rnd); 93238106Sdes free(w->env); 94238106Sdes } 95249141Sdes#ifdef HAVE_SSL 96238106Sdes SSL_CTX_free(w->sslctx); 97249141Sdes#endif 98238106Sdes outside_network_delete(w->back); 99269257Sdes} 100269257Sdes 101269257Sdes/** delete libworker struct */ 102269257Sdesstatic void 103269257Sdeslibworker_delete(struct libworker* w) 104269257Sdes{ 105269257Sdes if(!w) return; 106269257Sdes libworker_delete_env(w); 107238106Sdes comm_base_delete(w->base); 108238106Sdes free(w); 109238106Sdes} 110238106Sdes 111269257Sdesvoid 112269257Sdeslibworker_delete_event(struct libworker* w) 113269257Sdes{ 114269257Sdes if(!w) return; 115269257Sdes libworker_delete_env(w); 116269257Sdes comm_base_delete_no_base(w->base); 117269257Sdes free(w); 118269257Sdes} 119269257Sdes 120238106Sdes/** setup fresh libworker struct */ 121238106Sdesstatic struct libworker* 122269257Sdeslibworker_setup(struct ub_ctx* ctx, int is_bg, struct event_base* eb) 123238106Sdes{ 124238106Sdes unsigned int seed; 125238106Sdes struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); 126238106Sdes struct config_file* cfg = ctx->env->cfg; 127238106Sdes int* ports; 128238106Sdes int numports; 129238106Sdes if(!w) return NULL; 130238106Sdes w->is_bg = is_bg; 131238106Sdes w->ctx = ctx; 132238106Sdes w->env = (struct module_env*)malloc(sizeof(*w->env)); 133238106Sdes if(!w->env) { 134238106Sdes free(w); 135238106Sdes return NULL; 136238106Sdes } 137238106Sdes *w->env = *ctx->env; 138238106Sdes w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread); 139238106Sdes if(!w->env->alloc) { 140238106Sdes libworker_delete(w); 141238106Sdes return NULL; 142238106Sdes } 143238106Sdes w->thread_num = w->env->alloc->thread_num; 144238106Sdes alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w); 145238106Sdes if(!w->is_bg || w->is_bg_thread) { 146238106Sdes lock_basic_lock(&ctx->cfglock); 147238106Sdes } 148238106Sdes w->env->scratch = regional_create_custom(cfg->msg_buffer_size); 149269257Sdes w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); 150238106Sdes w->env->fwds = forwards_create(); 151238106Sdes if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { 152238106Sdes forwards_delete(w->env->fwds); 153238106Sdes w->env->fwds = NULL; 154238106Sdes } 155238106Sdes w->env->hints = hints_create(); 156238106Sdes if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { 157238106Sdes hints_delete(w->env->hints); 158238106Sdes w->env->hints = NULL; 159238106Sdes } 160238106Sdes if(cfg->ssl_upstream) { 161238106Sdes w->sslctx = connect_sslctx_create(NULL, NULL, NULL); 162238106Sdes if(!w->sslctx) { 163238106Sdes /* to make the setup fail after unlock */ 164238106Sdes hints_delete(w->env->hints); 165238106Sdes w->env->hints = NULL; 166238106Sdes } 167238106Sdes } 168238106Sdes if(!w->is_bg || w->is_bg_thread) { 169238106Sdes lock_basic_unlock(&ctx->cfglock); 170238106Sdes } 171238106Sdes if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds || 172238106Sdes !w->env->hints) { 173238106Sdes libworker_delete(w); 174238106Sdes return NULL; 175238106Sdes } 176238106Sdes w->env->worker = (struct worker*)w; 177238106Sdes w->env->probe_timer = NULL; 178238106Sdes seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ 179238106Sdes (((unsigned int)w->thread_num)<<17); 180238106Sdes seed ^= (unsigned int)w->env->alloc->next_id; 181238106Sdes if(!w->is_bg || w->is_bg_thread) { 182238106Sdes lock_basic_lock(&ctx->cfglock); 183238106Sdes } 184238106Sdes if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) { 185238106Sdes if(!w->is_bg || w->is_bg_thread) { 186238106Sdes lock_basic_unlock(&ctx->cfglock); 187238106Sdes } 188238106Sdes seed = 0; 189238106Sdes libworker_delete(w); 190238106Sdes return NULL; 191238106Sdes } 192238106Sdes if(!w->is_bg || w->is_bg_thread) { 193238106Sdes lock_basic_unlock(&ctx->cfglock); 194238106Sdes } 195238106Sdes if(1) { 196238106Sdes /* primitive lockout for threading: if it overwrites another 197238106Sdes * thread it is like wiping the cache (which is likely empty 198238106Sdes * at the start) */ 199238106Sdes /* note we are holding the ctx lock in normal threaded 200238106Sdes * cases so that is solved properly, it is only for many ctx 201238106Sdes * in different threads that this may clash */ 202238106Sdes static int done_raninit = 0; 203238106Sdes if(!done_raninit) { 204238106Sdes done_raninit = 1; 205238106Sdes hash_set_raninit((uint32_t)ub_random(w->env->rnd)); 206238106Sdes } 207238106Sdes } 208238106Sdes seed = 0; 209238106Sdes 210269257Sdes if(eb) 211269257Sdes w->base = comm_base_create_event(eb); 212269257Sdes else w->base = comm_base_create(0); 213238106Sdes if(!w->base) { 214238106Sdes libworker_delete(w); 215238106Sdes return NULL; 216238106Sdes } 217238106Sdes if(!w->is_bg || w->is_bg_thread) { 218238106Sdes lock_basic_lock(&ctx->cfglock); 219238106Sdes } 220238106Sdes numports = cfg_condense_ports(cfg, &ports); 221238106Sdes if(numports == 0) { 222269257Sdes int locked = !w->is_bg || w->is_bg_thread; 223238106Sdes libworker_delete(w); 224269257Sdes if(locked) { 225269257Sdes lock_basic_unlock(&ctx->cfglock); 226269257Sdes } 227238106Sdes return NULL; 228238106Sdes } 229238106Sdes w->back = outside_network_create(w->base, cfg->msg_buffer_size, 230238106Sdes (size_t)cfg->outgoing_num_ports, cfg->out_ifs, 231238106Sdes cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 232238106Sdes cfg->do_tcp?cfg->outgoing_num_tcp:0, 233238106Sdes w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, 234238106Sdes ports, numports, cfg->unwanted_threshold, 235269257Sdes &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx, 236285206Sdes cfg->delay_close, NULL); 237238106Sdes if(!w->is_bg || w->is_bg_thread) { 238238106Sdes lock_basic_unlock(&ctx->cfglock); 239238106Sdes } 240238106Sdes free(ports); 241238106Sdes if(!w->back) { 242238106Sdes libworker_delete(w); 243238106Sdes return NULL; 244238106Sdes } 245238106Sdes w->env->mesh = mesh_create(&ctx->mods, w->env); 246238106Sdes if(!w->env->mesh) { 247238106Sdes libworker_delete(w); 248238106Sdes return NULL; 249238106Sdes } 250238106Sdes w->env->send_query = &libworker_send_query; 251238106Sdes w->env->detach_subs = &mesh_detach_subs; 252238106Sdes w->env->attach_sub = &mesh_attach_sub; 253238106Sdes w->env->kill_sub = &mesh_state_delete; 254238106Sdes w->env->detect_cycle = &mesh_detect_cycle; 255238106Sdes comm_base_timept(w->base, &w->env->now, &w->env->now_tv); 256238106Sdes return w; 257238106Sdes} 258238106Sdes 259269257Sdesstruct libworker* libworker_create_event(struct ub_ctx* ctx, 260269257Sdes struct event_base* eb) 261269257Sdes{ 262269257Sdes return libworker_setup(ctx, 0, eb); 263269257Sdes} 264269257Sdes 265238106Sdes/** handle cancel command for bg worker */ 266238106Sdesstatic void 267238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len) 268238106Sdes{ 269238106Sdes struct ctx_query* q; 270238106Sdes if(w->is_bg_thread) { 271238106Sdes lock_basic_lock(&w->ctx->cfglock); 272238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 273238106Sdes lock_basic_unlock(&w->ctx->cfglock); 274238106Sdes } else { 275238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 276238106Sdes } 277238106Sdes if(!q) { 278238106Sdes /* probably simply lookup failed, i.e. the message had been 279238106Sdes * processed and answered before the cancel arrived */ 280238106Sdes return; 281238106Sdes } 282238106Sdes q->cancelled = 1; 283238106Sdes free(buf); 284238106Sdes} 285238106Sdes 286238106Sdes/** do control command coming into bg server */ 287238106Sdesstatic void 288238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len) 289238106Sdes{ 290238106Sdes switch(context_serial_getcmd(msg, len)) { 291238106Sdes default: 292238106Sdes case UB_LIBCMD_ANSWER: 293238106Sdes log_err("unknown command for bg worker %d", 294238106Sdes (int)context_serial_getcmd(msg, len)); 295238106Sdes /* and fall through to quit */ 296238106Sdes case UB_LIBCMD_QUIT: 297238106Sdes free(msg); 298238106Sdes comm_base_exit(w->base); 299238106Sdes break; 300238106Sdes case UB_LIBCMD_NEWQUERY: 301238106Sdes handle_newq(w, msg, len); 302238106Sdes break; 303238106Sdes case UB_LIBCMD_CANCEL: 304238106Sdes handle_cancel(w, msg, len); 305238106Sdes break; 306238106Sdes } 307238106Sdes} 308238106Sdes 309238106Sdes/** handle control command coming into server */ 310238106Sdesvoid 311238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 312238106Sdes uint8_t* msg, size_t len, int err, void* arg) 313238106Sdes{ 314238106Sdes struct libworker* w = (struct libworker*)arg; 315238106Sdes 316238106Sdes if(err != 0) { 317238106Sdes free(msg); 318238106Sdes /* it is of no use to go on, exit */ 319238106Sdes comm_base_exit(w->base); 320238106Sdes return; 321238106Sdes } 322238106Sdes libworker_do_cmd(w, msg, len); /* also frees the buf */ 323238106Sdes} 324238106Sdes 325238106Sdes/** the background thread func */ 326238106Sdesstatic void* 327238106Sdeslibworker_dobg(void* arg) 328238106Sdes{ 329238106Sdes /* setup */ 330238106Sdes uint32_t m; 331238106Sdes struct libworker* w = (struct libworker*)arg; 332238106Sdes struct ub_ctx* ctx; 333238106Sdes if(!w) { 334238106Sdes log_err("libunbound bg worker init failed, nomem"); 335238106Sdes return NULL; 336238106Sdes } 337238106Sdes ctx = w->ctx; 338238106Sdes log_thread_set(&w->thread_num); 339238106Sdes#ifdef THREADS_DISABLED 340238106Sdes /* we are forked */ 341238106Sdes w->is_bg_thread = 0; 342238106Sdes /* close non-used parts of the pipes */ 343238106Sdes tube_close_write(ctx->qq_pipe); 344238106Sdes tube_close_read(ctx->rr_pipe); 345238106Sdes#endif 346238106Sdes if(!tube_setup_bg_listen(ctx->qq_pipe, w->base, 347238106Sdes libworker_handle_control_cmd, w)) { 348238106Sdes log_err("libunbound bg worker init failed, no bglisten"); 349238106Sdes return NULL; 350238106Sdes } 351238106Sdes if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) { 352238106Sdes log_err("libunbound bg worker init failed, no bgwrite"); 353238106Sdes return NULL; 354238106Sdes } 355238106Sdes 356238106Sdes /* do the work */ 357238106Sdes comm_base_dispatch(w->base); 358238106Sdes 359238106Sdes /* cleanup */ 360238106Sdes m = UB_LIBCMD_QUIT; 361238106Sdes tube_remove_bg_listen(w->ctx->qq_pipe); 362238106Sdes tube_remove_bg_write(w->ctx->rr_pipe); 363238106Sdes libworker_delete(w); 364238106Sdes (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m, 365238106Sdes (uint32_t)sizeof(m), 0); 366238106Sdes#ifdef THREADS_DISABLED 367238106Sdes /* close pipes from forked process before exit */ 368238106Sdes tube_close_read(ctx->qq_pipe); 369238106Sdes tube_close_write(ctx->rr_pipe); 370238106Sdes#endif 371238106Sdes return NULL; 372238106Sdes} 373238106Sdes 374238106Sdesint libworker_bg(struct ub_ctx* ctx) 375238106Sdes{ 376238106Sdes struct libworker* w; 377238106Sdes /* fork or threadcreate */ 378238106Sdes lock_basic_lock(&ctx->cfglock); 379238106Sdes if(ctx->dothread) { 380238106Sdes lock_basic_unlock(&ctx->cfglock); 381269257Sdes w = libworker_setup(ctx, 1, NULL); 382238106Sdes if(!w) return UB_NOMEM; 383238106Sdes w->is_bg_thread = 1; 384238106Sdes#ifdef ENABLE_LOCK_CHECKS 385238106Sdes w->thread_num = 1; /* for nicer DEBUG checklocks */ 386238106Sdes#endif 387238106Sdes ub_thread_create(&ctx->bg_tid, libworker_dobg, w); 388238106Sdes } else { 389238106Sdes lock_basic_unlock(&ctx->cfglock); 390238106Sdes#ifndef HAVE_FORK 391238106Sdes /* no fork on windows */ 392238106Sdes return UB_FORKFAIL; 393238106Sdes#else /* HAVE_FORK */ 394238106Sdes switch((ctx->bg_pid=fork())) { 395238106Sdes case 0: 396269257Sdes w = libworker_setup(ctx, 1, NULL); 397238106Sdes if(!w) fatal_exit("out of memory"); 398238106Sdes /* close non-used parts of the pipes */ 399238106Sdes tube_close_write(ctx->qq_pipe); 400238106Sdes tube_close_read(ctx->rr_pipe); 401238106Sdes (void)libworker_dobg(w); 402238106Sdes exit(0); 403238106Sdes break; 404238106Sdes case -1: 405238106Sdes return UB_FORKFAIL; 406238106Sdes default: 407269257Sdes /* close non-used parts, so that the worker 408269257Sdes * bgprocess gets 'pipe closed' when the 409269257Sdes * main process exits */ 410269257Sdes tube_close_read(ctx->qq_pipe); 411269257Sdes tube_close_write(ctx->rr_pipe); 412238106Sdes break; 413238106Sdes } 414238106Sdes#endif /* HAVE_FORK */ 415238106Sdes } 416238106Sdes return UB_NOERROR; 417238106Sdes} 418238106Sdes 419238106Sdes/** get msg reply struct (in temp region) */ 420238106Sdesstatic struct reply_info* 421269257Sdesparse_reply(sldns_buffer* pkt, struct regional* region, struct query_info* qi) 422238106Sdes{ 423238106Sdes struct reply_info* rep; 424238106Sdes struct msg_parse* msg; 425238106Sdes if(!(msg = regional_alloc(region, sizeof(*msg)))) { 426238106Sdes return NULL; 427238106Sdes } 428238106Sdes memset(msg, 0, sizeof(*msg)); 429269257Sdes sldns_buffer_set_position(pkt, 0); 430238106Sdes if(parse_packet(pkt, msg, region) != 0) 431238106Sdes return 0; 432238106Sdes if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { 433238106Sdes return 0; 434238106Sdes } 435238106Sdes return rep; 436238106Sdes} 437238106Sdes 438238106Sdes/** insert canonname */ 439238106Sdesstatic int 440238106Sdesfill_canon(struct ub_result* res, uint8_t* s) 441238106Sdes{ 442238106Sdes char buf[255+2]; 443238106Sdes dname_str(s, buf); 444238106Sdes res->canonname = strdup(buf); 445238106Sdes return res->canonname != 0; 446238106Sdes} 447238106Sdes 448238106Sdes/** fill data into result */ 449238106Sdesstatic int 450238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, 451249141Sdes uint8_t* finalcname, struct query_info* rq, struct reply_info* rep) 452238106Sdes{ 453238106Sdes size_t i; 454238106Sdes struct packed_rrset_data* data; 455249141Sdes res->ttl = 0; 456238106Sdes if(!answer) { 457238106Sdes if(finalcname) { 458238106Sdes if(!fill_canon(res, finalcname)) 459238106Sdes return 0; /* out of memory */ 460238106Sdes } 461249141Sdes if(rep->rrset_count != 0) 462249141Sdes res->ttl = (int)rep->ttl; 463238106Sdes res->data = (char**)calloc(1, sizeof(char*)); 464238106Sdes res->len = (int*)calloc(1, sizeof(int)); 465238106Sdes return (res->data && res->len); 466238106Sdes } 467238106Sdes data = (struct packed_rrset_data*)answer->entry.data; 468238106Sdes if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { 469238106Sdes if(!fill_canon(res, answer->rk.dname)) 470238106Sdes return 0; /* out of memory */ 471238106Sdes } else res->canonname = NULL; 472238106Sdes res->data = (char**)calloc(data->count+1, sizeof(char*)); 473238106Sdes res->len = (int*)calloc(data->count+1, sizeof(int)); 474238106Sdes if(!res->data || !res->len) 475238106Sdes return 0; /* out of memory */ 476238106Sdes for(i=0; i<data->count; i++) { 477238106Sdes /* remove rdlength from rdata */ 478238106Sdes res->len[i] = (int)(data->rr_len[i] - 2); 479238106Sdes res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]); 480238106Sdes if(!res->data[i]) 481238106Sdes return 0; /* out of memory */ 482238106Sdes } 483249141Sdes /* ttl for positive answers, from CNAME and answer RRs */ 484249141Sdes if(data->count != 0) { 485249141Sdes size_t j; 486249141Sdes res->ttl = (int)data->ttl; 487249141Sdes for(j=0; j<rep->an_numrrsets; j++) { 488249141Sdes struct packed_rrset_data* d = 489249141Sdes (struct packed_rrset_data*)rep->rrsets[j]-> 490249141Sdes entry.data; 491249141Sdes if((int)d->ttl < res->ttl) 492249141Sdes res->ttl = (int)d->ttl; 493249141Sdes } 494249141Sdes } 495249141Sdes /* ttl for negative answers */ 496249141Sdes if(data->count == 0 && rep->rrset_count != 0) 497249141Sdes res->ttl = (int)rep->ttl; 498238106Sdes res->data[data->count] = NULL; 499238106Sdes res->len[data->count] = 0; 500238106Sdes return 1; 501238106Sdes} 502238106Sdes 503238106Sdes/** fill result from parsed message, on error fills servfail */ 504238106Sdesvoid 505269257Sdeslibworker_enter_result(struct ub_result* res, sldns_buffer* buf, 506238106Sdes struct regional* temp, enum sec_status msg_security) 507238106Sdes{ 508238106Sdes struct query_info rq; 509238106Sdes struct reply_info* rep; 510238106Sdes res->rcode = LDNS_RCODE_SERVFAIL; 511238106Sdes rep = parse_reply(buf, temp, &rq); 512238106Sdes if(!rep) { 513238106Sdes log_err("cannot parse buf"); 514238106Sdes return; /* error parsing buf, or out of memory */ 515238106Sdes } 516238106Sdes if(!fill_res(res, reply_find_answer_rrset(&rq, rep), 517249141Sdes reply_find_final_cname_target(&rq, rep), &rq, rep)) 518238106Sdes return; /* out of memory */ 519238106Sdes /* rcode, havedata, nxdomain, secure, bogus */ 520238106Sdes res->rcode = (int)FLAGS_GET_RCODE(rep->flags); 521238106Sdes if(res->data && res->data[0]) 522238106Sdes res->havedata = 1; 523238106Sdes if(res->rcode == LDNS_RCODE_NXDOMAIN) 524238106Sdes res->nxdomain = 1; 525238106Sdes if(msg_security == sec_status_secure) 526238106Sdes res->secure = 1; 527238106Sdes if(msg_security == sec_status_bogus) 528238106Sdes res->bogus = 1; 529238106Sdes} 530238106Sdes 531238106Sdes/** fillup fg results */ 532238106Sdesstatic void 533269257Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, 534238106Sdes enum sec_status s, char* why_bogus) 535238106Sdes{ 536238106Sdes if(why_bogus) 537238106Sdes q->res->why_bogus = strdup(why_bogus); 538238106Sdes if(rcode != 0) { 539238106Sdes q->res->rcode = rcode; 540238106Sdes q->msg_security = s; 541238106Sdes return; 542238106Sdes } 543238106Sdes 544238106Sdes q->res->rcode = LDNS_RCODE_SERVFAIL; 545238106Sdes q->msg_security = 0; 546269257Sdes q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf)); 547269257Sdes q->msg_len = sldns_buffer_limit(buf); 548238106Sdes if(!q->msg) { 549238106Sdes return; /* the error is in the rcode */ 550238106Sdes } 551238106Sdes 552238106Sdes /* canonname and results */ 553238106Sdes q->msg_security = s; 554238106Sdes libworker_enter_result(q->res, buf, q->w->env->scratch, s); 555238106Sdes} 556238106Sdes 557238106Sdesvoid 558269257Sdeslibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, 559238106Sdes char* why_bogus) 560238106Sdes{ 561238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 562238106Sdes /* fg query is done; exit comm base */ 563238106Sdes comm_base_exit(q->w->base); 564238106Sdes 565238106Sdes libworker_fillup_fg(q, rcode, buf, s, why_bogus); 566238106Sdes} 567238106Sdes 568238106Sdes/** setup qinfo and edns */ 569238106Sdesstatic int 570238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q, 571238106Sdes struct query_info* qinfo, struct edns_data* edns) 572238106Sdes{ 573238106Sdes qinfo->qtype = (uint16_t)q->res->qtype; 574238106Sdes qinfo->qclass = (uint16_t)q->res->qclass; 575269257Sdes qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len); 576269257Sdes if(!qinfo->qname) { 577238106Sdes return 0; 578238106Sdes } 579238106Sdes edns->edns_present = 1; 580238106Sdes edns->ext_rcode = 0; 581238106Sdes edns->edns_version = 0; 582238106Sdes edns->bits = EDNS_DO; 583269257Sdes if(sldns_buffer_capacity(w->back->udp_buff) < 65535) 584269257Sdes edns->udp_size = (uint16_t)sldns_buffer_capacity( 585238106Sdes w->back->udp_buff); 586238106Sdes else edns->udp_size = 65535; 587238106Sdes return 1; 588238106Sdes} 589238106Sdes 590238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) 591238106Sdes{ 592269257Sdes struct libworker* w = libworker_setup(ctx, 0, NULL); 593238106Sdes uint16_t qflags, qid; 594238106Sdes struct query_info qinfo; 595238106Sdes struct edns_data edns; 596238106Sdes if(!w) 597238106Sdes return UB_INITFAIL; 598238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 599238106Sdes libworker_delete(w); 600238106Sdes return UB_SYNTAX; 601238106Sdes } 602238106Sdes qid = 0; 603238106Sdes qflags = BIT_RD; 604238106Sdes q->w = w; 605238106Sdes /* see if there is a fixed answer */ 606269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 607269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 608238106Sdes if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 609285206Sdes w->back->udp_buff, w->env->scratch, NULL)) { 610238106Sdes regional_free_all(w->env->scratch); 611238106Sdes libworker_fillup_fg(q, LDNS_RCODE_NOERROR, 612238106Sdes w->back->udp_buff, sec_status_insecure, NULL); 613238106Sdes libworker_delete(w); 614238106Sdes free(qinfo.qname); 615238106Sdes return UB_NOERROR; 616238106Sdes } 617238106Sdes /* process new query */ 618238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 619238106Sdes w->back->udp_buff, qid, libworker_fg_done_cb, q)) { 620238106Sdes free(qinfo.qname); 621238106Sdes return UB_NOMEM; 622238106Sdes } 623238106Sdes free(qinfo.qname); 624238106Sdes 625238106Sdes /* wait for reply */ 626238106Sdes comm_base_dispatch(w->base); 627238106Sdes 628238106Sdes libworker_delete(w); 629238106Sdes return UB_NOERROR; 630238106Sdes} 631238106Sdes 632269257Sdesvoid 633269257Sdeslibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, 634269257Sdes enum sec_status s, char* why_bogus) 635269257Sdes{ 636269257Sdes struct ctx_query* q = (struct ctx_query*)arg; 637269257Sdes ub_event_callback_t cb = (ub_event_callback_t)q->cb; 638269257Sdes void* cb_arg = q->cb_arg; 639269257Sdes int cancelled = q->cancelled; 640269257Sdes 641269257Sdes /* delete it now */ 642269257Sdes struct ub_ctx* ctx = q->w->ctx; 643269257Sdes lock_basic_lock(&ctx->cfglock); 644269257Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 645269257Sdes ctx->num_async--; 646269257Sdes context_query_delete(q); 647269257Sdes lock_basic_unlock(&ctx->cfglock); 648269257Sdes 649269257Sdes if(!cancelled) { 650269257Sdes /* call callback */ 651269257Sdes int sec = 0; 652269257Sdes if(s == sec_status_bogus) 653269257Sdes sec = 1; 654269257Sdes else if(s == sec_status_secure) 655269257Sdes sec = 2; 656269257Sdes (*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf), 657269257Sdes (int)sldns_buffer_limit(buf), sec, why_bogus); 658269257Sdes } 659269257Sdes} 660269257Sdes 661269257Sdesint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, 662269257Sdes int* async_id) 663269257Sdes{ 664269257Sdes struct libworker* w = ctx->event_worker; 665269257Sdes uint16_t qflags, qid; 666269257Sdes struct query_info qinfo; 667269257Sdes struct edns_data edns; 668269257Sdes if(!w) 669269257Sdes return UB_INITFAIL; 670269257Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) 671269257Sdes return UB_SYNTAX; 672269257Sdes qid = 0; 673269257Sdes qflags = BIT_RD; 674269257Sdes q->w = w; 675269257Sdes /* see if there is a fixed answer */ 676269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 677269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 678269257Sdes if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 679285206Sdes w->back->udp_buff, w->env->scratch, NULL)) { 680269257Sdes regional_free_all(w->env->scratch); 681269257Sdes free(qinfo.qname); 682269257Sdes libworker_event_done_cb(q, LDNS_RCODE_NOERROR, 683269257Sdes w->back->udp_buff, sec_status_insecure, NULL); 684269257Sdes return UB_NOERROR; 685269257Sdes } 686269257Sdes /* process new query */ 687269257Sdes if(async_id) 688269257Sdes *async_id = q->querynum; 689269257Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 690269257Sdes w->back->udp_buff, qid, libworker_event_done_cb, q)) { 691269257Sdes free(qinfo.qname); 692269257Sdes return UB_NOMEM; 693269257Sdes } 694269257Sdes free(qinfo.qname); 695269257Sdes return UB_NOERROR; 696269257Sdes} 697269257Sdes 698238106Sdes/** add result to the bg worker result queue */ 699238106Sdesstatic void 700269257Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 701238106Sdes int err, char* reason) 702238106Sdes{ 703238106Sdes uint8_t* msg = NULL; 704238106Sdes uint32_t len = 0; 705238106Sdes 706238106Sdes /* serialize and delete unneeded q */ 707238106Sdes if(w->is_bg_thread) { 708238106Sdes lock_basic_lock(&w->ctx->cfglock); 709238106Sdes if(reason) 710238106Sdes q->res->why_bogus = strdup(reason); 711238106Sdes if(pkt) { 712269257Sdes q->msg_len = sldns_buffer_remaining(pkt); 713269257Sdes q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len); 714238106Sdes if(!q->msg) 715238106Sdes msg = context_serialize_answer(q, UB_NOMEM, 716238106Sdes NULL, &len); 717238106Sdes else msg = context_serialize_answer(q, err, 718238106Sdes NULL, &len); 719238106Sdes } else msg = context_serialize_answer(q, err, NULL, &len); 720238106Sdes lock_basic_unlock(&w->ctx->cfglock); 721238106Sdes } else { 722238106Sdes if(reason) 723238106Sdes q->res->why_bogus = strdup(reason); 724238106Sdes msg = context_serialize_answer(q, err, pkt, &len); 725238106Sdes (void)rbtree_delete(&w->ctx->queries, q->node.key); 726238106Sdes w->ctx->num_async--; 727238106Sdes context_query_delete(q); 728238106Sdes } 729238106Sdes 730238106Sdes if(!msg) { 731238106Sdes log_err("out of memory for async answer"); 732238106Sdes return; 733238106Sdes } 734238106Sdes if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) { 735238106Sdes log_err("out of memory for async answer"); 736238106Sdes return; 737238106Sdes } 738238106Sdes} 739238106Sdes 740238106Sdesvoid 741269257Sdeslibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, 742238106Sdes char* why_bogus) 743238106Sdes{ 744238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 745238106Sdes 746238106Sdes if(q->cancelled) { 747238106Sdes if(q->w->is_bg_thread) { 748238106Sdes /* delete it now */ 749238106Sdes struct ub_ctx* ctx = q->w->ctx; 750238106Sdes lock_basic_lock(&ctx->cfglock); 751238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 752238106Sdes ctx->num_async--; 753238106Sdes context_query_delete(q); 754238106Sdes lock_basic_unlock(&ctx->cfglock); 755238106Sdes } 756238106Sdes /* cancelled, do not give answer */ 757238106Sdes return; 758238106Sdes } 759238106Sdes q->msg_security = s; 760249141Sdes if(!buf) 761249141Sdes buf = q->w->env->scratch_buffer; 762238106Sdes if(rcode != 0) { 763238106Sdes error_encode(buf, rcode, NULL, 0, BIT_RD, NULL); 764238106Sdes } 765238106Sdes add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus); 766238106Sdes} 767238106Sdes 768238106Sdes 769238106Sdes/** handle new query command for bg worker */ 770238106Sdesstatic void 771238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len) 772238106Sdes{ 773238106Sdes uint16_t qflags, qid; 774238106Sdes struct query_info qinfo; 775238106Sdes struct edns_data edns; 776238106Sdes struct ctx_query* q; 777238106Sdes if(w->is_bg_thread) { 778238106Sdes lock_basic_lock(&w->ctx->cfglock); 779238106Sdes q = context_lookup_new_query(w->ctx, buf, len); 780238106Sdes lock_basic_unlock(&w->ctx->cfglock); 781238106Sdes } else { 782238106Sdes q = context_deserialize_new_query(w->ctx, buf, len); 783238106Sdes } 784238106Sdes free(buf); 785238106Sdes if(!q) { 786238106Sdes log_err("failed to deserialize newq"); 787238106Sdes return; 788238106Sdes } 789238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 790238106Sdes add_bg_result(w, q, NULL, UB_SYNTAX, NULL); 791238106Sdes return; 792238106Sdes } 793238106Sdes qid = 0; 794238106Sdes qflags = BIT_RD; 795238106Sdes /* see if there is a fixed answer */ 796269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 797269257Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 798238106Sdes if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, 799285206Sdes w->back->udp_buff, w->env->scratch, NULL)) { 800238106Sdes regional_free_all(w->env->scratch); 801238106Sdes q->msg_security = sec_status_insecure; 802238106Sdes add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL); 803238106Sdes free(qinfo.qname); 804238106Sdes return; 805238106Sdes } 806238106Sdes q->w = w; 807238106Sdes /* process new query */ 808238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 809238106Sdes w->back->udp_buff, qid, libworker_bg_done_cb, q)) { 810238106Sdes add_bg_result(w, q, NULL, UB_NOMEM, NULL); 811238106Sdes } 812238106Sdes free(qinfo.qname); 813238106Sdes} 814238106Sdes 815238106Sdesvoid libworker_alloc_cleanup(void* arg) 816238106Sdes{ 817238106Sdes struct libworker* w = (struct libworker*)arg; 818238106Sdes slabhash_clear(&w->env->rrset_cache->table); 819238106Sdes slabhash_clear(w->env->msg_cache); 820238106Sdes} 821238106Sdes 822238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, 823238106Sdes uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 824285206Sdes int want_dnssec, int nocaps, struct sockaddr_storage* addr, 825285206Sdes socklen_t addrlen, uint8_t* zone, size_t zonelen, 826285206Sdes struct module_qstate* q) 827238106Sdes{ 828238106Sdes struct libworker* w = (struct libworker*)q->env->worker; 829238106Sdes struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 830238106Sdes q->region, sizeof(*e)); 831238106Sdes if(!e) 832238106Sdes return NULL; 833238106Sdes e->qstate = q; 834238106Sdes e->qsent = outnet_serviced_query(w->back, qname, 835285206Sdes qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, 836238106Sdes q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, 837238106Sdes addrlen, zone, zonelen, libworker_handle_service_reply, e, 838249141Sdes w->back->udp_buff); 839238106Sdes if(!e->qsent) { 840238106Sdes return NULL; 841238106Sdes } 842238106Sdes return e; 843238106Sdes} 844238106Sdes 845238106Sdesint 846238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error, 847238106Sdes struct comm_reply* reply_info) 848238106Sdes{ 849238106Sdes struct module_qstate* q = (struct module_qstate*)arg; 850238106Sdes struct libworker* lw = (struct libworker*)q->env->worker; 851238106Sdes struct outbound_entry e; 852238106Sdes e.qstate = q; 853238106Sdes e.qsent = NULL; 854238106Sdes 855238106Sdes if(error != 0) { 856238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, error); 857238106Sdes return 0; 858238106Sdes } 859238106Sdes /* sanity check. */ 860269257Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 861269257Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 862238106Sdes LDNS_PACKET_QUERY 863269257Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 864238106Sdes /* error becomes timeout for the module as if this reply 865238106Sdes * never arrived. */ 866238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, 867238106Sdes NETEVENT_TIMEOUT); 868238106Sdes return 0; 869238106Sdes } 870238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR); 871238106Sdes return 0; 872238106Sdes} 873238106Sdes 874238106Sdesint 875238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error, 876238106Sdes struct comm_reply* reply_info) 877238106Sdes{ 878238106Sdes struct outbound_entry* e = (struct outbound_entry*)arg; 879238106Sdes struct libworker* lw = (struct libworker*)e->qstate->env->worker; 880238106Sdes 881238106Sdes if(error != 0) { 882238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, error); 883238106Sdes return 0; 884238106Sdes } 885238106Sdes /* sanity check. */ 886269257Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 887269257Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 888238106Sdes LDNS_PACKET_QUERY 889269257Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 890238106Sdes /* error becomes timeout for the module as if this reply 891238106Sdes * never arrived. */ 892238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, 893238106Sdes NETEVENT_TIMEOUT); 894238106Sdes return 0; 895238106Sdes } 896238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR); 897238106Sdes return 0; 898238106Sdes} 899238106Sdes 900238106Sdes/* --- fake callbacks for fptr_wlist to work --- */ 901238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 902238106Sdes uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 903238106Sdes int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 904238106Sdes{ 905238106Sdes log_assert(0); 906238106Sdes} 907238106Sdes 908238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c), 909238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 910238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 911238106Sdes{ 912238106Sdes log_assert(0); 913238106Sdes return 0; 914238106Sdes} 915238106Sdes 916238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c), 917238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 918238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 919238106Sdes{ 920238106Sdes log_assert(0); 921238106Sdes return 0; 922238106Sdes} 923238106Sdes 924238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 925238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 926238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 927238106Sdes{ 928238106Sdes log_assert(0); 929238106Sdes return 0; 930238106Sdes} 931238106Sdes 932238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c), 933238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 934238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 935238106Sdes{ 936238106Sdes log_assert(0); 937238106Sdes return 0; 938238106Sdes} 939238106Sdes 940238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c), 941238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 942238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 943238106Sdes{ 944238106Sdes log_assert(0); 945238106Sdes return 0; 946238106Sdes} 947238106Sdes 948238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) 949238106Sdes{ 950238106Sdes log_assert(0); 951238106Sdes} 952238106Sdes 953238106Sdesstruct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), 954238106Sdes size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 955238106Sdes uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 956238106Sdes int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 957285206Sdes int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), 958255579Sdes socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 959255579Sdes size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) 960238106Sdes{ 961238106Sdes log_assert(0); 962238106Sdes return 0; 963238106Sdes} 964238106Sdes 965238106Sdesvoid 966238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg)) 967238106Sdes{ 968238106Sdes log_assert(0); 969238106Sdes} 970238106Sdes 971238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg)) 972238106Sdes{ 973238106Sdes log_assert(0); 974238106Sdes} 975238106Sdes 976238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg)) 977238106Sdes{ 978238106Sdes log_assert(0); 979238106Sdes} 980238106Sdes 981238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg)) 982238106Sdes{ 983238106Sdes log_assert(0); 984238106Sdes} 985238106Sdes 986238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg)) 987238106Sdes{ 988238106Sdes log_assert(0); 989238106Sdes} 990238106Sdes 991238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 992238106Sdes{ 993238106Sdes log_assert(0); 994238106Sdes return 0; 995238106Sdes} 996238106Sdes 997238106Sdesint 998238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 999238106Sdes{ 1000238106Sdes log_assert(0); 1001238106Sdes return 0; 1002238106Sdes} 1003238106Sdes 1004238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1005238106Sdes{ 1006238106Sdes log_assert(0); 1007238106Sdes return 0; 1008238106Sdes} 1009238106Sdes 1010238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) 1011238106Sdes{ 1012238106Sdes log_assert(0); 1013238106Sdes} 1014238106Sdes 1015238106Sdes#ifdef UB_ON_WINDOWS 1016238106Sdesvoid 1017238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* 1018238106Sdes ATTR_UNUSED(arg)) { 1019238106Sdes log_assert(0); 1020238106Sdes} 1021238106Sdes 1022238106Sdesvoid 1023238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg)) 1024238106Sdes{ 1025238106Sdes log_assert(0); 1026238106Sdes} 1027238106Sdes#endif /* UB_ON_WINDOWS */ 1028