worker.c revision 266114
1238106Sdes/* 2238106Sdes * daemon/worker.c - worker that handles a pending list of requests. 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 implements the worker that handles callbacks on events, for 40238106Sdes * pending requests. 41238106Sdes */ 42238106Sdes#include "config.h" 43238106Sdes#include "util/log.h" 44238106Sdes#include "util/net_help.h" 45238106Sdes#include "util/random.h" 46238106Sdes#include "daemon/worker.h" 47238106Sdes#include "daemon/daemon.h" 48238106Sdes#include "daemon/remote.h" 49238106Sdes#include "daemon/acl_list.h" 50238106Sdes#include "util/netevent.h" 51238106Sdes#include "util/config_file.h" 52238106Sdes#include "util/module.h" 53238106Sdes#include "util/regional.h" 54238106Sdes#include "util/storage/slabhash.h" 55238106Sdes#include "services/listen_dnsport.h" 56238106Sdes#include "services/outside_network.h" 57238106Sdes#include "services/outbound_list.h" 58238106Sdes#include "services/cache/rrset.h" 59238106Sdes#include "services/cache/infra.h" 60238106Sdes#include "services/cache/dns.h" 61238106Sdes#include "services/mesh.h" 62238106Sdes#include "services/localzone.h" 63238106Sdes#include "util/data/msgparse.h" 64238106Sdes#include "util/data/msgencode.h" 65238106Sdes#include "util/data/dname.h" 66238106Sdes#include "util/fptr_wlist.h" 67238106Sdes#include "util/tube.h" 68238106Sdes#include "iterator/iter_fwd.h" 69238106Sdes#include "iterator/iter_hints.h" 70238106Sdes#include "validator/autotrust.h" 71238106Sdes#include "validator/val_anchor.h" 72255579Sdes#include "libunbound/context.h" 73255579Sdes#include "libunbound/libworker.h" 74266114Sdes#include "ldns/sbuffer.h" 75238106Sdes 76238106Sdes#ifdef HAVE_SYS_TYPES_H 77238106Sdes# include <sys/types.h> 78238106Sdes#endif 79238106Sdes#ifdef HAVE_NETDB_H 80238106Sdes#include <netdb.h> 81238106Sdes#endif 82238106Sdes#include <signal.h> 83238106Sdes#ifdef UB_ON_WINDOWS 84238106Sdes#include "winrc/win_svc.h" 85238106Sdes#endif 86238106Sdes 87238106Sdes/** Size of an UDP datagram */ 88238106Sdes#define NORMAL_UDP_SIZE 512 /* bytes */ 89238106Sdes 90238106Sdes/** 91238106Sdes * seconds to add to prefetch leeway. This is a TTL that expires old rrsets 92238106Sdes * earlier than they should in order to put the new update into the cache. 93238106Sdes * This additional value is to make sure that if not all TTLs are equal in 94238106Sdes * the message to be updated(and replaced), that rrsets with up to this much 95238106Sdes * extra TTL are also replaced. This means that the resulting new message 96238106Sdes * will have (most likely) this TTL at least, avoiding very small 'split 97238106Sdes * second' TTLs due to operators choosing relative primes for TTLs (or so). 98238106Sdes * Also has to be at least one to break ties (and overwrite cached entry). 99238106Sdes */ 100238106Sdes#define PREFETCH_EXPIRY_ADD 60 101238106Sdes 102238106Sdes#ifdef UNBOUND_ALLOC_STATS 103238106Sdes/** measure memory leakage */ 104238106Sdesstatic void 105238106Sdesdebug_memleak(size_t accounted, size_t heap, 106238106Sdes size_t total_alloc, size_t total_free) 107238106Sdes{ 108238106Sdes static int init = 0; 109238106Sdes static size_t base_heap, base_accounted, base_alloc, base_free; 110238106Sdes size_t base_af, cur_af, grow_af, grow_acc; 111238106Sdes if(!init) { 112238106Sdes init = 1; 113238106Sdes base_heap = heap; 114238106Sdes base_accounted = accounted; 115238106Sdes base_alloc = total_alloc; 116238106Sdes base_free = total_free; 117238106Sdes } 118238106Sdes base_af = base_alloc - base_free; 119238106Sdes cur_af = total_alloc - total_free; 120238106Sdes grow_af = cur_af - base_af; 121238106Sdes grow_acc = accounted - base_accounted; 122238106Sdes log_info("Leakage: %d leaked. growth: %u use, %u acc, %u heap", 123238106Sdes (int)(grow_af - grow_acc), (unsigned)grow_af, 124238106Sdes (unsigned)grow_acc, (unsigned)(heap - base_heap)); 125238106Sdes} 126238106Sdes 127238106Sdes/** give debug heap size indication */ 128238106Sdesstatic void 129238106Sdesdebug_total_mem(size_t calctotal) 130238106Sdes{ 131238106Sdes#ifdef HAVE_SBRK 132238106Sdes extern void* unbound_start_brk; 133238106Sdes extern size_t unbound_mem_alloc, unbound_mem_freed; 134238106Sdes void* cur = sbrk(0); 135238106Sdes int total = cur-unbound_start_brk; 136238106Sdes log_info("Total heap memory estimate: %u total-alloc: %u " 137238106Sdes "total-free: %u", (unsigned)total, 138238106Sdes (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); 139238106Sdes debug_memleak(calctotal, (size_t)total, 140238106Sdes unbound_mem_alloc, unbound_mem_freed); 141238106Sdes#else 142238106Sdes (void)calctotal; 143238106Sdes#endif /* HAVE_SBRK */ 144238106Sdes} 145238106Sdes#endif /* UNBOUND_ALLOC_STATS */ 146238106Sdes 147238106Sdes/** Report on memory usage by this thread and global */ 148238106Sdesstatic void 149238106Sdesworker_mem_report(struct worker* ATTR_UNUSED(worker), 150238106Sdes struct serviced_query* ATTR_UNUSED(cur_serv)) 151238106Sdes{ 152238106Sdes#ifdef UNBOUND_ALLOC_STATS 153238106Sdes /* debug func in validator module */ 154238106Sdes size_t total, front, back, mesh, msg, rrset, infra, ac, superac; 155238106Sdes size_t me, iter, val, anch; 156238106Sdes int i; 157238106Sdes if(verbosity < VERB_ALGO) 158238106Sdes return; 159238106Sdes front = listen_get_mem(worker->front); 160238106Sdes back = outnet_get_mem(worker->back); 161238106Sdes msg = slabhash_get_mem(worker->env.msg_cache); 162238106Sdes rrset = slabhash_get_mem(&worker->env.rrset_cache->table); 163238106Sdes infra = infra_get_mem(worker->env.infra_cache); 164238106Sdes mesh = mesh_get_mem(worker->env.mesh); 165238106Sdes ac = alloc_get_mem(&worker->alloc); 166238106Sdes superac = alloc_get_mem(&worker->daemon->superalloc); 167238106Sdes anch = anchors_get_mem(worker->env.anchors); 168238106Sdes iter = 0; 169238106Sdes val = 0; 170238106Sdes for(i=0; i<worker->env.mesh->mods.num; i++) { 171238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 172238106Sdes mods.mod[i]->get_mem)); 173238106Sdes if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 174238106Sdes val += (*worker->env.mesh->mods.mod[i]->get_mem) 175238106Sdes (&worker->env, i); 176238106Sdes else iter += (*worker->env.mesh->mods.mod[i]->get_mem) 177238106Sdes (&worker->env, i); 178238106Sdes } 179238106Sdes me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig) 180238106Sdes + comm_point_get_mem(worker->cmd_com) 181238106Sdes + sizeof(worker->rndstate) 182238106Sdes + regional_get_mem(worker->scratchpad) 183238106Sdes + sizeof(*worker->env.scratch_buffer) 184266114Sdes + sldns_buffer_capacity(worker->env.scratch_buffer) 185238106Sdes + forwards_get_mem(worker->env.fwds) 186238106Sdes + hints_get_mem(worker->env.hints); 187238106Sdes if(worker->thread_num == 0) 188238106Sdes me += acl_list_get_mem(worker->daemon->acl); 189238106Sdes if(cur_serv) { 190238106Sdes me += serviced_get_mem(cur_serv); 191238106Sdes } 192238106Sdes total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me; 193238106Sdes log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " 194238106Sdes "rrset=%u infra=%u iter=%u val=%u anchors=%u " 195238106Sdes "alloccache=%u globalalloccache=%u me=%u", 196238106Sdes (unsigned)total, (unsigned)front, (unsigned)back, 197238106Sdes (unsigned)mesh, (unsigned)msg, (unsigned)rrset, 198238106Sdes (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, 199238106Sdes (unsigned)ac, (unsigned)superac, (unsigned)me); 200238106Sdes debug_total_mem(total); 201238106Sdes#else /* no UNBOUND_ALLOC_STATS */ 202238106Sdes size_t val = 0; 203238106Sdes int i; 204238106Sdes if(verbosity < VERB_QUERY) 205238106Sdes return; 206238106Sdes for(i=0; i<worker->env.mesh->mods.num; i++) { 207238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 208238106Sdes mods.mod[i]->get_mem)); 209238106Sdes if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 210238106Sdes val += (*worker->env.mesh->mods.mod[i]->get_mem) 211238106Sdes (&worker->env, i); 212238106Sdes } 213238106Sdes verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u", 214238106Sdes (unsigned)slabhash_get_mem(worker->env.msg_cache), 215238106Sdes (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), 216238106Sdes (unsigned)infra_get_mem(worker->env.infra_cache), 217238106Sdes (unsigned)val); 218238106Sdes#endif /* UNBOUND_ALLOC_STATS */ 219238106Sdes} 220238106Sdes 221238106Sdesvoid 222238106Sdesworker_send_cmd(struct worker* worker, enum worker_commands cmd) 223238106Sdes{ 224238106Sdes uint32_t c = (uint32_t)htonl(cmd); 225238106Sdes if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) { 226238106Sdes log_err("worker send cmd %d failed", (int)cmd); 227238106Sdes } 228238106Sdes} 229238106Sdes 230238106Sdesint 231238106Sdesworker_handle_reply(struct comm_point* c, void* arg, int error, 232238106Sdes struct comm_reply* reply_info) 233238106Sdes{ 234238106Sdes struct module_qstate* q = (struct module_qstate*)arg; 235238106Sdes struct worker* worker = q->env->worker; 236238106Sdes struct outbound_entry e; 237238106Sdes e.qstate = q; 238238106Sdes e.qsent = NULL; 239238106Sdes 240238106Sdes if(error != 0) { 241238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, error); 242238106Sdes worker_mem_report(worker, NULL); 243238106Sdes return 0; 244238106Sdes } 245238106Sdes /* sanity check. */ 246266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 247266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 248238106Sdes LDNS_PACKET_QUERY 249266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 250238106Sdes /* error becomes timeout for the module as if this reply 251238106Sdes * never arrived. */ 252238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, 253238106Sdes NETEVENT_TIMEOUT); 254238106Sdes worker_mem_report(worker, NULL); 255238106Sdes return 0; 256238106Sdes } 257238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR); 258238106Sdes worker_mem_report(worker, NULL); 259238106Sdes return 0; 260238106Sdes} 261238106Sdes 262238106Sdesint 263238106Sdesworker_handle_service_reply(struct comm_point* c, void* arg, int error, 264238106Sdes struct comm_reply* reply_info) 265238106Sdes{ 266238106Sdes struct outbound_entry* e = (struct outbound_entry*)arg; 267238106Sdes struct worker* worker = e->qstate->env->worker; 268238106Sdes struct serviced_query *sq = e->qsent; 269238106Sdes 270238106Sdes verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); 271238106Sdes if(error != 0) { 272238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, error); 273238106Sdes worker_mem_report(worker, sq); 274238106Sdes return 0; 275238106Sdes } 276238106Sdes /* sanity check. */ 277266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 278266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 279238106Sdes LDNS_PACKET_QUERY 280266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 281238106Sdes /* error becomes timeout for the module as if this reply 282238106Sdes * never arrived. */ 283238106Sdes verbose(VERB_ALGO, "worker: bad reply handled as timeout"); 284238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, 285238106Sdes NETEVENT_TIMEOUT); 286238106Sdes worker_mem_report(worker, sq); 287238106Sdes return 0; 288238106Sdes } 289238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR); 290238106Sdes worker_mem_report(worker, sq); 291238106Sdes return 0; 292238106Sdes} 293238106Sdes 294238106Sdes/** check request sanity. 295238106Sdes * @param pkt: the wire packet to examine for sanity. 296238106Sdes * @param worker: parameters for checking. 297238106Sdes * @return error code, 0 OK, or -1 discard. 298238106Sdes*/ 299238106Sdesstatic int 300266114Sdesworker_check_request(sldns_buffer* pkt, struct worker* worker) 301238106Sdes{ 302266114Sdes if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) { 303238106Sdes verbose(VERB_QUERY, "request too short, discarded"); 304238106Sdes return -1; 305238106Sdes } 306266114Sdes if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 307238106Sdes worker->daemon->cfg->harden_large_queries) { 308238106Sdes verbose(VERB_QUERY, "request too large, discarded"); 309238106Sdes return -1; 310238106Sdes } 311266114Sdes if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) { 312238106Sdes verbose(VERB_QUERY, "request has QR bit on, discarded"); 313238106Sdes return -1; 314238106Sdes } 315266114Sdes if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { 316266114Sdes LDNS_TC_CLR(sldns_buffer_begin(pkt)); 317238106Sdes verbose(VERB_QUERY, "request bad, has TC bit on"); 318238106Sdes return LDNS_RCODE_FORMERR; 319238106Sdes } 320266114Sdes if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) { 321238106Sdes verbose(VERB_QUERY, "request unknown opcode %d", 322266114Sdes LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt))); 323238106Sdes return LDNS_RCODE_NOTIMPL; 324238106Sdes } 325266114Sdes if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) { 326238106Sdes verbose(VERB_QUERY, "request wrong nr qd=%d", 327266114Sdes LDNS_QDCOUNT(sldns_buffer_begin(pkt))); 328238106Sdes return LDNS_RCODE_FORMERR; 329238106Sdes } 330266114Sdes if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) { 331238106Sdes verbose(VERB_QUERY, "request wrong nr an=%d", 332266114Sdes LDNS_ANCOUNT(sldns_buffer_begin(pkt))); 333238106Sdes return LDNS_RCODE_FORMERR; 334238106Sdes } 335266114Sdes if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) { 336238106Sdes verbose(VERB_QUERY, "request wrong nr ns=%d", 337266114Sdes LDNS_NSCOUNT(sldns_buffer_begin(pkt))); 338238106Sdes return LDNS_RCODE_FORMERR; 339238106Sdes } 340266114Sdes if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { 341238106Sdes verbose(VERB_QUERY, "request wrong nr ar=%d", 342266114Sdes LDNS_ARCOUNT(sldns_buffer_begin(pkt))); 343238106Sdes return LDNS_RCODE_FORMERR; 344238106Sdes } 345238106Sdes return 0; 346238106Sdes} 347238106Sdes 348238106Sdesvoid 349238106Sdesworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, 350238106Sdes size_t len, int error, void* arg) 351238106Sdes{ 352238106Sdes struct worker* worker = (struct worker*)arg; 353238106Sdes enum worker_commands cmd; 354238106Sdes if(error != NETEVENT_NOERROR) { 355238106Sdes free(msg); 356238106Sdes if(error == NETEVENT_CLOSED) 357238106Sdes comm_base_exit(worker->base); 358238106Sdes else log_info("control event: %d", error); 359238106Sdes return; 360238106Sdes } 361238106Sdes if(len != sizeof(uint32_t)) { 362238106Sdes fatal_exit("bad control msg length %d", (int)len); 363238106Sdes } 364266114Sdes cmd = sldns_read_uint32(msg); 365238106Sdes free(msg); 366238106Sdes switch(cmd) { 367238106Sdes case worker_cmd_quit: 368238106Sdes verbose(VERB_ALGO, "got control cmd quit"); 369238106Sdes comm_base_exit(worker->base); 370238106Sdes break; 371238106Sdes case worker_cmd_stats: 372238106Sdes verbose(VERB_ALGO, "got control cmd stats"); 373238106Sdes server_stats_reply(worker, 1); 374238106Sdes break; 375238106Sdes case worker_cmd_stats_noreset: 376238106Sdes verbose(VERB_ALGO, "got control cmd stats_noreset"); 377238106Sdes server_stats_reply(worker, 0); 378238106Sdes break; 379238106Sdes case worker_cmd_remote: 380238106Sdes verbose(VERB_ALGO, "got control cmd remote"); 381238106Sdes daemon_remote_exec(worker); 382238106Sdes break; 383238106Sdes default: 384238106Sdes log_err("bad command %d", (int)cmd); 385238106Sdes break; 386238106Sdes } 387238106Sdes} 388238106Sdes 389238106Sdes/** check if a delegation is secure */ 390238106Sdesstatic enum sec_status 391238106Sdescheck_delegation_secure(struct reply_info *rep) 392238106Sdes{ 393238106Sdes /* return smallest security status */ 394238106Sdes size_t i; 395238106Sdes enum sec_status sec = sec_status_secure; 396238106Sdes enum sec_status s; 397238106Sdes size_t num = rep->an_numrrsets + rep->ns_numrrsets; 398238106Sdes /* check if answer and authority are OK */ 399238106Sdes for(i=0; i<num; i++) { 400238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 401238106Sdes ->security; 402238106Sdes if(s < sec) 403238106Sdes sec = s; 404238106Sdes } 405238106Sdes /* in additional, only unchecked triggers revalidation */ 406238106Sdes for(i=num; i<rep->rrset_count; i++) { 407238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 408238106Sdes ->security; 409238106Sdes if(s == sec_status_unchecked) 410238106Sdes return s; 411238106Sdes } 412238106Sdes return sec; 413238106Sdes} 414238106Sdes 415238106Sdes/** remove nonsecure from a delegation referral additional section */ 416238106Sdesstatic void 417238106Sdesdeleg_remove_nonsecure_additional(struct reply_info* rep) 418238106Sdes{ 419238106Sdes /* we can simply edit it, since we are working in the scratch region */ 420238106Sdes size_t i; 421238106Sdes enum sec_status s; 422238106Sdes 423238106Sdes for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { 424238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 425238106Sdes ->security; 426238106Sdes if(s != sec_status_secure) { 427238106Sdes memmove(rep->rrsets+i, rep->rrsets+i+1, 428238106Sdes sizeof(struct ub_packed_rrset_key*)* 429238106Sdes (rep->rrset_count - i - 1)); 430238106Sdes rep->ar_numrrsets--; 431238106Sdes rep->rrset_count--; 432238106Sdes i--; 433238106Sdes } 434238106Sdes } 435238106Sdes} 436238106Sdes 437238106Sdes/** answer nonrecursive query from the cache */ 438238106Sdesstatic int 439238106Sdesanswer_norec_from_cache(struct worker* worker, struct query_info* qinfo, 440238106Sdes uint16_t id, uint16_t flags, struct comm_reply* repinfo, 441238106Sdes struct edns_data* edns) 442238106Sdes{ 443238106Sdes /* for a nonrecursive query return either: 444238106Sdes * o an error (servfail; we try to avoid this) 445238106Sdes * o a delegation (closest we have; this routine tries that) 446238106Sdes * o the answer (checked by answer_from_cache) 447238106Sdes * 448238106Sdes * So, grab a delegation from the rrset cache. 449238106Sdes * Then check if it needs validation, if so, this routine fails, 450238106Sdes * so that iterator can prime and validator can verify rrsets. 451238106Sdes */ 452238106Sdes uint16_t udpsize = edns->udp_size; 453238106Sdes int secure = 0; 454266114Sdes time_t timenow = *worker->env.now; 455238106Sdes int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) 456238106Sdes && worker->env.need_to_validate; 457238106Sdes struct dns_msg *msg = NULL; 458238106Sdes struct delegpt *dp; 459238106Sdes 460238106Sdes dp = dns_cache_find_delegation(&worker->env, qinfo->qname, 461238106Sdes qinfo->qname_len, qinfo->qtype, qinfo->qclass, 462238106Sdes worker->scratchpad, &msg, timenow); 463238106Sdes if(!dp) { /* no delegation, need to reprime */ 464238106Sdes regional_free_all(worker->scratchpad); 465238106Sdes return 0; 466238106Sdes } 467238106Sdes if(must_validate) { 468238106Sdes switch(check_delegation_secure(msg->rep)) { 469238106Sdes case sec_status_unchecked: 470238106Sdes /* some rrsets have not been verified yet, go and 471238106Sdes * let validator do that */ 472238106Sdes regional_free_all(worker->scratchpad); 473238106Sdes return 0; 474238106Sdes case sec_status_bogus: 475238106Sdes /* some rrsets are bogus, reply servfail */ 476238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 477238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 478238106Sdes edns->ext_rcode = 0; 479238106Sdes edns->bits &= EDNS_DO; 480238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 481238106Sdes &msg->qinfo, id, flags, edns); 482238106Sdes regional_free_all(worker->scratchpad); 483238106Sdes if(worker->stats.extended) { 484238106Sdes worker->stats.ans_bogus++; 485238106Sdes worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; 486238106Sdes } 487238106Sdes return 1; 488238106Sdes case sec_status_secure: 489238106Sdes /* all rrsets are secure */ 490238106Sdes /* remove non-secure rrsets from the add. section*/ 491238106Sdes if(worker->env.cfg->val_clean_additional) 492238106Sdes deleg_remove_nonsecure_additional(msg->rep); 493238106Sdes secure = 1; 494238106Sdes break; 495238106Sdes case sec_status_indeterminate: 496238106Sdes case sec_status_insecure: 497238106Sdes default: 498238106Sdes /* not secure */ 499238106Sdes secure = 0; 500238106Sdes break; 501238106Sdes } 502238106Sdes } 503238106Sdes /* return this delegation from the cache */ 504238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 505238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 506238106Sdes edns->ext_rcode = 0; 507238106Sdes edns->bits &= EDNS_DO; 508238106Sdes msg->rep->flags |= BIT_QR|BIT_RA; 509238106Sdes if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 510238106Sdes repinfo->c->buffer, 0, 1, worker->scratchpad, 511238106Sdes udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 512238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 513238106Sdes &msg->qinfo, id, flags, edns); 514238106Sdes } 515238106Sdes regional_free_all(worker->scratchpad); 516238106Sdes if(worker->stats.extended) { 517238106Sdes if(secure) worker->stats.ans_secure++; 518238106Sdes server_stats_insrcode(&worker->stats, repinfo->c->buffer); 519238106Sdes } 520238106Sdes return 1; 521238106Sdes} 522238106Sdes 523238106Sdes/** answer query from the cache */ 524238106Sdesstatic int 525238106Sdesanswer_from_cache(struct worker* worker, struct query_info* qinfo, 526238106Sdes struct reply_info* rep, uint16_t id, uint16_t flags, 527238106Sdes struct comm_reply* repinfo, struct edns_data* edns) 528238106Sdes{ 529266114Sdes time_t timenow = *worker->env.now; 530238106Sdes uint16_t udpsize = edns->udp_size; 531238106Sdes int secure; 532238106Sdes int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) 533238106Sdes && worker->env.need_to_validate; 534238106Sdes /* see if it is possible */ 535238106Sdes if(rep->ttl < timenow) { 536238106Sdes /* the rrsets may have been updated in the meantime. 537238106Sdes * we will refetch the message format from the 538238106Sdes * authoritative server 539238106Sdes */ 540238106Sdes return 0; 541238106Sdes } 542238106Sdes if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) 543238106Sdes return 0; 544238106Sdes /* locked and ids and ttls are OK. */ 545238106Sdes /* check CNAME chain (if any) */ 546238106Sdes if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == 547238106Sdes htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == 548238106Sdes htons(LDNS_RR_TYPE_DNAME))) { 549238106Sdes if(!reply_check_cname_chain(rep)) { 550238106Sdes /* cname chain invalid, redo iterator steps */ 551238106Sdes verbose(VERB_ALGO, "Cache reply: cname chain broken"); 552238106Sdes bail_out: 553238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, 554238106Sdes worker->scratchpad, rep->ref, rep->rrset_count); 555238106Sdes regional_free_all(worker->scratchpad); 556238106Sdes return 0; 557238106Sdes } 558238106Sdes } 559238106Sdes /* check security status of the cached answer */ 560238106Sdes if( rep->security == sec_status_bogus && must_validate) { 561238106Sdes /* BAD cached */ 562238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 563238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 564238106Sdes edns->ext_rcode = 0; 565238106Sdes edns->bits &= EDNS_DO; 566238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 567238106Sdes qinfo, id, flags, edns); 568238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, 569238106Sdes worker->scratchpad, rep->ref, rep->rrset_count); 570238106Sdes regional_free_all(worker->scratchpad); 571238106Sdes if(worker->stats.extended) { 572238106Sdes worker->stats.ans_bogus ++; 573238106Sdes worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; 574238106Sdes } 575238106Sdes return 1; 576238106Sdes } else if( rep->security == sec_status_unchecked && must_validate) { 577238106Sdes verbose(VERB_ALGO, "Cache reply: unchecked entry needs " 578238106Sdes "validation"); 579238106Sdes goto bail_out; /* need to validate cache entry first */ 580238106Sdes } else if(rep->security == sec_status_secure) { 581238106Sdes if(reply_all_rrsets_secure(rep)) 582238106Sdes secure = 1; 583238106Sdes else { 584238106Sdes if(must_validate) { 585238106Sdes verbose(VERB_ALGO, "Cache reply: secure entry" 586238106Sdes " changed status"); 587238106Sdes goto bail_out; /* rrset changed, re-verify */ 588238106Sdes } 589238106Sdes secure = 0; 590238106Sdes } 591238106Sdes } else secure = 0; 592238106Sdes 593238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 594238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 595238106Sdes edns->ext_rcode = 0; 596238106Sdes edns->bits &= EDNS_DO; 597238106Sdes if(!reply_info_answer_encode(qinfo, rep, id, flags, 598238106Sdes repinfo->c->buffer, timenow, 1, worker->scratchpad, 599238106Sdes udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 600238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 601238106Sdes qinfo, id, flags, edns); 602238106Sdes } 603238106Sdes /* cannot send the reply right now, because blocking network syscall 604238106Sdes * is bad while holding locks. */ 605238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, 606238106Sdes rep->ref, rep->rrset_count); 607238106Sdes regional_free_all(worker->scratchpad); 608238106Sdes if(worker->stats.extended) { 609238106Sdes if(secure) worker->stats.ans_secure++; 610238106Sdes server_stats_insrcode(&worker->stats, repinfo->c->buffer); 611238106Sdes } 612238106Sdes /* go and return this buffer to the client */ 613238106Sdes return 1; 614238106Sdes} 615238106Sdes 616238106Sdes/** Reply to client and perform prefetch to keep cache up to date */ 617238106Sdesstatic void 618238106Sdesreply_and_prefetch(struct worker* worker, struct query_info* qinfo, 619266114Sdes uint16_t flags, struct comm_reply* repinfo, time_t leeway) 620238106Sdes{ 621238106Sdes /* first send answer to client to keep its latency 622238106Sdes * as small as a cachereply */ 623238106Sdes comm_point_send_reply(repinfo); 624238106Sdes server_stats_prefetch(&worker->stats, worker); 625238106Sdes 626238106Sdes /* create the prefetch in the mesh as a normal lookup without 627238106Sdes * client addrs waiting, which has the cache blacklisted (to bypass 628238106Sdes * the cache and go to the network for the data). */ 629238106Sdes /* this (potentially) runs the mesh for the new query */ 630238106Sdes mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 631238106Sdes PREFETCH_EXPIRY_ADD); 632238106Sdes} 633238106Sdes 634238106Sdes/** 635238106Sdes * Fill CH class answer into buffer. Keeps query. 636238106Sdes * @param pkt: buffer 637238106Sdes * @param str: string to put into text record (<255). 638238106Sdes * @param edns: edns reply information. 639238106Sdes */ 640238106Sdesstatic void 641266114Sdeschaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns) 642238106Sdes{ 643238106Sdes size_t len = strlen(str); 644266114Sdes unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); 645266114Sdes unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); 646238106Sdes if(len>255) len=255; /* cap size of TXT record */ 647266114Sdes sldns_buffer_clear(pkt); 648266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ 649266114Sdes sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); 650266114Sdes if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); 651266114Sdes if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); 652266114Sdes sldns_buffer_write_u16(pkt, 1); /* qdcount */ 653266114Sdes sldns_buffer_write_u16(pkt, 1); /* ancount */ 654266114Sdes sldns_buffer_write_u16(pkt, 0); /* nscount */ 655266114Sdes sldns_buffer_write_u16(pkt, 0); /* arcount */ 656238106Sdes (void)query_dname_len(pkt); /* skip qname */ 657266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 658266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 659266114Sdes sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ 660266114Sdes sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); 661266114Sdes sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); 662266114Sdes sldns_buffer_write_u32(pkt, 0); /* TTL */ 663266114Sdes sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); 664266114Sdes sldns_buffer_write_u8(pkt, len); 665266114Sdes sldns_buffer_write(pkt, str, len); 666266114Sdes sldns_buffer_flip(pkt); 667238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 668238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 669238106Sdes edns->bits &= EDNS_DO; 670238106Sdes attach_edns_record(pkt, edns); 671238106Sdes} 672238106Sdes 673238106Sdes/** 674238106Sdes * Answer CH class queries. 675238106Sdes * @param w: worker 676238106Sdes * @param qinfo: query info. Pointer into packet buffer. 677238106Sdes * @param edns: edns info from query. 678238106Sdes * @param pkt: packet buffer. 679238106Sdes * @return: true if a reply is to be sent. 680238106Sdes */ 681238106Sdesstatic int 682238106Sdesanswer_chaos(struct worker* w, struct query_info* qinfo, 683266114Sdes struct edns_data* edns, sldns_buffer* pkt) 684238106Sdes{ 685238106Sdes struct config_file* cfg = w->env.cfg; 686238106Sdes if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) 687238106Sdes return 0; 688238106Sdes if(query_dname_compare(qinfo->qname, 689238106Sdes (uint8_t*)"\002id\006server") == 0 || 690238106Sdes query_dname_compare(qinfo->qname, 691238106Sdes (uint8_t*)"\010hostname\004bind") == 0) 692238106Sdes { 693238106Sdes if(cfg->hide_identity) 694238106Sdes return 0; 695238106Sdes if(cfg->identity==NULL || cfg->identity[0]==0) { 696238106Sdes char buf[MAXHOSTNAMELEN+1]; 697238106Sdes if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 698238106Sdes buf[MAXHOSTNAMELEN] = 0; 699238106Sdes chaos_replystr(pkt, buf, edns); 700238106Sdes } else { 701238106Sdes log_err("gethostname: %s", strerror(errno)); 702238106Sdes chaos_replystr(pkt, "no hostname", edns); 703238106Sdes } 704238106Sdes } 705238106Sdes else chaos_replystr(pkt, cfg->identity, edns); 706238106Sdes return 1; 707238106Sdes } 708238106Sdes if(query_dname_compare(qinfo->qname, 709238106Sdes (uint8_t*)"\007version\006server") == 0 || 710238106Sdes query_dname_compare(qinfo->qname, 711238106Sdes (uint8_t*)"\007version\004bind") == 0) 712238106Sdes { 713238106Sdes if(cfg->hide_version) 714238106Sdes return 0; 715238106Sdes if(cfg->version==NULL || cfg->version[0]==0) 716238106Sdes chaos_replystr(pkt, PACKAGE_STRING, edns); 717238106Sdes else chaos_replystr(pkt, cfg->version, edns); 718238106Sdes return 1; 719238106Sdes } 720238106Sdes return 0; 721238106Sdes} 722238106Sdes 723266114Sdesstatic int 724266114Sdesdeny_refuse(struct comm_point* c, enum acl_access acl, 725266114Sdes enum acl_access deny, enum acl_access refuse, 726266114Sdes struct worker* worker, struct comm_reply* repinfo) 727266114Sdes{ 728266114Sdes if(acl == deny) { 729266114Sdes comm_point_drop_reply(repinfo); 730266114Sdes if(worker->stats.extended) 731266114Sdes worker->stats.unwanted_queries++; 732266114Sdes return 0; 733266114Sdes } else if(acl == refuse) { 734266114Sdes log_addr(VERB_ALGO, "refused query from", 735266114Sdes &repinfo->addr, repinfo->addrlen); 736266114Sdes log_buf(VERB_ALGO, "refuse", c->buffer); 737266114Sdes if(worker->stats.extended) 738266114Sdes worker->stats.unwanted_queries++; 739266114Sdes if(worker_check_request(c->buffer, worker) == -1) { 740266114Sdes comm_point_drop_reply(repinfo); 741266114Sdes return 0; /* discard this */ 742266114Sdes } 743266114Sdes sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); 744266114Sdes sldns_buffer_write_at(c->buffer, 4, 745266114Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 746266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 747266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 748266114Sdes LDNS_RCODE_REFUSED); 749266114Sdes return 1; 750266114Sdes } 751266114Sdes 752266114Sdes return -1; 753266114Sdes} 754266114Sdes 755266114Sdesstatic int 756266114Sdesdeny_refuse_all(struct comm_point* c, enum acl_access acl, 757266114Sdes struct worker* worker, struct comm_reply* repinfo) 758266114Sdes{ 759266114Sdes return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo); 760266114Sdes} 761266114Sdes 762266114Sdesstatic int 763266114Sdesdeny_refuse_non_local(struct comm_point* c, enum acl_access acl, 764266114Sdes struct worker* worker, struct comm_reply* repinfo) 765266114Sdes{ 766266114Sdes return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, worker, repinfo); 767266114Sdes} 768266114Sdes 769238106Sdesint 770238106Sdesworker_handle_request(struct comm_point* c, void* arg, int error, 771238106Sdes struct comm_reply* repinfo) 772238106Sdes{ 773238106Sdes struct worker* worker = (struct worker*)arg; 774238106Sdes int ret; 775238106Sdes hashvalue_t h; 776238106Sdes struct lruhash_entry* e; 777238106Sdes struct query_info qinfo; 778238106Sdes struct edns_data edns; 779238106Sdes enum acl_access acl; 780238106Sdes 781238106Sdes if(error != NETEVENT_NOERROR) { 782238106Sdes /* some bad tcp query DNS formats give these error calls */ 783238106Sdes verbose(VERB_ALGO, "handle request called with err=%d", error); 784238106Sdes return 0; 785238106Sdes } 786238106Sdes acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, 787238106Sdes repinfo->addrlen); 788266114Sdes if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1) 789266114Sdes { 790266114Sdes return ret; 791238106Sdes } 792238106Sdes if((ret=worker_check_request(c->buffer, worker)) != 0) { 793238106Sdes verbose(VERB_ALGO, "worker check request: bad query."); 794238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 795238106Sdes if(ret != -1) { 796266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 797266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); 798238106Sdes return 1; 799238106Sdes } 800238106Sdes comm_point_drop_reply(repinfo); 801238106Sdes return 0; 802238106Sdes } 803238106Sdes worker->stats.num_queries++; 804238106Sdes /* see if query is in the cache */ 805238106Sdes if(!query_info_parse(&qinfo, c->buffer)) { 806238106Sdes verbose(VERB_ALGO, "worker parse request: formerror."); 807238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 808266114Sdes sldns_buffer_rewind(c->buffer); 809266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 810266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 811238106Sdes LDNS_RCODE_FORMERR); 812238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 813238106Sdes return 1; 814238106Sdes } 815238106Sdes if(worker->env.cfg->log_queries) { 816238106Sdes char ip[128]; 817238106Sdes addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); 818238106Sdes log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); 819238106Sdes } 820238106Sdes if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 821238106Sdes qinfo.qtype == LDNS_RR_TYPE_IXFR) { 822238106Sdes verbose(VERB_ALGO, "worker request: refused zone transfer."); 823238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 824266114Sdes sldns_buffer_rewind(c->buffer); 825266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 826266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 827238106Sdes LDNS_RCODE_REFUSED); 828238106Sdes if(worker->stats.extended) { 829238106Sdes worker->stats.qtype[qinfo.qtype]++; 830238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 831238106Sdes } 832238106Sdes return 1; 833238106Sdes } 834238106Sdes if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) { 835238106Sdes verbose(VERB_ALGO, "worker parse edns: formerror."); 836238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 837266114Sdes sldns_buffer_rewind(c->buffer); 838266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 839266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); 840238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 841238106Sdes return 1; 842238106Sdes } 843238106Sdes if(edns.edns_present && edns.edns_version != 0) { 844238106Sdes edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); 845238106Sdes edns.edns_version = EDNS_ADVERTISED_VERSION; 846238106Sdes edns.udp_size = EDNS_ADVERTISED_SIZE; 847238106Sdes edns.bits &= EDNS_DO; 848238106Sdes verbose(VERB_ALGO, "query with bad edns version."); 849238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 850238106Sdes error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, 851266114Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 852266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), NULL); 853238106Sdes attach_edns_record(c->buffer, &edns); 854238106Sdes return 1; 855238106Sdes } 856238106Sdes if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE && 857238106Sdes worker->daemon->cfg->harden_short_bufsize) { 858238106Sdes verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", 859238106Sdes (int)edns.udp_size); 860238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 861238106Sdes edns.udp_size = NORMAL_UDP_SIZE; 862238106Sdes } 863266114Sdes if(edns.udp_size > worker->daemon->cfg->max_udp_size && 864266114Sdes c->type == comm_udp) { 865266114Sdes verbose(VERB_QUERY, 866266114Sdes "worker request: max UDP reply size modified" 867266114Sdes " (%d to max-udp-size)", (int)edns.udp_size); 868266114Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 869266114Sdes edns.udp_size = worker->daemon->cfg->max_udp_size; 870266114Sdes } 871266114Sdes if(edns.udp_size < LDNS_HEADER_SIZE) { 872238106Sdes verbose(VERB_ALGO, "worker request: edns is too small."); 873238106Sdes log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen); 874266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 875266114Sdes LDNS_TC_SET(sldns_buffer_begin(c->buffer)); 876266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 877238106Sdes LDNS_RCODE_SERVFAIL); 878266114Sdes sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 879266114Sdes sldns_buffer_write_at(c->buffer, 4, 880238106Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 881266114Sdes sldns_buffer_flip(c->buffer); 882238106Sdes return 1; 883238106Sdes } 884238106Sdes if(worker->stats.extended) 885238106Sdes server_stats_insquery(&worker->stats, c, qinfo.qtype, 886238106Sdes qinfo.qclass, &edns, repinfo); 887238106Sdes if(c->type != comm_udp) 888238106Sdes edns.udp_size = 65535; /* max size for TCP replies */ 889238106Sdes if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, 890238106Sdes &edns, c->buffer)) { 891238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 892238106Sdes return 1; 893238106Sdes } 894238106Sdes if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns, 895238106Sdes c->buffer, worker->scratchpad)) { 896238106Sdes regional_free_all(worker->scratchpad); 897266114Sdes if(sldns_buffer_limit(c->buffer) == 0) { 898238106Sdes comm_point_drop_reply(repinfo); 899238106Sdes return 0; 900238106Sdes } 901238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 902238106Sdes return 1; 903238106Sdes } 904266114Sdes 905266114Sdes /* We've looked in our local zones. If the answer isn't there, we 906266114Sdes * might need to bail out based on ACLs now. */ 907266114Sdes if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1) 908266114Sdes { 909266114Sdes return ret; 910266114Sdes } 911266114Sdes 912266114Sdes /* If this request does not have the recursion bit set, verify 913266114Sdes * ACLs allow the snooping. */ 914266114Sdes if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 915238106Sdes acl != acl_allow_snoop ) { 916266114Sdes sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); 917266114Sdes sldns_buffer_write_at(c->buffer, 4, 918238106Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 919266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 920266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 921238106Sdes LDNS_RCODE_REFUSED); 922266114Sdes sldns_buffer_flip(c->buffer); 923238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 924238106Sdes log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", 925238106Sdes &repinfo->addr, repinfo->addrlen); 926238106Sdes return 1; 927238106Sdes } 928238106Sdes h = query_info_hash(&qinfo); 929238106Sdes if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { 930238106Sdes /* answer from cache - we have acquired a readlock on it */ 931238106Sdes if(answer_from_cache(worker, &qinfo, 932238106Sdes (struct reply_info*)e->data, 933266114Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 934266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 935238106Sdes &edns)) { 936238106Sdes /* prefetch it if the prefetch TTL expired */ 937238106Sdes if(worker->env.cfg->prefetch && *worker->env.now >= 938238106Sdes ((struct reply_info*)e->data)->prefetch_ttl) { 939266114Sdes time_t leeway = ((struct reply_info*)e-> 940238106Sdes data)->ttl - *worker->env.now; 941238106Sdes lock_rw_unlock(&e->lock); 942238106Sdes reply_and_prefetch(worker, &qinfo, 943266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), 944238106Sdes repinfo, leeway); 945238106Sdes return 0; 946238106Sdes } 947238106Sdes lock_rw_unlock(&e->lock); 948238106Sdes return 1; 949238106Sdes } 950238106Sdes verbose(VERB_ALGO, "answer from the cache failed"); 951238106Sdes lock_rw_unlock(&e->lock); 952238106Sdes } 953266114Sdes if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { 954238106Sdes if(answer_norec_from_cache(worker, &qinfo, 955266114Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 956266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 957238106Sdes &edns)) { 958238106Sdes return 1; 959238106Sdes } 960238106Sdes verbose(VERB_ALGO, "answer norec from cache -- " 961238106Sdes "need to validate or not primed"); 962238106Sdes } 963266114Sdes sldns_buffer_rewind(c->buffer); 964238106Sdes server_stats_querymiss(&worker->stats, worker); 965238106Sdes 966238106Sdes if(verbosity >= VERB_CLIENT) { 967238106Sdes if(c->type == comm_udp) 968238106Sdes log_addr(VERB_CLIENT, "udp request from", 969238106Sdes &repinfo->addr, repinfo->addrlen); 970238106Sdes else log_addr(VERB_CLIENT, "tcp request from", 971238106Sdes &repinfo->addr, repinfo->addrlen); 972238106Sdes } 973238106Sdes 974238106Sdes /* grab a work request structure for this new request */ 975238106Sdes mesh_new_client(worker->env.mesh, &qinfo, 976266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), 977266114Sdes &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer)); 978238106Sdes worker_mem_report(worker, NULL); 979238106Sdes return 0; 980238106Sdes} 981238106Sdes 982238106Sdesvoid 983238106Sdesworker_sighandler(int sig, void* arg) 984238106Sdes{ 985238106Sdes /* note that log, print, syscalls here give race conditions. */ 986238106Sdes /* we still print DETAIL logs, because this is extensive per message 987238106Sdes * logging anyway, and the operator may then have an interest 988238106Sdes * in the cause for unbound to exit */ 989238106Sdes struct worker* worker = (struct worker*)arg; 990238106Sdes switch(sig) { 991238106Sdes#ifdef SIGHUP 992238106Sdes case SIGHUP: 993238106Sdes verbose(VERB_QUERY, "caught signal SIGHUP"); 994238106Sdes comm_base_exit(worker->base); 995238106Sdes break; 996238106Sdes#endif 997238106Sdes case SIGINT: 998238106Sdes verbose(VERB_QUERY, "caught signal SIGINT"); 999238106Sdes worker->need_to_exit = 1; 1000238106Sdes comm_base_exit(worker->base); 1001238106Sdes break; 1002238106Sdes#ifdef SIGQUIT 1003238106Sdes case SIGQUIT: 1004238106Sdes verbose(VERB_QUERY, "caught signal SIGQUIT"); 1005238106Sdes worker->need_to_exit = 1; 1006238106Sdes comm_base_exit(worker->base); 1007238106Sdes break; 1008238106Sdes#endif 1009238106Sdes case SIGTERM: 1010238106Sdes verbose(VERB_QUERY, "caught signal SIGTERM"); 1011238106Sdes worker->need_to_exit = 1; 1012238106Sdes comm_base_exit(worker->base); 1013238106Sdes break; 1014238106Sdes default: 1015238106Sdes log_err("unknown signal: %d, ignored", sig); 1016238106Sdes break; 1017238106Sdes } 1018238106Sdes} 1019238106Sdes 1020238106Sdes/** restart statistics timer for worker, if enabled */ 1021238106Sdesstatic void 1022238106Sdesworker_restart_timer(struct worker* worker) 1023238106Sdes{ 1024238106Sdes if(worker->env.cfg->stat_interval > 0) { 1025238106Sdes struct timeval tv; 1026238106Sdes#ifndef S_SPLINT_S 1027238106Sdes tv.tv_sec = worker->env.cfg->stat_interval; 1028238106Sdes tv.tv_usec = 0; 1029238106Sdes#endif 1030238106Sdes comm_timer_set(worker->stat_timer, &tv); 1031238106Sdes } 1032238106Sdes} 1033238106Sdes 1034238106Sdesvoid worker_stat_timer_cb(void* arg) 1035238106Sdes{ 1036238106Sdes struct worker* worker = (struct worker*)arg; 1037238106Sdes server_stats_log(&worker->stats, worker, worker->thread_num); 1038238106Sdes mesh_stats(worker->env.mesh, "mesh has"); 1039238106Sdes worker_mem_report(worker, NULL); 1040238106Sdes if(!worker->daemon->cfg->stat_cumulative) { 1041238106Sdes worker_stats_clear(worker); 1042238106Sdes } 1043238106Sdes /* start next timer */ 1044238106Sdes worker_restart_timer(worker); 1045238106Sdes} 1046238106Sdes 1047238106Sdesvoid worker_probe_timer_cb(void* arg) 1048238106Sdes{ 1049238106Sdes struct worker* worker = (struct worker*)arg; 1050238106Sdes struct timeval tv; 1051238106Sdes#ifndef S_SPLINT_S 1052238106Sdes tv.tv_sec = (time_t)autr_probe_timer(&worker->env); 1053238106Sdes tv.tv_usec = 0; 1054238106Sdes#endif 1055238106Sdes if(tv.tv_sec != 0) 1056238106Sdes comm_timer_set(worker->env.probe_timer, &tv); 1057238106Sdes} 1058238106Sdes 1059238106Sdesstruct worker* 1060238106Sdesworker_create(struct daemon* daemon, int id, int* ports, int n) 1061238106Sdes{ 1062238106Sdes unsigned int seed; 1063238106Sdes struct worker* worker = (struct worker*)calloc(1, 1064238106Sdes sizeof(struct worker)); 1065238106Sdes if(!worker) 1066238106Sdes return NULL; 1067238106Sdes worker->numports = n; 1068238106Sdes worker->ports = (int*)memdup(ports, sizeof(int)*n); 1069238106Sdes if(!worker->ports) { 1070238106Sdes free(worker); 1071238106Sdes return NULL; 1072238106Sdes } 1073238106Sdes worker->daemon = daemon; 1074238106Sdes worker->thread_num = id; 1075238106Sdes if(!(worker->cmd = tube_create())) { 1076238106Sdes free(worker->ports); 1077238106Sdes free(worker); 1078238106Sdes return NULL; 1079238106Sdes } 1080238106Sdes /* create random state here to avoid locking trouble in RAND_bytes */ 1081238106Sdes seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ 1082238106Sdes (((unsigned int)worker->thread_num)<<17); 1083238106Sdes /* shift thread_num so it does not match out pid bits */ 1084238106Sdes if(!(worker->rndstate = ub_initstate(seed, daemon->rand))) { 1085238106Sdes seed = 0; 1086238106Sdes log_err("could not init random numbers."); 1087238106Sdes tube_delete(worker->cmd); 1088238106Sdes free(worker->ports); 1089238106Sdes free(worker); 1090238106Sdes return NULL; 1091238106Sdes } 1092238106Sdes seed = 0; 1093238106Sdes return worker; 1094238106Sdes} 1095238106Sdes 1096238106Sdesint 1097238106Sdesworker_init(struct worker* worker, struct config_file *cfg, 1098238106Sdes struct listen_port* ports, int do_sigs) 1099238106Sdes{ 1100238106Sdes worker->need_to_exit = 0; 1101238106Sdes worker->base = comm_base_create(do_sigs); 1102238106Sdes if(!worker->base) { 1103238106Sdes log_err("could not create event handling base"); 1104238106Sdes worker_delete(worker); 1105238106Sdes return 0; 1106238106Sdes } 1107238106Sdes comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept, 1108238106Sdes &worker_start_accept, worker); 1109238106Sdes if(do_sigs) { 1110238106Sdes#ifdef SIGHUP 1111238106Sdes ub_thread_sig_unblock(SIGHUP); 1112238106Sdes#endif 1113238106Sdes ub_thread_sig_unblock(SIGINT); 1114238106Sdes#ifdef SIGQUIT 1115238106Sdes ub_thread_sig_unblock(SIGQUIT); 1116238106Sdes#endif 1117238106Sdes ub_thread_sig_unblock(SIGTERM); 1118238106Sdes#ifndef LIBEVENT_SIGNAL_PROBLEM 1119238106Sdes worker->comsig = comm_signal_create(worker->base, 1120238106Sdes worker_sighandler, worker); 1121238106Sdes if(!worker->comsig 1122238106Sdes#ifdef SIGHUP 1123238106Sdes || !comm_signal_bind(worker->comsig, SIGHUP) 1124238106Sdes#endif 1125238106Sdes#ifdef SIGQUIT 1126238106Sdes || !comm_signal_bind(worker->comsig, SIGQUIT) 1127238106Sdes#endif 1128238106Sdes || !comm_signal_bind(worker->comsig, SIGTERM) 1129238106Sdes || !comm_signal_bind(worker->comsig, SIGINT)) { 1130238106Sdes log_err("could not create signal handlers"); 1131238106Sdes worker_delete(worker); 1132238106Sdes return 0; 1133238106Sdes } 1134238106Sdes#endif /* LIBEVENT_SIGNAL_PROBLEM */ 1135238106Sdes if(!daemon_remote_open_accept(worker->daemon->rc, 1136238106Sdes worker->daemon->rc_ports, worker)) { 1137238106Sdes worker_delete(worker); 1138238106Sdes return 0; 1139238106Sdes } 1140238106Sdes#ifdef UB_ON_WINDOWS 1141238106Sdes wsvc_setup_worker(worker); 1142238106Sdes#endif /* UB_ON_WINDOWS */ 1143238106Sdes } else { /* !do_sigs */ 1144238106Sdes worker->comsig = NULL; 1145238106Sdes } 1146238106Sdes worker->front = listen_create(worker->base, ports, 1147238106Sdes cfg->msg_buffer_size, (int)cfg->incoming_num_tcp, 1148238106Sdes worker->daemon->listen_sslctx, worker_handle_request, worker); 1149238106Sdes if(!worker->front) { 1150238106Sdes log_err("could not create listening sockets"); 1151238106Sdes worker_delete(worker); 1152238106Sdes return 0; 1153238106Sdes } 1154238106Sdes worker->back = outside_network_create(worker->base, 1155238106Sdes cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, 1156238106Sdes cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 1157238106Sdes cfg->do_tcp?cfg->outgoing_num_tcp:0, 1158238106Sdes worker->daemon->env->infra_cache, worker->rndstate, 1159238106Sdes cfg->use_caps_bits_for_id, worker->ports, worker->numports, 1160238106Sdes cfg->unwanted_threshold, &worker_alloc_cleanup, worker, 1161266114Sdes cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close); 1162238106Sdes if(!worker->back) { 1163238106Sdes log_err("could not create outgoing sockets"); 1164238106Sdes worker_delete(worker); 1165238106Sdes return 0; 1166238106Sdes } 1167238106Sdes /* start listening to commands */ 1168238106Sdes if(!tube_setup_bg_listen(worker->cmd, worker->base, 1169238106Sdes &worker_handle_control_cmd, worker)) { 1170238106Sdes log_err("could not create control compt."); 1171238106Sdes worker_delete(worker); 1172238106Sdes return 0; 1173238106Sdes } 1174238106Sdes worker->stat_timer = comm_timer_create(worker->base, 1175238106Sdes worker_stat_timer_cb, worker); 1176238106Sdes if(!worker->stat_timer) { 1177238106Sdes log_err("could not create statistics timer"); 1178238106Sdes } 1179238106Sdes 1180238106Sdes /* we use the msg_buffer_size as a good estimate for what the 1181238106Sdes * user wants for memory usage sizes */ 1182238106Sdes worker->scratchpad = regional_create_custom(cfg->msg_buffer_size); 1183238106Sdes if(!worker->scratchpad) { 1184238106Sdes log_err("malloc failure"); 1185238106Sdes worker_delete(worker); 1186238106Sdes return 0; 1187238106Sdes } 1188238106Sdes 1189238106Sdes server_stats_init(&worker->stats, cfg); 1190238106Sdes alloc_init(&worker->alloc, &worker->daemon->superalloc, 1191238106Sdes worker->thread_num); 1192238106Sdes alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker); 1193238106Sdes worker->env = *worker->daemon->env; 1194238106Sdes comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); 1195238106Sdes if(worker->thread_num == 0) 1196238106Sdes log_set_time(worker->env.now); 1197238106Sdes worker->env.worker = worker; 1198238106Sdes worker->env.send_query = &worker_send_query; 1199238106Sdes worker->env.alloc = &worker->alloc; 1200238106Sdes worker->env.rnd = worker->rndstate; 1201238106Sdes worker->env.scratch = worker->scratchpad; 1202238106Sdes worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); 1203238106Sdes worker->env.detach_subs = &mesh_detach_subs; 1204238106Sdes worker->env.attach_sub = &mesh_attach_sub; 1205238106Sdes worker->env.kill_sub = &mesh_state_delete; 1206238106Sdes worker->env.detect_cycle = &mesh_detect_cycle; 1207266114Sdes worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); 1208238106Sdes if(!(worker->env.fwds = forwards_create()) || 1209238106Sdes !forwards_apply_cfg(worker->env.fwds, cfg)) { 1210238106Sdes log_err("Could not set forward zones"); 1211238106Sdes worker_delete(worker); 1212238106Sdes return 0; 1213238106Sdes } 1214238106Sdes if(!(worker->env.hints = hints_create()) || 1215238106Sdes !hints_apply_cfg(worker->env.hints, cfg)) { 1216238106Sdes log_err("Could not set root or stub hints"); 1217238106Sdes worker_delete(worker); 1218238106Sdes return 0; 1219238106Sdes } 1220238106Sdes /* one probe timer per process -- if we have 5011 anchors */ 1221238106Sdes if(autr_get_num_anchors(worker->env.anchors) > 0 1222238106Sdes#ifndef THREADS_DISABLED 1223238106Sdes && worker->thread_num == 0 1224238106Sdes#endif 1225238106Sdes ) { 1226238106Sdes struct timeval tv; 1227238106Sdes tv.tv_sec = 0; 1228238106Sdes tv.tv_usec = 0; 1229238106Sdes worker->env.probe_timer = comm_timer_create(worker->base, 1230238106Sdes worker_probe_timer_cb, worker); 1231238106Sdes if(!worker->env.probe_timer) { 1232238106Sdes log_err("could not create 5011-probe timer"); 1233238106Sdes } else { 1234238106Sdes /* let timer fire, then it can reset itself */ 1235238106Sdes comm_timer_set(worker->env.probe_timer, &tv); 1236238106Sdes } 1237238106Sdes } 1238238106Sdes if(!worker->env.mesh || !worker->env.scratch_buffer) { 1239238106Sdes worker_delete(worker); 1240238106Sdes return 0; 1241238106Sdes } 1242238106Sdes worker_mem_report(worker, NULL); 1243238106Sdes /* if statistics enabled start timer */ 1244238106Sdes if(worker->env.cfg->stat_interval > 0) { 1245238106Sdes verbose(VERB_ALGO, "set statistics interval %d secs", 1246238106Sdes worker->env.cfg->stat_interval); 1247238106Sdes worker_restart_timer(worker); 1248238106Sdes } 1249238106Sdes return 1; 1250238106Sdes} 1251238106Sdes 1252238106Sdesvoid 1253238106Sdesworker_work(struct worker* worker) 1254238106Sdes{ 1255238106Sdes comm_base_dispatch(worker->base); 1256238106Sdes} 1257238106Sdes 1258238106Sdesvoid 1259238106Sdesworker_delete(struct worker* worker) 1260238106Sdes{ 1261238106Sdes if(!worker) 1262238106Sdes return; 1263238106Sdes if(worker->env.mesh && verbosity >= VERB_OPS) { 1264238106Sdes server_stats_log(&worker->stats, worker, worker->thread_num); 1265238106Sdes mesh_stats(worker->env.mesh, "mesh has"); 1266238106Sdes worker_mem_report(worker, NULL); 1267238106Sdes } 1268238106Sdes outside_network_quit_prepare(worker->back); 1269238106Sdes mesh_delete(worker->env.mesh); 1270266114Sdes sldns_buffer_free(worker->env.scratch_buffer); 1271238106Sdes forwards_delete(worker->env.fwds); 1272238106Sdes hints_delete(worker->env.hints); 1273238106Sdes listen_delete(worker->front); 1274238106Sdes outside_network_delete(worker->back); 1275238106Sdes comm_signal_delete(worker->comsig); 1276238106Sdes tube_delete(worker->cmd); 1277238106Sdes comm_timer_delete(worker->stat_timer); 1278238106Sdes comm_timer_delete(worker->env.probe_timer); 1279238106Sdes free(worker->ports); 1280238106Sdes if(worker->thread_num == 0) { 1281238106Sdes log_set_time(NULL); 1282238106Sdes#ifdef UB_ON_WINDOWS 1283238106Sdes wsvc_desetup_worker(worker); 1284238106Sdes#endif /* UB_ON_WINDOWS */ 1285238106Sdes } 1286238106Sdes comm_base_delete(worker->base); 1287238106Sdes ub_randfree(worker->rndstate); 1288238106Sdes alloc_clear(&worker->alloc); 1289238106Sdes regional_destroy(worker->scratchpad); 1290238106Sdes free(worker); 1291238106Sdes} 1292238106Sdes 1293238106Sdesstruct outbound_entry* 1294238106Sdesworker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, 1295238106Sdes uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, 1296238106Sdes struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, 1297238106Sdes size_t zonelen, struct module_qstate* q) 1298238106Sdes{ 1299238106Sdes struct worker* worker = q->env->worker; 1300238106Sdes struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 1301238106Sdes q->region, sizeof(*e)); 1302238106Sdes if(!e) 1303238106Sdes return NULL; 1304238106Sdes e->qstate = q; 1305238106Sdes e->qsent = outnet_serviced_query(worker->back, qname, 1306238106Sdes qnamelen, qtype, qclass, flags, dnssec, want_dnssec, 1307238106Sdes q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, 1308238106Sdes addrlen, zone, zonelen, worker_handle_service_reply, e, 1309249141Sdes worker->back->udp_buff); 1310238106Sdes if(!e->qsent) { 1311238106Sdes return NULL; 1312238106Sdes } 1313238106Sdes return e; 1314238106Sdes} 1315238106Sdes 1316238106Sdesvoid 1317238106Sdesworker_alloc_cleanup(void* arg) 1318238106Sdes{ 1319238106Sdes struct worker* worker = (struct worker*)arg; 1320238106Sdes slabhash_clear(&worker->env.rrset_cache->table); 1321238106Sdes slabhash_clear(worker->env.msg_cache); 1322238106Sdes} 1323238106Sdes 1324238106Sdesvoid worker_stats_clear(struct worker* worker) 1325238106Sdes{ 1326238106Sdes server_stats_init(&worker->stats, worker->env.cfg); 1327238106Sdes mesh_stats_clear(worker->env.mesh); 1328238106Sdes worker->back->unwanted_replies = 0; 1329238106Sdes} 1330238106Sdes 1331238106Sdesvoid worker_start_accept(void* arg) 1332238106Sdes{ 1333238106Sdes struct worker* worker = (struct worker*)arg; 1334238106Sdes listen_start_accept(worker->front); 1335238106Sdes if(worker->thread_num == 0) 1336238106Sdes daemon_remote_start_accept(worker->daemon->rc); 1337238106Sdes} 1338238106Sdes 1339238106Sdesvoid worker_stop_accept(void* arg) 1340238106Sdes{ 1341238106Sdes struct worker* worker = (struct worker*)arg; 1342238106Sdes listen_stop_accept(worker->front); 1343238106Sdes if(worker->thread_num == 0) 1344238106Sdes daemon_remote_stop_accept(worker->daemon->rc); 1345238106Sdes} 1346238106Sdes 1347238106Sdes/* --- fake callbacks for fptr_wlist to work --- */ 1348238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), 1349238106Sdes size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 1350238106Sdes uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 1351238106Sdes int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 1352238106Sdes struct sockaddr_storage* ATTR_UNUSED(addr), 1353255579Sdes socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 1354255579Sdes size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) 1355238106Sdes{ 1356238106Sdes log_assert(0); 1357238106Sdes return 0; 1358238106Sdes} 1359238106Sdes 1360238106Sdesint libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), 1361238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 1362238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 1363238106Sdes{ 1364238106Sdes log_assert(0); 1365238106Sdes return 0; 1366238106Sdes} 1367238106Sdes 1368238106Sdesint libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 1369238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 1370238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 1371238106Sdes{ 1372238106Sdes log_assert(0); 1373238106Sdes return 0; 1374238106Sdes} 1375238106Sdes 1376238106Sdesvoid libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 1377238106Sdes uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 1378238106Sdes int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 1379238106Sdes{ 1380238106Sdes log_assert(0); 1381238106Sdes} 1382238106Sdes 1383238106Sdesvoid libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1384266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1385238106Sdes char* ATTR_UNUSED(why_bogus)) 1386238106Sdes{ 1387238106Sdes log_assert(0); 1388238106Sdes} 1389238106Sdes 1390238106Sdesvoid libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1391266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1392238106Sdes char* ATTR_UNUSED(why_bogus)) 1393238106Sdes{ 1394238106Sdes log_assert(0); 1395238106Sdes} 1396238106Sdes 1397266114Sdesvoid libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1398266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1399266114Sdes char* ATTR_UNUSED(why_bogus)) 1400266114Sdes{ 1401266114Sdes log_assert(0); 1402266114Sdes} 1403266114Sdes 1404238106Sdesint context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1405238106Sdes{ 1406238106Sdes log_assert(0); 1407238106Sdes return 0; 1408238106Sdes} 1409238106Sdes 1410238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 1411238106Sdes{ 1412238106Sdes log_assert(0); 1413238106Sdes return 0; 1414238106Sdes} 1415238106Sdes 1416238106Sdesint codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1417238106Sdes{ 1418238106Sdes log_assert(0); 1419238106Sdes return 0; 1420238106Sdes} 1421238106Sdes 1422