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" 74287917Sdes#include "sldns/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 */ 89287917Sdes/** ratelimit for error responses */ 90287917Sdes#define ERROR_RATELIMIT 100 /* qps */ 91238106Sdes 92238106Sdes/** 93238106Sdes * seconds to add to prefetch leeway. This is a TTL that expires old rrsets 94238106Sdes * earlier than they should in order to put the new update into the cache. 95238106Sdes * This additional value is to make sure that if not all TTLs are equal in 96238106Sdes * the message to be updated(and replaced), that rrsets with up to this much 97238106Sdes * extra TTL are also replaced. This means that the resulting new message 98238106Sdes * will have (most likely) this TTL at least, avoiding very small 'split 99238106Sdes * second' TTLs due to operators choosing relative primes for TTLs (or so). 100238106Sdes * Also has to be at least one to break ties (and overwrite cached entry). 101238106Sdes */ 102238106Sdes#define PREFETCH_EXPIRY_ADD 60 103238106Sdes 104238106Sdes#ifdef UNBOUND_ALLOC_STATS 105238106Sdes/** measure memory leakage */ 106238106Sdesstatic void 107238106Sdesdebug_memleak(size_t accounted, size_t heap, 108238106Sdes size_t total_alloc, size_t total_free) 109238106Sdes{ 110238106Sdes static int init = 0; 111238106Sdes static size_t base_heap, base_accounted, base_alloc, base_free; 112238106Sdes size_t base_af, cur_af, grow_af, grow_acc; 113238106Sdes if(!init) { 114238106Sdes init = 1; 115238106Sdes base_heap = heap; 116238106Sdes base_accounted = accounted; 117238106Sdes base_alloc = total_alloc; 118238106Sdes base_free = total_free; 119238106Sdes } 120238106Sdes base_af = base_alloc - base_free; 121238106Sdes cur_af = total_alloc - total_free; 122238106Sdes grow_af = cur_af - base_af; 123238106Sdes grow_acc = accounted - base_accounted; 124238106Sdes log_info("Leakage: %d leaked. growth: %u use, %u acc, %u heap", 125238106Sdes (int)(grow_af - grow_acc), (unsigned)grow_af, 126238106Sdes (unsigned)grow_acc, (unsigned)(heap - base_heap)); 127238106Sdes} 128238106Sdes 129238106Sdes/** give debug heap size indication */ 130238106Sdesstatic void 131238106Sdesdebug_total_mem(size_t calctotal) 132238106Sdes{ 133238106Sdes#ifdef HAVE_SBRK 134238106Sdes extern void* unbound_start_brk; 135238106Sdes extern size_t unbound_mem_alloc, unbound_mem_freed; 136238106Sdes void* cur = sbrk(0); 137238106Sdes int total = cur-unbound_start_brk; 138238106Sdes log_info("Total heap memory estimate: %u total-alloc: %u " 139238106Sdes "total-free: %u", (unsigned)total, 140238106Sdes (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); 141238106Sdes debug_memleak(calctotal, (size_t)total, 142238106Sdes unbound_mem_alloc, unbound_mem_freed); 143238106Sdes#else 144238106Sdes (void)calctotal; 145238106Sdes#endif /* HAVE_SBRK */ 146238106Sdes} 147238106Sdes#endif /* UNBOUND_ALLOC_STATS */ 148238106Sdes 149238106Sdes/** Report on memory usage by this thread and global */ 150238106Sdesstatic void 151238106Sdesworker_mem_report(struct worker* ATTR_UNUSED(worker), 152238106Sdes struct serviced_query* ATTR_UNUSED(cur_serv)) 153238106Sdes{ 154238106Sdes#ifdef UNBOUND_ALLOC_STATS 155238106Sdes /* debug func in validator module */ 156238106Sdes size_t total, front, back, mesh, msg, rrset, infra, ac, superac; 157238106Sdes size_t me, iter, val, anch; 158238106Sdes int i; 159238106Sdes if(verbosity < VERB_ALGO) 160238106Sdes return; 161238106Sdes front = listen_get_mem(worker->front); 162238106Sdes back = outnet_get_mem(worker->back); 163238106Sdes msg = slabhash_get_mem(worker->env.msg_cache); 164238106Sdes rrset = slabhash_get_mem(&worker->env.rrset_cache->table); 165238106Sdes infra = infra_get_mem(worker->env.infra_cache); 166238106Sdes mesh = mesh_get_mem(worker->env.mesh); 167238106Sdes ac = alloc_get_mem(&worker->alloc); 168238106Sdes superac = alloc_get_mem(&worker->daemon->superalloc); 169238106Sdes anch = anchors_get_mem(worker->env.anchors); 170238106Sdes iter = 0; 171238106Sdes val = 0; 172238106Sdes for(i=0; i<worker->env.mesh->mods.num; i++) { 173238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 174238106Sdes mods.mod[i]->get_mem)); 175238106Sdes if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 176238106Sdes val += (*worker->env.mesh->mods.mod[i]->get_mem) 177238106Sdes (&worker->env, i); 178238106Sdes else iter += (*worker->env.mesh->mods.mod[i]->get_mem) 179238106Sdes (&worker->env, i); 180238106Sdes } 181238106Sdes me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig) 182238106Sdes + comm_point_get_mem(worker->cmd_com) 183238106Sdes + sizeof(worker->rndstate) 184238106Sdes + regional_get_mem(worker->scratchpad) 185238106Sdes + sizeof(*worker->env.scratch_buffer) 186266114Sdes + sldns_buffer_capacity(worker->env.scratch_buffer) 187238106Sdes + forwards_get_mem(worker->env.fwds) 188238106Sdes + hints_get_mem(worker->env.hints); 189238106Sdes if(worker->thread_num == 0) 190238106Sdes me += acl_list_get_mem(worker->daemon->acl); 191238106Sdes if(cur_serv) { 192238106Sdes me += serviced_get_mem(cur_serv); 193238106Sdes } 194238106Sdes total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me; 195238106Sdes log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " 196238106Sdes "rrset=%u infra=%u iter=%u val=%u anchors=%u " 197238106Sdes "alloccache=%u globalalloccache=%u me=%u", 198238106Sdes (unsigned)total, (unsigned)front, (unsigned)back, 199238106Sdes (unsigned)mesh, (unsigned)msg, (unsigned)rrset, 200238106Sdes (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, 201238106Sdes (unsigned)ac, (unsigned)superac, (unsigned)me); 202238106Sdes debug_total_mem(total); 203238106Sdes#else /* no UNBOUND_ALLOC_STATS */ 204238106Sdes size_t val = 0; 205238106Sdes int i; 206238106Sdes if(verbosity < VERB_QUERY) 207238106Sdes return; 208238106Sdes for(i=0; i<worker->env.mesh->mods.num; i++) { 209238106Sdes fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 210238106Sdes mods.mod[i]->get_mem)); 211238106Sdes if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 212238106Sdes val += (*worker->env.mesh->mods.mod[i]->get_mem) 213238106Sdes (&worker->env, i); 214238106Sdes } 215238106Sdes verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u", 216238106Sdes (unsigned)slabhash_get_mem(worker->env.msg_cache), 217238106Sdes (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), 218238106Sdes (unsigned)infra_get_mem(worker->env.infra_cache), 219238106Sdes (unsigned)val); 220238106Sdes#endif /* UNBOUND_ALLOC_STATS */ 221238106Sdes} 222238106Sdes 223238106Sdesvoid 224238106Sdesworker_send_cmd(struct worker* worker, enum worker_commands cmd) 225238106Sdes{ 226238106Sdes uint32_t c = (uint32_t)htonl(cmd); 227238106Sdes if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) { 228238106Sdes log_err("worker send cmd %d failed", (int)cmd); 229238106Sdes } 230238106Sdes} 231238106Sdes 232238106Sdesint 233238106Sdesworker_handle_reply(struct comm_point* c, void* arg, int error, 234238106Sdes struct comm_reply* reply_info) 235238106Sdes{ 236238106Sdes struct module_qstate* q = (struct module_qstate*)arg; 237238106Sdes struct worker* worker = q->env->worker; 238238106Sdes struct outbound_entry e; 239238106Sdes e.qstate = q; 240238106Sdes e.qsent = NULL; 241238106Sdes 242238106Sdes if(error != 0) { 243238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, error); 244238106Sdes worker_mem_report(worker, NULL); 245238106Sdes return 0; 246238106Sdes } 247238106Sdes /* sanity check. */ 248266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 249266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 250238106Sdes LDNS_PACKET_QUERY 251266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 252238106Sdes /* error becomes timeout for the module as if this reply 253238106Sdes * never arrived. */ 254238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, 255238106Sdes NETEVENT_TIMEOUT); 256238106Sdes worker_mem_report(worker, NULL); 257238106Sdes return 0; 258238106Sdes } 259238106Sdes mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR); 260238106Sdes worker_mem_report(worker, NULL); 261238106Sdes return 0; 262238106Sdes} 263238106Sdes 264238106Sdesint 265238106Sdesworker_handle_service_reply(struct comm_point* c, void* arg, int error, 266238106Sdes struct comm_reply* reply_info) 267238106Sdes{ 268238106Sdes struct outbound_entry* e = (struct outbound_entry*)arg; 269238106Sdes struct worker* worker = e->qstate->env->worker; 270238106Sdes struct serviced_query *sq = e->qsent; 271238106Sdes 272238106Sdes verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); 273238106Sdes if(error != 0) { 274238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, error); 275238106Sdes worker_mem_report(worker, sq); 276238106Sdes return 0; 277238106Sdes } 278238106Sdes /* sanity check. */ 279266114Sdes if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 280266114Sdes || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 281238106Sdes LDNS_PACKET_QUERY 282266114Sdes || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 283238106Sdes /* error becomes timeout for the module as if this reply 284238106Sdes * never arrived. */ 285238106Sdes verbose(VERB_ALGO, "worker: bad reply handled as timeout"); 286238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, 287238106Sdes NETEVENT_TIMEOUT); 288238106Sdes worker_mem_report(worker, sq); 289238106Sdes return 0; 290238106Sdes } 291238106Sdes mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR); 292238106Sdes worker_mem_report(worker, sq); 293238106Sdes return 0; 294238106Sdes} 295238106Sdes 296287917Sdes/** ratelimit error replies 297287917Sdes * @param worker: the worker struct with ratelimit counter 298287917Sdes * @param err: error code that would be wanted. 299287917Sdes * @return value of err if okay, or -1 if it should be discarded instead. 300287917Sdes */ 301287917Sdesstatic int 302287917Sdesworker_err_ratelimit(struct worker* worker, int err) 303287917Sdes{ 304287917Sdes if(worker->err_limit_time == *worker->env.now) { 305287917Sdes /* see if limit is exceeded for this second */ 306287917Sdes if(worker->err_limit_count++ > ERROR_RATELIMIT) 307287917Sdes return -1; 308287917Sdes } else { 309287917Sdes /* new second, new limits */ 310287917Sdes worker->err_limit_time = *worker->env.now; 311287917Sdes worker->err_limit_count = 1; 312287917Sdes } 313287917Sdes return err; 314287917Sdes} 315287917Sdes 316238106Sdes/** check request sanity. 317238106Sdes * @param pkt: the wire packet to examine for sanity. 318238106Sdes * @param worker: parameters for checking. 319238106Sdes * @return error code, 0 OK, or -1 discard. 320238106Sdes*/ 321238106Sdesstatic int 322266114Sdesworker_check_request(sldns_buffer* pkt, struct worker* worker) 323238106Sdes{ 324266114Sdes if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) { 325238106Sdes verbose(VERB_QUERY, "request too short, discarded"); 326238106Sdes return -1; 327238106Sdes } 328266114Sdes if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 329238106Sdes worker->daemon->cfg->harden_large_queries) { 330238106Sdes verbose(VERB_QUERY, "request too large, discarded"); 331238106Sdes return -1; 332238106Sdes } 333266114Sdes if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) { 334238106Sdes verbose(VERB_QUERY, "request has QR bit on, discarded"); 335238106Sdes return -1; 336238106Sdes } 337266114Sdes if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { 338266114Sdes LDNS_TC_CLR(sldns_buffer_begin(pkt)); 339238106Sdes verbose(VERB_QUERY, "request bad, has TC bit on"); 340287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 341238106Sdes } 342266114Sdes if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) { 343238106Sdes verbose(VERB_QUERY, "request unknown opcode %d", 344266114Sdes LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt))); 345287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL); 346238106Sdes } 347266114Sdes if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) { 348238106Sdes verbose(VERB_QUERY, "request wrong nr qd=%d", 349266114Sdes LDNS_QDCOUNT(sldns_buffer_begin(pkt))); 350287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 351238106Sdes } 352266114Sdes if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) { 353238106Sdes verbose(VERB_QUERY, "request wrong nr an=%d", 354266114Sdes LDNS_ANCOUNT(sldns_buffer_begin(pkt))); 355287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 356238106Sdes } 357266114Sdes if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) { 358238106Sdes verbose(VERB_QUERY, "request wrong nr ns=%d", 359266114Sdes LDNS_NSCOUNT(sldns_buffer_begin(pkt))); 360287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 361238106Sdes } 362266114Sdes if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { 363238106Sdes verbose(VERB_QUERY, "request wrong nr ar=%d", 364266114Sdes LDNS_ARCOUNT(sldns_buffer_begin(pkt))); 365287917Sdes return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 366238106Sdes } 367238106Sdes return 0; 368238106Sdes} 369238106Sdes 370238106Sdesvoid 371238106Sdesworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, 372238106Sdes size_t len, int error, void* arg) 373238106Sdes{ 374238106Sdes struct worker* worker = (struct worker*)arg; 375238106Sdes enum worker_commands cmd; 376238106Sdes if(error != NETEVENT_NOERROR) { 377238106Sdes free(msg); 378238106Sdes if(error == NETEVENT_CLOSED) 379238106Sdes comm_base_exit(worker->base); 380238106Sdes else log_info("control event: %d", error); 381238106Sdes return; 382238106Sdes } 383238106Sdes if(len != sizeof(uint32_t)) { 384238106Sdes fatal_exit("bad control msg length %d", (int)len); 385238106Sdes } 386266114Sdes cmd = sldns_read_uint32(msg); 387238106Sdes free(msg); 388238106Sdes switch(cmd) { 389238106Sdes case worker_cmd_quit: 390238106Sdes verbose(VERB_ALGO, "got control cmd quit"); 391238106Sdes comm_base_exit(worker->base); 392238106Sdes break; 393238106Sdes case worker_cmd_stats: 394238106Sdes verbose(VERB_ALGO, "got control cmd stats"); 395238106Sdes server_stats_reply(worker, 1); 396238106Sdes break; 397238106Sdes case worker_cmd_stats_noreset: 398238106Sdes verbose(VERB_ALGO, "got control cmd stats_noreset"); 399238106Sdes server_stats_reply(worker, 0); 400238106Sdes break; 401238106Sdes case worker_cmd_remote: 402238106Sdes verbose(VERB_ALGO, "got control cmd remote"); 403238106Sdes daemon_remote_exec(worker); 404238106Sdes break; 405238106Sdes default: 406238106Sdes log_err("bad command %d", (int)cmd); 407238106Sdes break; 408238106Sdes } 409238106Sdes} 410238106Sdes 411238106Sdes/** check if a delegation is secure */ 412238106Sdesstatic enum sec_status 413238106Sdescheck_delegation_secure(struct reply_info *rep) 414238106Sdes{ 415238106Sdes /* return smallest security status */ 416238106Sdes size_t i; 417238106Sdes enum sec_status sec = sec_status_secure; 418238106Sdes enum sec_status s; 419238106Sdes size_t num = rep->an_numrrsets + rep->ns_numrrsets; 420238106Sdes /* check if answer and authority are OK */ 421238106Sdes for(i=0; i<num; i++) { 422238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 423238106Sdes ->security; 424238106Sdes if(s < sec) 425238106Sdes sec = s; 426238106Sdes } 427238106Sdes /* in additional, only unchecked triggers revalidation */ 428238106Sdes for(i=num; i<rep->rrset_count; i++) { 429238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 430238106Sdes ->security; 431238106Sdes if(s == sec_status_unchecked) 432238106Sdes return s; 433238106Sdes } 434238106Sdes return sec; 435238106Sdes} 436238106Sdes 437238106Sdes/** remove nonsecure from a delegation referral additional section */ 438238106Sdesstatic void 439238106Sdesdeleg_remove_nonsecure_additional(struct reply_info* rep) 440238106Sdes{ 441238106Sdes /* we can simply edit it, since we are working in the scratch region */ 442238106Sdes size_t i; 443238106Sdes enum sec_status s; 444238106Sdes 445238106Sdes for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { 446238106Sdes s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 447238106Sdes ->security; 448238106Sdes if(s != sec_status_secure) { 449238106Sdes memmove(rep->rrsets+i, rep->rrsets+i+1, 450238106Sdes sizeof(struct ub_packed_rrset_key*)* 451238106Sdes (rep->rrset_count - i - 1)); 452238106Sdes rep->ar_numrrsets--; 453238106Sdes rep->rrset_count--; 454238106Sdes i--; 455238106Sdes } 456238106Sdes } 457238106Sdes} 458238106Sdes 459238106Sdes/** answer nonrecursive query from the cache */ 460238106Sdesstatic int 461238106Sdesanswer_norec_from_cache(struct worker* worker, struct query_info* qinfo, 462238106Sdes uint16_t id, uint16_t flags, struct comm_reply* repinfo, 463238106Sdes struct edns_data* edns) 464238106Sdes{ 465238106Sdes /* for a nonrecursive query return either: 466238106Sdes * o an error (servfail; we try to avoid this) 467238106Sdes * o a delegation (closest we have; this routine tries that) 468238106Sdes * o the answer (checked by answer_from_cache) 469238106Sdes * 470238106Sdes * So, grab a delegation from the rrset cache. 471238106Sdes * Then check if it needs validation, if so, this routine fails, 472238106Sdes * so that iterator can prime and validator can verify rrsets. 473238106Sdes */ 474238106Sdes uint16_t udpsize = edns->udp_size; 475238106Sdes int secure = 0; 476266114Sdes time_t timenow = *worker->env.now; 477238106Sdes int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) 478238106Sdes && worker->env.need_to_validate; 479238106Sdes struct dns_msg *msg = NULL; 480238106Sdes struct delegpt *dp; 481238106Sdes 482238106Sdes dp = dns_cache_find_delegation(&worker->env, qinfo->qname, 483238106Sdes qinfo->qname_len, qinfo->qtype, qinfo->qclass, 484238106Sdes worker->scratchpad, &msg, timenow); 485238106Sdes if(!dp) { /* no delegation, need to reprime */ 486238106Sdes regional_free_all(worker->scratchpad); 487238106Sdes return 0; 488238106Sdes } 489238106Sdes if(must_validate) { 490238106Sdes switch(check_delegation_secure(msg->rep)) { 491238106Sdes case sec_status_unchecked: 492238106Sdes /* some rrsets have not been verified yet, go and 493238106Sdes * let validator do that */ 494238106Sdes regional_free_all(worker->scratchpad); 495238106Sdes return 0; 496238106Sdes case sec_status_bogus: 497238106Sdes /* some rrsets are bogus, reply servfail */ 498238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 499238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 500238106Sdes edns->ext_rcode = 0; 501238106Sdes edns->bits &= EDNS_DO; 502238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 503238106Sdes &msg->qinfo, id, flags, edns); 504238106Sdes regional_free_all(worker->scratchpad); 505238106Sdes if(worker->stats.extended) { 506238106Sdes worker->stats.ans_bogus++; 507238106Sdes worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; 508238106Sdes } 509238106Sdes return 1; 510238106Sdes case sec_status_secure: 511238106Sdes /* all rrsets are secure */ 512238106Sdes /* remove non-secure rrsets from the add. section*/ 513238106Sdes if(worker->env.cfg->val_clean_additional) 514238106Sdes deleg_remove_nonsecure_additional(msg->rep); 515238106Sdes secure = 1; 516238106Sdes break; 517238106Sdes case sec_status_indeterminate: 518238106Sdes case sec_status_insecure: 519238106Sdes default: 520238106Sdes /* not secure */ 521238106Sdes secure = 0; 522238106Sdes break; 523238106Sdes } 524238106Sdes } 525238106Sdes /* return this delegation from the cache */ 526238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 527238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 528238106Sdes edns->ext_rcode = 0; 529238106Sdes edns->bits &= EDNS_DO; 530238106Sdes msg->rep->flags |= BIT_QR|BIT_RA; 531238106Sdes if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 532238106Sdes repinfo->c->buffer, 0, 1, worker->scratchpad, 533238106Sdes udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 534238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 535238106Sdes &msg->qinfo, id, flags, edns); 536238106Sdes } 537238106Sdes regional_free_all(worker->scratchpad); 538238106Sdes if(worker->stats.extended) { 539238106Sdes if(secure) worker->stats.ans_secure++; 540238106Sdes server_stats_insrcode(&worker->stats, repinfo->c->buffer); 541238106Sdes } 542238106Sdes return 1; 543238106Sdes} 544238106Sdes 545238106Sdes/** answer query from the cache */ 546238106Sdesstatic int 547238106Sdesanswer_from_cache(struct worker* worker, struct query_info* qinfo, 548238106Sdes struct reply_info* rep, uint16_t id, uint16_t flags, 549238106Sdes struct comm_reply* repinfo, struct edns_data* edns) 550238106Sdes{ 551266114Sdes time_t timenow = *worker->env.now; 552238106Sdes uint16_t udpsize = edns->udp_size; 553238106Sdes int secure; 554238106Sdes int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) 555238106Sdes && worker->env.need_to_validate; 556238106Sdes /* see if it is possible */ 557238106Sdes if(rep->ttl < timenow) { 558238106Sdes /* the rrsets may have been updated in the meantime. 559238106Sdes * we will refetch the message format from the 560238106Sdes * authoritative server 561238106Sdes */ 562238106Sdes return 0; 563238106Sdes } 564238106Sdes if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) 565238106Sdes return 0; 566238106Sdes /* locked and ids and ttls are OK. */ 567238106Sdes /* check CNAME chain (if any) */ 568238106Sdes if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == 569238106Sdes htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == 570238106Sdes htons(LDNS_RR_TYPE_DNAME))) { 571287917Sdes if(!reply_check_cname_chain(qinfo, rep)) { 572238106Sdes /* cname chain invalid, redo iterator steps */ 573238106Sdes verbose(VERB_ALGO, "Cache reply: cname chain broken"); 574238106Sdes bail_out: 575238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, 576238106Sdes worker->scratchpad, rep->ref, rep->rrset_count); 577238106Sdes regional_free_all(worker->scratchpad); 578238106Sdes return 0; 579238106Sdes } 580238106Sdes } 581238106Sdes /* check security status of the cached answer */ 582238106Sdes if( rep->security == sec_status_bogus && must_validate) { 583238106Sdes /* BAD cached */ 584238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 585238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 586238106Sdes edns->ext_rcode = 0; 587238106Sdes edns->bits &= EDNS_DO; 588238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 589238106Sdes qinfo, id, flags, edns); 590238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, 591238106Sdes worker->scratchpad, rep->ref, rep->rrset_count); 592238106Sdes regional_free_all(worker->scratchpad); 593238106Sdes if(worker->stats.extended) { 594238106Sdes worker->stats.ans_bogus ++; 595238106Sdes worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; 596238106Sdes } 597238106Sdes return 1; 598238106Sdes } else if( rep->security == sec_status_unchecked && must_validate) { 599238106Sdes verbose(VERB_ALGO, "Cache reply: unchecked entry needs " 600238106Sdes "validation"); 601238106Sdes goto bail_out; /* need to validate cache entry first */ 602238106Sdes } else if(rep->security == sec_status_secure) { 603238106Sdes if(reply_all_rrsets_secure(rep)) 604238106Sdes secure = 1; 605238106Sdes else { 606238106Sdes if(must_validate) { 607238106Sdes verbose(VERB_ALGO, "Cache reply: secure entry" 608238106Sdes " changed status"); 609238106Sdes goto bail_out; /* rrset changed, re-verify */ 610238106Sdes } 611238106Sdes secure = 0; 612238106Sdes } 613238106Sdes } else secure = 0; 614238106Sdes 615238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 616238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 617238106Sdes edns->ext_rcode = 0; 618238106Sdes edns->bits &= EDNS_DO; 619238106Sdes if(!reply_info_answer_encode(qinfo, rep, id, flags, 620238106Sdes repinfo->c->buffer, timenow, 1, worker->scratchpad, 621238106Sdes udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 622238106Sdes error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 623238106Sdes qinfo, id, flags, edns); 624238106Sdes } 625238106Sdes /* cannot send the reply right now, because blocking network syscall 626238106Sdes * is bad while holding locks. */ 627238106Sdes rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, 628238106Sdes rep->ref, rep->rrset_count); 629238106Sdes regional_free_all(worker->scratchpad); 630238106Sdes if(worker->stats.extended) { 631238106Sdes if(secure) worker->stats.ans_secure++; 632238106Sdes server_stats_insrcode(&worker->stats, repinfo->c->buffer); 633238106Sdes } 634238106Sdes /* go and return this buffer to the client */ 635238106Sdes return 1; 636238106Sdes} 637238106Sdes 638238106Sdes/** Reply to client and perform prefetch to keep cache up to date */ 639238106Sdesstatic void 640238106Sdesreply_and_prefetch(struct worker* worker, struct query_info* qinfo, 641266114Sdes uint16_t flags, struct comm_reply* repinfo, time_t leeway) 642238106Sdes{ 643238106Sdes /* first send answer to client to keep its latency 644238106Sdes * as small as a cachereply */ 645238106Sdes comm_point_send_reply(repinfo); 646238106Sdes server_stats_prefetch(&worker->stats, worker); 647238106Sdes 648238106Sdes /* create the prefetch in the mesh as a normal lookup without 649238106Sdes * client addrs waiting, which has the cache blacklisted (to bypass 650238106Sdes * the cache and go to the network for the data). */ 651238106Sdes /* this (potentially) runs the mesh for the new query */ 652238106Sdes mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 653238106Sdes PREFETCH_EXPIRY_ADD); 654238106Sdes} 655238106Sdes 656238106Sdes/** 657238106Sdes * Fill CH class answer into buffer. Keeps query. 658238106Sdes * @param pkt: buffer 659238106Sdes * @param str: string to put into text record (<255). 660238106Sdes * @param edns: edns reply information. 661238106Sdes */ 662238106Sdesstatic void 663266114Sdeschaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns) 664238106Sdes{ 665238106Sdes size_t len = strlen(str); 666266114Sdes unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); 667266114Sdes unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); 668238106Sdes if(len>255) len=255; /* cap size of TXT record */ 669266114Sdes sldns_buffer_clear(pkt); 670266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ 671266114Sdes sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); 672266114Sdes if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); 673266114Sdes if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); 674266114Sdes sldns_buffer_write_u16(pkt, 1); /* qdcount */ 675266114Sdes sldns_buffer_write_u16(pkt, 1); /* ancount */ 676266114Sdes sldns_buffer_write_u16(pkt, 0); /* nscount */ 677266114Sdes sldns_buffer_write_u16(pkt, 0); /* arcount */ 678238106Sdes (void)query_dname_len(pkt); /* skip qname */ 679266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 680266114Sdes sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 681266114Sdes sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ 682266114Sdes sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); 683266114Sdes sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); 684266114Sdes sldns_buffer_write_u32(pkt, 0); /* TTL */ 685266114Sdes sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); 686266114Sdes sldns_buffer_write_u8(pkt, len); 687266114Sdes sldns_buffer_write(pkt, str, len); 688266114Sdes sldns_buffer_flip(pkt); 689238106Sdes edns->edns_version = EDNS_ADVERTISED_VERSION; 690238106Sdes edns->udp_size = EDNS_ADVERTISED_SIZE; 691238106Sdes edns->bits &= EDNS_DO; 692238106Sdes attach_edns_record(pkt, edns); 693238106Sdes} 694238106Sdes 695238106Sdes/** 696238106Sdes * Answer CH class queries. 697238106Sdes * @param w: worker 698238106Sdes * @param qinfo: query info. Pointer into packet buffer. 699238106Sdes * @param edns: edns info from query. 700238106Sdes * @param pkt: packet buffer. 701238106Sdes * @return: true if a reply is to be sent. 702238106Sdes */ 703238106Sdesstatic int 704238106Sdesanswer_chaos(struct worker* w, struct query_info* qinfo, 705266114Sdes struct edns_data* edns, sldns_buffer* pkt) 706238106Sdes{ 707238106Sdes struct config_file* cfg = w->env.cfg; 708238106Sdes if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) 709238106Sdes return 0; 710238106Sdes if(query_dname_compare(qinfo->qname, 711238106Sdes (uint8_t*)"\002id\006server") == 0 || 712238106Sdes query_dname_compare(qinfo->qname, 713238106Sdes (uint8_t*)"\010hostname\004bind") == 0) 714238106Sdes { 715238106Sdes if(cfg->hide_identity) 716238106Sdes return 0; 717238106Sdes if(cfg->identity==NULL || cfg->identity[0]==0) { 718238106Sdes char buf[MAXHOSTNAMELEN+1]; 719238106Sdes if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 720238106Sdes buf[MAXHOSTNAMELEN] = 0; 721238106Sdes chaos_replystr(pkt, buf, edns); 722238106Sdes } else { 723238106Sdes log_err("gethostname: %s", strerror(errno)); 724238106Sdes chaos_replystr(pkt, "no hostname", edns); 725238106Sdes } 726238106Sdes } 727238106Sdes else chaos_replystr(pkt, cfg->identity, edns); 728238106Sdes return 1; 729238106Sdes } 730238106Sdes if(query_dname_compare(qinfo->qname, 731238106Sdes (uint8_t*)"\007version\006server") == 0 || 732238106Sdes query_dname_compare(qinfo->qname, 733238106Sdes (uint8_t*)"\007version\004bind") == 0) 734238106Sdes { 735238106Sdes if(cfg->hide_version) 736238106Sdes return 0; 737238106Sdes if(cfg->version==NULL || cfg->version[0]==0) 738238106Sdes chaos_replystr(pkt, PACKAGE_STRING, edns); 739238106Sdes else chaos_replystr(pkt, cfg->version, edns); 740238106Sdes return 1; 741238106Sdes } 742238106Sdes return 0; 743238106Sdes} 744238106Sdes 745266114Sdesstatic int 746266114Sdesdeny_refuse(struct comm_point* c, enum acl_access acl, 747266114Sdes enum acl_access deny, enum acl_access refuse, 748266114Sdes struct worker* worker, struct comm_reply* repinfo) 749266114Sdes{ 750266114Sdes if(acl == deny) { 751266114Sdes comm_point_drop_reply(repinfo); 752266114Sdes if(worker->stats.extended) 753266114Sdes worker->stats.unwanted_queries++; 754266114Sdes return 0; 755266114Sdes } else if(acl == refuse) { 756266114Sdes log_addr(VERB_ALGO, "refused query from", 757266114Sdes &repinfo->addr, repinfo->addrlen); 758266114Sdes log_buf(VERB_ALGO, "refuse", c->buffer); 759266114Sdes if(worker->stats.extended) 760266114Sdes worker->stats.unwanted_queries++; 761266114Sdes if(worker_check_request(c->buffer, worker) == -1) { 762266114Sdes comm_point_drop_reply(repinfo); 763266114Sdes return 0; /* discard this */ 764266114Sdes } 765266114Sdes sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); 766266114Sdes sldns_buffer_write_at(c->buffer, 4, 767266114Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 768266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 769266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 770266114Sdes LDNS_RCODE_REFUSED); 771266114Sdes return 1; 772266114Sdes } 773266114Sdes 774266114Sdes return -1; 775266114Sdes} 776266114Sdes 777266114Sdesstatic int 778266114Sdesdeny_refuse_all(struct comm_point* c, enum acl_access acl, 779266114Sdes struct worker* worker, struct comm_reply* repinfo) 780266114Sdes{ 781266114Sdes return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo); 782266114Sdes} 783266114Sdes 784266114Sdesstatic int 785266114Sdesdeny_refuse_non_local(struct comm_point* c, enum acl_access acl, 786266114Sdes struct worker* worker, struct comm_reply* repinfo) 787266114Sdes{ 788266114Sdes return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, worker, repinfo); 789266114Sdes} 790266114Sdes 791238106Sdesint 792238106Sdesworker_handle_request(struct comm_point* c, void* arg, int error, 793238106Sdes struct comm_reply* repinfo) 794238106Sdes{ 795238106Sdes struct worker* worker = (struct worker*)arg; 796238106Sdes int ret; 797238106Sdes hashvalue_t h; 798238106Sdes struct lruhash_entry* e; 799238106Sdes struct query_info qinfo; 800238106Sdes struct edns_data edns; 801238106Sdes enum acl_access acl; 802276605Sdes int rc = 0; 803238106Sdes 804238106Sdes if(error != NETEVENT_NOERROR) { 805238106Sdes /* some bad tcp query DNS formats give these error calls */ 806238106Sdes verbose(VERB_ALGO, "handle request called with err=%d", error); 807238106Sdes return 0; 808238106Sdes } 809276605Sdes#ifdef USE_DNSTAP 810276605Sdes if(worker->dtenv.log_client_query_messages) 811276605Sdes dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type, 812276605Sdes c->buffer); 813276605Sdes#endif 814238106Sdes acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, 815238106Sdes repinfo->addrlen); 816266114Sdes if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1) 817266114Sdes { 818276605Sdes if(ret == 1) 819276605Sdes goto send_reply; 820266114Sdes return ret; 821238106Sdes } 822238106Sdes if((ret=worker_check_request(c->buffer, worker)) != 0) { 823238106Sdes verbose(VERB_ALGO, "worker check request: bad query."); 824238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 825238106Sdes if(ret != -1) { 826266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 827266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); 828238106Sdes return 1; 829238106Sdes } 830238106Sdes comm_point_drop_reply(repinfo); 831238106Sdes return 0; 832238106Sdes } 833238106Sdes worker->stats.num_queries++; 834238106Sdes /* see if query is in the cache */ 835238106Sdes if(!query_info_parse(&qinfo, c->buffer)) { 836238106Sdes verbose(VERB_ALGO, "worker parse request: formerror."); 837238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 838287917Sdes if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { 839287917Sdes comm_point_drop_reply(repinfo); 840287917Sdes return 0; 841287917Sdes } 842266114Sdes sldns_buffer_rewind(c->buffer); 843266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 844266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 845238106Sdes LDNS_RCODE_FORMERR); 846238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 847276605Sdes goto send_reply; 848238106Sdes } 849238106Sdes if(worker->env.cfg->log_queries) { 850238106Sdes char ip[128]; 851238106Sdes addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); 852238106Sdes log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); 853238106Sdes } 854238106Sdes if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 855238106Sdes qinfo.qtype == LDNS_RR_TYPE_IXFR) { 856238106Sdes verbose(VERB_ALGO, "worker request: refused zone transfer."); 857238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 858266114Sdes sldns_buffer_rewind(c->buffer); 859266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 860266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 861238106Sdes LDNS_RCODE_REFUSED); 862238106Sdes if(worker->stats.extended) { 863238106Sdes worker->stats.qtype[qinfo.qtype]++; 864238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 865238106Sdes } 866276605Sdes goto send_reply; 867238106Sdes } 868238106Sdes if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) { 869292206Sdes struct edns_data reply_edns; 870238106Sdes verbose(VERB_ALGO, "worker parse edns: formerror."); 871238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 872292206Sdes memset(&reply_edns, 0, sizeof(reply_edns)); 873292206Sdes reply_edns.edns_present = 1; 874292206Sdes reply_edns.udp_size = EDNS_ADVERTISED_SIZE; 875266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret); 876292206Sdes error_encode(c->buffer, ret, &qinfo, 877292206Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 878292206Sdes sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); 879238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 880276605Sdes goto send_reply; 881238106Sdes } 882238106Sdes if(edns.edns_present && edns.edns_version != 0) { 883238106Sdes edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); 884238106Sdes edns.edns_version = EDNS_ADVERTISED_VERSION; 885238106Sdes edns.udp_size = EDNS_ADVERTISED_SIZE; 886238106Sdes edns.bits &= EDNS_DO; 887238106Sdes verbose(VERB_ALGO, "query with bad edns version."); 888238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 889238106Sdes error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo, 890276605Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 891266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), NULL); 892238106Sdes attach_edns_record(c->buffer, &edns); 893276605Sdes goto send_reply; 894238106Sdes } 895238106Sdes if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE && 896238106Sdes worker->daemon->cfg->harden_short_bufsize) { 897238106Sdes verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", 898238106Sdes (int)edns.udp_size); 899238106Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 900238106Sdes edns.udp_size = NORMAL_UDP_SIZE; 901238106Sdes } 902266114Sdes if(edns.udp_size > worker->daemon->cfg->max_udp_size && 903266114Sdes c->type == comm_udp) { 904266114Sdes verbose(VERB_QUERY, 905266114Sdes "worker request: max UDP reply size modified" 906266114Sdes " (%d to max-udp-size)", (int)edns.udp_size); 907266114Sdes log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); 908266114Sdes edns.udp_size = worker->daemon->cfg->max_udp_size; 909266114Sdes } 910266114Sdes if(edns.udp_size < LDNS_HEADER_SIZE) { 911238106Sdes verbose(VERB_ALGO, "worker request: edns is too small."); 912238106Sdes log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen); 913266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 914266114Sdes LDNS_TC_SET(sldns_buffer_begin(c->buffer)); 915266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 916238106Sdes LDNS_RCODE_SERVFAIL); 917266114Sdes sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 918266114Sdes sldns_buffer_write_at(c->buffer, 4, 919238106Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 920266114Sdes sldns_buffer_flip(c->buffer); 921276605Sdes goto send_reply; 922238106Sdes } 923238106Sdes if(worker->stats.extended) 924238106Sdes server_stats_insquery(&worker->stats, c, qinfo.qtype, 925238106Sdes qinfo.qclass, &edns, repinfo); 926238106Sdes if(c->type != comm_udp) 927238106Sdes edns.udp_size = 65535; /* max size for TCP replies */ 928238106Sdes if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, 929238106Sdes &edns, c->buffer)) { 930238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 931276605Sdes goto send_reply; 932238106Sdes } 933238106Sdes if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns, 934282089Sdes c->buffer, worker->scratchpad, repinfo)) { 935238106Sdes regional_free_all(worker->scratchpad); 936266114Sdes if(sldns_buffer_limit(c->buffer) == 0) { 937238106Sdes comm_point_drop_reply(repinfo); 938238106Sdes return 0; 939238106Sdes } 940238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 941276605Sdes goto send_reply; 942238106Sdes } 943266114Sdes 944266114Sdes /* We've looked in our local zones. If the answer isn't there, we 945266114Sdes * might need to bail out based on ACLs now. */ 946266114Sdes if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1) 947266114Sdes { 948276605Sdes if(ret == 1) 949276605Sdes goto send_reply; 950266114Sdes return ret; 951266114Sdes } 952266114Sdes 953266114Sdes /* If this request does not have the recursion bit set, verify 954266114Sdes * ACLs allow the snooping. */ 955266114Sdes if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 956238106Sdes acl != acl_allow_snoop ) { 957266114Sdes sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE); 958266114Sdes sldns_buffer_write_at(c->buffer, 4, 959238106Sdes (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 960266114Sdes LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 961266114Sdes LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 962238106Sdes LDNS_RCODE_REFUSED); 963266114Sdes sldns_buffer_flip(c->buffer); 964238106Sdes server_stats_insrcode(&worker->stats, c->buffer); 965238106Sdes log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", 966238106Sdes &repinfo->addr, repinfo->addrlen); 967276605Sdes goto send_reply; 968238106Sdes } 969276605Sdes h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); 970238106Sdes if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { 971238106Sdes /* answer from cache - we have acquired a readlock on it */ 972238106Sdes if(answer_from_cache(worker, &qinfo, 973238106Sdes (struct reply_info*)e->data, 974266114Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 975266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 976238106Sdes &edns)) { 977238106Sdes /* prefetch it if the prefetch TTL expired */ 978238106Sdes if(worker->env.cfg->prefetch && *worker->env.now >= 979238106Sdes ((struct reply_info*)e->data)->prefetch_ttl) { 980266114Sdes time_t leeway = ((struct reply_info*)e-> 981238106Sdes data)->ttl - *worker->env.now; 982238106Sdes lock_rw_unlock(&e->lock); 983238106Sdes reply_and_prefetch(worker, &qinfo, 984266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), 985238106Sdes repinfo, leeway); 986276605Sdes rc = 0; 987276605Sdes goto send_reply_rc; 988238106Sdes } 989238106Sdes lock_rw_unlock(&e->lock); 990276605Sdes goto send_reply; 991238106Sdes } 992238106Sdes verbose(VERB_ALGO, "answer from the cache failed"); 993238106Sdes lock_rw_unlock(&e->lock); 994238106Sdes } 995266114Sdes if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { 996238106Sdes if(answer_norec_from_cache(worker, &qinfo, 997266114Sdes *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 998266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 999238106Sdes &edns)) { 1000276605Sdes goto send_reply; 1001238106Sdes } 1002238106Sdes verbose(VERB_ALGO, "answer norec from cache -- " 1003238106Sdes "need to validate or not primed"); 1004238106Sdes } 1005266114Sdes sldns_buffer_rewind(c->buffer); 1006238106Sdes server_stats_querymiss(&worker->stats, worker); 1007238106Sdes 1008238106Sdes if(verbosity >= VERB_CLIENT) { 1009238106Sdes if(c->type == comm_udp) 1010238106Sdes log_addr(VERB_CLIENT, "udp request from", 1011238106Sdes &repinfo->addr, repinfo->addrlen); 1012238106Sdes else log_addr(VERB_CLIENT, "tcp request from", 1013238106Sdes &repinfo->addr, repinfo->addrlen); 1014238106Sdes } 1015238106Sdes 1016238106Sdes /* grab a work request structure for this new request */ 1017238106Sdes mesh_new_client(worker->env.mesh, &qinfo, 1018266114Sdes sldns_buffer_read_u16_at(c->buffer, 2), 1019276605Sdes &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer)); 1020238106Sdes worker_mem_report(worker, NULL); 1021238106Sdes return 0; 1022276605Sdes 1023276605Sdessend_reply: 1024276605Sdes rc = 1; 1025276605Sdessend_reply_rc: 1026276605Sdes#ifdef USE_DNSTAP 1027276605Sdes if(worker->dtenv.log_client_response_messages) 1028276605Sdes dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, 1029276605Sdes c->type, c->buffer); 1030276605Sdes#endif 1031276605Sdes return rc; 1032238106Sdes} 1033238106Sdes 1034238106Sdesvoid 1035238106Sdesworker_sighandler(int sig, void* arg) 1036238106Sdes{ 1037276605Sdes /* note that log, print, syscalls here give race conditions. 1038276605Sdes * And cause hangups if the log-lock is held by the application. */ 1039238106Sdes struct worker* worker = (struct worker*)arg; 1040238106Sdes switch(sig) { 1041238106Sdes#ifdef SIGHUP 1042238106Sdes case SIGHUP: 1043238106Sdes comm_base_exit(worker->base); 1044238106Sdes break; 1045238106Sdes#endif 1046238106Sdes case SIGINT: 1047238106Sdes worker->need_to_exit = 1; 1048238106Sdes comm_base_exit(worker->base); 1049238106Sdes break; 1050238106Sdes#ifdef SIGQUIT 1051238106Sdes case SIGQUIT: 1052238106Sdes worker->need_to_exit = 1; 1053238106Sdes comm_base_exit(worker->base); 1054238106Sdes break; 1055238106Sdes#endif 1056238106Sdes case SIGTERM: 1057238106Sdes worker->need_to_exit = 1; 1058238106Sdes comm_base_exit(worker->base); 1059238106Sdes break; 1060238106Sdes default: 1061276605Sdes /* unknown signal, ignored */ 1062238106Sdes break; 1063238106Sdes } 1064238106Sdes} 1065238106Sdes 1066238106Sdes/** restart statistics timer for worker, if enabled */ 1067238106Sdesstatic void 1068238106Sdesworker_restart_timer(struct worker* worker) 1069238106Sdes{ 1070238106Sdes if(worker->env.cfg->stat_interval > 0) { 1071238106Sdes struct timeval tv; 1072238106Sdes#ifndef S_SPLINT_S 1073238106Sdes tv.tv_sec = worker->env.cfg->stat_interval; 1074238106Sdes tv.tv_usec = 0; 1075238106Sdes#endif 1076238106Sdes comm_timer_set(worker->stat_timer, &tv); 1077238106Sdes } 1078238106Sdes} 1079238106Sdes 1080238106Sdesvoid worker_stat_timer_cb(void* arg) 1081238106Sdes{ 1082238106Sdes struct worker* worker = (struct worker*)arg; 1083238106Sdes server_stats_log(&worker->stats, worker, worker->thread_num); 1084238106Sdes mesh_stats(worker->env.mesh, "mesh has"); 1085238106Sdes worker_mem_report(worker, NULL); 1086238106Sdes if(!worker->daemon->cfg->stat_cumulative) { 1087238106Sdes worker_stats_clear(worker); 1088238106Sdes } 1089238106Sdes /* start next timer */ 1090238106Sdes worker_restart_timer(worker); 1091238106Sdes} 1092238106Sdes 1093238106Sdesvoid worker_probe_timer_cb(void* arg) 1094238106Sdes{ 1095238106Sdes struct worker* worker = (struct worker*)arg; 1096238106Sdes struct timeval tv; 1097238106Sdes#ifndef S_SPLINT_S 1098238106Sdes tv.tv_sec = (time_t)autr_probe_timer(&worker->env); 1099238106Sdes tv.tv_usec = 0; 1100238106Sdes#endif 1101238106Sdes if(tv.tv_sec != 0) 1102238106Sdes comm_timer_set(worker->env.probe_timer, &tv); 1103238106Sdes} 1104238106Sdes 1105238106Sdesstruct worker* 1106238106Sdesworker_create(struct daemon* daemon, int id, int* ports, int n) 1107238106Sdes{ 1108238106Sdes unsigned int seed; 1109238106Sdes struct worker* worker = (struct worker*)calloc(1, 1110238106Sdes sizeof(struct worker)); 1111238106Sdes if(!worker) 1112238106Sdes return NULL; 1113238106Sdes worker->numports = n; 1114238106Sdes worker->ports = (int*)memdup(ports, sizeof(int)*n); 1115238106Sdes if(!worker->ports) { 1116238106Sdes free(worker); 1117238106Sdes return NULL; 1118238106Sdes } 1119238106Sdes worker->daemon = daemon; 1120238106Sdes worker->thread_num = id; 1121238106Sdes if(!(worker->cmd = tube_create())) { 1122238106Sdes free(worker->ports); 1123238106Sdes free(worker); 1124238106Sdes return NULL; 1125238106Sdes } 1126238106Sdes /* create random state here to avoid locking trouble in RAND_bytes */ 1127238106Sdes seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ 1128238106Sdes (((unsigned int)worker->thread_num)<<17); 1129238106Sdes /* shift thread_num so it does not match out pid bits */ 1130238106Sdes if(!(worker->rndstate = ub_initstate(seed, daemon->rand))) { 1131238106Sdes seed = 0; 1132238106Sdes log_err("could not init random numbers."); 1133238106Sdes tube_delete(worker->cmd); 1134238106Sdes free(worker->ports); 1135238106Sdes free(worker); 1136238106Sdes return NULL; 1137238106Sdes } 1138238106Sdes seed = 0; 1139276605Sdes#ifdef USE_DNSTAP 1140276605Sdes if(daemon->cfg->dnstap) { 1141276605Sdes log_assert(daemon->dtenv != NULL); 1142276605Sdes memcpy(&worker->dtenv, daemon->dtenv, sizeof(struct dt_env)); 1143276605Sdes if(!dt_init(&worker->dtenv)) 1144276605Sdes fatal_exit("dt_init failed"); 1145276605Sdes } 1146276605Sdes#endif 1147238106Sdes return worker; 1148238106Sdes} 1149238106Sdes 1150238106Sdesint 1151238106Sdesworker_init(struct worker* worker, struct config_file *cfg, 1152238106Sdes struct listen_port* ports, int do_sigs) 1153238106Sdes{ 1154276605Sdes#ifdef USE_DNSTAP 1155276605Sdes struct dt_env* dtenv = &worker->dtenv; 1156276605Sdes#else 1157276605Sdes void* dtenv = NULL; 1158276605Sdes#endif 1159238106Sdes worker->need_to_exit = 0; 1160238106Sdes worker->base = comm_base_create(do_sigs); 1161238106Sdes if(!worker->base) { 1162238106Sdes log_err("could not create event handling base"); 1163238106Sdes worker_delete(worker); 1164238106Sdes return 0; 1165238106Sdes } 1166238106Sdes comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept, 1167238106Sdes &worker_start_accept, worker); 1168238106Sdes if(do_sigs) { 1169238106Sdes#ifdef SIGHUP 1170238106Sdes ub_thread_sig_unblock(SIGHUP); 1171238106Sdes#endif 1172238106Sdes ub_thread_sig_unblock(SIGINT); 1173238106Sdes#ifdef SIGQUIT 1174238106Sdes ub_thread_sig_unblock(SIGQUIT); 1175238106Sdes#endif 1176238106Sdes ub_thread_sig_unblock(SIGTERM); 1177238106Sdes#ifndef LIBEVENT_SIGNAL_PROBLEM 1178238106Sdes worker->comsig = comm_signal_create(worker->base, 1179238106Sdes worker_sighandler, worker); 1180238106Sdes if(!worker->comsig 1181238106Sdes#ifdef SIGHUP 1182238106Sdes || !comm_signal_bind(worker->comsig, SIGHUP) 1183238106Sdes#endif 1184238106Sdes#ifdef SIGQUIT 1185238106Sdes || !comm_signal_bind(worker->comsig, SIGQUIT) 1186238106Sdes#endif 1187238106Sdes || !comm_signal_bind(worker->comsig, SIGTERM) 1188238106Sdes || !comm_signal_bind(worker->comsig, SIGINT)) { 1189238106Sdes log_err("could not create signal handlers"); 1190238106Sdes worker_delete(worker); 1191238106Sdes return 0; 1192238106Sdes } 1193238106Sdes#endif /* LIBEVENT_SIGNAL_PROBLEM */ 1194238106Sdes if(!daemon_remote_open_accept(worker->daemon->rc, 1195238106Sdes worker->daemon->rc_ports, worker)) { 1196238106Sdes worker_delete(worker); 1197238106Sdes return 0; 1198238106Sdes } 1199238106Sdes#ifdef UB_ON_WINDOWS 1200238106Sdes wsvc_setup_worker(worker); 1201238106Sdes#endif /* UB_ON_WINDOWS */ 1202238106Sdes } else { /* !do_sigs */ 1203238106Sdes worker->comsig = NULL; 1204238106Sdes } 1205238106Sdes worker->front = listen_create(worker->base, ports, 1206238106Sdes cfg->msg_buffer_size, (int)cfg->incoming_num_tcp, 1207276605Sdes worker->daemon->listen_sslctx, dtenv, worker_handle_request, 1208276605Sdes worker); 1209238106Sdes if(!worker->front) { 1210238106Sdes log_err("could not create listening sockets"); 1211238106Sdes worker_delete(worker); 1212238106Sdes return 0; 1213238106Sdes } 1214238106Sdes worker->back = outside_network_create(worker->base, 1215238106Sdes cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, 1216238106Sdes cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 1217238106Sdes cfg->do_tcp?cfg->outgoing_num_tcp:0, 1218238106Sdes worker->daemon->env->infra_cache, worker->rndstate, 1219238106Sdes cfg->use_caps_bits_for_id, worker->ports, worker->numports, 1220296415Sdes cfg->unwanted_threshold, cfg->outgoing_tcp_mss, 1221296415Sdes &worker_alloc_cleanup, worker, 1222276605Sdes cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close, 1223276605Sdes dtenv); 1224238106Sdes if(!worker->back) { 1225238106Sdes log_err("could not create outgoing sockets"); 1226238106Sdes worker_delete(worker); 1227238106Sdes return 0; 1228238106Sdes } 1229238106Sdes /* start listening to commands */ 1230238106Sdes if(!tube_setup_bg_listen(worker->cmd, worker->base, 1231238106Sdes &worker_handle_control_cmd, worker)) { 1232238106Sdes log_err("could not create control compt."); 1233238106Sdes worker_delete(worker); 1234238106Sdes return 0; 1235238106Sdes } 1236238106Sdes worker->stat_timer = comm_timer_create(worker->base, 1237238106Sdes worker_stat_timer_cb, worker); 1238238106Sdes if(!worker->stat_timer) { 1239238106Sdes log_err("could not create statistics timer"); 1240238106Sdes } 1241238106Sdes 1242238106Sdes /* we use the msg_buffer_size as a good estimate for what the 1243238106Sdes * user wants for memory usage sizes */ 1244238106Sdes worker->scratchpad = regional_create_custom(cfg->msg_buffer_size); 1245238106Sdes if(!worker->scratchpad) { 1246238106Sdes log_err("malloc failure"); 1247238106Sdes worker_delete(worker); 1248238106Sdes return 0; 1249238106Sdes } 1250238106Sdes 1251238106Sdes server_stats_init(&worker->stats, cfg); 1252238106Sdes alloc_init(&worker->alloc, &worker->daemon->superalloc, 1253238106Sdes worker->thread_num); 1254238106Sdes alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker); 1255238106Sdes worker->env = *worker->daemon->env; 1256238106Sdes comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); 1257238106Sdes if(worker->thread_num == 0) 1258238106Sdes log_set_time(worker->env.now); 1259238106Sdes worker->env.worker = worker; 1260238106Sdes worker->env.send_query = &worker_send_query; 1261238106Sdes worker->env.alloc = &worker->alloc; 1262238106Sdes worker->env.rnd = worker->rndstate; 1263238106Sdes worker->env.scratch = worker->scratchpad; 1264238106Sdes worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); 1265238106Sdes worker->env.detach_subs = &mesh_detach_subs; 1266238106Sdes worker->env.attach_sub = &mesh_attach_sub; 1267238106Sdes worker->env.kill_sub = &mesh_state_delete; 1268238106Sdes worker->env.detect_cycle = &mesh_detect_cycle; 1269266114Sdes worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); 1270238106Sdes if(!(worker->env.fwds = forwards_create()) || 1271238106Sdes !forwards_apply_cfg(worker->env.fwds, cfg)) { 1272238106Sdes log_err("Could not set forward zones"); 1273238106Sdes worker_delete(worker); 1274238106Sdes return 0; 1275238106Sdes } 1276238106Sdes if(!(worker->env.hints = hints_create()) || 1277238106Sdes !hints_apply_cfg(worker->env.hints, cfg)) { 1278238106Sdes log_err("Could not set root or stub hints"); 1279238106Sdes worker_delete(worker); 1280238106Sdes return 0; 1281238106Sdes } 1282238106Sdes /* one probe timer per process -- if we have 5011 anchors */ 1283238106Sdes if(autr_get_num_anchors(worker->env.anchors) > 0 1284238106Sdes#ifndef THREADS_DISABLED 1285238106Sdes && worker->thread_num == 0 1286238106Sdes#endif 1287238106Sdes ) { 1288238106Sdes struct timeval tv; 1289238106Sdes tv.tv_sec = 0; 1290238106Sdes tv.tv_usec = 0; 1291238106Sdes worker->env.probe_timer = comm_timer_create(worker->base, 1292238106Sdes worker_probe_timer_cb, worker); 1293238106Sdes if(!worker->env.probe_timer) { 1294238106Sdes log_err("could not create 5011-probe timer"); 1295238106Sdes } else { 1296238106Sdes /* let timer fire, then it can reset itself */ 1297238106Sdes comm_timer_set(worker->env.probe_timer, &tv); 1298238106Sdes } 1299238106Sdes } 1300238106Sdes if(!worker->env.mesh || !worker->env.scratch_buffer) { 1301238106Sdes worker_delete(worker); 1302238106Sdes return 0; 1303238106Sdes } 1304238106Sdes worker_mem_report(worker, NULL); 1305238106Sdes /* if statistics enabled start timer */ 1306238106Sdes if(worker->env.cfg->stat_interval > 0) { 1307238106Sdes verbose(VERB_ALGO, "set statistics interval %d secs", 1308238106Sdes worker->env.cfg->stat_interval); 1309238106Sdes worker_restart_timer(worker); 1310238106Sdes } 1311238106Sdes return 1; 1312238106Sdes} 1313238106Sdes 1314238106Sdesvoid 1315238106Sdesworker_work(struct worker* worker) 1316238106Sdes{ 1317238106Sdes comm_base_dispatch(worker->base); 1318238106Sdes} 1319238106Sdes 1320238106Sdesvoid 1321238106Sdesworker_delete(struct worker* worker) 1322238106Sdes{ 1323238106Sdes if(!worker) 1324238106Sdes return; 1325238106Sdes if(worker->env.mesh && verbosity >= VERB_OPS) { 1326238106Sdes server_stats_log(&worker->stats, worker, worker->thread_num); 1327238106Sdes mesh_stats(worker->env.mesh, "mesh has"); 1328238106Sdes worker_mem_report(worker, NULL); 1329238106Sdes } 1330238106Sdes outside_network_quit_prepare(worker->back); 1331238106Sdes mesh_delete(worker->env.mesh); 1332266114Sdes sldns_buffer_free(worker->env.scratch_buffer); 1333238106Sdes forwards_delete(worker->env.fwds); 1334238106Sdes hints_delete(worker->env.hints); 1335238106Sdes listen_delete(worker->front); 1336238106Sdes outside_network_delete(worker->back); 1337238106Sdes comm_signal_delete(worker->comsig); 1338238106Sdes tube_delete(worker->cmd); 1339238106Sdes comm_timer_delete(worker->stat_timer); 1340238106Sdes comm_timer_delete(worker->env.probe_timer); 1341238106Sdes free(worker->ports); 1342238106Sdes if(worker->thread_num == 0) { 1343238106Sdes log_set_time(NULL); 1344238106Sdes#ifdef UB_ON_WINDOWS 1345238106Sdes wsvc_desetup_worker(worker); 1346238106Sdes#endif /* UB_ON_WINDOWS */ 1347238106Sdes } 1348238106Sdes comm_base_delete(worker->base); 1349238106Sdes ub_randfree(worker->rndstate); 1350238106Sdes alloc_clear(&worker->alloc); 1351238106Sdes regional_destroy(worker->scratchpad); 1352238106Sdes free(worker); 1353238106Sdes} 1354238106Sdes 1355238106Sdesstruct outbound_entry* 1356238106Sdesworker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, 1357238106Sdes uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, 1358276605Sdes int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, 1359276605Sdes uint8_t* zone, size_t zonelen, struct module_qstate* q) 1360238106Sdes{ 1361238106Sdes struct worker* worker = q->env->worker; 1362238106Sdes struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 1363238106Sdes q->region, sizeof(*e)); 1364238106Sdes if(!e) 1365238106Sdes return NULL; 1366238106Sdes e->qstate = q; 1367238106Sdes e->qsent = outnet_serviced_query(worker->back, qname, 1368276605Sdes qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, 1369238106Sdes q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr, 1370238106Sdes addrlen, zone, zonelen, worker_handle_service_reply, e, 1371249141Sdes worker->back->udp_buff); 1372238106Sdes if(!e->qsent) { 1373238106Sdes return NULL; 1374238106Sdes } 1375238106Sdes return e; 1376238106Sdes} 1377238106Sdes 1378238106Sdesvoid 1379238106Sdesworker_alloc_cleanup(void* arg) 1380238106Sdes{ 1381238106Sdes struct worker* worker = (struct worker*)arg; 1382238106Sdes slabhash_clear(&worker->env.rrset_cache->table); 1383238106Sdes slabhash_clear(worker->env.msg_cache); 1384238106Sdes} 1385238106Sdes 1386238106Sdesvoid worker_stats_clear(struct worker* worker) 1387238106Sdes{ 1388238106Sdes server_stats_init(&worker->stats, worker->env.cfg); 1389238106Sdes mesh_stats_clear(worker->env.mesh); 1390238106Sdes worker->back->unwanted_replies = 0; 1391276605Sdes worker->back->num_tcp_outgoing = 0; 1392238106Sdes} 1393238106Sdes 1394238106Sdesvoid worker_start_accept(void* arg) 1395238106Sdes{ 1396238106Sdes struct worker* worker = (struct worker*)arg; 1397238106Sdes listen_start_accept(worker->front); 1398238106Sdes if(worker->thread_num == 0) 1399238106Sdes daemon_remote_start_accept(worker->daemon->rc); 1400238106Sdes} 1401238106Sdes 1402238106Sdesvoid worker_stop_accept(void* arg) 1403238106Sdes{ 1404238106Sdes struct worker* worker = (struct worker*)arg; 1405238106Sdes listen_stop_accept(worker->front); 1406238106Sdes if(worker->thread_num == 0) 1407238106Sdes daemon_remote_stop_accept(worker->daemon->rc); 1408238106Sdes} 1409238106Sdes 1410238106Sdes/* --- fake callbacks for fptr_wlist to work --- */ 1411238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), 1412238106Sdes size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), 1413238106Sdes uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), 1414238106Sdes int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), 1415276605Sdes int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), 1416255579Sdes socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), 1417255579Sdes size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) 1418238106Sdes{ 1419238106Sdes log_assert(0); 1420238106Sdes return 0; 1421238106Sdes} 1422238106Sdes 1423238106Sdesint libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), 1424238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 1425238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 1426238106Sdes{ 1427238106Sdes log_assert(0); 1428238106Sdes return 0; 1429238106Sdes} 1430238106Sdes 1431238106Sdesint libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 1432238106Sdes void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 1433238106Sdes struct comm_reply* ATTR_UNUSED(reply_info)) 1434238106Sdes{ 1435238106Sdes log_assert(0); 1436238106Sdes return 0; 1437238106Sdes} 1438238106Sdes 1439238106Sdesvoid libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 1440238106Sdes uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 1441238106Sdes int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 1442238106Sdes{ 1443238106Sdes log_assert(0); 1444238106Sdes} 1445238106Sdes 1446238106Sdesvoid libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1447266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1448238106Sdes char* ATTR_UNUSED(why_bogus)) 1449238106Sdes{ 1450238106Sdes log_assert(0); 1451238106Sdes} 1452238106Sdes 1453238106Sdesvoid libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1454266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1455238106Sdes char* ATTR_UNUSED(why_bogus)) 1456238106Sdes{ 1457238106Sdes log_assert(0); 1458238106Sdes} 1459238106Sdes 1460266114Sdesvoid libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 1461266114Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 1462266114Sdes char* ATTR_UNUSED(why_bogus)) 1463266114Sdes{ 1464266114Sdes log_assert(0); 1465266114Sdes} 1466266114Sdes 1467238106Sdesint context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1468238106Sdes{ 1469238106Sdes log_assert(0); 1470238106Sdes return 0; 1471238106Sdes} 1472238106Sdes 1473238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 1474238106Sdes{ 1475238106Sdes log_assert(0); 1476238106Sdes return 0; 1477238106Sdes} 1478238106Sdes 1479238106Sdesint codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 1480238106Sdes{ 1481238106Sdes log_assert(0); 1482238106Sdes return 0; 1483238106Sdes} 1484238106Sdes 1485