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 24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33266114Sdes * 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" 52266114Sdes#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" 73287917Sdes#include "sldns/sbuffer.h" 74287917Sdes#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 79266114Sdes/** delete libworker env */ 80238106Sdesstatic void 81266114Sdeslibworker_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); 88266114Sdes 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); 99266114Sdes} 100266114Sdes 101266114Sdes/** delete libworker struct */ 102266114Sdesstatic void 103266114Sdeslibworker_delete(struct libworker* w) 104266114Sdes{ 105266114Sdes if(!w) return; 106266114Sdes libworker_delete_env(w); 107238106Sdes comm_base_delete(w->base); 108238106Sdes free(w); 109238106Sdes} 110238106Sdes 111266114Sdesvoid 112266114Sdeslibworker_delete_event(struct libworker* w) 113266114Sdes{ 114266114Sdes if(!w) return; 115266114Sdes libworker_delete_env(w); 116266114Sdes comm_base_delete_no_base(w->base); 117266114Sdes free(w); 118266114Sdes} 119266114Sdes 120238106Sdes/** setup fresh libworker struct */ 121238106Sdesstatic struct libworker* 122266114Sdeslibworker_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); 149266114Sdes 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 210266114Sdes if(eb) 211266114Sdes w->base = comm_base_create_event(eb); 212266114Sdes 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) { 222266114Sdes int locked = !w->is_bg || w->is_bg_thread; 223238106Sdes libworker_delete(w); 224266114Sdes if(locked) { 225266114Sdes lock_basic_unlock(&ctx->cfglock); 226266114Sdes } 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, 235296415Sdes cfg->outgoing_tcp_mss, 236266114Sdes &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx, 237276605Sdes cfg->delay_close, NULL); 238238106Sdes if(!w->is_bg || w->is_bg_thread) { 239238106Sdes lock_basic_unlock(&ctx->cfglock); 240238106Sdes } 241238106Sdes free(ports); 242238106Sdes if(!w->back) { 243238106Sdes libworker_delete(w); 244238106Sdes return NULL; 245238106Sdes } 246238106Sdes w->env->mesh = mesh_create(&ctx->mods, w->env); 247238106Sdes if(!w->env->mesh) { 248238106Sdes libworker_delete(w); 249238106Sdes return NULL; 250238106Sdes } 251238106Sdes w->env->send_query = &libworker_send_query; 252238106Sdes w->env->detach_subs = &mesh_detach_subs; 253238106Sdes w->env->attach_sub = &mesh_attach_sub; 254238106Sdes w->env->kill_sub = &mesh_state_delete; 255238106Sdes w->env->detect_cycle = &mesh_detect_cycle; 256238106Sdes comm_base_timept(w->base, &w->env->now, &w->env->now_tv); 257238106Sdes return w; 258238106Sdes} 259238106Sdes 260266114Sdesstruct libworker* libworker_create_event(struct ub_ctx* ctx, 261266114Sdes struct event_base* eb) 262266114Sdes{ 263266114Sdes return libworker_setup(ctx, 0, eb); 264266114Sdes} 265266114Sdes 266238106Sdes/** handle cancel command for bg worker */ 267238106Sdesstatic void 268238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len) 269238106Sdes{ 270238106Sdes struct ctx_query* q; 271238106Sdes if(w->is_bg_thread) { 272238106Sdes lock_basic_lock(&w->ctx->cfglock); 273238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 274238106Sdes lock_basic_unlock(&w->ctx->cfglock); 275238106Sdes } else { 276238106Sdes q = context_deserialize_cancel(w->ctx, buf, len); 277238106Sdes } 278238106Sdes if(!q) { 279238106Sdes /* probably simply lookup failed, i.e. the message had been 280238106Sdes * processed and answered before the cancel arrived */ 281238106Sdes return; 282238106Sdes } 283238106Sdes q->cancelled = 1; 284238106Sdes free(buf); 285238106Sdes} 286238106Sdes 287238106Sdes/** do control command coming into bg server */ 288238106Sdesstatic void 289238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len) 290238106Sdes{ 291238106Sdes switch(context_serial_getcmd(msg, len)) { 292238106Sdes default: 293238106Sdes case UB_LIBCMD_ANSWER: 294238106Sdes log_err("unknown command for bg worker %d", 295238106Sdes (int)context_serial_getcmd(msg, len)); 296238106Sdes /* and fall through to quit */ 297238106Sdes case UB_LIBCMD_QUIT: 298238106Sdes free(msg); 299238106Sdes comm_base_exit(w->base); 300238106Sdes break; 301238106Sdes case UB_LIBCMD_NEWQUERY: 302238106Sdes handle_newq(w, msg, len); 303238106Sdes break; 304238106Sdes case UB_LIBCMD_CANCEL: 305238106Sdes handle_cancel(w, msg, len); 306238106Sdes break; 307238106Sdes } 308238106Sdes} 309238106Sdes 310238106Sdes/** handle control command coming into server */ 311238106Sdesvoid 312238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 313238106Sdes uint8_t* msg, size_t len, int err, void* arg) 314238106Sdes{ 315238106Sdes struct libworker* w = (struct libworker*)arg; 316238106Sdes 317238106Sdes if(err != 0) { 318238106Sdes free(msg); 319238106Sdes /* it is of no use to go on, exit */ 320238106Sdes comm_base_exit(w->base); 321238106Sdes return; 322238106Sdes } 323238106Sdes libworker_do_cmd(w, msg, len); /* also frees the buf */ 324238106Sdes} 325238106Sdes 326238106Sdes/** the background thread func */ 327238106Sdesstatic void* 328238106Sdeslibworker_dobg(void* arg) 329238106Sdes{ 330238106Sdes /* setup */ 331238106Sdes uint32_t m; 332238106Sdes struct libworker* w = (struct libworker*)arg; 333238106Sdes struct ub_ctx* ctx; 334238106Sdes if(!w) { 335238106Sdes log_err("libunbound bg worker init failed, nomem"); 336238106Sdes return NULL; 337238106Sdes } 338238106Sdes ctx = w->ctx; 339238106Sdes log_thread_set(&w->thread_num); 340238106Sdes#ifdef THREADS_DISABLED 341238106Sdes /* we are forked */ 342238106Sdes w->is_bg_thread = 0; 343238106Sdes /* close non-used parts of the pipes */ 344238106Sdes tube_close_write(ctx->qq_pipe); 345238106Sdes tube_close_read(ctx->rr_pipe); 346238106Sdes#endif 347238106Sdes if(!tube_setup_bg_listen(ctx->qq_pipe, w->base, 348238106Sdes libworker_handle_control_cmd, w)) { 349238106Sdes log_err("libunbound bg worker init failed, no bglisten"); 350238106Sdes return NULL; 351238106Sdes } 352238106Sdes if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) { 353238106Sdes log_err("libunbound bg worker init failed, no bgwrite"); 354238106Sdes return NULL; 355238106Sdes } 356238106Sdes 357238106Sdes /* do the work */ 358238106Sdes comm_base_dispatch(w->base); 359238106Sdes 360238106Sdes /* cleanup */ 361238106Sdes m = UB_LIBCMD_QUIT; 362238106Sdes tube_remove_bg_listen(w->ctx->qq_pipe); 363238106Sdes tube_remove_bg_write(w->ctx->rr_pipe); 364238106Sdes libworker_delete(w); 365238106Sdes (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m, 366238106Sdes (uint32_t)sizeof(m), 0); 367238106Sdes#ifdef THREADS_DISABLED 368238106Sdes /* close pipes from forked process before exit */ 369238106Sdes tube_close_read(ctx->qq_pipe); 370238106Sdes tube_close_write(ctx->rr_pipe); 371238106Sdes#endif 372238106Sdes return NULL; 373238106Sdes} 374238106Sdes 375238106Sdesint libworker_bg(struct ub_ctx* ctx) 376238106Sdes{ 377238106Sdes struct libworker* w; 378238106Sdes /* fork or threadcreate */ 379238106Sdes lock_basic_lock(&ctx->cfglock); 380238106Sdes if(ctx->dothread) { 381238106Sdes lock_basic_unlock(&ctx->cfglock); 382266114Sdes w = libworker_setup(ctx, 1, NULL); 383238106Sdes if(!w) return UB_NOMEM; 384238106Sdes w->is_bg_thread = 1; 385238106Sdes#ifdef ENABLE_LOCK_CHECKS 386238106Sdes w->thread_num = 1; /* for nicer DEBUG checklocks */ 387238106Sdes#endif 388238106Sdes ub_thread_create(&ctx->bg_tid, libworker_dobg, w); 389238106Sdes } else { 390238106Sdes lock_basic_unlock(&ctx->cfglock); 391238106Sdes#ifndef HAVE_FORK 392238106Sdes /* no fork on windows */ 393238106Sdes return UB_FORKFAIL; 394238106Sdes#else /* HAVE_FORK */ 395238106Sdes switch((ctx->bg_pid=fork())) { 396238106Sdes case 0: 397266114Sdes w = libworker_setup(ctx, 1, NULL); 398238106Sdes if(!w) fatal_exit("out of memory"); 399238106Sdes /* close non-used parts of the pipes */ 400238106Sdes tube_close_write(ctx->qq_pipe); 401238106Sdes tube_close_read(ctx->rr_pipe); 402238106Sdes (void)libworker_dobg(w); 403238106Sdes exit(0); 404238106Sdes break; 405238106Sdes case -1: 406238106Sdes return UB_FORKFAIL; 407238106Sdes default: 408266114Sdes /* close non-used parts, so that the worker 409266114Sdes * bgprocess gets 'pipe closed' when the 410266114Sdes * main process exits */ 411266114Sdes tube_close_read(ctx->qq_pipe); 412266114Sdes tube_close_write(ctx->rr_pipe); 413238106Sdes break; 414238106Sdes } 415238106Sdes#endif /* HAVE_FORK */ 416238106Sdes } 417238106Sdes return UB_NOERROR; 418238106Sdes} 419238106Sdes 420238106Sdes/** get msg reply struct (in temp region) */ 421238106Sdesstatic struct reply_info* 422266114Sdesparse_reply(sldns_buffer* pkt, struct regional* region, struct query_info* qi) 423238106Sdes{ 424238106Sdes struct reply_info* rep; 425238106Sdes struct msg_parse* msg; 426238106Sdes if(!(msg = regional_alloc(region, sizeof(*msg)))) { 427238106Sdes return NULL; 428238106Sdes } 429238106Sdes memset(msg, 0, sizeof(*msg)); 430266114Sdes sldns_buffer_set_position(pkt, 0); 431238106Sdes if(parse_packet(pkt, msg, region) != 0) 432238106Sdes return 0; 433238106Sdes if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { 434238106Sdes return 0; 435238106Sdes } 436238106Sdes return rep; 437238106Sdes} 438238106Sdes 439238106Sdes/** insert canonname */ 440238106Sdesstatic int 441238106Sdesfill_canon(struct ub_result* res, uint8_t* s) 442238106Sdes{ 443238106Sdes char buf[255+2]; 444238106Sdes dname_str(s, buf); 445238106Sdes res->canonname = strdup(buf); 446238106Sdes return res->canonname != 0; 447238106Sdes} 448238106Sdes 449238106Sdes/** fill data into result */ 450238106Sdesstatic int 451238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer, 452249141Sdes uint8_t* finalcname, struct query_info* rq, struct reply_info* rep) 453238106Sdes{ 454238106Sdes size_t i; 455238106Sdes struct packed_rrset_data* data; 456249141Sdes res->ttl = 0; 457238106Sdes if(!answer) { 458238106Sdes if(finalcname) { 459238106Sdes if(!fill_canon(res, finalcname)) 460238106Sdes return 0; /* out of memory */ 461238106Sdes } 462249141Sdes if(rep->rrset_count != 0) 463249141Sdes res->ttl = (int)rep->ttl; 464238106Sdes res->data = (char**)calloc(1, sizeof(char*)); 465238106Sdes res->len = (int*)calloc(1, sizeof(int)); 466238106Sdes return (res->data && res->len); 467238106Sdes } 468238106Sdes data = (struct packed_rrset_data*)answer->entry.data; 469238106Sdes if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { 470238106Sdes if(!fill_canon(res, answer->rk.dname)) 471238106Sdes return 0; /* out of memory */ 472238106Sdes } else res->canonname = NULL; 473238106Sdes res->data = (char**)calloc(data->count+1, sizeof(char*)); 474238106Sdes res->len = (int*)calloc(data->count+1, sizeof(int)); 475238106Sdes if(!res->data || !res->len) 476238106Sdes return 0; /* out of memory */ 477238106Sdes for(i=0; i<data->count; i++) { 478238106Sdes /* remove rdlength from rdata */ 479238106Sdes res->len[i] = (int)(data->rr_len[i] - 2); 480238106Sdes res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]); 481238106Sdes if(!res->data[i]) 482238106Sdes return 0; /* out of memory */ 483238106Sdes } 484249141Sdes /* ttl for positive answers, from CNAME and answer RRs */ 485249141Sdes if(data->count != 0) { 486249141Sdes size_t j; 487249141Sdes res->ttl = (int)data->ttl; 488249141Sdes for(j=0; j<rep->an_numrrsets; j++) { 489249141Sdes struct packed_rrset_data* d = 490249141Sdes (struct packed_rrset_data*)rep->rrsets[j]-> 491249141Sdes entry.data; 492249141Sdes if((int)d->ttl < res->ttl) 493249141Sdes res->ttl = (int)d->ttl; 494249141Sdes } 495249141Sdes } 496249141Sdes /* ttl for negative answers */ 497249141Sdes if(data->count == 0 && rep->rrset_count != 0) 498249141Sdes res->ttl = (int)rep->ttl; 499238106Sdes res->data[data->count] = NULL; 500238106Sdes res->len[data->count] = 0; 501238106Sdes return 1; 502238106Sdes} 503238106Sdes 504238106Sdes/** fill result from parsed message, on error fills servfail */ 505238106Sdesvoid 506266114Sdeslibworker_enter_result(struct ub_result* res, sldns_buffer* buf, 507238106Sdes struct regional* temp, enum sec_status msg_security) 508238106Sdes{ 509238106Sdes struct query_info rq; 510238106Sdes struct reply_info* rep; 511238106Sdes res->rcode = LDNS_RCODE_SERVFAIL; 512238106Sdes rep = parse_reply(buf, temp, &rq); 513238106Sdes if(!rep) { 514238106Sdes log_err("cannot parse buf"); 515238106Sdes return; /* error parsing buf, or out of memory */ 516238106Sdes } 517238106Sdes if(!fill_res(res, reply_find_answer_rrset(&rq, rep), 518249141Sdes reply_find_final_cname_target(&rq, rep), &rq, rep)) 519238106Sdes return; /* out of memory */ 520238106Sdes /* rcode, havedata, nxdomain, secure, bogus */ 521238106Sdes res->rcode = (int)FLAGS_GET_RCODE(rep->flags); 522238106Sdes if(res->data && res->data[0]) 523238106Sdes res->havedata = 1; 524238106Sdes if(res->rcode == LDNS_RCODE_NXDOMAIN) 525238106Sdes res->nxdomain = 1; 526238106Sdes if(msg_security == sec_status_secure) 527238106Sdes res->secure = 1; 528238106Sdes if(msg_security == sec_status_bogus) 529238106Sdes res->bogus = 1; 530238106Sdes} 531238106Sdes 532238106Sdes/** fillup fg results */ 533238106Sdesstatic void 534266114Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, 535238106Sdes enum sec_status s, char* why_bogus) 536238106Sdes{ 537238106Sdes if(why_bogus) 538238106Sdes q->res->why_bogus = strdup(why_bogus); 539238106Sdes if(rcode != 0) { 540238106Sdes q->res->rcode = rcode; 541238106Sdes q->msg_security = s; 542238106Sdes return; 543238106Sdes } 544238106Sdes 545238106Sdes q->res->rcode = LDNS_RCODE_SERVFAIL; 546238106Sdes q->msg_security = 0; 547266114Sdes q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf)); 548266114Sdes q->msg_len = sldns_buffer_limit(buf); 549238106Sdes if(!q->msg) { 550238106Sdes return; /* the error is in the rcode */ 551238106Sdes } 552238106Sdes 553238106Sdes /* canonname and results */ 554238106Sdes q->msg_security = s; 555238106Sdes libworker_enter_result(q->res, buf, q->w->env->scratch, s); 556238106Sdes} 557238106Sdes 558238106Sdesvoid 559266114Sdeslibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, 560238106Sdes char* why_bogus) 561238106Sdes{ 562238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 563238106Sdes /* fg query is done; exit comm base */ 564238106Sdes comm_base_exit(q->w->base); 565238106Sdes 566238106Sdes libworker_fillup_fg(q, rcode, buf, s, why_bogus); 567238106Sdes} 568238106Sdes 569238106Sdes/** setup qinfo and edns */ 570238106Sdesstatic int 571238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q, 572238106Sdes struct query_info* qinfo, struct edns_data* edns) 573238106Sdes{ 574238106Sdes qinfo->qtype = (uint16_t)q->res->qtype; 575238106Sdes qinfo->qclass = (uint16_t)q->res->qclass; 576266114Sdes qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len); 577266114Sdes if(!qinfo->qname) { 578238106Sdes return 0; 579238106Sdes } 580238106Sdes edns->edns_present = 1; 581238106Sdes edns->ext_rcode = 0; 582238106Sdes edns->edns_version = 0; 583238106Sdes edns->bits = EDNS_DO; 584266114Sdes if(sldns_buffer_capacity(w->back->udp_buff) < 65535) 585266114Sdes edns->udp_size = (uint16_t)sldns_buffer_capacity( 586238106Sdes w->back->udp_buff); 587238106Sdes else edns->udp_size = 65535; 588238106Sdes return 1; 589238106Sdes} 590238106Sdes 591238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) 592238106Sdes{ 593266114Sdes struct libworker* w = libworker_setup(ctx, 0, NULL); 594238106Sdes uint16_t qflags, qid; 595238106Sdes struct query_info qinfo; 596238106Sdes struct edns_data edns; 597238106Sdes if(!w) 598238106Sdes return UB_INITFAIL; 599238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 600238106Sdes libworker_delete(w); 601238106Sdes return UB_SYNTAX; 602238106Sdes } 603238106Sdes qid = 0; 604238106Sdes qflags = BIT_RD; 605238106Sdes q->w = w; 606238106Sdes /* see if there is a fixed answer */ 607266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 608266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 609238106Sdes if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 610282089Sdes w->back->udp_buff, w->env->scratch, NULL)) { 611238106Sdes regional_free_all(w->env->scratch); 612238106Sdes libworker_fillup_fg(q, LDNS_RCODE_NOERROR, 613238106Sdes w->back->udp_buff, sec_status_insecure, NULL); 614238106Sdes libworker_delete(w); 615238106Sdes free(qinfo.qname); 616238106Sdes return UB_NOERROR; 617238106Sdes } 618238106Sdes /* process new query */ 619238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 620238106Sdes w->back->udp_buff, qid, libworker_fg_done_cb, q)) { 621238106Sdes free(qinfo.qname); 622238106Sdes return UB_NOMEM; 623238106Sdes } 624238106Sdes free(qinfo.qname); 625238106Sdes 626238106Sdes /* wait for reply */ 627238106Sdes comm_base_dispatch(w->base); 628238106Sdes 629238106Sdes libworker_delete(w); 630238106Sdes return UB_NOERROR; 631238106Sdes} 632238106Sdes 633266114Sdesvoid 634266114Sdeslibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, 635266114Sdes enum sec_status s, char* why_bogus) 636266114Sdes{ 637266114Sdes struct ctx_query* q = (struct ctx_query*)arg; 638266114Sdes ub_event_callback_t cb = (ub_event_callback_t)q->cb; 639266114Sdes void* cb_arg = q->cb_arg; 640266114Sdes int cancelled = q->cancelled; 641266114Sdes 642266114Sdes /* delete it now */ 643266114Sdes struct ub_ctx* ctx = q->w->ctx; 644266114Sdes lock_basic_lock(&ctx->cfglock); 645266114Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 646266114Sdes ctx->num_async--; 647266114Sdes context_query_delete(q); 648266114Sdes lock_basic_unlock(&ctx->cfglock); 649266114Sdes 650266114Sdes if(!cancelled) { 651266114Sdes /* call callback */ 652266114Sdes int sec = 0; 653266114Sdes if(s == sec_status_bogus) 654266114Sdes sec = 1; 655266114Sdes else if(s == sec_status_secure) 656266114Sdes sec = 2; 657266114Sdes (*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf), 658266114Sdes (int)sldns_buffer_limit(buf), sec, why_bogus); 659266114Sdes } 660266114Sdes} 661266114Sdes 662266114Sdesint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, 663266114Sdes int* async_id) 664266114Sdes{ 665266114Sdes struct libworker* w = ctx->event_worker; 666266114Sdes uint16_t qflags, qid; 667266114Sdes struct query_info qinfo; 668266114Sdes struct edns_data edns; 669266114Sdes if(!w) 670266114Sdes return UB_INITFAIL; 671266114Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) 672266114Sdes return UB_SYNTAX; 673266114Sdes qid = 0; 674266114Sdes qflags = BIT_RD; 675266114Sdes q->w = w; 676266114Sdes /* see if there is a fixed answer */ 677266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 678266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 679266114Sdes if(local_zones_answer(ctx->local_zones, &qinfo, &edns, 680282089Sdes w->back->udp_buff, w->env->scratch, NULL)) { 681266114Sdes regional_free_all(w->env->scratch); 682266114Sdes free(qinfo.qname); 683266114Sdes libworker_event_done_cb(q, LDNS_RCODE_NOERROR, 684266114Sdes w->back->udp_buff, sec_status_insecure, NULL); 685266114Sdes return UB_NOERROR; 686266114Sdes } 687266114Sdes /* process new query */ 688266114Sdes if(async_id) 689266114Sdes *async_id = q->querynum; 690266114Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 691266114Sdes w->back->udp_buff, qid, libworker_event_done_cb, q)) { 692266114Sdes free(qinfo.qname); 693266114Sdes return UB_NOMEM; 694266114Sdes } 695266114Sdes free(qinfo.qname); 696266114Sdes return UB_NOERROR; 697266114Sdes} 698266114Sdes 699238106Sdes/** add result to the bg worker result queue */ 700238106Sdesstatic void 701266114Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 702238106Sdes int err, char* reason) 703238106Sdes{ 704238106Sdes uint8_t* msg = NULL; 705238106Sdes uint32_t len = 0; 706238106Sdes 707238106Sdes /* serialize and delete unneeded q */ 708238106Sdes if(w->is_bg_thread) { 709238106Sdes lock_basic_lock(&w->ctx->cfglock); 710238106Sdes if(reason) 711238106Sdes q->res->why_bogus = strdup(reason); 712238106Sdes if(pkt) { 713266114Sdes q->msg_len = sldns_buffer_remaining(pkt); 714266114Sdes q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len); 715238106Sdes if(!q->msg) 716238106Sdes msg = context_serialize_answer(q, UB_NOMEM, 717238106Sdes NULL, &len); 718238106Sdes else msg = context_serialize_answer(q, err, 719238106Sdes NULL, &len); 720238106Sdes } else msg = context_serialize_answer(q, err, NULL, &len); 721238106Sdes lock_basic_unlock(&w->ctx->cfglock); 722238106Sdes } else { 723238106Sdes if(reason) 724238106Sdes q->res->why_bogus = strdup(reason); 725238106Sdes msg = context_serialize_answer(q, err, pkt, &len); 726238106Sdes (void)rbtree_delete(&w->ctx->queries, q->node.key); 727238106Sdes w->ctx->num_async--; 728238106Sdes context_query_delete(q); 729238106Sdes } 730238106Sdes 731238106Sdes if(!msg) { 732238106Sdes log_err("out of memory for async answer"); 733238106Sdes return; 734238106Sdes } 735238106Sdes if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) { 736238106Sdes log_err("out of memory for async answer"); 737238106Sdes return; 738238106Sdes } 739238106Sdes} 740238106Sdes 741238106Sdesvoid 742266114Sdeslibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, 743238106Sdes char* why_bogus) 744238106Sdes{ 745238106Sdes struct ctx_query* q = (struct ctx_query*)arg; 746238106Sdes 747238106Sdes if(q->cancelled) { 748238106Sdes if(q->w->is_bg_thread) { 749238106Sdes /* delete it now */ 750238106Sdes struct ub_ctx* ctx = q->w->ctx; 751238106Sdes lock_basic_lock(&ctx->cfglock); 752238106Sdes (void)rbtree_delete(&ctx->queries, q->node.key); 753238106Sdes ctx->num_async--; 754238106Sdes context_query_delete(q); 755238106Sdes lock_basic_unlock(&ctx->cfglock); 756238106Sdes } 757238106Sdes /* cancelled, do not give answer */ 758238106Sdes return; 759238106Sdes } 760238106Sdes q->msg_security = s; 761249141Sdes if(!buf) 762249141Sdes buf = q->w->env->scratch_buffer; 763238106Sdes if(rcode != 0) { 764238106Sdes error_encode(buf, rcode, NULL, 0, BIT_RD, NULL); 765238106Sdes } 766238106Sdes add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus); 767238106Sdes} 768238106Sdes 769238106Sdes 770238106Sdes/** handle new query command for bg worker */ 771238106Sdesstatic void 772238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len) 773238106Sdes{ 774238106Sdes uint16_t qflags, qid; 775238106Sdes struct query_info qinfo; 776238106Sdes struct edns_data edns; 777238106Sdes struct ctx_query* q; 778238106Sdes if(w->is_bg_thread) { 779238106Sdes lock_basic_lock(&w->ctx->cfglock); 780238106Sdes q = context_lookup_new_query(w->ctx, buf, len); 781238106Sdes lock_basic_unlock(&w->ctx->cfglock); 782238106Sdes } else { 783238106Sdes q = context_deserialize_new_query(w->ctx, buf, len); 784238106Sdes } 785238106Sdes free(buf); 786238106Sdes if(!q) { 787238106Sdes log_err("failed to deserialize newq"); 788238106Sdes return; 789238106Sdes } 790238106Sdes if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { 791238106Sdes add_bg_result(w, q, NULL, UB_SYNTAX, NULL); 792238106Sdes return; 793238106Sdes } 794238106Sdes qid = 0; 795238106Sdes qflags = BIT_RD; 796238106Sdes /* see if there is a fixed answer */ 797266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); 798266114Sdes sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); 799238106Sdes if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, 800282089Sdes w->back->udp_buff, w->env->scratch, NULL)) { 801238106Sdes regional_free_all(w->env->scratch); 802238106Sdes q->msg_security = sec_status_insecure; 803238106Sdes add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL); 804238106Sdes free(qinfo.qname); 805238106Sdes return; 806238106Sdes } 807238106Sdes q->w = w; 808238106Sdes /* process new query */ 809238106Sdes if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 810238106Sdes w->back->udp_buff, qid, libworker_bg_done_cb, q)) { 811238106Sdes add_bg_result(w, q, NULL, UB_NOMEM, NULL); 812238106Sdes } 813238106Sdes free(qinfo.qname); 814238106Sdes} 815238106Sdes 816238106Sdesvoid libworker_alloc_cleanup(void* arg) 817238106Sdes{ 818238106Sdes struct libworker* w = (struct libworker*)arg; 819238106Sdes slabhash_clear(&w->env->rrset_cache->table); 820238106Sdes slabhash_clear(w->env->msg_cache); 821238106Sdes} 822238106Sdes 823238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, 824238106Sdes uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, 825276605Sdes int want_dnssec, int nocaps, struct sockaddr_storage* addr, 826276605Sdes socklen_t addrlen, uint8_t* zone, size_t zonelen, 827276605Sdes struct module_qstate* q) 828238106Sdes{ 829238106Sdes struct libworker* w = (struct libworker*)q->env->worker; 830238106Sdes struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 831238106Sdes q->region, sizeof(*e)); 832238106Sdes if(!e) 833238106Sdes return NULL; 834238106Sdes e->qstate = q; 835238106Sdes e->qsent = outnet_serviced_query(w->back, qname, 836276605Sdes qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, 837238106Sdes q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, 838238106Sdes addrlen, zone, zonelen, libworker_handle_service_reply, e, 839249141Sdes w->back->udp_buff); 840238106Sdes if(!e->qsent) { 841238106Sdes return NULL; 842238106Sdes } 843238106Sdes return e; 844238106Sdes} 845238106Sdes 846238106Sdesint 847238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error, 848238106Sdes struct comm_reply* reply_info) 849238106Sdes{ 850238106Sdes struct module_qstate* q = (struct module_qstate*)arg; 851238106Sdes struct libworker* lw = (struct libworker*)q->env->worker; 852238106Sdes struct outbound_entry e; 853238106Sdes e.qstate = q; 854238106Sdes e.qsent = NULL; 855238106Sdes 856238106Sdes if(error != 0) { 857238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, error); 858238106Sdes return 0; 859238106Sdes } 860238106Sdes /* sanity check. */ 861266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 862266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 863238106Sdes LDNS_PACKET_QUERY 864266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 865238106Sdes /* error becomes timeout for the module as if this reply 866238106Sdes * never arrived. */ 867238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, 868238106Sdes NETEVENT_TIMEOUT); 869238106Sdes return 0; 870238106Sdes } 871238106Sdes mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR); 872238106Sdes return 0; 873238106Sdes} 874238106Sdes 875238106Sdesint 876238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error, 877238106Sdes struct comm_reply* reply_info) 878238106Sdes{ 879238106Sdes struct outbound_entry* e = (struct outbound_entry*)arg; 880238106Sdes struct libworker* lw = (struct libworker*)e->qstate->env->worker; 881238106Sdes 882238106Sdes if(error != 0) { 883238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, error); 884238106Sdes return 0; 885238106Sdes } 886238106Sdes /* sanity check. */ 887266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 888266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 889238106Sdes LDNS_PACKET_QUERY 890266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 891238106Sdes /* error becomes timeout for the module as if this reply 892238106Sdes * never arrived. */ 893238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, 894238106Sdes NETEVENT_TIMEOUT); 895238106Sdes return 0; 896238106Sdes } 897238106Sdes mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR); 898238106Sdes return 0; 899238106Sdes} 900238106Sdes 901238106Sdes/* --- fake callbacks for fptr_wlist to work --- */ 902238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 903238106Sdes uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 904238106Sdes int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 905238106Sdes{ 906238106Sdes log_assert(0); 907238106Sdes} 908238106Sdes 909238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c), 910238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 911238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 912238106Sdes{ 913238106Sdes log_assert(0); 914238106Sdes return 0; 915238106Sdes} 916238106Sdes 917238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c), 918238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 919238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 920238106Sdes{ 921238106Sdes log_assert(0); 922238106Sdes return 0; 923238106Sdes} 924238106Sdes 925238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 926238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 927238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 928238106Sdes{ 929238106Sdes log_assert(0); 930238106Sdes return 0; 931238106Sdes} 932238106Sdes 933238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c), 934238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 935238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 936238106Sdes{ 937238106Sdes log_assert(0); 938238106Sdes return 0; 939238106Sdes} 940238106Sdes 941238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c), 942238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 943238106Sdes struct comm_reply* ATTR_UNUSED(repinfo)) 944238106Sdes{ 945238106Sdes log_assert(0); 946238106Sdes return 0; 947238106Sdes} 948238106Sdes 949238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) 950238106Sdes{ 951238106Sdes log_assert(0); 952238106Sdes} 953238106Sdes 954238106Sdesstruct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), 955238106Sdes size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 956238106Sdes uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 957238106Sdes int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 958276605Sdes int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), 959255579Sdes socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 960255579Sdes size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) 961238106Sdes{ 962238106Sdes log_assert(0); 963238106Sdes return 0; 964238106Sdes} 965238106Sdes 966238106Sdesvoid 967238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg)) 968238106Sdes{ 969238106Sdes log_assert(0); 970238106Sdes} 971238106Sdes 972238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg)) 973238106Sdes{ 974238106Sdes log_assert(0); 975238106Sdes} 976238106Sdes 977238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg)) 978238106Sdes{ 979238106Sdes log_assert(0); 980238106Sdes} 981238106Sdes 982238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg)) 983238106Sdes{ 984238106Sdes log_assert(0); 985238106Sdes} 986238106Sdes 987238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg)) 988238106Sdes{ 989238106Sdes log_assert(0); 990238106Sdes} 991238106Sdes 992238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 993238106Sdes{ 994238106Sdes log_assert(0); 995238106Sdes return 0; 996238106Sdes} 997238106Sdes 998238106Sdesint 999238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1000238106Sdes{ 1001238106Sdes log_assert(0); 1002238106Sdes return 0; 1003238106Sdes} 1004238106Sdes 1005238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1006238106Sdes{ 1007238106Sdes log_assert(0); 1008238106Sdes return 0; 1009238106Sdes} 1010238106Sdes 1011238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) 1012238106Sdes{ 1013238106Sdes log_assert(0); 1014238106Sdes} 1015238106Sdes 1016238106Sdes#ifdef UB_ON_WINDOWS 1017238106Sdesvoid 1018238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* 1019238106Sdes ATTR_UNUSED(arg)) { 1020238106Sdes log_assert(0); 1021238106Sdes} 1022238106Sdes 1023238106Sdesvoid 1024238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg)) 1025238106Sdes{ 1026238106Sdes log_assert(0); 1027238106Sdes} 1028238106Sdes#endif /* UB_ON_WINDOWS */ 1029