1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * daemon/worker.c - worker that handles a pending list of requests. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file implements the worker that handles callbacks on events, for 40b7579f77SDag-Erling Smørgrav * pending requests. 41b7579f77SDag-Erling Smørgrav */ 42b7579f77SDag-Erling Smørgrav #include "config.h" 43b7579f77SDag-Erling Smørgrav #include "util/log.h" 44b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 45b7579f77SDag-Erling Smørgrav #include "util/random.h" 46b7579f77SDag-Erling Smørgrav #include "daemon/worker.h" 47b7579f77SDag-Erling Smørgrav #include "daemon/daemon.h" 48b7579f77SDag-Erling Smørgrav #include "daemon/remote.h" 49b7579f77SDag-Erling Smørgrav #include "daemon/acl_list.h" 50b7579f77SDag-Erling Smørgrav #include "util/netevent.h" 51b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 52b7579f77SDag-Erling Smørgrav #include "util/module.h" 53b7579f77SDag-Erling Smørgrav #include "util/regional.h" 54b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 55b7579f77SDag-Erling Smørgrav #include "services/listen_dnsport.h" 56b7579f77SDag-Erling Smørgrav #include "services/outside_network.h" 57b7579f77SDag-Erling Smørgrav #include "services/outbound_list.h" 58b7579f77SDag-Erling Smørgrav #include "services/cache/rrset.h" 59b7579f77SDag-Erling Smørgrav #include "services/cache/infra.h" 60b7579f77SDag-Erling Smørgrav #include "services/cache/dns.h" 6157bddd21SDag-Erling Smørgrav #include "services/authzone.h" 62b7579f77SDag-Erling Smørgrav #include "services/mesh.h" 63b7579f77SDag-Erling Smørgrav #include "services/localzone.h" 64091e9e46SCy Schubert #include "services/rpz.h" 65b7579f77SDag-Erling Smørgrav #include "util/data/msgparse.h" 66b7579f77SDag-Erling Smørgrav #include "util/data/msgencode.h" 67b7579f77SDag-Erling Smørgrav #include "util/data/dname.h" 68b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h" 69103ba509SCy Schubert #include "util/proxy_protocol.h" 70b7579f77SDag-Erling Smørgrav #include "util/tube.h" 714c75e3aaSDag-Erling Smørgrav #include "util/edns.h" 728f76bb7dSCy Schubert #include "util/timeval_func.h" 73b7579f77SDag-Erling Smørgrav #include "iterator/iter_fwd.h" 74b7579f77SDag-Erling Smørgrav #include "iterator/iter_hints.h" 755469a995SCy Schubert #include "iterator/iter_utils.h" 76b7579f77SDag-Erling Smørgrav #include "validator/autotrust.h" 77b7579f77SDag-Erling Smørgrav #include "validator/val_anchor.h" 7865b390aaSDag-Erling Smørgrav #include "respip/respip.h" 7904b59eacSDag-Erling Smørgrav #include "libunbound/context.h" 8004b59eacSDag-Erling Smørgrav #include "libunbound/libworker.h" 8109a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h" 8265b390aaSDag-Erling Smørgrav #include "sldns/wire2str.h" 8365b390aaSDag-Erling Smørgrav #include "util/shm_side/shm_main.h" 8465b390aaSDag-Erling Smørgrav #include "dnscrypt/dnscrypt.h" 8525039b37SCy Schubert #include "dnstap/dtstream.h" 86b7579f77SDag-Erling Smørgrav 87b7579f77SDag-Erling Smørgrav #ifdef HAVE_SYS_TYPES_H 88b7579f77SDag-Erling Smørgrav # include <sys/types.h> 89b7579f77SDag-Erling Smørgrav #endif 90b7579f77SDag-Erling Smørgrav #ifdef HAVE_NETDB_H 91b7579f77SDag-Erling Smørgrav #include <netdb.h> 92b7579f77SDag-Erling Smørgrav #endif 93b7579f77SDag-Erling Smørgrav #include <signal.h> 94b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 95b7579f77SDag-Erling Smørgrav #include "winrc/win_svc.h" 96b7579f77SDag-Erling Smørgrav #endif 97b7579f77SDag-Erling Smørgrav 98b7579f77SDag-Erling Smørgrav /** Size of an UDP datagram */ 99b7579f77SDag-Erling Smørgrav #define NORMAL_UDP_SIZE 512 /* bytes */ 10009a3aaf3SDag-Erling Smørgrav /** ratelimit for error responses */ 10109a3aaf3SDag-Erling Smørgrav #define ERROR_RATELIMIT 100 /* qps */ 102b7579f77SDag-Erling Smørgrav 103b7579f77SDag-Erling Smørgrav /** 104b7579f77SDag-Erling Smørgrav * seconds to add to prefetch leeway. This is a TTL that expires old rrsets 105b7579f77SDag-Erling Smørgrav * earlier than they should in order to put the new update into the cache. 106b7579f77SDag-Erling Smørgrav * This additional value is to make sure that if not all TTLs are equal in 107b7579f77SDag-Erling Smørgrav * the message to be updated(and replaced), that rrsets with up to this much 108b7579f77SDag-Erling Smørgrav * extra TTL are also replaced. This means that the resulting new message 109b7579f77SDag-Erling Smørgrav * will have (most likely) this TTL at least, avoiding very small 'split 110b7579f77SDag-Erling Smørgrav * second' TTLs due to operators choosing relative primes for TTLs (or so). 111b7579f77SDag-Erling Smørgrav * Also has to be at least one to break ties (and overwrite cached entry). 112b7579f77SDag-Erling Smørgrav */ 113b7579f77SDag-Erling Smørgrav #define PREFETCH_EXPIRY_ADD 60 114b7579f77SDag-Erling Smørgrav 115b7579f77SDag-Erling Smørgrav /** Report on memory usage by this thread and global */ 116b7579f77SDag-Erling Smørgrav static void 117b7579f77SDag-Erling Smørgrav worker_mem_report(struct worker* ATTR_UNUSED(worker), 118b7579f77SDag-Erling Smørgrav struct serviced_query* ATTR_UNUSED(cur_serv)) 119b7579f77SDag-Erling Smørgrav { 120b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_ALLOC_STATS 121bc892140SDag-Erling Smørgrav /* measure memory leakage */ 122bc892140SDag-Erling Smørgrav extern size_t unbound_mem_alloc, unbound_mem_freed; 123b7579f77SDag-Erling Smørgrav /* debug func in validator module */ 124b7579f77SDag-Erling Smørgrav size_t total, front, back, mesh, msg, rrset, infra, ac, superac; 125b7579f77SDag-Erling Smørgrav size_t me, iter, val, anch; 126b7579f77SDag-Erling Smørgrav int i; 12765b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 12865b390aaSDag-Erling Smørgrav size_t subnet = 0; 12965b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 130b7579f77SDag-Erling Smørgrav if(verbosity < VERB_ALGO) 131b7579f77SDag-Erling Smørgrav return; 132b7579f77SDag-Erling Smørgrav front = listen_get_mem(worker->front); 133b7579f77SDag-Erling Smørgrav back = outnet_get_mem(worker->back); 134b7579f77SDag-Erling Smørgrav msg = slabhash_get_mem(worker->env.msg_cache); 135b7579f77SDag-Erling Smørgrav rrset = slabhash_get_mem(&worker->env.rrset_cache->table); 136b7579f77SDag-Erling Smørgrav infra = infra_get_mem(worker->env.infra_cache); 137b7579f77SDag-Erling Smørgrav mesh = mesh_get_mem(worker->env.mesh); 1381838dec3SCy Schubert ac = alloc_get_mem(worker->alloc); 139b7579f77SDag-Erling Smørgrav superac = alloc_get_mem(&worker->daemon->superalloc); 140b7579f77SDag-Erling Smørgrav anch = anchors_get_mem(worker->env.anchors); 141b7579f77SDag-Erling Smørgrav iter = 0; 142b7579f77SDag-Erling Smørgrav val = 0; 143b7579f77SDag-Erling Smørgrav for(i=0; i<worker->env.mesh->mods.num; i++) { 144b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 145b7579f77SDag-Erling Smørgrav mods.mod[i]->get_mem)); 146b7579f77SDag-Erling Smørgrav if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 147b7579f77SDag-Erling Smørgrav val += (*worker->env.mesh->mods.mod[i]->get_mem) 148b7579f77SDag-Erling Smørgrav (&worker->env, i); 14965b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 15065b390aaSDag-Erling Smørgrav else if(strcmp(worker->env.mesh->mods.mod[i]->name, 15124e36522SCy Schubert "subnetcache")==0) 15265b390aaSDag-Erling Smørgrav subnet += (*worker->env.mesh->mods.mod[i]->get_mem) 15365b390aaSDag-Erling Smørgrav (&worker->env, i); 15465b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 155b7579f77SDag-Erling Smørgrav else iter += (*worker->env.mesh->mods.mod[i]->get_mem) 156b7579f77SDag-Erling Smørgrav (&worker->env, i); 157b7579f77SDag-Erling Smørgrav } 158b7579f77SDag-Erling Smørgrav me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig) 159b7579f77SDag-Erling Smørgrav + comm_point_get_mem(worker->cmd_com) 160b7579f77SDag-Erling Smørgrav + sizeof(worker->rndstate) 161b7579f77SDag-Erling Smørgrav + regional_get_mem(worker->scratchpad) 162b7579f77SDag-Erling Smørgrav + sizeof(*worker->env.scratch_buffer) 16356850988SCy Schubert + sldns_buffer_capacity(worker->env.scratch_buffer); 16456850988SCy Schubert if(worker->daemon->env->fwds) 16556850988SCy Schubert log_info("forwards=%u", (unsigned)forwards_get_mem(worker->env.fwds)); 16656850988SCy Schubert if(worker->daemon->env->hints) 16756850988SCy Schubert log_info("hints=%u", (unsigned)hints_get_mem(worker->env.hints)); 168b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) 169b7579f77SDag-Erling Smørgrav me += acl_list_get_mem(worker->daemon->acl); 170b7579f77SDag-Erling Smørgrav if(cur_serv) { 171b7579f77SDag-Erling Smørgrav me += serviced_get_mem(cur_serv); 172b7579f77SDag-Erling Smørgrav } 173b7579f77SDag-Erling Smørgrav total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me; 17465b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 17565b390aaSDag-Erling Smørgrav total += subnet; 17665b390aaSDag-Erling Smørgrav log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " 17765b390aaSDag-Erling Smørgrav "rrset=%u infra=%u iter=%u val=%u subnet=%u anchors=%u " 17865b390aaSDag-Erling Smørgrav "alloccache=%u globalalloccache=%u me=%u", 17965b390aaSDag-Erling Smørgrav (unsigned)total, (unsigned)front, (unsigned)back, 18065b390aaSDag-Erling Smørgrav (unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra, 18165b390aaSDag-Erling Smørgrav (unsigned)iter, (unsigned)val, 18265b390aaSDag-Erling Smørgrav (unsigned)subnet, (unsigned)anch, (unsigned)ac, 18365b390aaSDag-Erling Smørgrav (unsigned)superac, (unsigned)me); 18465b390aaSDag-Erling Smørgrav #else /* no CLIENT_SUBNET */ 185b7579f77SDag-Erling Smørgrav log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u " 186b7579f77SDag-Erling Smørgrav "rrset=%u infra=%u iter=%u val=%u anchors=%u " 187b7579f77SDag-Erling Smørgrav "alloccache=%u globalalloccache=%u me=%u", 188b7579f77SDag-Erling Smørgrav (unsigned)total, (unsigned)front, (unsigned)back, 189b7579f77SDag-Erling Smørgrav (unsigned)mesh, (unsigned)msg, (unsigned)rrset, 190b7579f77SDag-Erling Smørgrav (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, 191b7579f77SDag-Erling Smørgrav (unsigned)ac, (unsigned)superac, (unsigned)me); 19265b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 193bc892140SDag-Erling Smørgrav log_info("Total heap memory estimate: %u total-alloc: %u " 194bc892140SDag-Erling Smørgrav "total-free: %u", (unsigned)total, 195bc892140SDag-Erling Smørgrav (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); 196b7579f77SDag-Erling Smørgrav #else /* no UNBOUND_ALLOC_STATS */ 197b7579f77SDag-Erling Smørgrav size_t val = 0; 19865b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 19965b390aaSDag-Erling Smørgrav size_t subnet = 0; 20065b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 201b7579f77SDag-Erling Smørgrav int i; 202b7579f77SDag-Erling Smørgrav if(verbosity < VERB_QUERY) 203b7579f77SDag-Erling Smørgrav return; 204b7579f77SDag-Erling Smørgrav for(i=0; i<worker->env.mesh->mods.num; i++) { 205b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh-> 206b7579f77SDag-Erling Smørgrav mods.mod[i]->get_mem)); 207b7579f77SDag-Erling Smørgrav if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0) 208b7579f77SDag-Erling Smørgrav val += (*worker->env.mesh->mods.mod[i]->get_mem) 209b7579f77SDag-Erling Smørgrav (&worker->env, i); 21065b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 21165b390aaSDag-Erling Smørgrav else if(strcmp(worker->env.mesh->mods.mod[i]->name, 21224e36522SCy Schubert "subnetcache")==0) 21365b390aaSDag-Erling Smørgrav subnet += (*worker->env.mesh->mods.mod[i]->get_mem) 21465b390aaSDag-Erling Smørgrav (&worker->env, i); 21565b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 216b7579f77SDag-Erling Smørgrav } 21765b390aaSDag-Erling Smørgrav #ifdef CLIENT_SUBNET 21865b390aaSDag-Erling Smørgrav verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u " 21965b390aaSDag-Erling Smørgrav "subnet=%u", 22065b390aaSDag-Erling Smørgrav (unsigned)slabhash_get_mem(worker->env.msg_cache), 22165b390aaSDag-Erling Smørgrav (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), 22265b390aaSDag-Erling Smørgrav (unsigned)infra_get_mem(worker->env.infra_cache), 22365b390aaSDag-Erling Smørgrav (unsigned)val, (unsigned)subnet); 22465b390aaSDag-Erling Smørgrav #else /* no CLIENT_SUBNET */ 225b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u", 226b7579f77SDag-Erling Smørgrav (unsigned)slabhash_get_mem(worker->env.msg_cache), 227b7579f77SDag-Erling Smørgrav (unsigned)slabhash_get_mem(&worker->env.rrset_cache->table), 228b7579f77SDag-Erling Smørgrav (unsigned)infra_get_mem(worker->env.infra_cache), 229b7579f77SDag-Erling Smørgrav (unsigned)val); 23065b390aaSDag-Erling Smørgrav #endif /* CLIENT_SUBNET */ 231b7579f77SDag-Erling Smørgrav #endif /* UNBOUND_ALLOC_STATS */ 232b7579f77SDag-Erling Smørgrav } 233b7579f77SDag-Erling Smørgrav 234b7579f77SDag-Erling Smørgrav void 235b7579f77SDag-Erling Smørgrav worker_send_cmd(struct worker* worker, enum worker_commands cmd) 236b7579f77SDag-Erling Smørgrav { 237b7579f77SDag-Erling Smørgrav uint32_t c = (uint32_t)htonl(cmd); 238b7579f77SDag-Erling Smørgrav if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) { 239b7579f77SDag-Erling Smørgrav log_err("worker send cmd %d failed", (int)cmd); 240b7579f77SDag-Erling Smørgrav } 241b7579f77SDag-Erling Smørgrav } 242b7579f77SDag-Erling Smørgrav 243b7579f77SDag-Erling Smørgrav int 244b7579f77SDag-Erling Smørgrav worker_handle_service_reply(struct comm_point* c, void* arg, int error, 245b7579f77SDag-Erling Smørgrav struct comm_reply* reply_info) 246b7579f77SDag-Erling Smørgrav { 247b7579f77SDag-Erling Smørgrav struct outbound_entry* e = (struct outbound_entry*)arg; 248b7579f77SDag-Erling Smørgrav struct worker* worker = e->qstate->env->worker; 249b7579f77SDag-Erling Smørgrav struct serviced_query *sq = e->qsent; 250b7579f77SDag-Erling Smørgrav 251b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); 252b7579f77SDag-Erling Smørgrav if(error != 0) { 253b7579f77SDag-Erling Smørgrav mesh_report_reply(worker->env.mesh, e, reply_info, error); 254b7579f77SDag-Erling Smørgrav worker_mem_report(worker, sq); 255b7579f77SDag-Erling Smørgrav return 0; 256b7579f77SDag-Erling Smørgrav } 257b7579f77SDag-Erling Smørgrav /* sanity check. */ 25817d15b25SDag-Erling Smørgrav if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer)) 25917d15b25SDag-Erling Smørgrav || LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) != 260b7579f77SDag-Erling Smørgrav LDNS_PACKET_QUERY 26117d15b25SDag-Erling Smørgrav || LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) { 262b7579f77SDag-Erling Smørgrav /* error becomes timeout for the module as if this reply 263b7579f77SDag-Erling Smørgrav * never arrived. */ 264b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker: bad reply handled as timeout"); 265b7579f77SDag-Erling Smørgrav mesh_report_reply(worker->env.mesh, e, reply_info, 266b7579f77SDag-Erling Smørgrav NETEVENT_TIMEOUT); 267b7579f77SDag-Erling Smørgrav worker_mem_report(worker, sq); 268b7579f77SDag-Erling Smørgrav return 0; 269b7579f77SDag-Erling Smørgrav } 270b7579f77SDag-Erling Smørgrav mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR); 271b7579f77SDag-Erling Smørgrav worker_mem_report(worker, sq); 272b7579f77SDag-Erling Smørgrav return 0; 273b7579f77SDag-Erling Smørgrav } 274b7579f77SDag-Erling Smørgrav 27509a3aaf3SDag-Erling Smørgrav /** ratelimit error replies 27609a3aaf3SDag-Erling Smørgrav * @param worker: the worker struct with ratelimit counter 27709a3aaf3SDag-Erling Smørgrav * @param err: error code that would be wanted. 27809a3aaf3SDag-Erling Smørgrav * @return value of err if okay, or -1 if it should be discarded instead. 27909a3aaf3SDag-Erling Smørgrav */ 28009a3aaf3SDag-Erling Smørgrav static int 28109a3aaf3SDag-Erling Smørgrav worker_err_ratelimit(struct worker* worker, int err) 28209a3aaf3SDag-Erling Smørgrav { 28309a3aaf3SDag-Erling Smørgrav if(worker->err_limit_time == *worker->env.now) { 28409a3aaf3SDag-Erling Smørgrav /* see if limit is exceeded for this second */ 28509a3aaf3SDag-Erling Smørgrav if(worker->err_limit_count++ > ERROR_RATELIMIT) 28609a3aaf3SDag-Erling Smørgrav return -1; 28709a3aaf3SDag-Erling Smørgrav } else { 28809a3aaf3SDag-Erling Smørgrav /* new second, new limits */ 28909a3aaf3SDag-Erling Smørgrav worker->err_limit_time = *worker->env.now; 29009a3aaf3SDag-Erling Smørgrav worker->err_limit_count = 1; 29109a3aaf3SDag-Erling Smørgrav } 29209a3aaf3SDag-Erling Smørgrav return err; 29309a3aaf3SDag-Erling Smørgrav } 29409a3aaf3SDag-Erling Smørgrav 2958f76bb7dSCy Schubert /** 2968f76bb7dSCy Schubert * Structure holding the result of the worker_check_request function. 2978f76bb7dSCy Schubert * Based on configuration it could be called up to four times; ideally should 2988f76bb7dSCy Schubert * be called once. 2998f76bb7dSCy Schubert */ 3008f76bb7dSCy Schubert struct check_request_result { 3018f76bb7dSCy Schubert int checked; 3028f76bb7dSCy Schubert int value; 3038f76bb7dSCy Schubert }; 304b7579f77SDag-Erling Smørgrav /** check request sanity. 305b7579f77SDag-Erling Smørgrav * @param pkt: the wire packet to examine for sanity. 306b7579f77SDag-Erling Smørgrav * @param worker: parameters for checking. 3078f76bb7dSCy Schubert * @param out: struct to update with the result. 308b7579f77SDag-Erling Smørgrav */ 3098f76bb7dSCy Schubert static void 3108f76bb7dSCy Schubert worker_check_request(sldns_buffer* pkt, struct worker* worker, 3118f76bb7dSCy Schubert struct check_request_result* out) 312b7579f77SDag-Erling Smørgrav { 3138f76bb7dSCy Schubert if(out->checked) return; 3148f76bb7dSCy Schubert out->checked = 1; 31517d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) { 316b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request too short, discarded"); 3178f76bb7dSCy Schubert out->value = -1; 3188f76bb7dSCy Schubert return; 319b7579f77SDag-Erling Smørgrav } 32017d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 321b7579f77SDag-Erling Smørgrav worker->daemon->cfg->harden_large_queries) { 322b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request too large, discarded"); 3238f76bb7dSCy Schubert out->value = -1; 3248f76bb7dSCy Schubert return; 325b7579f77SDag-Erling Smørgrav } 32617d15b25SDag-Erling Smørgrav if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) { 327b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request has QR bit on, discarded"); 3288f76bb7dSCy Schubert out->value = -1; 3298f76bb7dSCy Schubert return; 330b7579f77SDag-Erling Smørgrav } 33117d15b25SDag-Erling Smørgrav if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { 33217d15b25SDag-Erling Smørgrav LDNS_TC_CLR(sldns_buffer_begin(pkt)); 333b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request bad, has TC bit on"); 3348f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 3358f76bb7dSCy Schubert return; 336b7579f77SDag-Erling Smørgrav } 3370fb34990SDag-Erling Smørgrav if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY && 3380fb34990SDag-Erling Smørgrav LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) { 339b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request unknown opcode %d", 34017d15b25SDag-Erling Smørgrav LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt))); 3418f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL); 3428f76bb7dSCy Schubert return; 343b7579f77SDag-Erling Smørgrav } 34417d15b25SDag-Erling Smørgrav if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) { 345b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request wrong nr qd=%d", 34617d15b25SDag-Erling Smørgrav LDNS_QDCOUNT(sldns_buffer_begin(pkt))); 3478f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 3488f76bb7dSCy Schubert return; 349b7579f77SDag-Erling Smørgrav } 3500fb34990SDag-Erling Smørgrav if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 && 3510fb34990SDag-Erling Smørgrav (LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 || 3520fb34990SDag-Erling Smørgrav LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) { 353b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request wrong nr an=%d", 35417d15b25SDag-Erling Smørgrav LDNS_ANCOUNT(sldns_buffer_begin(pkt))); 3558f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 3568f76bb7dSCy Schubert return; 357b7579f77SDag-Erling Smørgrav } 35817d15b25SDag-Erling Smørgrav if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) { 359b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request wrong nr ns=%d", 36017d15b25SDag-Erling Smørgrav LDNS_NSCOUNT(sldns_buffer_begin(pkt))); 3618f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 3628f76bb7dSCy Schubert return; 363b7579f77SDag-Erling Smørgrav } 36417d15b25SDag-Erling Smørgrav if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { 365b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "request wrong nr ar=%d", 36617d15b25SDag-Erling Smørgrav LDNS_ARCOUNT(sldns_buffer_begin(pkt))); 3678f76bb7dSCy Schubert out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR); 3688f76bb7dSCy Schubert return; 369b7579f77SDag-Erling Smørgrav } 3708f76bb7dSCy Schubert out->value = 0; 3718f76bb7dSCy Schubert return; 372b7579f77SDag-Erling Smørgrav } 373b7579f77SDag-Erling Smørgrav 374*be771a7bSCy Schubert /** 375*be771a7bSCy Schubert * Send fast-reload acknowledgement to the mainthread in one byte. 376*be771a7bSCy Schubert * This signals that this worker has received the previous command. 377*be771a7bSCy Schubert * The worker is waiting if that is after a reload_stop command. 378*be771a7bSCy Schubert * Or the worker has briefly processed the event itself, and in doing so 379*be771a7bSCy Schubert * released data pointers to old config, after a reload_poll command. 380*be771a7bSCy Schubert */ 381*be771a7bSCy Schubert static void 382*be771a7bSCy Schubert worker_send_reload_ack(struct worker* worker) 383*be771a7bSCy Schubert { 384*be771a7bSCy Schubert /* If this is clipped to 8 bits because thread_num>255, then that 385*be771a7bSCy Schubert * is not a problem, the receiver counts the number of bytes received. 386*be771a7bSCy Schubert * The number is informative only. */ 387*be771a7bSCy Schubert uint8_t c = (uint8_t)worker->thread_num; 388*be771a7bSCy Schubert ssize_t ret; 389*be771a7bSCy Schubert while(1) { 390*be771a7bSCy Schubert ret = send(worker->daemon->fast_reload_thread->commreload[1], 391*be771a7bSCy Schubert (void*)&c, 1, 0); 392*be771a7bSCy Schubert if(ret == -1) { 393*be771a7bSCy Schubert if( 394*be771a7bSCy Schubert #ifndef USE_WINSOCK 395*be771a7bSCy Schubert errno == EINTR || errno == EAGAIN 396*be771a7bSCy Schubert # ifdef EWOULDBLOCK 397*be771a7bSCy Schubert || errno == EWOULDBLOCK 398*be771a7bSCy Schubert # endif 399*be771a7bSCy Schubert #else 400*be771a7bSCy Schubert WSAGetLastError() == WSAEINTR || 401*be771a7bSCy Schubert WSAGetLastError() == WSAEINPROGRESS || 402*be771a7bSCy Schubert WSAGetLastError() == WSAEWOULDBLOCK 403*be771a7bSCy Schubert #endif 404*be771a7bSCy Schubert ) 405*be771a7bSCy Schubert continue; /* Try again. */ 406*be771a7bSCy Schubert log_err("worker reload ack reply: send failed: %s", 407*be771a7bSCy Schubert sock_strerror(errno)); 408*be771a7bSCy Schubert break; 409*be771a7bSCy Schubert } 410*be771a7bSCy Schubert break; 411*be771a7bSCy Schubert } 412*be771a7bSCy Schubert } 413*be771a7bSCy Schubert 414*be771a7bSCy Schubert /** stop and wait to resume the worker */ 415*be771a7bSCy Schubert static void 416*be771a7bSCy Schubert worker_stop_and_wait(struct worker* worker) 417*be771a7bSCy Schubert { 418*be771a7bSCy Schubert uint8_t* buf = NULL; 419*be771a7bSCy Schubert uint32_t len = 0, cmd; 420*be771a7bSCy Schubert worker_send_reload_ack(worker); 421*be771a7bSCy Schubert /* wait for reload */ 422*be771a7bSCy Schubert if(!tube_read_msg(worker->cmd, &buf, &len, 0)) { 423*be771a7bSCy Schubert log_err("worker reload read reply failed"); 424*be771a7bSCy Schubert return; 425*be771a7bSCy Schubert } 426*be771a7bSCy Schubert if(len != sizeof(uint32_t)) { 427*be771a7bSCy Schubert log_err("worker reload reply, bad control msg length %d", 428*be771a7bSCy Schubert (int)len); 429*be771a7bSCy Schubert free(buf); 430*be771a7bSCy Schubert return; 431*be771a7bSCy Schubert } 432*be771a7bSCy Schubert cmd = sldns_read_uint32(buf); 433*be771a7bSCy Schubert free(buf); 434*be771a7bSCy Schubert if(cmd == worker_cmd_quit) { 435*be771a7bSCy Schubert /* quit anyway */ 436*be771a7bSCy Schubert verbose(VERB_ALGO, "reload reply, control cmd quit"); 437*be771a7bSCy Schubert comm_base_exit(worker->base); 438*be771a7bSCy Schubert return; 439*be771a7bSCy Schubert } 440*be771a7bSCy Schubert if(cmd != worker_cmd_reload_start) { 441*be771a7bSCy Schubert log_err("worker reload reply, wrong reply command"); 442*be771a7bSCy Schubert } 443*be771a7bSCy Schubert if(worker->daemon->fast_reload_drop_mesh) { 444*be771a7bSCy Schubert verbose(VERB_ALGO, "worker: drop mesh queries after reload"); 445*be771a7bSCy Schubert mesh_delete_all(worker->env.mesh); 446*be771a7bSCy Schubert } 447*be771a7bSCy Schubert fast_reload_worker_pickup_changes(worker); 448*be771a7bSCy Schubert worker_send_reload_ack(worker); 449*be771a7bSCy Schubert verbose(VERB_ALGO, "worker resume after reload"); 450*be771a7bSCy Schubert } 451*be771a7bSCy Schubert 452b7579f77SDag-Erling Smørgrav void 453b7579f77SDag-Erling Smørgrav worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, 454b7579f77SDag-Erling Smørgrav size_t len, int error, void* arg) 455b7579f77SDag-Erling Smørgrav { 456b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 457b7579f77SDag-Erling Smørgrav enum worker_commands cmd; 458b7579f77SDag-Erling Smørgrav if(error != NETEVENT_NOERROR) { 459b7579f77SDag-Erling Smørgrav free(msg); 460b7579f77SDag-Erling Smørgrav if(error == NETEVENT_CLOSED) 461b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 462b7579f77SDag-Erling Smørgrav else log_info("control event: %d", error); 463b7579f77SDag-Erling Smørgrav return; 464b7579f77SDag-Erling Smørgrav } 465b7579f77SDag-Erling Smørgrav if(len != sizeof(uint32_t)) { 466b7579f77SDag-Erling Smørgrav fatal_exit("bad control msg length %d", (int)len); 467b7579f77SDag-Erling Smørgrav } 46817d15b25SDag-Erling Smørgrav cmd = sldns_read_uint32(msg); 469b7579f77SDag-Erling Smørgrav free(msg); 470b7579f77SDag-Erling Smørgrav switch(cmd) { 471b7579f77SDag-Erling Smørgrav case worker_cmd_quit: 472b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd quit"); 473b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 474b7579f77SDag-Erling Smørgrav break; 475b7579f77SDag-Erling Smørgrav case worker_cmd_stats: 476b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd stats"); 477b7579f77SDag-Erling Smørgrav server_stats_reply(worker, 1); 478b7579f77SDag-Erling Smørgrav break; 479b7579f77SDag-Erling Smørgrav case worker_cmd_stats_noreset: 480b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd stats_noreset"); 481b7579f77SDag-Erling Smørgrav server_stats_reply(worker, 0); 482b7579f77SDag-Erling Smørgrav break; 483b7579f77SDag-Erling Smørgrav case worker_cmd_remote: 484b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd remote"); 485b7579f77SDag-Erling Smørgrav daemon_remote_exec(worker); 486b7579f77SDag-Erling Smørgrav break; 487*be771a7bSCy Schubert case worker_cmd_reload_stop: 488*be771a7bSCy Schubert verbose(VERB_ALGO, "got control cmd reload_stop"); 489*be771a7bSCy Schubert worker_stop_and_wait(worker); 490*be771a7bSCy Schubert break; 491*be771a7bSCy Schubert case worker_cmd_reload_poll: 492*be771a7bSCy Schubert verbose(VERB_ALGO, "got control cmd reload_poll"); 493*be771a7bSCy Schubert fast_reload_worker_pickup_changes(worker); 494*be771a7bSCy Schubert worker_send_reload_ack(worker); 495*be771a7bSCy Schubert break; 496b7579f77SDag-Erling Smørgrav default: 497b7579f77SDag-Erling Smørgrav log_err("bad command %d", (int)cmd); 498b7579f77SDag-Erling Smørgrav break; 499b7579f77SDag-Erling Smørgrav } 500b7579f77SDag-Erling Smørgrav } 501b7579f77SDag-Erling Smørgrav 502b7579f77SDag-Erling Smørgrav /** check if a delegation is secure */ 503b7579f77SDag-Erling Smørgrav static enum sec_status 504b7579f77SDag-Erling Smørgrav check_delegation_secure(struct reply_info *rep) 505b7579f77SDag-Erling Smørgrav { 506b7579f77SDag-Erling Smørgrav /* return smallest security status */ 507b7579f77SDag-Erling Smørgrav size_t i; 508b7579f77SDag-Erling Smørgrav enum sec_status sec = sec_status_secure; 509b7579f77SDag-Erling Smørgrav enum sec_status s; 510b7579f77SDag-Erling Smørgrav size_t num = rep->an_numrrsets + rep->ns_numrrsets; 511b7579f77SDag-Erling Smørgrav /* check if answer and authority are OK */ 512b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) { 513b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 514b7579f77SDag-Erling Smørgrav ->security; 515b7579f77SDag-Erling Smørgrav if(s < sec) 516b7579f77SDag-Erling Smørgrav sec = s; 517b7579f77SDag-Erling Smørgrav } 518b7579f77SDag-Erling Smørgrav /* in additional, only unchecked triggers revalidation */ 519b7579f77SDag-Erling Smørgrav for(i=num; i<rep->rrset_count; i++) { 520b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 521b7579f77SDag-Erling Smørgrav ->security; 522b7579f77SDag-Erling Smørgrav if(s == sec_status_unchecked) 523b7579f77SDag-Erling Smørgrav return s; 524b7579f77SDag-Erling Smørgrav } 525b7579f77SDag-Erling Smørgrav return sec; 526b7579f77SDag-Erling Smørgrav } 527b7579f77SDag-Erling Smørgrav 528b7579f77SDag-Erling Smørgrav /** remove nonsecure from a delegation referral additional section */ 529b7579f77SDag-Erling Smørgrav static void 530b7579f77SDag-Erling Smørgrav deleg_remove_nonsecure_additional(struct reply_info* rep) 531b7579f77SDag-Erling Smørgrav { 532b7579f77SDag-Erling Smørgrav /* we can simply edit it, since we are working in the scratch region */ 533b7579f77SDag-Erling Smørgrav size_t i; 534b7579f77SDag-Erling Smørgrav enum sec_status s; 535b7579f77SDag-Erling Smørgrav 536b7579f77SDag-Erling Smørgrav for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { 537b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 538b7579f77SDag-Erling Smørgrav ->security; 539b7579f77SDag-Erling Smørgrav if(s != sec_status_secure) { 540b7579f77SDag-Erling Smørgrav memmove(rep->rrsets+i, rep->rrsets+i+1, 541b7579f77SDag-Erling Smørgrav sizeof(struct ub_packed_rrset_key*)* 542b7579f77SDag-Erling Smørgrav (rep->rrset_count - i - 1)); 543b7579f77SDag-Erling Smørgrav rep->ar_numrrsets--; 544b7579f77SDag-Erling Smørgrav rep->rrset_count--; 545b7579f77SDag-Erling Smørgrav i--; 546b7579f77SDag-Erling Smørgrav } 547b7579f77SDag-Erling Smørgrav } 548b7579f77SDag-Erling Smørgrav } 549b7579f77SDag-Erling Smørgrav 550b7579f77SDag-Erling Smørgrav /** answer nonrecursive query from the cache */ 551b7579f77SDag-Erling Smørgrav static int 552b7579f77SDag-Erling Smørgrav answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, 553b7579f77SDag-Erling Smørgrav uint16_t id, uint16_t flags, struct comm_reply* repinfo, 554b7579f77SDag-Erling Smørgrav struct edns_data* edns) 555b7579f77SDag-Erling Smørgrav { 556b7579f77SDag-Erling Smørgrav /* for a nonrecursive query return either: 557b7579f77SDag-Erling Smørgrav * o an error (servfail; we try to avoid this) 558b7579f77SDag-Erling Smørgrav * o a delegation (closest we have; this routine tries that) 559b7579f77SDag-Erling Smørgrav * o the answer (checked by answer_from_cache) 560b7579f77SDag-Erling Smørgrav * 561b7579f77SDag-Erling Smørgrav * So, grab a delegation from the rrset cache. 562b7579f77SDag-Erling Smørgrav * Then check if it needs validation, if so, this routine fails, 563b7579f77SDag-Erling Smørgrav * so that iterator can prime and validator can verify rrsets. 564b7579f77SDag-Erling Smørgrav */ 565b7579f77SDag-Erling Smørgrav uint16_t udpsize = edns->udp_size; 566b7579f77SDag-Erling Smørgrav int secure = 0; 56717d15b25SDag-Erling Smørgrav time_t timenow = *worker->env.now; 5688f76bb7dSCy Schubert int has_cd_bit = (flags&BIT_CD); 5698f76bb7dSCy Schubert int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd) 570b7579f77SDag-Erling Smørgrav && worker->env.need_to_validate; 571b7579f77SDag-Erling Smørgrav struct dns_msg *msg = NULL; 572b7579f77SDag-Erling Smørgrav struct delegpt *dp; 573b7579f77SDag-Erling Smørgrav 574b7579f77SDag-Erling Smørgrav dp = dns_cache_find_delegation(&worker->env, qinfo->qname, 575b7579f77SDag-Erling Smørgrav qinfo->qname_len, qinfo->qtype, qinfo->qclass, 576790c6b24SCy Schubert worker->scratchpad, &msg, timenow, 0, NULL, 0); 577b7579f77SDag-Erling Smørgrav if(!dp) { /* no delegation, need to reprime */ 578b7579f77SDag-Erling Smørgrav return 0; 579b7579f77SDag-Erling Smørgrav } 580bc892140SDag-Erling Smørgrav /* In case we have a local alias, copy it into the delegation message. 581bc892140SDag-Erling Smørgrav * Shallow copy should be fine, as we'll be done with msg in this 582bc892140SDag-Erling Smørgrav * function. */ 583bc892140SDag-Erling Smørgrav msg->qinfo.local_alias = qinfo->local_alias; 584b7579f77SDag-Erling Smørgrav if(must_validate) { 585b7579f77SDag-Erling Smørgrav switch(check_delegation_secure(msg->rep)) { 586b7579f77SDag-Erling Smørgrav case sec_status_unchecked: 587b7579f77SDag-Erling Smørgrav /* some rrsets have not been verified yet, go and 588b7579f77SDag-Erling Smørgrav * let validator do that */ 589b7579f77SDag-Erling Smørgrav return 0; 590b7579f77SDag-Erling Smørgrav case sec_status_bogus: 5910fb34990SDag-Erling Smørgrav case sec_status_secure_sentinel_fail: 592b7579f77SDag-Erling Smørgrav /* some rrsets are bogus, reply servfail */ 593b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 594b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 595b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 596b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 597bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, 598f44e67d1SCy Schubert msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 599f44e67d1SCy Schubert worker->env.now_tv)) 600e2d15004SDag-Erling Smørgrav return 0; 6018f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) */ 6028f76bb7dSCy Schubert if(worker->env.cfg->ede && 6038f76bb7dSCy Schubert msg->rep->reason_bogus != LDNS_EDE_NONE) { 6048f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 6058f76bb7dSCy Schubert worker->scratchpad, msg->rep->reason_bogus, 6068f76bb7dSCy Schubert msg->rep->reason_bogus_str); 607a39a5a69SCy Schubert } 608b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 609b7579f77SDag-Erling Smørgrav &msg->qinfo, id, flags, edns); 610b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 611b7579f77SDag-Erling Smørgrav worker->stats.ans_bogus++; 612b7579f77SDag-Erling Smørgrav worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; 613b7579f77SDag-Erling Smørgrav } 614b7579f77SDag-Erling Smørgrav return 1; 615b7579f77SDag-Erling Smørgrav case sec_status_secure: 616b7579f77SDag-Erling Smørgrav /* all rrsets are secure */ 617b7579f77SDag-Erling Smørgrav /* remove non-secure rrsets from the add. section*/ 618b7579f77SDag-Erling Smørgrav if(worker->env.cfg->val_clean_additional) 619b7579f77SDag-Erling Smørgrav deleg_remove_nonsecure_additional(msg->rep); 620b7579f77SDag-Erling Smørgrav secure = 1; 621b7579f77SDag-Erling Smørgrav break; 622b7579f77SDag-Erling Smørgrav case sec_status_indeterminate: 623b7579f77SDag-Erling Smørgrav case sec_status_insecure: 624b7579f77SDag-Erling Smørgrav default: 625b7579f77SDag-Erling Smørgrav /* not secure */ 626b7579f77SDag-Erling Smørgrav secure = 0; 627b7579f77SDag-Erling Smørgrav break; 628b7579f77SDag-Erling Smørgrav } 629b7579f77SDag-Erling Smørgrav } 630b7579f77SDag-Erling Smørgrav /* return this delegation from the cache */ 631b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 632b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 633b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 634b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 635103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 636103ba509SCy Schubert edns->edns_present = 0; 637bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep, 638f44e67d1SCy Schubert (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad, 639f44e67d1SCy Schubert worker->env.now_tv)) 640e2d15004SDag-Erling Smørgrav return 0; 641b7579f77SDag-Erling Smørgrav msg->rep->flags |= BIT_QR|BIT_RA; 6428f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) if CD bit is set and the answer is 6438f76bb7dSCy Schubert * bogus. */ 6448f76bb7dSCy Schubert if(worker->env.cfg->ede && has_cd_bit && 6458f76bb7dSCy Schubert (check_delegation_secure(msg->rep) == sec_status_bogus || 6468f76bb7dSCy Schubert check_delegation_secure(msg->rep) == sec_status_secure_sentinel_fail) && 6478f76bb7dSCy Schubert msg->rep->reason_bogus != LDNS_EDE_NONE) { 6488f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 6498f76bb7dSCy Schubert worker->scratchpad, msg->rep->reason_bogus, 6508f76bb7dSCy Schubert msg->rep->reason_bogus_str); 6518f76bb7dSCy Schubert } 65224e36522SCy Schubert if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 653b7579f77SDag-Erling Smørgrav repinfo->c->buffer, 0, 1, worker->scratchpad, 654b7579f77SDag-Erling Smørgrav udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 655bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, 656f44e67d1SCy Schubert LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 657f44e67d1SCy Schubert worker->env.now_tv)) 65824e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 659b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 660b7579f77SDag-Erling Smørgrav &msg->qinfo, id, flags, edns); 661b7579f77SDag-Erling Smørgrav } 662b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 663b7579f77SDag-Erling Smørgrav if(secure) worker->stats.ans_secure++; 664b7579f77SDag-Erling Smørgrav server_stats_insrcode(&worker->stats, repinfo->c->buffer); 665b7579f77SDag-Erling Smørgrav } 666b7579f77SDag-Erling Smørgrav return 1; 667b7579f77SDag-Erling Smørgrav } 668b7579f77SDag-Erling Smørgrav 66965b390aaSDag-Erling Smørgrav /** Apply, if applicable, a response IP action to a cached answer. 67065b390aaSDag-Erling Smørgrav * If the answer is rewritten as a result of an action, '*encode_repp' will 67165b390aaSDag-Erling Smørgrav * point to the reply info containing the modified answer. '*encode_repp' will 67265b390aaSDag-Erling Smørgrav * be intact otherwise. 67365b390aaSDag-Erling Smørgrav * It returns 1 on success, 0 otherwise. */ 67465b390aaSDag-Erling Smørgrav static int 67565b390aaSDag-Erling Smørgrav apply_respip_action(struct worker* worker, const struct query_info* qinfo, 67665b390aaSDag-Erling Smørgrav struct respip_client_info* cinfo, struct reply_info* rep, 677865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, 678865f46b2SCy Schubert struct ub_packed_rrset_key** alias_rrset, 679091e9e46SCy Schubert struct reply_info** encode_repp, struct auth_zones* az) 68065b390aaSDag-Erling Smørgrav { 681369c6923SCy Schubert struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 682091e9e46SCy Schubert actinfo.action = respip_none; 68365b390aaSDag-Erling Smørgrav 68465b390aaSDag-Erling Smørgrav if(qinfo->qtype != LDNS_RR_TYPE_A && 68565b390aaSDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_AAAA && 68665b390aaSDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_ANY) 68765b390aaSDag-Erling Smørgrav return 1; 68865b390aaSDag-Erling Smørgrav 68965b390aaSDag-Erling Smørgrav if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, 690*be771a7bSCy Schubert alias_rrset, 0, worker->scratchpad, az, NULL, 691*be771a7bSCy Schubert worker->env.views, worker->env.respip_set)) 69265b390aaSDag-Erling Smørgrav return 0; 69365b390aaSDag-Erling Smørgrav 69465b390aaSDag-Erling Smørgrav /* xxx_deny actions mean dropping the reply, unless the original reply 69565b390aaSDag-Erling Smørgrav * was redirected to response-ip data. */ 6968f76bb7dSCy Schubert if(actinfo.action == respip_always_deny || 6978f76bb7dSCy Schubert ((actinfo.action == respip_deny || 69865b390aaSDag-Erling Smørgrav actinfo.action == respip_inform_deny) && 6998f76bb7dSCy Schubert *encode_repp == rep)) 70065b390aaSDag-Erling Smørgrav *encode_repp = NULL; 70165b390aaSDag-Erling Smørgrav 70265b390aaSDag-Erling Smørgrav /* If address info is returned, it means the action should be an 70365b390aaSDag-Erling Smørgrav * 'inform' variant and the information should be logged. */ 70465b390aaSDag-Erling Smørgrav if(actinfo.addrinfo) { 705091e9e46SCy Schubert respip_inform_print(&actinfo, qinfo->qname, 70665b390aaSDag-Erling Smørgrav qinfo->qtype, qinfo->qclass, qinfo->local_alias, 707865f46b2SCy Schubert addr, addrlen); 708091e9e46SCy Schubert 709091e9e46SCy Schubert if(worker->stats.extended && actinfo.rpz_used) { 710091e9e46SCy Schubert if(actinfo.rpz_disabled) 711091e9e46SCy Schubert worker->stats.rpz_action[RPZ_DISABLED_ACTION]++; 712091e9e46SCy Schubert if(actinfo.rpz_cname_override) 713091e9e46SCy Schubert worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++; 714091e9e46SCy Schubert else 715091e9e46SCy Schubert worker->stats.rpz_action[ 716091e9e46SCy Schubert respip_action_to_rpz_action(actinfo.action)]++; 717091e9e46SCy Schubert } 71865b390aaSDag-Erling Smørgrav } 71965b390aaSDag-Erling Smørgrav 72065b390aaSDag-Erling Smørgrav return 1; 72165b390aaSDag-Erling Smørgrav } 72265b390aaSDag-Erling Smørgrav 72365b390aaSDag-Erling Smørgrav /** answer query from the cache. 72465b390aaSDag-Erling Smørgrav * Normally, the answer message will be built in repinfo->c->buffer; if the 72565b390aaSDag-Erling Smørgrav * answer is supposed to be suppressed or the answer is supposed to be an 72665b390aaSDag-Erling Smørgrav * incomplete CNAME chain, the buffer is explicitly cleared to signal the 72765b390aaSDag-Erling Smørgrav * caller as such. In the latter case *partial_rep will point to the incomplete 72865b390aaSDag-Erling Smørgrav * reply, and this function is (possibly) supposed to be called again with that 72965b390aaSDag-Erling Smørgrav * *partial_rep value to complete the chain. In addition, if the query should 73065b390aaSDag-Erling Smørgrav * be completely dropped, '*need_drop' will be set to 1. */ 731b7579f77SDag-Erling Smørgrav static int 732b7579f77SDag-Erling Smørgrav answer_from_cache(struct worker* worker, struct query_info* qinfo, 733091e9e46SCy Schubert struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer, 734091e9e46SCy Schubert int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset, 73565b390aaSDag-Erling Smørgrav struct reply_info** partial_repp, 736b7579f77SDag-Erling Smørgrav struct reply_info* rep, uint16_t id, uint16_t flags, 737b7579f77SDag-Erling Smørgrav struct comm_reply* repinfo, struct edns_data* edns) 738b7579f77SDag-Erling Smørgrav { 73917d15b25SDag-Erling Smørgrav time_t timenow = *worker->env.now; 740b7579f77SDag-Erling Smørgrav uint16_t udpsize = edns->udp_size; 74165b390aaSDag-Erling Smørgrav struct reply_info* encode_rep = rep; 74265b390aaSDag-Erling Smørgrav struct reply_info* partial_rep = *partial_repp; 7438f76bb7dSCy Schubert int has_cd_bit = (flags&BIT_CD); 7448f76bb7dSCy Schubert int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd) 745b7579f77SDag-Erling Smørgrav && worker->env.need_to_validate; 74665b390aaSDag-Erling Smørgrav *partial_repp = NULL; /* avoid accidental further pass */ 747091e9e46SCy Schubert 748091e9e46SCy Schubert /* Check TTL */ 749091e9e46SCy Schubert if(rep->ttl < timenow) { 750091e9e46SCy Schubert /* Check if we need to serve expired now */ 751091e9e46SCy Schubert if(worker->env.cfg->serve_expired && 75246d2f618SCy Schubert /* if serve-expired-client-timeout is set, serve 75346d2f618SCy Schubert * an expired record without attempting recursion 75446d2f618SCy Schubert * if the serve_expired_norec_ttl is set for the record 75546d2f618SCy Schubert * as we know that recursion is currently failing. */ 75646d2f618SCy Schubert (!worker->env.cfg->serve_expired_client_timeout || 75746d2f618SCy Schubert timenow < rep->serve_expired_norec_ttl) 758335c7cdaSCy Schubert #ifdef USE_CACHEDB 759335c7cdaSCy Schubert && !(worker->env.cachedb_enabled && 760335c7cdaSCy Schubert worker->env.cfg->cachedb_check_when_serve_expired) 761335c7cdaSCy Schubert #endif 762335c7cdaSCy Schubert ) { 76346d2f618SCy Schubert if(!reply_info_can_answer_expired(rep, timenow)) 7641838dec3SCy Schubert return 0; 765bc892140SDag-Erling Smørgrav if(!rrset_array_lock(rep->ref, rep->rrset_count, 0)) 766bc892140SDag-Erling Smørgrav return 0; 767091e9e46SCy Schubert *is_expired_answer = 1; 768bc892140SDag-Erling Smørgrav } else { 769b7579f77SDag-Erling Smørgrav /* the rrsets may have been updated in the meantime. 770b7579f77SDag-Erling Smørgrav * we will refetch the message format from the 771b7579f77SDag-Erling Smørgrav * authoritative server 772b7579f77SDag-Erling Smørgrav */ 773b7579f77SDag-Erling Smørgrav return 0; 774b7579f77SDag-Erling Smørgrav } 775091e9e46SCy Schubert } else { 776b7579f77SDag-Erling Smørgrav if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) 777b7579f77SDag-Erling Smørgrav return 0; 778bc892140SDag-Erling Smørgrav } 779091e9e46SCy Schubert /* locked and ids and ttls are OK. */ 780091e9e46SCy Schubert 781b7579f77SDag-Erling Smørgrav /* check CNAME chain (if any) */ 782b7579f77SDag-Erling Smørgrav if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == 783b7579f77SDag-Erling Smørgrav htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == 784b7579f77SDag-Erling Smørgrav htons(LDNS_RR_TYPE_DNAME))) { 78509a3aaf3SDag-Erling Smørgrav if(!reply_check_cname_chain(qinfo, rep)) { 786b7579f77SDag-Erling Smørgrav /* cname chain invalid, redo iterator steps */ 787b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: cname chain broken"); 788e86b9096SDag-Erling Smørgrav goto bail_out; 789b7579f77SDag-Erling Smørgrav } 790b7579f77SDag-Erling Smørgrav } 791b7579f77SDag-Erling Smørgrav /* check security status of the cached answer */ 7920fb34990SDag-Erling Smørgrav if(must_validate && (rep->security == sec_status_bogus || 7930fb34990SDag-Erling Smørgrav rep->security == sec_status_secure_sentinel_fail)) { 794b7579f77SDag-Erling Smørgrav /* BAD cached */ 795b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 796b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 797b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 798b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 799103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 800103ba509SCy Schubert edns->edns_present = 0; 801bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, 802f44e67d1SCy Schubert LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 803f44e67d1SCy Schubert worker->env.now_tv)) 8043005e0a3SDag-Erling Smørgrav goto bail_out; 8058f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) */ 8068f76bb7dSCy Schubert if(worker->env.cfg->ede && rep->reason_bogus != LDNS_EDE_NONE) { 8078f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 8088f76bb7dSCy Schubert worker->scratchpad, rep->reason_bogus, 8098f76bb7dSCy Schubert rep->reason_bogus_str); 810a39a5a69SCy Schubert } 811b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 812b7579f77SDag-Erling Smørgrav qinfo, id, flags, edns); 813b7579f77SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, 814b7579f77SDag-Erling Smørgrav worker->scratchpad, rep->ref, rep->rrset_count); 815b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 816b7579f77SDag-Erling Smørgrav worker->stats.ans_bogus ++; 817b7579f77SDag-Erling Smørgrav worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; 818b7579f77SDag-Erling Smørgrav } 819b7579f77SDag-Erling Smørgrav return 1; 820b7579f77SDag-Erling Smørgrav } else if(rep->security == sec_status_unchecked && must_validate) { 821b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: unchecked entry needs " 822b7579f77SDag-Erling Smørgrav "validation"); 823b7579f77SDag-Erling Smørgrav goto bail_out; /* need to validate cache entry first */ 824b7579f77SDag-Erling Smørgrav } else if(rep->security == sec_status_secure) { 825091e9e46SCy Schubert if(reply_all_rrsets_secure(rep)) { 826091e9e46SCy Schubert *is_secure_answer = 1; 827091e9e46SCy Schubert } else { 828b7579f77SDag-Erling Smørgrav if(must_validate) { 829b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: secure entry" 830b7579f77SDag-Erling Smørgrav " changed status"); 831b7579f77SDag-Erling Smørgrav goto bail_out; /* rrset changed, re-verify */ 832b7579f77SDag-Erling Smørgrav } 833091e9e46SCy Schubert *is_secure_answer = 0; 834b7579f77SDag-Erling Smørgrav } 835091e9e46SCy Schubert } else *is_secure_answer = 0; 836b7579f77SDag-Erling Smørgrav 837b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 838b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 839b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 840b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 841103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 842103ba509SCy Schubert edns->edns_present = 0; 84365b390aaSDag-Erling Smørgrav *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ 844091e9e46SCy Schubert if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && 845091e9e46SCy Schubert !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep, 846865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, alias_rrset, 847091e9e46SCy Schubert &encode_rep, worker->env.auth_zones)) { 84865b390aaSDag-Erling Smørgrav goto bail_out; 84965b390aaSDag-Erling Smørgrav } else if(partial_rep && 85065b390aaSDag-Erling Smørgrav !respip_merge_cname(partial_rep, qinfo, rep, cinfo, 851091e9e46SCy Schubert must_validate, &encode_rep, worker->scratchpad, 852*be771a7bSCy Schubert worker->env.auth_zones, worker->env.views, 853*be771a7bSCy Schubert worker->env.respip_set)) { 85465b390aaSDag-Erling Smørgrav goto bail_out; 85565b390aaSDag-Erling Smørgrav } 856091e9e46SCy Schubert if(encode_rep != rep) { 857091e9e46SCy Schubert /* if rewritten, it can't be considered "secure" */ 858091e9e46SCy Schubert *is_secure_answer = 0; 859091e9e46SCy Schubert } 86065b390aaSDag-Erling Smørgrav if(!encode_rep || *alias_rrset) { 86165b390aaSDag-Erling Smørgrav if(!encode_rep) 86265b390aaSDag-Erling Smørgrav *need_drop = 1; 86365b390aaSDag-Erling Smørgrav else { 86465b390aaSDag-Erling Smørgrav /* If a partial CNAME chain is found, we first need to 86565b390aaSDag-Erling Smørgrav * make a copy of the reply in the scratchpad so we 86665b390aaSDag-Erling Smørgrav * can release the locks and lookup the cache again. */ 86765b390aaSDag-Erling Smørgrav *partial_repp = reply_info_copy(encode_rep, NULL, 86865b390aaSDag-Erling Smørgrav worker->scratchpad); 86965b390aaSDag-Erling Smørgrav if(!*partial_repp) 87065b390aaSDag-Erling Smørgrav goto bail_out; 87165b390aaSDag-Erling Smørgrav } 872a39a5a69SCy Schubert } else { 873a39a5a69SCy Schubert if(*is_expired_answer == 1 && 874a39a5a69SCy Schubert worker->env.cfg->ede_serve_expired && worker->env.cfg->ede) { 875a39a5a69SCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out, 876a39a5a69SCy Schubert worker->scratchpad, LDNS_EDE_STALE_ANSWER, ""); 877a39a5a69SCy Schubert } 8788f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) if CD bit is set and the 8798f76bb7dSCy Schubert * answer is bogus. */ 8808f76bb7dSCy Schubert if(*is_secure_answer == 0 && 8818f76bb7dSCy Schubert worker->env.cfg->ede && has_cd_bit && 8828f76bb7dSCy Schubert encode_rep->reason_bogus != LDNS_EDE_NONE) { 8838f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 8848f76bb7dSCy Schubert worker->scratchpad, encode_rep->reason_bogus, 8858f76bb7dSCy Schubert encode_rep->reason_bogus_str); 8868f76bb7dSCy Schubert } 8878f76bb7dSCy Schubert if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, encode_rep, 8888f76bb7dSCy Schubert (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad, 8898f76bb7dSCy Schubert worker->env.now_tv)) 8908f76bb7dSCy Schubert goto bail_out; 891a39a5a69SCy Schubert if(!reply_info_answer_encode(qinfo, encode_rep, id, flags, 892b7579f77SDag-Erling Smørgrav repinfo->c->buffer, timenow, 1, worker->scratchpad, 893a39a5a69SCy Schubert udpsize, edns, (int)(edns->bits & EDNS_DO), 894a39a5a69SCy Schubert *is_secure_answer)) { 895a39a5a69SCy Schubert if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, 896a39a5a69SCy Schubert NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, 897a39a5a69SCy Schubert worker->scratchpad, worker->env.now_tv)) 89824e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 899b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 900b7579f77SDag-Erling Smørgrav qinfo, id, flags, edns); 901b7579f77SDag-Erling Smørgrav } 902a39a5a69SCy Schubert } 903b7579f77SDag-Erling Smørgrav /* cannot send the reply right now, because blocking network syscall 904b7579f77SDag-Erling Smørgrav * is bad while holding locks. */ 905b7579f77SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, 906b7579f77SDag-Erling Smørgrav rep->ref, rep->rrset_count); 907b7579f77SDag-Erling Smørgrav /* go and return this buffer to the client */ 908b7579f77SDag-Erling Smørgrav return 1; 909e86b9096SDag-Erling Smørgrav 910e86b9096SDag-Erling Smørgrav bail_out: 911e86b9096SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, 912e86b9096SDag-Erling Smørgrav worker->scratchpad, rep->ref, rep->rrset_count); 913e86b9096SDag-Erling Smørgrav return 0; 914b7579f77SDag-Erling Smørgrav } 915b7579f77SDag-Erling Smørgrav 9160eefd307SCy Schubert /** Reply to client and perform prefetch to keep cache up to date. */ 917b7579f77SDag-Erling Smørgrav static void 918b7579f77SDag-Erling Smørgrav reply_and_prefetch(struct worker* worker, struct query_info* qinfo, 919a39a5a69SCy Schubert uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply, 920a39a5a69SCy Schubert int rpz_passthru, struct edns_option* opt_list) 921b7579f77SDag-Erling Smørgrav { 922a39a5a69SCy Schubert (void)opt_list; 923b7579f77SDag-Erling Smørgrav /* first send answer to client to keep its latency 924b7579f77SDag-Erling Smørgrav * as small as a cachereply */ 9250eefd307SCy Schubert if(!noreply) { 926e86b9096SDag-Erling Smørgrav if(repinfo->c->tcp_req_info) { 927e86b9096SDag-Erling Smørgrav sldns_buffer_copy( 928e86b9096SDag-Erling Smørgrav repinfo->c->tcp_req_info->spool_buffer, 929e86b9096SDag-Erling Smørgrav repinfo->c->buffer); 930e86b9096SDag-Erling Smørgrav } 931b7579f77SDag-Erling Smørgrav comm_point_send_reply(repinfo); 932e86b9096SDag-Erling Smørgrav } 933b7579f77SDag-Erling Smørgrav server_stats_prefetch(&worker->stats, worker); 934a39a5a69SCy Schubert #ifdef CLIENT_SUBNET 935a39a5a69SCy Schubert /* Check if the subnet module is enabled. In that case pass over the 936a39a5a69SCy Schubert * comm_reply information for ECS generation later. The mesh states are 937a39a5a69SCy Schubert * unique when subnet is enabled. */ 938a39a5a69SCy Schubert if(modstack_find(&worker->env.mesh->mods, "subnetcache") != -1 939a39a5a69SCy Schubert && worker->env.unique_mesh) { 940a39a5a69SCy Schubert mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 9418f76bb7dSCy Schubert PREFETCH_EXPIRY_ADD, rpz_passthru, 9428f76bb7dSCy Schubert &repinfo->client_addr, opt_list); 943a39a5a69SCy Schubert return; 944a39a5a69SCy Schubert } 945a39a5a69SCy Schubert #endif 946b7579f77SDag-Erling Smørgrav /* create the prefetch in the mesh as a normal lookup without 947b7579f77SDag-Erling Smørgrav * client addrs waiting, which has the cache blacklisted (to bypass 948b7579f77SDag-Erling Smørgrav * the cache and go to the network for the data). */ 949b7579f77SDag-Erling Smørgrav /* this (potentially) runs the mesh for the new query */ 950b7579f77SDag-Erling Smørgrav mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 951a39a5a69SCy Schubert PREFETCH_EXPIRY_ADD, rpz_passthru, NULL, NULL); 952b7579f77SDag-Erling Smørgrav } 953b7579f77SDag-Erling Smørgrav 954b7579f77SDag-Erling Smørgrav /** 955b7579f77SDag-Erling Smørgrav * Fill CH class answer into buffer. Keeps query. 956b7579f77SDag-Erling Smørgrav * @param pkt: buffer 957b7579f77SDag-Erling Smørgrav * @param str: string to put into text record (<255). 95865b390aaSDag-Erling Smørgrav * array of strings, every string becomes a text record. 95965b390aaSDag-Erling Smørgrav * @param num: number of strings in array. 960b7579f77SDag-Erling Smørgrav * @param edns: edns reply information. 961e2d15004SDag-Erling Smørgrav * @param worker: worker with scratch region. 9624c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 963b7579f77SDag-Erling Smørgrav */ 964b7579f77SDag-Erling Smørgrav static void 96565b390aaSDag-Erling Smørgrav chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, 9664c75e3aaSDag-Erling Smørgrav struct worker* worker, struct comm_reply* repinfo) 967b7579f77SDag-Erling Smørgrav { 96865b390aaSDag-Erling Smørgrav int i; 96917d15b25SDag-Erling Smørgrav unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); 97017d15b25SDag-Erling Smørgrav unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); 97124e36522SCy Schubert size_t udpsize = edns->udp_size; 97224e36522SCy Schubert edns->edns_version = EDNS_ADVERTISED_VERSION; 97324e36522SCy Schubert edns->udp_size = EDNS_ADVERTISED_SIZE; 97424e36522SCy Schubert edns->bits &= EDNS_DO; 97524e36522SCy Schubert if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, 97624e36522SCy Schubert LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad, 97724e36522SCy Schubert worker->env.now_tv)) 97824e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 97917d15b25SDag-Erling Smørgrav sldns_buffer_clear(pkt); 98017d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ 98117d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); 98217d15b25SDag-Erling Smørgrav if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); 98317d15b25SDag-Erling Smørgrav if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); 98417d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 1); /* qdcount */ 98565b390aaSDag-Erling Smørgrav sldns_buffer_write_u16(pkt, (uint16_t)num); /* ancount */ 98617d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0); /* nscount */ 98717d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0); /* arcount */ 988b7579f77SDag-Erling Smørgrav (void)query_dname_len(pkt); /* skip qname */ 98917d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 99017d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 99165b390aaSDag-Erling Smørgrav for(i=0; i<num; i++) { 99265b390aaSDag-Erling Smørgrav size_t len = strlen(str[i]); 99365b390aaSDag-Erling Smørgrav if(len>255) len=255; /* cap size of TXT record */ 99424e36522SCy Schubert if(sldns_buffer_position(pkt)+2+2+2+4+2+1+len+ 99524e36522SCy Schubert calc_edns_field_size(edns) > udpsize) { 99624e36522SCy Schubert sldns_buffer_write_u16_at(pkt, 6, i); /* ANCOUNT */ 99724e36522SCy Schubert LDNS_TC_SET(sldns_buffer_begin(pkt)); 99824e36522SCy Schubert break; 99924e36522SCy Schubert } 100017d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ 100117d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); 100217d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); 100317d15b25SDag-Erling Smørgrav sldns_buffer_write_u32(pkt, 0); /* TTL */ 100417d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); 100517d15b25SDag-Erling Smørgrav sldns_buffer_write_u8(pkt, len); 100665b390aaSDag-Erling Smørgrav sldns_buffer_write(pkt, str[i], len); 100765b390aaSDag-Erling Smørgrav } 100817d15b25SDag-Erling Smørgrav sldns_buffer_flip(pkt); 1009c7f4d7adSDag-Erling Smørgrav if(sldns_buffer_capacity(pkt) >= 1010c7f4d7adSDag-Erling Smørgrav sldns_buffer_limit(pkt)+calc_edns_field_size(edns)) 1011b7579f77SDag-Erling Smørgrav attach_edns_record(pkt, edns); 1012b7579f77SDag-Erling Smørgrav } 1013b7579f77SDag-Erling Smørgrav 101465b390aaSDag-Erling Smørgrav /** Reply with one string */ 101565b390aaSDag-Erling Smørgrav static void 101665b390aaSDag-Erling Smørgrav chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns, 10174c75e3aaSDag-Erling Smørgrav struct worker* worker, struct comm_reply* repinfo) 101865b390aaSDag-Erling Smørgrav { 10194c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, (char**)&str, 1, edns, worker, repinfo); 102065b390aaSDag-Erling Smørgrav } 102165b390aaSDag-Erling Smørgrav 102265b390aaSDag-Erling Smørgrav /** 102365b390aaSDag-Erling Smørgrav * Create CH class trustanchor answer. 102465b390aaSDag-Erling Smørgrav * @param pkt: buffer 102565b390aaSDag-Erling Smørgrav * @param edns: edns reply information. 102665b390aaSDag-Erling Smørgrav * @param w: worker with scratch region. 10274c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 102865b390aaSDag-Erling Smørgrav */ 102965b390aaSDag-Erling Smørgrav static void 10304c75e3aaSDag-Erling Smørgrav chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w, 10314c75e3aaSDag-Erling Smørgrav struct comm_reply* repinfo) 103265b390aaSDag-Erling Smørgrav { 103365b390aaSDag-Erling Smørgrav #define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */ 103465b390aaSDag-Erling Smørgrav #define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */ 103565b390aaSDag-Erling Smørgrav char* str_array[TA_RESPONSE_MAX_TXT]; 103665b390aaSDag-Erling Smørgrav uint16_t tags[TA_RESPONSE_MAX_TAGS]; 103765b390aaSDag-Erling Smørgrav int num = 0; 103865b390aaSDag-Erling Smørgrav struct trust_anchor* ta; 103965b390aaSDag-Erling Smørgrav 104065b390aaSDag-Erling Smørgrav if(!w->env.need_to_validate) { 104165b390aaSDag-Erling Smørgrav /* no validator module, reply no trustanchors */ 10424c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, NULL, 0, edns, w, repinfo); 104365b390aaSDag-Erling Smørgrav return; 104465b390aaSDag-Erling Smørgrav } 104565b390aaSDag-Erling Smørgrav 104665b390aaSDag-Erling Smørgrav /* fill the string with contents */ 104765b390aaSDag-Erling Smørgrav lock_basic_lock(&w->env.anchors->lock); 104865b390aaSDag-Erling Smørgrav RBTREE_FOR(ta, struct trust_anchor*, w->env.anchors->tree) { 104965b390aaSDag-Erling Smørgrav char* str; 105065b390aaSDag-Erling Smørgrav size_t i, numtag, str_len = 255; 105165b390aaSDag-Erling Smørgrav if(num == TA_RESPONSE_MAX_TXT) continue; 105265b390aaSDag-Erling Smørgrav str = (char*)regional_alloc(w->scratchpad, str_len); 105365b390aaSDag-Erling Smørgrav if(!str) continue; 105465b390aaSDag-Erling Smørgrav lock_basic_lock(&ta->lock); 105565b390aaSDag-Erling Smørgrav numtag = anchor_list_keytags(ta, tags, TA_RESPONSE_MAX_TAGS); 105665b390aaSDag-Erling Smørgrav if(numtag == 0) { 105765b390aaSDag-Erling Smørgrav /* empty, insecure point */ 105865b390aaSDag-Erling Smørgrav lock_basic_unlock(&ta->lock); 105965b390aaSDag-Erling Smørgrav continue; 106065b390aaSDag-Erling Smørgrav } 106165b390aaSDag-Erling Smørgrav str_array[num] = str; 106265b390aaSDag-Erling Smørgrav num++; 106365b390aaSDag-Erling Smørgrav 106465b390aaSDag-Erling Smørgrav /* spool name of anchor */ 106565b390aaSDag-Erling Smørgrav (void)sldns_wire2str_dname_buf(ta->name, ta->namelen, str, str_len); 106665b390aaSDag-Erling Smørgrav str_len -= strlen(str); str += strlen(str); 106765b390aaSDag-Erling Smørgrav /* spool tags */ 106865b390aaSDag-Erling Smørgrav for(i=0; i<numtag; i++) { 106965b390aaSDag-Erling Smørgrav snprintf(str, str_len, " %u", (unsigned)tags[i]); 107065b390aaSDag-Erling Smørgrav str_len -= strlen(str); str += strlen(str); 107165b390aaSDag-Erling Smørgrav } 107265b390aaSDag-Erling Smørgrav lock_basic_unlock(&ta->lock); 107365b390aaSDag-Erling Smørgrav } 107465b390aaSDag-Erling Smørgrav lock_basic_unlock(&w->env.anchors->lock); 107565b390aaSDag-Erling Smørgrav 10764c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, str_array, num, edns, w, repinfo); 107765b390aaSDag-Erling Smørgrav regional_free_all(w->scratchpad); 107865b390aaSDag-Erling Smørgrav } 107965b390aaSDag-Erling Smørgrav 1080b7579f77SDag-Erling Smørgrav /** 1081b7579f77SDag-Erling Smørgrav * Answer CH class queries. 1082b7579f77SDag-Erling Smørgrav * @param w: worker 1083b7579f77SDag-Erling Smørgrav * @param qinfo: query info. Pointer into packet buffer. 1084b7579f77SDag-Erling Smørgrav * @param edns: edns info from query. 10854c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 1086b7579f77SDag-Erling Smørgrav * @param pkt: packet buffer. 1087b7579f77SDag-Erling Smørgrav * @return: true if a reply is to be sent. 1088b7579f77SDag-Erling Smørgrav */ 1089b7579f77SDag-Erling Smørgrav static int 1090b7579f77SDag-Erling Smørgrav answer_chaos(struct worker* w, struct query_info* qinfo, 10914c75e3aaSDag-Erling Smørgrav struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* pkt) 1092b7579f77SDag-Erling Smørgrav { 1093b7579f77SDag-Erling Smørgrav struct config_file* cfg = w->env.cfg; 1094b7579f77SDag-Erling Smørgrav if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) 1095b7579f77SDag-Erling Smørgrav return 0; 1096b7579f77SDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 1097b7579f77SDag-Erling Smørgrav (uint8_t*)"\002id\006server") == 0 || 1098b7579f77SDag-Erling Smørgrav query_dname_compare(qinfo->qname, 1099b7579f77SDag-Erling Smørgrav (uint8_t*)"\010hostname\004bind") == 0) 1100b7579f77SDag-Erling Smørgrav { 1101b7579f77SDag-Erling Smørgrav if(cfg->hide_identity) 1102b7579f77SDag-Erling Smørgrav return 0; 1103b7579f77SDag-Erling Smørgrav if(cfg->identity==NULL || cfg->identity[0]==0) { 1104b7579f77SDag-Erling Smørgrav char buf[MAXHOSTNAMELEN+1]; 1105b7579f77SDag-Erling Smørgrav if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 1106b7579f77SDag-Erling Smørgrav buf[MAXHOSTNAMELEN] = 0; 11074c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, buf, edns, w, repinfo); 1108b7579f77SDag-Erling Smørgrav } else { 1109b7579f77SDag-Erling Smørgrav log_err("gethostname: %s", strerror(errno)); 11104c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, "no hostname", edns, w, repinfo); 1111b7579f77SDag-Erling Smørgrav } 1112b7579f77SDag-Erling Smørgrav } 11134c75e3aaSDag-Erling Smørgrav else chaos_replyonestr(pkt, cfg->identity, edns, w, repinfo); 1114b7579f77SDag-Erling Smørgrav return 1; 1115b7579f77SDag-Erling Smørgrav } 1116b7579f77SDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 1117b7579f77SDag-Erling Smørgrav (uint8_t*)"\007version\006server") == 0 || 1118b7579f77SDag-Erling Smørgrav query_dname_compare(qinfo->qname, 1119b7579f77SDag-Erling Smørgrav (uint8_t*)"\007version\004bind") == 0) 1120b7579f77SDag-Erling Smørgrav { 1121b7579f77SDag-Erling Smørgrav if(cfg->hide_version) 1122b7579f77SDag-Erling Smørgrav return 0; 1123b7579f77SDag-Erling Smørgrav if(cfg->version==NULL || cfg->version[0]==0) 11244c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, PACKAGE_STRING, edns, w, repinfo); 11254c75e3aaSDag-Erling Smørgrav else chaos_replyonestr(pkt, cfg->version, edns, w, repinfo); 1126b7579f77SDag-Erling Smørgrav return 1; 1127b7579f77SDag-Erling Smørgrav } 112865b390aaSDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 112965b390aaSDag-Erling Smørgrav (uint8_t*)"\013trustanchor\007unbound") == 0) 113065b390aaSDag-Erling Smørgrav { 113165b390aaSDag-Erling Smørgrav if(cfg->hide_trustanchor) 113265b390aaSDag-Erling Smørgrav return 0; 11334c75e3aaSDag-Erling Smørgrav chaos_trustanchor(pkt, edns, w, repinfo); 113465b390aaSDag-Erling Smørgrav return 1; 113565b390aaSDag-Erling Smørgrav } 113665b390aaSDag-Erling Smørgrav 1137b7579f77SDag-Erling Smørgrav return 0; 1138b7579f77SDag-Erling Smørgrav } 1139b7579f77SDag-Erling Smørgrav 11400fb34990SDag-Erling Smørgrav /** 11410fb34990SDag-Erling Smørgrav * Answer notify queries. These are notifies for authoritative zones, 11420fb34990SDag-Erling Smørgrav * the reply is an ack that the notify has been received. We need to check 11430fb34990SDag-Erling Smørgrav * access permission here. 11440fb34990SDag-Erling Smørgrav * @param w: worker 11450fb34990SDag-Erling Smørgrav * @param qinfo: query info. Pointer into packet buffer. 11460fb34990SDag-Erling Smørgrav * @param edns: edns info from query. 1147865f46b2SCy Schubert * @param addr: client address. 1148865f46b2SCy Schubert * @param addrlen: client address length. 11490fb34990SDag-Erling Smørgrav * @param pkt: packet buffer. 11500fb34990SDag-Erling Smørgrav */ 11510fb34990SDag-Erling Smørgrav static void 11520fb34990SDag-Erling Smørgrav answer_notify(struct worker* w, struct query_info* qinfo, 1153865f46b2SCy Schubert struct edns_data* edns, sldns_buffer* pkt, 1154865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen) 11550fb34990SDag-Erling Smørgrav { 11560fb34990SDag-Erling Smørgrav int refused = 0; 11570fb34990SDag-Erling Smørgrav int rcode = LDNS_RCODE_NOERROR; 11580fb34990SDag-Erling Smørgrav uint32_t serial = 0; 11590fb34990SDag-Erling Smørgrav int has_serial; 11600fb34990SDag-Erling Smørgrav if(!w->env.auth_zones) return; 11610fb34990SDag-Erling Smørgrav has_serial = auth_zone_parse_notify_serial(pkt, &serial); 11620fb34990SDag-Erling Smørgrav if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname, 1163865f46b2SCy Schubert qinfo->qname_len, qinfo->qclass, addr, 1164865f46b2SCy Schubert addrlen, has_serial, serial, &refused)) { 11650fb34990SDag-Erling Smørgrav rcode = LDNS_RCODE_NOERROR; 11660fb34990SDag-Erling Smørgrav } else { 11670fb34990SDag-Erling Smørgrav if(refused) 11680fb34990SDag-Erling Smørgrav rcode = LDNS_RCODE_REFUSED; 11690fb34990SDag-Erling Smørgrav else rcode = LDNS_RCODE_SERVFAIL; 11700fb34990SDag-Erling Smørgrav } 11710fb34990SDag-Erling Smørgrav 11720fb34990SDag-Erling Smørgrav if(verbosity >= VERB_DETAIL) { 11730fb34990SDag-Erling Smørgrav char buf[380]; 1174*be771a7bSCy Schubert char zname[LDNS_MAX_DOMAINLEN]; 11750fb34990SDag-Erling Smørgrav char sr[25]; 11760fb34990SDag-Erling Smørgrav dname_str(qinfo->qname, zname); 11770fb34990SDag-Erling Smørgrav sr[0]=0; 11780fb34990SDag-Erling Smørgrav if(has_serial) 11790fb34990SDag-Erling Smørgrav snprintf(sr, sizeof(sr), "serial %u ", 11800fb34990SDag-Erling Smørgrav (unsigned)serial); 11810fb34990SDag-Erling Smørgrav if(rcode == LDNS_RCODE_REFUSED) 11820fb34990SDag-Erling Smørgrav snprintf(buf, sizeof(buf), 11830fb34990SDag-Erling Smørgrav "refused NOTIFY %sfor %s from", sr, zname); 11840fb34990SDag-Erling Smørgrav else if(rcode == LDNS_RCODE_SERVFAIL) 11850fb34990SDag-Erling Smørgrav snprintf(buf, sizeof(buf), 11860fb34990SDag-Erling Smørgrav "servfail for NOTIFY %sfor %s from", sr, zname); 11870fb34990SDag-Erling Smørgrav else snprintf(buf, sizeof(buf), 11880fb34990SDag-Erling Smørgrav "received NOTIFY %sfor %s from", sr, zname); 1189865f46b2SCy Schubert log_addr(VERB_DETAIL, buf, addr, addrlen); 11900fb34990SDag-Erling Smørgrav } 11910fb34990SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 11920fb34990SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 11930fb34990SDag-Erling Smørgrav edns->ext_rcode = 0; 11940fb34990SDag-Erling Smørgrav edns->bits &= EDNS_DO; 11950fb34990SDag-Erling Smørgrav error_encode(pkt, rcode, qinfo, 11960fb34990SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(pkt), 11970fb34990SDag-Erling Smørgrav sldns_buffer_read_u16_at(pkt, 2), edns); 11980fb34990SDag-Erling Smørgrav LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY); 11990fb34990SDag-Erling Smørgrav } 12000fb34990SDag-Erling Smørgrav 120117d15b25SDag-Erling Smørgrav static int 120217d15b25SDag-Erling Smørgrav deny_refuse(struct comm_point* c, enum acl_access acl, 120317d15b25SDag-Erling Smørgrav enum acl_access deny, enum acl_access refuse, 1204a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 12058f76bb7dSCy Schubert struct acl_addr* acladdr, int ede, 12068f76bb7dSCy Schubert struct check_request_result* check_result) 120717d15b25SDag-Erling Smørgrav { 120817d15b25SDag-Erling Smørgrav if(acl == deny) { 1209a39a5a69SCy Schubert if(verbosity >= VERB_ALGO) { 1210865f46b2SCy Schubert log_acl_action("dropped", &repinfo->client_addr, 1211865f46b2SCy Schubert repinfo->client_addrlen, acl, acladdr); 1212a39a5a69SCy Schubert log_buf(VERB_ALGO, "dropped", c->buffer); 1213a39a5a69SCy Schubert } 121417d15b25SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 121517d15b25SDag-Erling Smørgrav if(worker->stats.extended) 121617d15b25SDag-Erling Smørgrav worker->stats.unwanted_queries++; 121717d15b25SDag-Erling Smørgrav return 0; 121817d15b25SDag-Erling Smørgrav } else if(acl == refuse) { 1219a39a5a69SCy Schubert size_t opt_rr_mark; 1220a39a5a69SCy Schubert 1221a39a5a69SCy Schubert if(verbosity >= VERB_ALGO) { 1222865f46b2SCy Schubert log_acl_action("refused", &repinfo->client_addr, 1223865f46b2SCy Schubert repinfo->client_addrlen, acl, acladdr); 122417d15b25SDag-Erling Smørgrav log_buf(VERB_ALGO, "refuse", c->buffer); 1225a39a5a69SCy Schubert } 1226a39a5a69SCy Schubert 122717d15b25SDag-Erling Smørgrav if(worker->stats.extended) 122817d15b25SDag-Erling Smørgrav worker->stats.unwanted_queries++; 12298f76bb7dSCy Schubert worker_check_request(c->buffer, worker, check_result); 12308f76bb7dSCy Schubert if(check_result->value != 0) { 12318f76bb7dSCy Schubert if(check_result->value != -1) { 12328f76bb7dSCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 12338f76bb7dSCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 12348f76bb7dSCy Schubert check_result->value); 12358f76bb7dSCy Schubert return 1; 12368f76bb7dSCy Schubert } 123717d15b25SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 12388f76bb7dSCy Schubert return 0; 123917d15b25SDag-Erling Smørgrav } 1240a39a5a69SCy Schubert /* worker_check_request() above guarantees that the buffer contains at 1241a39a5a69SCy Schubert * least a header and that qdcount == 1 1242a39a5a69SCy Schubert */ 1243a39a5a69SCy Schubert log_assert(sldns_buffer_limit(c->buffer) >= LDNS_HEADER_SIZE 1244a39a5a69SCy Schubert && LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1); 1245a39a5a69SCy Schubert 1246b7c0c8c1SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); /* skip header */ 1247a39a5a69SCy Schubert 1248a39a5a69SCy Schubert /* check additional section is present and that we respond with EDEs */ 1249a39a5a69SCy Schubert if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1 1250a39a5a69SCy Schubert || !ede) { 1251a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1252a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1253a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1254a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 125517d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 125617d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 125717d15b25SDag-Erling Smørgrav LDNS_RCODE_REFUSED); 1258b7c0c8c1SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1259a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1260a39a5a69SCy Schubert return 1; 1261a39a5a69SCy Schubert } 1262a39a5a69SCy Schubert 1263a39a5a69SCy Schubert if (!query_dname_len(c->buffer)) { 1264a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1265a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1266a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1267a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1268a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1269a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1270a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1271b5663de9SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1272b5663de9SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 127317d15b25SDag-Erling Smørgrav return 1; 127417d15b25SDag-Erling Smørgrav } 1275a39a5a69SCy Schubert /* space available for query type and class? */ 1276a39a5a69SCy Schubert if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) { 1277a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1278a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1279a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1280a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1281a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1282a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1283a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1284a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1285a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1286a39a5a69SCy Schubert return 1; 1287a39a5a69SCy Schubert } 1288a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1289a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1290a39a5a69SCy Schubert LDNS_RCODE_REFUSED); 1291a39a5a69SCy Schubert 1292a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 1293a39a5a69SCy Schubert 1294a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 1295a39a5a69SCy Schubert 1296a39a5a69SCy Schubert /* The OPT RR to be returned should come directly after 1297a39a5a69SCy Schubert * the query, so mark this spot. 1298a39a5a69SCy Schubert */ 1299a39a5a69SCy Schubert opt_rr_mark = sldns_buffer_position(c->buffer); 1300a39a5a69SCy Schubert 1301a39a5a69SCy Schubert /* Skip through the RR records */ 1302a39a5a69SCy Schubert if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 || 1303a39a5a69SCy Schubert LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) { 1304a39a5a69SCy Schubert if(!skip_pkt_rrs(c->buffer, 1305a39a5a69SCy Schubert ((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+ 1306a39a5a69SCy Schubert ((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) { 1307a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1308a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1309a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1310a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1311a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1312a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1313a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1314a39a5a69SCy Schubert return 1; 1315a39a5a69SCy Schubert } 1316a39a5a69SCy Schubert } 1317a39a5a69SCy Schubert /* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */ 1318a39a5a69SCy Schubert /* domain name must be the root of length 1. */ 1319a39a5a69SCy Schubert if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) { 1320a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1321a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1322a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1323a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1324a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1325a39a5a69SCy Schubert return 1; 1326a39a5a69SCy Schubert } else { 1327a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, 1); /* skip root label */ 1328a39a5a69SCy Schubert } 1329a39a5a69SCy Schubert if(sldns_buffer_remaining(c->buffer) < 2 || 1330a39a5a69SCy Schubert sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) { 1331a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1332a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1333a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1334a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1335a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1336a39a5a69SCy Schubert return 1; 1337a39a5a69SCy Schubert } 1338a39a5a69SCy Schubert /* Write OPT RR directly after the query, 1339a39a5a69SCy Schubert * so without the (possibly skipped) Answer and NS RRs 1340a39a5a69SCy Schubert */ 1341a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1342a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1343a39a5a69SCy Schubert sldns_buffer_clear(c->buffer); /* reset write limit */ 1344a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1345a39a5a69SCy Schubert 1346a39a5a69SCy Schubert /* Check if OPT record can be written 1347a39a5a69SCy Schubert * 17 == root label (1) + RR type (2) + UDP Size (2) 1348a39a5a69SCy Schubert * + Fields (4) + rdata len (2) + EDE Option code (2) 1349a39a5a69SCy Schubert * + EDE Option length (2) + EDE info-code (2) 1350a39a5a69SCy Schubert */ 1351a39a5a69SCy Schubert if (sldns_buffer_available(c->buffer, 17) == 0) { 1352a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1353a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1354a39a5a69SCy Schubert return 1; 1355a39a5a69SCy Schubert } 1356a39a5a69SCy Schubert 1357a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1); 1358a39a5a69SCy Schubert 1359a39a5a69SCy Schubert /* root label */ 1360a39a5a69SCy Schubert sldns_buffer_write_u8(c->buffer, 0); 1361a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT); 1362a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE); 1363a39a5a69SCy Schubert 1364a39a5a69SCy Schubert /* write OPT Record TTL Field */ 1365a39a5a69SCy Schubert sldns_buffer_write_u32(c->buffer, 0); 1366a39a5a69SCy Schubert 1367a39a5a69SCy Schubert /* write rdata len: EDE option + length + info-code */ 1368a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, 6); 1369a39a5a69SCy Schubert 1370a39a5a69SCy Schubert /* write OPTIONS; add EDE option code */ 1371a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE); 1372a39a5a69SCy Schubert 1373a39a5a69SCy Schubert /* write single EDE option length (for just 1 info-code) */ 1374a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, 2); 1375a39a5a69SCy Schubert 1376a39a5a69SCy Schubert /* write single EDE info-code */ 1377a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_EDE_PROHIBITED); 1378a39a5a69SCy Schubert 1379a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1380a39a5a69SCy Schubert 1381a39a5a69SCy Schubert verbose(VERB_ALGO, "attached EDE code: %d", LDNS_EDE_PROHIBITED); 1382a39a5a69SCy Schubert 1383a39a5a69SCy Schubert return 1; 1384a39a5a69SCy Schubert 1385a39a5a69SCy Schubert } 138617d15b25SDag-Erling Smørgrav 138717d15b25SDag-Erling Smørgrav return -1; 138817d15b25SDag-Erling Smørgrav } 138917d15b25SDag-Erling Smørgrav 139017d15b25SDag-Erling Smørgrav static int 1391865f46b2SCy Schubert deny_refuse_all(struct comm_point* c, enum acl_access* acl, 1392a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 13938f76bb7dSCy Schubert struct acl_addr** acladdr, int ede, int check_proxy, 13948f76bb7dSCy Schubert struct check_request_result* check_result) 139517d15b25SDag-Erling Smørgrav { 1396865f46b2SCy Schubert if(check_proxy) { 1397865f46b2SCy Schubert *acladdr = acl_addr_lookup(worker->daemon->acl, 1398865f46b2SCy Schubert &repinfo->remote_addr, repinfo->remote_addrlen); 1399865f46b2SCy Schubert } else { 1400865f46b2SCy Schubert *acladdr = acl_addr_lookup(worker->daemon->acl, 1401865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1402865f46b2SCy Schubert } 1403865f46b2SCy Schubert /* If there is no ACL based on client IP use the interface ACL. */ 1404865f46b2SCy Schubert if(!(*acladdr) && c->socket) { 1405865f46b2SCy Schubert *acladdr = c->socket->acl; 1406865f46b2SCy Schubert } 1407865f46b2SCy Schubert *acl = acl_get_control(*acladdr); 1408865f46b2SCy Schubert return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo, 14098f76bb7dSCy Schubert *acladdr, ede, check_result); 141017d15b25SDag-Erling Smørgrav } 141117d15b25SDag-Erling Smørgrav 141217d15b25SDag-Erling Smørgrav static int 141317d15b25SDag-Erling Smørgrav deny_refuse_non_local(struct comm_point* c, enum acl_access acl, 1414a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 14158f76bb7dSCy Schubert struct acl_addr* acladdr, int ede, 14168f76bb7dSCy Schubert struct check_request_result* check_result) 141717d15b25SDag-Erling Smørgrav { 1418a39a5a69SCy Schubert return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, 14198f76bb7dSCy Schubert worker, repinfo, acladdr, ede, check_result); 14208f76bb7dSCy Schubert } 14218f76bb7dSCy Schubert 14228f76bb7dSCy Schubert /* Check if the query is blocked by source IP rate limiting. 14238f76bb7dSCy Schubert * Returns 1 if it passes the check, 0 otherwise. */ 14248f76bb7dSCy Schubert static int 14258f76bb7dSCy Schubert check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr, 14268f76bb7dSCy Schubert socklen_t addrlen, int has_cookie, sldns_buffer* pkt) 14278f76bb7dSCy Schubert { 14288f76bb7dSCy Schubert if(!infra_ip_ratelimit_inc(worker->env.infra_cache, addr, addrlen, 14298f76bb7dSCy Schubert *worker->env.now, has_cookie, 14308f76bb7dSCy Schubert worker->env.cfg->ip_ratelimit_backoff, pkt)) { 14318f76bb7dSCy Schubert /* See if we can pass through with slip factor */ 14328f76bb7dSCy Schubert if(!has_cookie && worker->env.cfg->ip_ratelimit_factor != 0 && 14338f76bb7dSCy Schubert ub_random_max(worker->env.rnd, 14348f76bb7dSCy Schubert worker->env.cfg->ip_ratelimit_factor) == 0) { 14358f76bb7dSCy Schubert char addrbuf[128]; 14368f76bb7dSCy Schubert addr_to_str(addr, addrlen, addrbuf, sizeof(addrbuf)); 14378f76bb7dSCy Schubert verbose(VERB_QUERY, "ip_ratelimit allowed through for " 14388f76bb7dSCy Schubert "ip address %s because of slip in " 14398f76bb7dSCy Schubert "ip_ratelimit_factor", addrbuf); 14408f76bb7dSCy Schubert return 1; 14418f76bb7dSCy Schubert } 14428f76bb7dSCy Schubert return 0; 14438f76bb7dSCy Schubert } 14448f76bb7dSCy Schubert return 1; 144517d15b25SDag-Erling Smørgrav } 144617d15b25SDag-Erling Smørgrav 1447b7579f77SDag-Erling Smørgrav int 1448b7579f77SDag-Erling Smørgrav worker_handle_request(struct comm_point* c, void* arg, int error, 1449b7579f77SDag-Erling Smørgrav struct comm_reply* repinfo) 1450b7579f77SDag-Erling Smørgrav { 1451b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 1452b7579f77SDag-Erling Smørgrav int ret; 14533005e0a3SDag-Erling Smørgrav hashvalue_type h; 1454b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 1455b7579f77SDag-Erling Smørgrav struct query_info qinfo; 1456b7579f77SDag-Erling Smørgrav struct edns_data edns; 1457a39a5a69SCy Schubert struct edns_option* original_edns_list = NULL; 1458b7579f77SDag-Erling Smørgrav enum acl_access acl; 1459b5663de9SDag-Erling Smørgrav struct acl_addr* acladdr; 14608f76bb7dSCy Schubert int pre_edns_ip_ratelimit = 1; 1461ff825849SDag-Erling Smørgrav int rc = 0; 146265b390aaSDag-Erling Smørgrav int need_drop = 0; 1463091e9e46SCy Schubert int is_expired_answer = 0; 1464091e9e46SCy Schubert int is_secure_answer = 0; 1465a39a5a69SCy Schubert int rpz_passthru = 0; 14668f76bb7dSCy Schubert long long wait_queue_time = 0; 146765b390aaSDag-Erling Smørgrav /* We might have to chase a CNAME chain internally, in which case 146865b390aaSDag-Erling Smørgrav * we'll have up to two replies and combine them to build a complete 146965b390aaSDag-Erling Smørgrav * answer. These variables control this case. */ 147065b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* alias_rrset = NULL; 147165b390aaSDag-Erling Smørgrav struct reply_info* partial_rep = NULL; 147265b390aaSDag-Erling Smørgrav struct query_info* lookup_qinfo = &qinfo; 1473e86b9096SDag-Erling Smørgrav struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */ 147465b390aaSDag-Erling Smørgrav struct respip_client_info* cinfo = NULL, cinfo_tmp; 14758f76bb7dSCy Schubert struct timeval wait_time; 14768f76bb7dSCy Schubert struct check_request_result check_result = {0,0}; 1477971980c3SDag-Erling Smørgrav memset(&qinfo, 0, sizeof(qinfo)); 1478b7579f77SDag-Erling Smørgrav 1479c0caa2e2SCy Schubert if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) { 1480b7579f77SDag-Erling Smørgrav /* some bad tcp query DNS formats give these error calls */ 1481b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "handle request called with err=%d", error); 1482b7579f77SDag-Erling Smørgrav return 0; 1483b7579f77SDag-Erling Smørgrav } 14848f76bb7dSCy Schubert 14858f76bb7dSCy Schubert if (worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv)) { 14868f76bb7dSCy Schubert timeval_subtract(&wait_time, worker->env.now_tv, &c->recv_tv); 14878f76bb7dSCy Schubert wait_queue_time = wait_time.tv_sec * 1000000 + wait_time.tv_usec; 14888f76bb7dSCy Schubert if (worker->stats.max_query_time_us < wait_queue_time) 14898f76bb7dSCy Schubert worker->stats.max_query_time_us = wait_queue_time; 14908f76bb7dSCy Schubert if(wait_queue_time > 14918f76bb7dSCy Schubert (long long)(worker->env.cfg->sock_queue_timeout * 1000000)) { 14928f76bb7dSCy Schubert /* count and drop queries that were sitting in the socket queue too long */ 14938f76bb7dSCy Schubert worker->stats.num_queries_timed_out++; 14948f76bb7dSCy Schubert return 0; 14958f76bb7dSCy Schubert } 14968f76bb7dSCy Schubert } 14978f76bb7dSCy Schubert 149865b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 149965b390aaSDag-Erling Smørgrav repinfo->max_udp_size = worker->daemon->cfg->max_udp_size; 150065b390aaSDag-Erling Smørgrav if(!dnsc_handle_curved_request(worker->daemon->dnscenv, repinfo)) { 150165b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_crypted_malformed++; 150265b390aaSDag-Erling Smørgrav return 0; 150365b390aaSDag-Erling Smørgrav } 150465b390aaSDag-Erling Smørgrav if(c->dnscrypt && !repinfo->is_dnscrypted) { 1505*be771a7bSCy Schubert char buf[LDNS_MAX_DOMAINLEN]; 1506c7f4d7adSDag-Erling Smørgrav /* Check if this is unencrypted and asking for certs */ 15078f76bb7dSCy Schubert worker_check_request(c->buffer, worker, &check_result); 15088f76bb7dSCy Schubert if(check_result.value != 0) { 1509c7f4d7adSDag-Erling Smørgrav verbose(VERB_ALGO, 1510c7f4d7adSDag-Erling Smørgrav "dnscrypt: worker check request: bad query."); 1511865f46b2SCy Schubert log_addr(VERB_CLIENT,"from",&repinfo->client_addr, 1512865f46b2SCy Schubert repinfo->client_addrlen); 151365b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 151465b390aaSDag-Erling Smørgrav return 0; 151565b390aaSDag-Erling Smørgrav } 151665b390aaSDag-Erling Smørgrav if(!query_info_parse(&qinfo, c->buffer)) { 1517c7f4d7adSDag-Erling Smørgrav verbose(VERB_ALGO, 1518c7f4d7adSDag-Erling Smørgrav "dnscrypt: worker parse request: formerror."); 1519865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1520865f46b2SCy Schubert repinfo->client_addrlen); 152165b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 152265b390aaSDag-Erling Smørgrav return 0; 152365b390aaSDag-Erling Smørgrav } 152465b390aaSDag-Erling Smørgrav dname_str(qinfo.qname, buf); 152565b390aaSDag-Erling Smørgrav if(!(qinfo.qtype == LDNS_RR_TYPE_TXT && 1526c7f4d7adSDag-Erling Smørgrav strcasecmp(buf, 1527c7f4d7adSDag-Erling Smørgrav worker->daemon->dnscenv->provider_name) == 0)) { 152865b390aaSDag-Erling Smørgrav verbose(VERB_ALGO, 152957bddd21SDag-Erling Smørgrav "dnscrypt: not TXT \"%s\". Received: %s \"%s\"", 153065b390aaSDag-Erling Smørgrav worker->daemon->dnscenv->provider_name, 153165b390aaSDag-Erling Smørgrav sldns_rr_descript(qinfo.qtype)->_name, 153265b390aaSDag-Erling Smørgrav buf); 153365b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 153465b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_cleartext++; 153565b390aaSDag-Erling Smørgrav return 0; 153665b390aaSDag-Erling Smørgrav } 153765b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_cert++; 153865b390aaSDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 153965b390aaSDag-Erling Smørgrav } else if(c->dnscrypt && repinfo->is_dnscrypted) { 154065b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_crypted++; 154165b390aaSDag-Erling Smørgrav } 154265b390aaSDag-Erling Smørgrav #endif 1543ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 15445469a995SCy Schubert /* 15455469a995SCy Schubert * sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler 15465469a995SCy Schubert */ 15475469a995SCy Schubert if(worker->dtenv.log_client_query_messages) { 1548865f46b2SCy Schubert log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen); 1549335c7cdaSCy Schubert log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen); 1550335c7cdaSCy Schubert dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer, 15518f76bb7dSCy Schubert ((worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv))?&c->recv_tv:NULL)); 15525469a995SCy Schubert } 1553ff825849SDag-Erling Smørgrav #endif 1554865f46b2SCy Schubert /* Check deny/refuse ACLs */ 1555865f46b2SCy Schubert if(repinfo->is_proxied) { 1556865f46b2SCy Schubert if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, 15578f76bb7dSCy Schubert worker->env.cfg->ede, 1, &check_result)) != -1) { 15588cee2ebaSCy Schubert if(ret == 1) 15598cee2ebaSCy Schubert goto send_reply; 15608cee2ebaSCy Schubert return ret; 15618cee2ebaSCy Schubert } 1562865f46b2SCy Schubert } 1563865f46b2SCy Schubert if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, 15648f76bb7dSCy Schubert worker->env.cfg->ede, 0, &check_result)) != -1) { 1565865f46b2SCy Schubert if(ret == 1) 1566865f46b2SCy Schubert goto send_reply; 1567865f46b2SCy Schubert return ret; 1568865f46b2SCy Schubert } 1569865f46b2SCy Schubert 15708f76bb7dSCy Schubert worker_check_request(c->buffer, worker, &check_result); 15718f76bb7dSCy Schubert if(check_result.value != 0) { 1572b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker check request: bad query."); 1573865f46b2SCy Schubert log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen); 15748f76bb7dSCy Schubert if(check_result.value != -1) { 157517d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 15768f76bb7dSCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 15778f76bb7dSCy Schubert check_result.value); 1578b7579f77SDag-Erling Smørgrav return 1; 1579b7579f77SDag-Erling Smørgrav } 1580b7579f77SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 1581b7579f77SDag-Erling Smørgrav return 0; 1582b7579f77SDag-Erling Smørgrav } 15833005e0a3SDag-Erling Smørgrav 1584b7579f77SDag-Erling Smørgrav worker->stats.num_queries++; 1585b7c0c8c1SCy Schubert pre_edns_ip_ratelimit = !worker->env.cfg->do_answer_cookie 1586b7c0c8c1SCy Schubert || sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE 1587b7c0c8c1SCy Schubert || LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) == 0; 15883005e0a3SDag-Erling Smørgrav 15898f76bb7dSCy Schubert /* If the IP rate limiting check needs extra EDNS information (e.g., 15908f76bb7dSCy Schubert * DNS Cookies) postpone the check until after EDNS is parsed. */ 15918f76bb7dSCy Schubert if(pre_edns_ip_ratelimit) { 15928f76bb7dSCy Schubert /* NOTE: we always check the repinfo->client_address. 15938f76bb7dSCy Schubert * IP ratelimiting is implicitly disabled for proxies. */ 15948f76bb7dSCy Schubert if(!check_ip_ratelimit(worker, &repinfo->client_addr, 15958f76bb7dSCy Schubert repinfo->client_addrlen, 0, c->buffer)) { 15963005e0a3SDag-Erling Smørgrav worker->stats.num_queries_ip_ratelimited++; 15973005e0a3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 15983005e0a3SDag-Erling Smørgrav return 0; 15993005e0a3SDag-Erling Smørgrav } 16003005e0a3SDag-Erling Smørgrav } 16013005e0a3SDag-Erling Smørgrav 1602b7579f77SDag-Erling Smørgrav if(!query_info_parse(&qinfo, c->buffer)) { 1603b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker parse request: formerror."); 1604865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1605865f46b2SCy Schubert repinfo->client_addrlen); 1606971980c3SDag-Erling Smørgrav memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */ 160709a3aaf3SDag-Erling Smørgrav if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { 160809a3aaf3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 160909a3aaf3SDag-Erling Smørgrav return 0; 161009a3aaf3SDag-Erling Smørgrav } 161117d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 161217d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 161317d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1614b7579f77SDag-Erling Smørgrav LDNS_RCODE_FORMERR); 1615ff825849SDag-Erling Smørgrav goto send_reply; 1616b7579f77SDag-Erling Smørgrav } 1617b7579f77SDag-Erling Smørgrav if(worker->env.cfg->log_queries) { 1618b7579f77SDag-Erling Smørgrav char ip[128]; 1619865f46b2SCy Schubert addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip)); 1620e86b9096SDag-Erling Smørgrav log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass); 1621b7579f77SDag-Erling Smørgrav } 1622b7579f77SDag-Erling Smørgrav if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 1623b7579f77SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_IXFR) { 1624b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: refused zone transfer."); 1625865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1626865f46b2SCy Schubert repinfo->client_addrlen); 162717d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 162817d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 162917d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1630b7579f77SDag-Erling Smørgrav LDNS_RCODE_REFUSED); 1631b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 1632b7579f77SDag-Erling Smørgrav worker->stats.qtype[qinfo.qtype]++; 1633b7579f77SDag-Erling Smørgrav } 1634ff825849SDag-Erling Smørgrav goto send_reply; 1635b7579f77SDag-Erling Smørgrav } 16363005e0a3SDag-Erling Smørgrav if(qinfo.qtype == LDNS_RR_TYPE_OPT || 16373005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_TSIG || 16383005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_TKEY || 16393005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_MAILA || 16403005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_MAILB || 16413005e0a3SDag-Erling Smørgrav (qinfo.qtype >= 128 && qinfo.qtype <= 248)) { 16423005e0a3SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: formerror for meta-type."); 1643865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1644865f46b2SCy Schubert repinfo->client_addrlen); 16453005e0a3SDag-Erling Smørgrav if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { 16463005e0a3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 16473005e0a3SDag-Erling Smørgrav return 0; 16483005e0a3SDag-Erling Smørgrav } 16493005e0a3SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 16503005e0a3SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 16513005e0a3SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 16523005e0a3SDag-Erling Smørgrav LDNS_RCODE_FORMERR); 16533005e0a3SDag-Erling Smørgrav if(worker->stats.extended) { 16543005e0a3SDag-Erling Smørgrav worker->stats.qtype[qinfo.qtype]++; 16553005e0a3SDag-Erling Smørgrav } 16563005e0a3SDag-Erling Smørgrav goto send_reply; 16573005e0a3SDag-Erling Smørgrav } 16588f76bb7dSCy Schubert if((ret=parse_edns_from_query_pkt( 16598f76bb7dSCy Schubert c->buffer, &edns, worker->env.cfg, c, repinfo, 16608f76bb7dSCy Schubert (worker->env.now ? *worker->env.now : time(NULL)), 166156850988SCy Schubert worker->scratchpad, 166256850988SCy Schubert worker->daemon->cookie_secrets)) != 0) { 166305ab2901SDag-Erling Smørgrav struct edns_data reply_edns; 1664b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker parse edns: formerror."); 1665865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1666865f46b2SCy Schubert repinfo->client_addrlen); 166705ab2901SDag-Erling Smørgrav memset(&reply_edns, 0, sizeof(reply_edns)); 166805ab2901SDag-Erling Smørgrav reply_edns.edns_present = 1; 166905ab2901SDag-Erling Smørgrav error_encode(c->buffer, ret, &qinfo, 167005ab2901SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 167105ab2901SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); 1672e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1673ff825849SDag-Erling Smørgrav goto send_reply; 1674b7579f77SDag-Erling Smørgrav } 16754c75e3aaSDag-Erling Smørgrav if(edns.edns_present) { 16764c75e3aaSDag-Erling Smørgrav if(edns.edns_version != 0) { 167724e36522SCy Schubert edns.opt_list_in = NULL; 167824e36522SCy Schubert edns.opt_list_out = NULL; 167924e36522SCy Schubert edns.opt_list_inplace_cb_out = NULL; 1680b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "query with bad edns version."); 1681865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1682865f46b2SCy Schubert repinfo->client_addrlen); 16838f76bb7dSCy Schubert extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo, 168417d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 16858f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns); 1686e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1687ff825849SDag-Erling Smørgrav goto send_reply; 1688b7579f77SDag-Erling Smørgrav } 16894c75e3aaSDag-Erling Smørgrav if(edns.udp_size < NORMAL_UDP_SIZE && 1690b7579f77SDag-Erling Smørgrav worker->daemon->cfg->harden_short_bufsize) { 1691b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", 1692b7579f77SDag-Erling Smørgrav (int)edns.udp_size); 1693865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1694865f46b2SCy Schubert repinfo->client_addrlen); 1695b7579f77SDag-Erling Smørgrav edns.udp_size = NORMAL_UDP_SIZE; 1696b7579f77SDag-Erling Smørgrav } 16974c75e3aaSDag-Erling Smørgrav } 16988f76bb7dSCy Schubert 16998f76bb7dSCy Schubert /* Get stats for cookies */ 17008f76bb7dSCy Schubert server_stats_downstream_cookie(&worker->stats, &edns); 17018f76bb7dSCy Schubert 17028f76bb7dSCy Schubert /* If the IP rate limiting check was postponed, check now. */ 17038f76bb7dSCy Schubert if(!pre_edns_ip_ratelimit) { 17048f76bb7dSCy Schubert /* NOTE: we always check the repinfo->client_address. 17058f76bb7dSCy Schubert * IP ratelimiting is implicitly disabled for proxies. */ 17068f76bb7dSCy Schubert if(!check_ip_ratelimit(worker, &repinfo->client_addr, 17078f76bb7dSCy Schubert repinfo->client_addrlen, edns.cookie_valid, 17088f76bb7dSCy Schubert c->buffer)) { 17098f76bb7dSCy Schubert worker->stats.num_queries_ip_ratelimited++; 17108f76bb7dSCy Schubert comm_point_drop_reply(repinfo); 17118f76bb7dSCy Schubert return 0; 17128f76bb7dSCy Schubert } 17138f76bb7dSCy Schubert } 17148f76bb7dSCy Schubert 17158f76bb7dSCy Schubert /* "if, else if" sequence below deals with downstream DNS Cookies */ 17168f76bb7dSCy Schubert if(acl != acl_allow_cookie) 17178f76bb7dSCy Schubert ; /* pass; No cookie downstream processing whatsoever */ 17188f76bb7dSCy Schubert 17198f76bb7dSCy Schubert else if(edns.cookie_valid) 17208f76bb7dSCy Schubert ; /* pass; Valid cookie is good! */ 17218f76bb7dSCy Schubert 17228f76bb7dSCy Schubert else if(c->type != comm_udp) 17238f76bb7dSCy Schubert ; /* pass; Stateful transport */ 17248f76bb7dSCy Schubert 17258f76bb7dSCy Schubert else if(edns.cookie_present) { 17268f76bb7dSCy Schubert /* Cookie present, but not valid: Cookie was bad! */ 17278f76bb7dSCy Schubert extended_error_encode(c->buffer, 17288f76bb7dSCy Schubert LDNS_EXT_RCODE_BADCOOKIE, &qinfo, 17298f76bb7dSCy Schubert *(uint16_t*)(void *) 17308f76bb7dSCy Schubert sldns_buffer_begin(c->buffer), 17318f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 17328f76bb7dSCy Schubert 0, &edns); 17338f76bb7dSCy Schubert regional_free_all(worker->scratchpad); 17348f76bb7dSCy Schubert goto send_reply; 17358f76bb7dSCy Schubert } else { 17368f76bb7dSCy Schubert /* Cookie required, but no cookie present on UDP */ 17378f76bb7dSCy Schubert verbose(VERB_ALGO, "worker request: " 17388f76bb7dSCy Schubert "need cookie or stateful transport"); 17398f76bb7dSCy Schubert log_addr(VERB_ALGO, "from",&repinfo->remote_addr 17408f76bb7dSCy Schubert , repinfo->remote_addrlen); 17418f76bb7dSCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, 17428f76bb7dSCy Schubert worker->scratchpad, LDNS_EDE_OTHER, 17438f76bb7dSCy Schubert "DNS Cookie needed for UDP replies"); 17448f76bb7dSCy Schubert error_encode(c->buffer, 17458f76bb7dSCy Schubert (LDNS_RCODE_REFUSED|BIT_TC), &qinfo, 17468f76bb7dSCy Schubert *(uint16_t*)(void *) 17478f76bb7dSCy Schubert sldns_buffer_begin(c->buffer), 17488f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 17498f76bb7dSCy Schubert &edns); 17508f76bb7dSCy Schubert regional_free_all(worker->scratchpad); 17518f76bb7dSCy Schubert goto send_reply; 17528f76bb7dSCy Schubert } 17538f76bb7dSCy Schubert 175417d15b25SDag-Erling Smørgrav if(edns.udp_size > worker->daemon->cfg->max_udp_size && 175517d15b25SDag-Erling Smørgrav c->type == comm_udp) { 175617d15b25SDag-Erling Smørgrav verbose(VERB_QUERY, 175717d15b25SDag-Erling Smørgrav "worker request: max UDP reply size modified" 175817d15b25SDag-Erling Smørgrav " (%d to max-udp-size)", (int)edns.udp_size); 1759865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1760865f46b2SCy Schubert repinfo->client_addrlen); 176117d15b25SDag-Erling Smørgrav edns.udp_size = worker->daemon->cfg->max_udp_size; 176217d15b25SDag-Erling Smørgrav } 176317d15b25SDag-Erling Smørgrav if(edns.udp_size < LDNS_HEADER_SIZE) { 1764b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: edns is too small."); 1765865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1766865f46b2SCy Schubert repinfo->client_addrlen); 176717d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 176817d15b25SDag-Erling Smørgrav LDNS_TC_SET(sldns_buffer_begin(c->buffer)); 176917d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1770b7579f77SDag-Erling Smørgrav LDNS_RCODE_SERVFAIL); 177117d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 177217d15b25SDag-Erling Smørgrav sldns_buffer_write_at(c->buffer, 4, 1773b7579f77SDag-Erling Smørgrav (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 177417d15b25SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 1775e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1776ff825849SDag-Erling Smørgrav goto send_reply; 1777b7579f77SDag-Erling Smørgrav } 1778b7579f77SDag-Erling Smørgrav if(worker->stats.extended) 1779b7579f77SDag-Erling Smørgrav server_stats_insquery(&worker->stats, c, qinfo.qtype, 1780b7579f77SDag-Erling Smørgrav qinfo.qclass, &edns, repinfo); 1781b7579f77SDag-Erling Smørgrav if(c->type != comm_udp) 1782b7579f77SDag-Erling Smørgrav edns.udp_size = 65535; /* max size for TCP replies */ 1783b7579f77SDag-Erling Smørgrav if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, 17844c75e3aaSDag-Erling Smørgrav &edns, repinfo, c->buffer)) { 1785e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1786ff825849SDag-Erling Smørgrav goto send_reply; 1787b7579f77SDag-Erling Smørgrav } 17880fb34990SDag-Erling Smørgrav if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) == 17890fb34990SDag-Erling Smørgrav LDNS_PACKET_NOTIFY) { 1790865f46b2SCy Schubert answer_notify(worker, &qinfo, &edns, c->buffer, 1791865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 17920fb34990SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 17930fb34990SDag-Erling Smørgrav goto send_reply; 17940fb34990SDag-Erling Smørgrav } 1795bc892140SDag-Erling Smørgrav if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo, 1796bc892140SDag-Erling Smørgrav &edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist, 1797bc892140SDag-Erling Smørgrav acladdr->taglen, acladdr->tag_actions, 1798b5663de9SDag-Erling Smørgrav acladdr->tag_actions_size, acladdr->tag_datas, 1799b5663de9SDag-Erling Smørgrav acladdr->tag_datas_size, worker->daemon->cfg->tagname, 1800bc892140SDag-Erling Smørgrav worker->daemon->cfg->num_tags, acladdr->view)) { 1801b7579f77SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 180217d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) == 0) { 1803b7579f77SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 1804b7579f77SDag-Erling Smørgrav return 0; 1805b7579f77SDag-Erling Smørgrav } 1806ff825849SDag-Erling Smørgrav goto send_reply; 1807b7579f77SDag-Erling Smørgrav } 180857bddd21SDag-Erling Smørgrav if(worker->env.auth_zones && 180924e36522SCy Schubert rpz_callback_from_worker_request(worker->env.auth_zones, 1810091e9e46SCy Schubert &worker->env, &qinfo, &edns, c->buffer, worker->scratchpad, 1811a39a5a69SCy Schubert repinfo, acladdr->taglist, acladdr->taglen, &worker->stats, 1812a39a5a69SCy Schubert &rpz_passthru)) { 1813091e9e46SCy Schubert regional_free_all(worker->scratchpad); 1814091e9e46SCy Schubert if(sldns_buffer_limit(c->buffer) == 0) { 1815091e9e46SCy Schubert comm_point_drop_reply(repinfo); 1816091e9e46SCy Schubert return 0; 1817091e9e46SCy Schubert } 1818091e9e46SCy Schubert goto send_reply; 1819091e9e46SCy Schubert } 1820091e9e46SCy Schubert if(worker->env.auth_zones && 182157bddd21SDag-Erling Smørgrav auth_zones_answer(worker->env.auth_zones, &worker->env, 18224c75e3aaSDag-Erling Smørgrav &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) { 182357bddd21SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 182457bddd21SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) == 0) { 182557bddd21SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 182657bddd21SDag-Erling Smørgrav return 0; 182757bddd21SDag-Erling Smørgrav } 182857bddd21SDag-Erling Smørgrav /* set RA for everyone that can have recursion (based on 182957bddd21SDag-Erling Smørgrav * access control list) */ 183057bddd21SDag-Erling Smørgrav if(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer)) && 183157bddd21SDag-Erling Smørgrav acl != acl_deny_non_local && acl != acl_refuse_non_local) 183257bddd21SDag-Erling Smørgrav LDNS_RA_SET(sldns_buffer_begin(c->buffer)); 183357bddd21SDag-Erling Smørgrav goto send_reply; 183457bddd21SDag-Erling Smørgrav } 183517d15b25SDag-Erling Smørgrav 183617d15b25SDag-Erling Smørgrav /* We've looked in our local zones. If the answer isn't there, we 183717d15b25SDag-Erling Smørgrav * might need to bail out based on ACLs now. */ 1838a39a5a69SCy Schubert if((ret=deny_refuse_non_local(c, acl, worker, repinfo, acladdr, 18398f76bb7dSCy Schubert worker->env.cfg->ede, &check_result)) != -1) 184017d15b25SDag-Erling Smørgrav { 1841e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1842ff825849SDag-Erling Smørgrav if(ret == 1) 1843ff825849SDag-Erling Smørgrav goto send_reply; 184417d15b25SDag-Erling Smørgrav return ret; 184517d15b25SDag-Erling Smørgrav } 184617d15b25SDag-Erling Smørgrav 184717d15b25SDag-Erling Smørgrav /* If this request does not have the recursion bit set, verify 18483bd4df0aSDag-Erling Smørgrav * ACLs allow the recursion bit to be treated as set. */ 18493bd4df0aSDag-Erling Smørgrav if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 18503bd4df0aSDag-Erling Smørgrav acl == acl_allow_setrd ) { 18513bd4df0aSDag-Erling Smørgrav LDNS_RD_SET(sldns_buffer_begin(c->buffer)); 18523bd4df0aSDag-Erling Smørgrav } 18533bd4df0aSDag-Erling Smørgrav 18543bd4df0aSDag-Erling Smørgrav /* If this request does not have the recursion bit set, verify 185517d15b25SDag-Erling Smørgrav * ACLs allow the snooping. */ 185617d15b25SDag-Erling Smørgrav if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 1857b7579f77SDag-Erling Smørgrav acl != acl_allow_snoop ) { 1858a39a5a69SCy Schubert if(worker->env.cfg->ede) { 1859a39a5a69SCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, 1860a39a5a69SCy Schubert worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, ""); 1861a39a5a69SCy Schubert } 186257bddd21SDag-Erling Smørgrav error_encode(c->buffer, LDNS_RCODE_REFUSED, &qinfo, 186357bddd21SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 1864a39a5a69SCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), &edns); 1865e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1866b7579f77SDag-Erling Smørgrav log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", 1867865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1868a39a5a69SCy Schubert 1869ff825849SDag-Erling Smørgrav goto send_reply; 1870b7579f77SDag-Erling Smørgrav } 1871bc892140SDag-Erling Smørgrav 1872bc892140SDag-Erling Smørgrav /* If we've found a local alias, replace the qname with the alias 1873bc892140SDag-Erling Smørgrav * target before resolving it. */ 1874bc892140SDag-Erling Smørgrav if(qinfo.local_alias) { 1875bc892140SDag-Erling Smørgrav struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset; 1876bc892140SDag-Erling Smørgrav struct packed_rrset_data* d = rrset->entry.data; 1877bc892140SDag-Erling Smørgrav 1878bc892140SDag-Erling Smørgrav /* Sanity check: our current implementation only supports 1879bc892140SDag-Erling Smørgrav * a single CNAME RRset as a local alias. */ 1880bc892140SDag-Erling Smørgrav if(qinfo.local_alias->next || 1881bc892140SDag-Erling Smørgrav rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) || 1882bc892140SDag-Erling Smørgrav d->count != 1) { 1883bc892140SDag-Erling Smørgrav log_err("assumption failure: unexpected local alias"); 1884bc892140SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1885bc892140SDag-Erling Smørgrav return 0; /* drop it */ 1886bc892140SDag-Erling Smørgrav } 1887bc892140SDag-Erling Smørgrav qinfo.qname = d->rr_data[0] + 2; 1888bc892140SDag-Erling Smørgrav qinfo.qname_len = d->rr_len[0] - 2; 1889bc892140SDag-Erling Smørgrav } 1890bc892140SDag-Erling Smørgrav 189165b390aaSDag-Erling Smørgrav /* If we may apply IP-based actions to the answer, build the client 189265b390aaSDag-Erling Smørgrav * information. As this can be expensive, skip it if there is 189365b390aaSDag-Erling Smørgrav * absolutely no possibility of it. */ 1894091e9e46SCy Schubert if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && 189565b390aaSDag-Erling Smørgrav (qinfo.qtype == LDNS_RR_TYPE_A || 189665b390aaSDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_AAAA || 189765b390aaSDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_ANY)) { 189865b390aaSDag-Erling Smørgrav cinfo_tmp.taglist = acladdr->taglist; 189965b390aaSDag-Erling Smørgrav cinfo_tmp.taglen = acladdr->taglen; 190065b390aaSDag-Erling Smørgrav cinfo_tmp.tag_actions = acladdr->tag_actions; 190165b390aaSDag-Erling Smørgrav cinfo_tmp.tag_actions_size = acladdr->tag_actions_size; 190265b390aaSDag-Erling Smørgrav cinfo_tmp.tag_datas = acladdr->tag_datas; 190365b390aaSDag-Erling Smørgrav cinfo_tmp.tag_datas_size = acladdr->tag_datas_size; 190465b390aaSDag-Erling Smørgrav cinfo_tmp.view = acladdr->view; 1905*be771a7bSCy Schubert cinfo_tmp.view_name = NULL; 190665b390aaSDag-Erling Smørgrav cinfo = &cinfo_tmp; 190765b390aaSDag-Erling Smørgrav } 190865b390aaSDag-Erling Smørgrav 1909a39a5a69SCy Schubert /* Keep the original edns list around. The pointer could change if there is 1910a39a5a69SCy Schubert * a cached answer (through the inplace callback function there). 1911a39a5a69SCy Schubert * No need to actually copy the contents as they shouldn't change. 1912a39a5a69SCy Schubert * Used while prefetching and subnet is enabled. */ 1913a39a5a69SCy Schubert original_edns_list = edns.opt_list_in; 191465b390aaSDag-Erling Smørgrav lookup_cache: 191565b390aaSDag-Erling Smørgrav /* Lookup the cache. In case we chase an intermediate CNAME chain 191665b390aaSDag-Erling Smørgrav * this is a two-pass operation, and lookup_qinfo is different for 191765b390aaSDag-Erling Smørgrav * each pass. We should still pass the original qinfo to 191865b390aaSDag-Erling Smørgrav * answer_from_cache(), however, since it's used to build the reply. */ 191924e36522SCy Schubert if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) { 1920091e9e46SCy Schubert is_expired_answer = 0; 1921091e9e46SCy Schubert is_secure_answer = 0; 192265b390aaSDag-Erling Smørgrav h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); 192365b390aaSDag-Erling Smørgrav if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) { 19240a92a9fcSCy Schubert struct reply_info* rep = (struct reply_info*)e->data; 1925b7579f77SDag-Erling Smørgrav /* answer from cache - we have acquired a readlock on it */ 19260a92a9fcSCy Schubert if(answer_from_cache(worker, &qinfo, cinfo, &need_drop, 19270a92a9fcSCy Schubert &is_expired_answer, &is_secure_answer, 19280a92a9fcSCy Schubert &alias_rrset, &partial_rep, rep, 192917d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 193017d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 1931b7579f77SDag-Erling Smørgrav &edns)) { 193265b390aaSDag-Erling Smørgrav /* prefetch it if the prefetch TTL expired. 193365b390aaSDag-Erling Smørgrav * Note that if there is more than one pass 193465b390aaSDag-Erling Smørgrav * its qname must be that used for cache 193565b390aaSDag-Erling Smørgrav * lookup. */ 19360a92a9fcSCy Schubert if((worker->env.cfg->prefetch && 1937*be771a7bSCy Schubert rep->prefetch_ttl <= *worker->env.now) || 1938091e9e46SCy Schubert (worker->env.cfg->serve_expired && 1939*be771a7bSCy Schubert rep->ttl < *worker->env.now && 1940*be771a7bSCy Schubert !(*worker->env.now < rep->serve_expired_norec_ttl))) { 19410a92a9fcSCy Schubert time_t leeway = rep->ttl - *worker->env.now; 19420a92a9fcSCy Schubert if(rep->ttl < *worker->env.now) 1943bc892140SDag-Erling Smørgrav leeway = 0; 1944b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1945a39a5a69SCy Schubert 194665b390aaSDag-Erling Smørgrav reply_and_prefetch(worker, lookup_qinfo, 194717d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), 19480eefd307SCy Schubert repinfo, leeway, 1949a39a5a69SCy Schubert (partial_rep || need_drop), 1950a39a5a69SCy Schubert rpz_passthru, 1951a39a5a69SCy Schubert original_edns_list); 195265b390aaSDag-Erling Smørgrav if(!partial_rep) { 1953ff825849SDag-Erling Smørgrav rc = 0; 1954e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1955ff825849SDag-Erling Smørgrav goto send_reply_rc; 1956b7579f77SDag-Erling Smørgrav } 195765b390aaSDag-Erling Smørgrav } else if(!partial_rep) { 1958b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1959e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1960ff825849SDag-Erling Smørgrav goto send_reply; 1961971980c3SDag-Erling Smørgrav } else { 1962971980c3SDag-Erling Smørgrav /* Note that we've already released the 1963971980c3SDag-Erling Smørgrav * lock if we're here after prefetch. */ 1964971980c3SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1965b7579f77SDag-Erling Smørgrav } 196665b390aaSDag-Erling Smørgrav /* We've found a partial reply ending with an 196765b390aaSDag-Erling Smørgrav * alias. Replace the lookup qinfo for the 196865b390aaSDag-Erling Smørgrav * alias target and lookup the cache again to 196965b390aaSDag-Erling Smørgrav * (possibly) complete the reply. As we're 197065b390aaSDag-Erling Smørgrav * passing the "base" reply, there will be no 197165b390aaSDag-Erling Smørgrav * more alias chasing. */ 197265b390aaSDag-Erling Smørgrav memset(&qinfo_tmp, 0, sizeof(qinfo_tmp)); 197365b390aaSDag-Erling Smørgrav get_cname_target(alias_rrset, &qinfo_tmp.qname, 197465b390aaSDag-Erling Smørgrav &qinfo_tmp.qname_len); 197565b390aaSDag-Erling Smørgrav if(!qinfo_tmp.qname) { 197665b390aaSDag-Erling Smørgrav log_err("unexpected: invalid answer alias"); 197765b390aaSDag-Erling Smørgrav regional_free_all(worker->scratchpad); 197865b390aaSDag-Erling Smørgrav return 0; /* drop query */ 197965b390aaSDag-Erling Smørgrav } 198065b390aaSDag-Erling Smørgrav qinfo_tmp.qtype = qinfo.qtype; 198165b390aaSDag-Erling Smørgrav qinfo_tmp.qclass = qinfo.qclass; 198265b390aaSDag-Erling Smørgrav lookup_qinfo = &qinfo_tmp; 198365b390aaSDag-Erling Smørgrav goto lookup_cache; 198465b390aaSDag-Erling Smørgrav } 1985b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "answer from the cache failed"); 1986b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1987b7579f77SDag-Erling Smørgrav } 1988a39a5a69SCy Schubert 198917d15b25SDag-Erling Smørgrav if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { 1990b7579f77SDag-Erling Smørgrav if(answer_norec_from_cache(worker, &qinfo, 199117d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 199217d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 1993b7579f77SDag-Erling Smørgrav &edns)) { 1994e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1995ff825849SDag-Erling Smørgrav goto send_reply; 1996b7579f77SDag-Erling Smørgrav } 1997b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "answer norec from cache -- " 1998b7579f77SDag-Erling Smørgrav "need to validate or not primed"); 1999b7579f77SDag-Erling Smørgrav } 2000bc892140SDag-Erling Smørgrav } 200117d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 2002b7579f77SDag-Erling Smørgrav server_stats_querymiss(&worker->stats, worker); 2003b7579f77SDag-Erling Smørgrav 2004b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_CLIENT) { 2005b7579f77SDag-Erling Smørgrav if(c->type == comm_udp) 2006b7579f77SDag-Erling Smørgrav log_addr(VERB_CLIENT, "udp request from", 2007865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 2008b7579f77SDag-Erling Smørgrav else log_addr(VERB_CLIENT, "tcp request from", 2009865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 2010b7579f77SDag-Erling Smørgrav } 2011b7579f77SDag-Erling Smørgrav 2012b7579f77SDag-Erling Smørgrav /* grab a work request structure for this new request */ 201365b390aaSDag-Erling Smørgrav mesh_new_client(worker->env.mesh, &qinfo, cinfo, 201417d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), 2015a39a5a69SCy Schubert &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 2016a39a5a69SCy Schubert rpz_passthru); 2017e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 2018b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 2019b7579f77SDag-Erling Smørgrav return 0; 2020ff825849SDag-Erling Smørgrav 2021ff825849SDag-Erling Smørgrav send_reply: 2022ff825849SDag-Erling Smørgrav rc = 1; 2023ff825849SDag-Erling Smørgrav send_reply_rc: 202465b390aaSDag-Erling Smørgrav if(need_drop) { 202565b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 202665b390aaSDag-Erling Smørgrav return 0; 202765b390aaSDag-Erling Smørgrav } 2028091e9e46SCy Schubert if(is_expired_answer) { 2029091e9e46SCy Schubert worker->stats.ans_expired++; 2030091e9e46SCy Schubert } 2031c0caa2e2SCy Schubert server_stats_insrcode(&worker->stats, c->buffer); 2032091e9e46SCy Schubert if(worker->stats.extended) { 2033091e9e46SCy Schubert if(is_secure_answer) worker->stats.ans_secure++; 2034091e9e46SCy Schubert } 2035ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 20365469a995SCy Schubert /* 20375469a995SCy Schubert * sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.) 20385469a995SCy Schubert */ 2039335c7cdaSCy Schubert if(worker->dtenv.log_client_response_messages && rc !=0) { 2040335c7cdaSCy Schubert log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen); 2041865f46b2SCy Schubert log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen); 2042335c7cdaSCy Schubert dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer); 20435469a995SCy Schubert } 2044ff825849SDag-Erling Smørgrav #endif 20453005e0a3SDag-Erling Smørgrav if(worker->env.cfg->log_replies) 20463005e0a3SDag-Erling Smørgrav { 20470eefd307SCy Schubert struct timeval tv; 20480eefd307SCy Schubert memset(&tv, 0, sizeof(tv)); 2049e86b9096SDag-Erling Smørgrav if(qinfo.local_alias && qinfo.local_alias->rrset && 2050e86b9096SDag-Erling Smørgrav qinfo.local_alias->rrset->rk.dname) { 2051e86b9096SDag-Erling Smørgrav /* log original qname, before the local alias was 2052e86b9096SDag-Erling Smørgrav * used to resolve that CNAME to something else */ 2053e86b9096SDag-Erling Smørgrav qinfo.qname = qinfo.local_alias->rrset->rk.dname; 2054865f46b2SCy Schubert log_reply_info(NO_VERBOSE, &qinfo, 2055865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, 2056b7c0c8c1SCy Schubert tv, 1, c->buffer, 2057335c7cdaSCy Schubert (worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL), 2058*be771a7bSCy Schubert c->type, c->ssl); 2059e86b9096SDag-Erling Smørgrav } else { 2060865f46b2SCy Schubert log_reply_info(NO_VERBOSE, &qinfo, 2061865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, 2062b7c0c8c1SCy Schubert tv, 1, c->buffer, 2063335c7cdaSCy Schubert (worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL), 2064*be771a7bSCy Schubert c->type, c->ssl); 2065e86b9096SDag-Erling Smørgrav } 20663005e0a3SDag-Erling Smørgrav } 206765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 206865b390aaSDag-Erling Smørgrav if(!dnsc_handle_uncurved_request(repinfo)) { 206965b390aaSDag-Erling Smørgrav return 0; 207065b390aaSDag-Erling Smørgrav } 207165b390aaSDag-Erling Smørgrav #endif 2072ff825849SDag-Erling Smørgrav return rc; 2073b7579f77SDag-Erling Smørgrav } 2074b7579f77SDag-Erling Smørgrav 2075b7579f77SDag-Erling Smørgrav void 2076b7579f77SDag-Erling Smørgrav worker_sighandler(int sig, void* arg) 2077b7579f77SDag-Erling Smørgrav { 2078ff825849SDag-Erling Smørgrav /* note that log, print, syscalls here give race conditions. 2079ff825849SDag-Erling Smørgrav * And cause hangups if the log-lock is held by the application. */ 2080b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2081b7579f77SDag-Erling Smørgrav switch(sig) { 2082b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 2083b7579f77SDag-Erling Smørgrav case SIGHUP: 2084b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2085b7579f77SDag-Erling Smørgrav break; 2086b7579f77SDag-Erling Smørgrav #endif 2087a39a5a69SCy Schubert #ifdef SIGBREAK 2088a39a5a69SCy Schubert case SIGBREAK: 2089a39a5a69SCy Schubert #endif 2090b7579f77SDag-Erling Smørgrav case SIGINT: 2091b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2092b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2093b7579f77SDag-Erling Smørgrav break; 2094b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2095b7579f77SDag-Erling Smørgrav case SIGQUIT: 2096b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2097b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2098b7579f77SDag-Erling Smørgrav break; 2099b7579f77SDag-Erling Smørgrav #endif 2100b7579f77SDag-Erling Smørgrav case SIGTERM: 2101b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2102b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2103b7579f77SDag-Erling Smørgrav break; 2104b7579f77SDag-Erling Smørgrav default: 2105ff825849SDag-Erling Smørgrav /* unknown signal, ignored */ 2106b7579f77SDag-Erling Smørgrav break; 2107b7579f77SDag-Erling Smørgrav } 2108b7579f77SDag-Erling Smørgrav } 2109b7579f77SDag-Erling Smørgrav 2110b7579f77SDag-Erling Smørgrav /** restart statistics timer for worker, if enabled */ 2111b7579f77SDag-Erling Smørgrav static void 2112b7579f77SDag-Erling Smørgrav worker_restart_timer(struct worker* worker) 2113b7579f77SDag-Erling Smørgrav { 2114b7579f77SDag-Erling Smørgrav if(worker->env.cfg->stat_interval > 0) { 2115b7579f77SDag-Erling Smørgrav struct timeval tv; 2116b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 2117b7579f77SDag-Erling Smørgrav tv.tv_sec = worker->env.cfg->stat_interval; 2118b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2119b7579f77SDag-Erling Smørgrav #endif 2120b7579f77SDag-Erling Smørgrav comm_timer_set(worker->stat_timer, &tv); 2121b7579f77SDag-Erling Smørgrav } 2122b7579f77SDag-Erling Smørgrav } 2123b7579f77SDag-Erling Smørgrav 2124b7579f77SDag-Erling Smørgrav void worker_stat_timer_cb(void* arg) 2125b7579f77SDag-Erling Smørgrav { 2126b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2127b7579f77SDag-Erling Smørgrav server_stats_log(&worker->stats, worker, worker->thread_num); 2128b7579f77SDag-Erling Smørgrav mesh_stats(worker->env.mesh, "mesh has"); 2129b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 213065b390aaSDag-Erling Smørgrav /* SHM is enabled, process data to SHM */ 213165b390aaSDag-Erling Smørgrav if (worker->daemon->cfg->shm_enable) { 213265b390aaSDag-Erling Smørgrav shm_main_run(worker); 213365b390aaSDag-Erling Smørgrav } 2134b7579f77SDag-Erling Smørgrav if(!worker->daemon->cfg->stat_cumulative) { 2135b7579f77SDag-Erling Smørgrav worker_stats_clear(worker); 2136b7579f77SDag-Erling Smørgrav } 2137b7579f77SDag-Erling Smørgrav /* start next timer */ 2138b7579f77SDag-Erling Smørgrav worker_restart_timer(worker); 2139b7579f77SDag-Erling Smørgrav } 2140b7579f77SDag-Erling Smørgrav 2141b7579f77SDag-Erling Smørgrav void worker_probe_timer_cb(void* arg) 2142b7579f77SDag-Erling Smørgrav { 2143b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2144b7579f77SDag-Erling Smørgrav struct timeval tv; 2145b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 2146b7579f77SDag-Erling Smørgrav tv.tv_sec = (time_t)autr_probe_timer(&worker->env); 2147b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2148b7579f77SDag-Erling Smørgrav #endif 2149b7579f77SDag-Erling Smørgrav if(tv.tv_sec != 0) 2150b7579f77SDag-Erling Smørgrav comm_timer_set(worker->env.probe_timer, &tv); 2151b7579f77SDag-Erling Smørgrav } 2152b7579f77SDag-Erling Smørgrav 2153b7579f77SDag-Erling Smørgrav struct worker* 2154b7579f77SDag-Erling Smørgrav worker_create(struct daemon* daemon, int id, int* ports, int n) 2155b7579f77SDag-Erling Smørgrav { 2156b7579f77SDag-Erling Smørgrav unsigned int seed; 2157b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)calloc(1, 2158b7579f77SDag-Erling Smørgrav sizeof(struct worker)); 2159b7579f77SDag-Erling Smørgrav if(!worker) 2160b7579f77SDag-Erling Smørgrav return NULL; 2161b7579f77SDag-Erling Smørgrav worker->numports = n; 2162b7579f77SDag-Erling Smørgrav worker->ports = (int*)memdup(ports, sizeof(int)*n); 2163b7579f77SDag-Erling Smørgrav if(!worker->ports) { 2164b7579f77SDag-Erling Smørgrav free(worker); 2165b7579f77SDag-Erling Smørgrav return NULL; 2166b7579f77SDag-Erling Smørgrav } 2167b7579f77SDag-Erling Smørgrav worker->daemon = daemon; 2168b7579f77SDag-Erling Smørgrav worker->thread_num = id; 2169b7579f77SDag-Erling Smørgrav if(!(worker->cmd = tube_create())) { 2170b7579f77SDag-Erling Smørgrav free(worker->ports); 2171b7579f77SDag-Erling Smørgrav free(worker); 2172b7579f77SDag-Erling Smørgrav return NULL; 2173b7579f77SDag-Erling Smørgrav } 2174b7579f77SDag-Erling Smørgrav /* create random state here to avoid locking trouble in RAND_bytes */ 21750eefd307SCy Schubert if(!(worker->rndstate = ub_initstate(daemon->rand))) { 2176b7579f77SDag-Erling Smørgrav log_err("could not init random numbers."); 2177b7579f77SDag-Erling Smørgrav tube_delete(worker->cmd); 2178b7579f77SDag-Erling Smørgrav free(worker->ports); 2179b7579f77SDag-Erling Smørgrav free(worker); 2180b7579f77SDag-Erling Smørgrav return NULL; 2181b7579f77SDag-Erling Smørgrav } 2182a755b6f6SDag-Erling Smørgrav explicit_bzero(&seed, sizeof(seed)); 2183b7579f77SDag-Erling Smørgrav return worker; 2184b7579f77SDag-Erling Smørgrav } 2185b7579f77SDag-Erling Smørgrav 2186b7579f77SDag-Erling Smørgrav int 2187b7579f77SDag-Erling Smørgrav worker_init(struct worker* worker, struct config_file *cfg, 2188b7579f77SDag-Erling Smørgrav struct listen_port* ports, int do_sigs) 2189b7579f77SDag-Erling Smørgrav { 2190ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2191ff825849SDag-Erling Smørgrav struct dt_env* dtenv = &worker->dtenv; 2192ff825849SDag-Erling Smørgrav #else 2193ff825849SDag-Erling Smørgrav void* dtenv = NULL; 2194ff825849SDag-Erling Smørgrav #endif 2195865f46b2SCy Schubert #ifdef HAVE_GETTID 2196865f46b2SCy Schubert worker->thread_tid = gettid(); 2197865f46b2SCy Schubert #endif 2198b7579f77SDag-Erling Smørgrav worker->need_to_exit = 0; 2199b7579f77SDag-Erling Smørgrav worker->base = comm_base_create(do_sigs); 2200b7579f77SDag-Erling Smørgrav if(!worker->base) { 2201b7579f77SDag-Erling Smørgrav log_err("could not create event handling base"); 2202b7579f77SDag-Erling Smørgrav worker_delete(worker); 2203b7579f77SDag-Erling Smørgrav return 0; 2204b7579f77SDag-Erling Smørgrav } 2205b7579f77SDag-Erling Smørgrav comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept, 2206b7579f77SDag-Erling Smørgrav &worker_start_accept, worker); 2207b7579f77SDag-Erling Smørgrav if(do_sigs) { 2208b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 2209b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGHUP); 2210b7579f77SDag-Erling Smørgrav #endif 2211a39a5a69SCy Schubert #ifdef SIGBREAK 2212a39a5a69SCy Schubert ub_thread_sig_unblock(SIGBREAK); 2213a39a5a69SCy Schubert #endif 2214b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGINT); 2215b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2216b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGQUIT); 2217b7579f77SDag-Erling Smørgrav #endif 2218b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGTERM); 2219b7579f77SDag-Erling Smørgrav #ifndef LIBEVENT_SIGNAL_PROBLEM 2220b7579f77SDag-Erling Smørgrav worker->comsig = comm_signal_create(worker->base, 2221b7579f77SDag-Erling Smørgrav worker_sighandler, worker); 2222b7579f77SDag-Erling Smørgrav if(!worker->comsig 2223b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 2224b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGHUP) 2225b7579f77SDag-Erling Smørgrav #endif 2226b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2227b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGQUIT) 2228b7579f77SDag-Erling Smørgrav #endif 2229b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGTERM) 2230a39a5a69SCy Schubert #ifdef SIGBREAK 2231a39a5a69SCy Schubert || !comm_signal_bind(worker->comsig, SIGBREAK) 2232a39a5a69SCy Schubert #endif 2233b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGINT)) { 2234b7579f77SDag-Erling Smørgrav log_err("could not create signal handlers"); 2235b7579f77SDag-Erling Smørgrav worker_delete(worker); 2236b7579f77SDag-Erling Smørgrav return 0; 2237b7579f77SDag-Erling Smørgrav } 2238b7579f77SDag-Erling Smørgrav #endif /* LIBEVENT_SIGNAL_PROBLEM */ 2239b7579f77SDag-Erling Smørgrav if(!daemon_remote_open_accept(worker->daemon->rc, 2240b7579f77SDag-Erling Smørgrav worker->daemon->rc_ports, worker)) { 2241b7579f77SDag-Erling Smørgrav worker_delete(worker); 2242b7579f77SDag-Erling Smørgrav return 0; 2243b7579f77SDag-Erling Smørgrav } 2244b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 2245b7579f77SDag-Erling Smørgrav wsvc_setup_worker(worker); 2246b7579f77SDag-Erling Smørgrav #endif /* UB_ON_WINDOWS */ 2247b7579f77SDag-Erling Smørgrav } else { /* !do_sigs */ 2248b7579f77SDag-Erling Smørgrav worker->comsig = NULL; 2249b7579f77SDag-Erling Smørgrav } 2250c0caa2e2SCy Schubert #ifdef USE_DNSTAP 2251c0caa2e2SCy Schubert if(cfg->dnstap) { 2252c0caa2e2SCy Schubert log_assert(worker->daemon->dtenv != NULL); 2253c0caa2e2SCy Schubert memcpy(&worker->dtenv, worker->daemon->dtenv, sizeof(struct dt_env)); 2254c0caa2e2SCy Schubert if(!dt_init(&worker->dtenv, worker->base)) 2255c0caa2e2SCy Schubert fatal_exit("dt_init failed"); 2256c0caa2e2SCy Schubert } 2257c0caa2e2SCy Schubert #endif 2258b7579f77SDag-Erling Smørgrav worker->front = listen_create(worker->base, ports, 2259b7579f77SDag-Erling Smørgrav cfg->msg_buffer_size, (int)cfg->incoming_num_tcp, 22604c75e3aaSDag-Erling Smørgrav cfg->do_tcp_keepalive 22614c75e3aaSDag-Erling Smørgrav ? cfg->tcp_keepalive_timeout 22624c75e3aaSDag-Erling Smørgrav : cfg->tcp_idle_timeout, 2263c0caa2e2SCy Schubert cfg->harden_large_queries, cfg->http_max_streams, 2264369c6923SCy Schubert cfg->http_endpoint, cfg->http_notls_downstream, 2265*be771a7bSCy Schubert worker->daemon->tcl, worker->daemon->listen_dot_sslctx, 2266*be771a7bSCy Schubert worker->daemon->listen_doh_sslctx, 2267*be771a7bSCy Schubert worker->daemon->listen_quic_sslctx, 226846d2f618SCy Schubert dtenv, worker->daemon->doq_table, worker->env.rnd, 2269*be771a7bSCy Schubert cfg, worker_handle_request, worker); 2270b7579f77SDag-Erling Smørgrav if(!worker->front) { 2271b7579f77SDag-Erling Smørgrav log_err("could not create listening sockets"); 2272b7579f77SDag-Erling Smørgrav worker_delete(worker); 2273b7579f77SDag-Erling Smørgrav return 0; 2274b7579f77SDag-Erling Smørgrav } 2275b7579f77SDag-Erling Smørgrav worker->back = outside_network_create(worker->base, 2276b7579f77SDag-Erling Smørgrav cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, 2277b7579f77SDag-Erling Smørgrav cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 227825039b37SCy Schubert cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, 2279b7579f77SDag-Erling Smørgrav worker->daemon->env->infra_cache, worker->rndstate, 2280b7579f77SDag-Erling Smørgrav cfg->use_caps_bits_for_id, worker->ports, worker->numports, 2281f61ef7f6SDag-Erling Smørgrav cfg->unwanted_threshold, cfg->outgoing_tcp_mss, 2282f61ef7f6SDag-Erling Smørgrav &worker_alloc_cleanup, worker, 22838a384985SDag-Erling Smørgrav cfg->do_udp || cfg->udp_upstream_without_downstream, 2284*be771a7bSCy Schubert worker->daemon->connect_dot_sslctx, cfg->delay_close, 22855469a995SCy Schubert cfg->tls_use_sni, dtenv, cfg->udp_connect, 22865469a995SCy Schubert cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, 22875469a995SCy Schubert cfg->tcp_auth_query_timeout); 2288b7579f77SDag-Erling Smørgrav if(!worker->back) { 2289b7579f77SDag-Erling Smørgrav log_err("could not create outgoing sockets"); 2290b7579f77SDag-Erling Smørgrav worker_delete(worker); 2291b7579f77SDag-Erling Smørgrav return 0; 2292b7579f77SDag-Erling Smørgrav } 22935469a995SCy Schubert iterator_set_ip46_support(&worker->daemon->mods, worker->daemon->env, 22945469a995SCy Schubert worker->back); 2295b7579f77SDag-Erling Smørgrav /* start listening to commands */ 2296b7579f77SDag-Erling Smørgrav if(!tube_setup_bg_listen(worker->cmd, worker->base, 2297b7579f77SDag-Erling Smørgrav &worker_handle_control_cmd, worker)) { 2298b7579f77SDag-Erling Smørgrav log_err("could not create control compt."); 2299b7579f77SDag-Erling Smørgrav worker_delete(worker); 2300b7579f77SDag-Erling Smørgrav return 0; 2301b7579f77SDag-Erling Smørgrav } 2302b7579f77SDag-Erling Smørgrav worker->stat_timer = comm_timer_create(worker->base, 2303b7579f77SDag-Erling Smørgrav worker_stat_timer_cb, worker); 2304b7579f77SDag-Erling Smørgrav if(!worker->stat_timer) { 2305b7579f77SDag-Erling Smørgrav log_err("could not create statistics timer"); 2306b7579f77SDag-Erling Smørgrav } 2307b7579f77SDag-Erling Smørgrav 2308b7579f77SDag-Erling Smørgrav /* we use the msg_buffer_size as a good estimate for what the 2309b7579f77SDag-Erling Smørgrav * user wants for memory usage sizes */ 2310b7579f77SDag-Erling Smørgrav worker->scratchpad = regional_create_custom(cfg->msg_buffer_size); 2311b7579f77SDag-Erling Smørgrav if(!worker->scratchpad) { 2312b7579f77SDag-Erling Smørgrav log_err("malloc failure"); 2313b7579f77SDag-Erling Smørgrav worker_delete(worker); 2314b7579f77SDag-Erling Smørgrav return 0; 2315b7579f77SDag-Erling Smørgrav } 2316b7579f77SDag-Erling Smørgrav 2317b7579f77SDag-Erling Smørgrav server_stats_init(&worker->stats, cfg); 23181838dec3SCy Schubert worker->alloc = worker->daemon->worker_allocs[worker->thread_num]; 23191838dec3SCy Schubert alloc_set_id_cleanup(worker->alloc, &worker_alloc_cleanup, worker); 2320b7579f77SDag-Erling Smørgrav worker->env = *worker->daemon->env; 2321b7579f77SDag-Erling Smørgrav comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); 2322b7579f77SDag-Erling Smørgrav worker->env.worker = worker; 232357bddd21SDag-Erling Smørgrav worker->env.worker_base = worker->base; 2324b7579f77SDag-Erling Smørgrav worker->env.send_query = &worker_send_query; 23251838dec3SCy Schubert worker->env.alloc = worker->alloc; 232657bddd21SDag-Erling Smørgrav worker->env.outnet = worker->back; 2327b7579f77SDag-Erling Smørgrav worker->env.rnd = worker->rndstate; 2328971980c3SDag-Erling Smørgrav /* If case prefetch is triggered, the corresponding mesh will clear 2329971980c3SDag-Erling Smørgrav * the scratchpad for the module env in the middle of request handling. 2330971980c3SDag-Erling Smørgrav * It would be prone to a use-after-free kind of bug, so we avoid 2331971980c3SDag-Erling Smørgrav * sharing it with worker's own scratchpad at the cost of having 2332971980c3SDag-Erling Smørgrav * one more pad per worker. */ 2333971980c3SDag-Erling Smørgrav worker->env.scratch = regional_create_custom(cfg->msg_buffer_size); 2334971980c3SDag-Erling Smørgrav if(!worker->env.scratch) { 2335971980c3SDag-Erling Smørgrav log_err("malloc failure"); 2336971980c3SDag-Erling Smørgrav worker_delete(worker); 2337971980c3SDag-Erling Smørgrav return 0; 2338971980c3SDag-Erling Smørgrav } 2339b7579f77SDag-Erling Smørgrav worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); 23405469a995SCy Schubert if(!worker->env.mesh) { 23415469a995SCy Schubert log_err("malloc failure"); 23425469a995SCy Schubert worker_delete(worker); 23435469a995SCy Schubert return 0; 23445469a995SCy Schubert } 2345091e9e46SCy Schubert /* Pass on daemon variables that we would need in the mesh area */ 2346091e9e46SCy Schubert worker->env.mesh->use_response_ip = worker->daemon->use_response_ip; 2347091e9e46SCy Schubert worker->env.mesh->use_rpz = worker->daemon->use_rpz; 2348091e9e46SCy Schubert 2349b7579f77SDag-Erling Smørgrav worker->env.detach_subs = &mesh_detach_subs; 2350b7579f77SDag-Erling Smørgrav worker->env.attach_sub = &mesh_attach_sub; 2351c7f4d7adSDag-Erling Smørgrav worker->env.add_sub = &mesh_add_sub; 2352b7579f77SDag-Erling Smørgrav worker->env.kill_sub = &mesh_state_delete; 2353b7579f77SDag-Erling Smørgrav worker->env.detect_cycle = &mesh_detect_cycle; 235417d15b25SDag-Erling Smørgrav worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); 23555469a995SCy Schubert if(!worker->env.scratch_buffer) { 23565469a995SCy Schubert log_err("malloc failure"); 23575469a995SCy Schubert worker_delete(worker); 23585469a995SCy Schubert return 0; 23595469a995SCy Schubert } 2360b7579f77SDag-Erling Smørgrav /* one probe timer per process -- if we have 5011 anchors */ 2361b7579f77SDag-Erling Smørgrav if(autr_get_num_anchors(worker->env.anchors) > 0 2362b7579f77SDag-Erling Smørgrav #ifndef THREADS_DISABLED 2363b7579f77SDag-Erling Smørgrav && worker->thread_num == 0 2364b7579f77SDag-Erling Smørgrav #endif 2365b7579f77SDag-Erling Smørgrav ) { 2366b7579f77SDag-Erling Smørgrav struct timeval tv; 2367b7579f77SDag-Erling Smørgrav tv.tv_sec = 0; 2368b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2369b7579f77SDag-Erling Smørgrav worker->env.probe_timer = comm_timer_create(worker->base, 2370b7579f77SDag-Erling Smørgrav worker_probe_timer_cb, worker); 2371b7579f77SDag-Erling Smørgrav if(!worker->env.probe_timer) { 2372b7579f77SDag-Erling Smørgrav log_err("could not create 5011-probe timer"); 2373b7579f77SDag-Erling Smørgrav } else { 2374b7579f77SDag-Erling Smørgrav /* let timer fire, then it can reset itself */ 2375b7579f77SDag-Erling Smørgrav comm_timer_set(worker->env.probe_timer, &tv); 2376b7579f77SDag-Erling Smørgrav } 2377b7579f77SDag-Erling Smørgrav } 237857bddd21SDag-Erling Smørgrav /* zone transfer tasks, setup once per process, if any */ 237957bddd21SDag-Erling Smørgrav if(worker->env.auth_zones 238057bddd21SDag-Erling Smørgrav #ifndef THREADS_DISABLED 238157bddd21SDag-Erling Smørgrav && worker->thread_num == 0 238257bddd21SDag-Erling Smørgrav #endif 238357bddd21SDag-Erling Smørgrav ) { 238457bddd21SDag-Erling Smørgrav auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env); 23855469a995SCy Schubert auth_zones_pickup_zonemd_verify(worker->env.auth_zones, 23865469a995SCy Schubert &worker->env); 238757bddd21SDag-Erling Smørgrav } 238825039b37SCy Schubert #ifdef USE_DNSTAP 238925039b37SCy Schubert if(worker->daemon->cfg->dnstap 239025039b37SCy Schubert #ifndef THREADS_DISABLED 239125039b37SCy Schubert && worker->thread_num == 0 239225039b37SCy Schubert #endif 239325039b37SCy Schubert ) { 239425039b37SCy Schubert if(!dt_io_thread_start(dtenv->dtio, comm_base_internal( 239525039b37SCy Schubert worker->base), worker->daemon->num)) { 239625039b37SCy Schubert log_err("could not start dnstap io thread"); 239725039b37SCy Schubert worker_delete(worker); 239825039b37SCy Schubert return 0; 239925039b37SCy Schubert } 240025039b37SCy Schubert } 240125039b37SCy Schubert #endif /* USE_DNSTAP */ 2402b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 2403b7579f77SDag-Erling Smørgrav /* if statistics enabled start timer */ 2404b7579f77SDag-Erling Smørgrav if(worker->env.cfg->stat_interval > 0) { 2405b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "set statistics interval %d secs", 2406b7579f77SDag-Erling Smørgrav worker->env.cfg->stat_interval); 2407b7579f77SDag-Erling Smørgrav worker_restart_timer(worker); 2408b7579f77SDag-Erling Smørgrav } 2409103ba509SCy Schubert pp_init(&sldns_write_uint16, &sldns_write_uint32); 2410b7579f77SDag-Erling Smørgrav return 1; 2411b7579f77SDag-Erling Smørgrav } 2412b7579f77SDag-Erling Smørgrav 2413b7579f77SDag-Erling Smørgrav void 2414b7579f77SDag-Erling Smørgrav worker_work(struct worker* worker) 2415b7579f77SDag-Erling Smørgrav { 2416b7579f77SDag-Erling Smørgrav comm_base_dispatch(worker->base); 2417b7579f77SDag-Erling Smørgrav } 2418b7579f77SDag-Erling Smørgrav 2419b7579f77SDag-Erling Smørgrav void 2420b7579f77SDag-Erling Smørgrav worker_delete(struct worker* worker) 2421b7579f77SDag-Erling Smørgrav { 2422b7579f77SDag-Erling Smørgrav if(!worker) 2423b7579f77SDag-Erling Smørgrav return; 2424b7579f77SDag-Erling Smørgrav if(worker->env.mesh && verbosity >= VERB_OPS) { 2425b7579f77SDag-Erling Smørgrav server_stats_log(&worker->stats, worker, worker->thread_num); 2426b7579f77SDag-Erling Smørgrav mesh_stats(worker->env.mesh, "mesh has"); 2427b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 2428b7579f77SDag-Erling Smørgrav } 2429b7579f77SDag-Erling Smørgrav outside_network_quit_prepare(worker->back); 2430b7579f77SDag-Erling Smørgrav mesh_delete(worker->env.mesh); 243117d15b25SDag-Erling Smørgrav sldns_buffer_free(worker->env.scratch_buffer); 2432b7579f77SDag-Erling Smørgrav listen_delete(worker->front); 2433b7579f77SDag-Erling Smørgrav outside_network_delete(worker->back); 2434b7579f77SDag-Erling Smørgrav comm_signal_delete(worker->comsig); 2435b7579f77SDag-Erling Smørgrav tube_delete(worker->cmd); 2436b7579f77SDag-Erling Smørgrav comm_timer_delete(worker->stat_timer); 2437b7579f77SDag-Erling Smørgrav comm_timer_delete(worker->env.probe_timer); 2438b7579f77SDag-Erling Smørgrav free(worker->ports); 2439b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) { 2440b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 2441b7579f77SDag-Erling Smørgrav wsvc_desetup_worker(worker); 2442b7579f77SDag-Erling Smørgrav #endif /* UB_ON_WINDOWS */ 2443b7579f77SDag-Erling Smørgrav } 244425039b37SCy Schubert #ifdef USE_DNSTAP 244525039b37SCy Schubert if(worker->daemon->cfg->dnstap 244625039b37SCy Schubert #ifndef THREADS_DISABLED 244725039b37SCy Schubert && worker->thread_num == 0 244825039b37SCy Schubert #endif 244925039b37SCy Schubert ) { 245025039b37SCy Schubert dt_io_thread_stop(worker->dtenv.dtio); 245125039b37SCy Schubert } 245225039b37SCy Schubert dt_deinit(&worker->dtenv); 245325039b37SCy Schubert #endif /* USE_DNSTAP */ 2454b7579f77SDag-Erling Smørgrav comm_base_delete(worker->base); 2455b7579f77SDag-Erling Smørgrav ub_randfree(worker->rndstate); 24561838dec3SCy Schubert /* don't touch worker->alloc, as it's maintained in daemon */ 2457971980c3SDag-Erling Smørgrav regional_destroy(worker->env.scratch); 2458b7579f77SDag-Erling Smørgrav regional_destroy(worker->scratchpad); 2459b7579f77SDag-Erling Smørgrav free(worker); 2460b7579f77SDag-Erling Smørgrav } 2461b7579f77SDag-Erling Smørgrav 2462b7579f77SDag-Erling Smørgrav struct outbound_entry* 2463bc892140SDag-Erling Smørgrav worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec, 24649cf5bc93SCy Schubert int want_dnssec, int nocaps, int check_ratelimit, 24659cf5bc93SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, 24669cf5bc93SCy Schubert size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, 24679cf5bc93SCy Schubert struct module_qstate* q, int* was_ratelimited) 2468b7579f77SDag-Erling Smørgrav { 2469b7579f77SDag-Erling Smørgrav struct worker* worker = q->env->worker; 2470b7579f77SDag-Erling Smørgrav struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 2471b7579f77SDag-Erling Smørgrav q->region, sizeof(*e)); 2472b7579f77SDag-Erling Smørgrav if(!e) 2473b7579f77SDag-Erling Smørgrav return NULL; 2474b7579f77SDag-Erling Smørgrav e->qstate = q; 2475bc892140SDag-Erling Smørgrav e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec, 24769cf5bc93SCy Schubert want_dnssec, nocaps, check_ratelimit, tcp_upstream, 24770fb34990SDag-Erling Smørgrav ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q, 24789cf5bc93SCy Schubert worker_handle_service_reply, e, worker->back->udp_buff, q->env, 24799cf5bc93SCy Schubert was_ratelimited); 2480b7579f77SDag-Erling Smørgrav if(!e->qsent) { 2481b7579f77SDag-Erling Smørgrav return NULL; 2482b7579f77SDag-Erling Smørgrav } 2483b7579f77SDag-Erling Smørgrav return e; 2484b7579f77SDag-Erling Smørgrav } 2485b7579f77SDag-Erling Smørgrav 2486b7579f77SDag-Erling Smørgrav void 2487b7579f77SDag-Erling Smørgrav worker_alloc_cleanup(void* arg) 2488b7579f77SDag-Erling Smørgrav { 2489b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2490b7579f77SDag-Erling Smørgrav slabhash_clear(&worker->env.rrset_cache->table); 2491b7579f77SDag-Erling Smørgrav slabhash_clear(worker->env.msg_cache); 2492b7579f77SDag-Erling Smørgrav } 2493b7579f77SDag-Erling Smørgrav 2494b7579f77SDag-Erling Smørgrav void worker_stats_clear(struct worker* worker) 2495b7579f77SDag-Erling Smørgrav { 2496b7579f77SDag-Erling Smørgrav server_stats_init(&worker->stats, worker->env.cfg); 2497b7579f77SDag-Erling Smørgrav mesh_stats_clear(worker->env.mesh); 2498b7579f77SDag-Erling Smørgrav worker->back->unwanted_replies = 0; 2499ff825849SDag-Erling Smørgrav worker->back->num_tcp_outgoing = 0; 25000a92a9fcSCy Schubert worker->back->num_udp_outgoing = 0; 2501b7579f77SDag-Erling Smørgrav } 2502b7579f77SDag-Erling Smørgrav 2503b7579f77SDag-Erling Smørgrav void worker_start_accept(void* arg) 2504b7579f77SDag-Erling Smørgrav { 2505b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2506b7579f77SDag-Erling Smørgrav listen_start_accept(worker->front); 2507b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) 2508b7579f77SDag-Erling Smørgrav daemon_remote_start_accept(worker->daemon->rc); 2509b7579f77SDag-Erling Smørgrav } 2510b7579f77SDag-Erling Smørgrav 2511b7579f77SDag-Erling Smørgrav void worker_stop_accept(void* arg) 2512b7579f77SDag-Erling Smørgrav { 2513b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2514b7579f77SDag-Erling Smørgrav listen_stop_accept(worker->front); 2515b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) 2516b7579f77SDag-Erling Smørgrav daemon_remote_stop_accept(worker->daemon->rc); 2517b7579f77SDag-Erling Smørgrav } 2518b7579f77SDag-Erling Smørgrav 2519b7579f77SDag-Erling Smørgrav /* --- fake callbacks for fptr_wlist to work --- */ 2520bc892140SDag-Erling Smørgrav struct outbound_entry* libworker_send_query( 2521bc892140SDag-Erling Smørgrav struct query_info* ATTR_UNUSED(qinfo), 2522bc892140SDag-Erling Smørgrav uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), 2523bc892140SDag-Erling Smørgrav int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), 25249cf5bc93SCy Schubert int ATTR_UNUSED(check_ratelimit), 2525bc892140SDag-Erling Smørgrav struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), 252624e36522SCy Schubert uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), 25270fb34990SDag-Erling Smørgrav int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), 25289cf5bc93SCy Schubert struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) 2529b7579f77SDag-Erling Smørgrav { 2530b7579f77SDag-Erling Smørgrav log_assert(0); 2531b7579f77SDag-Erling Smørgrav return 0; 2532b7579f77SDag-Erling Smørgrav } 2533b7579f77SDag-Erling Smørgrav 2534b7579f77SDag-Erling Smørgrav int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 2535b7579f77SDag-Erling Smørgrav void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2536b7579f77SDag-Erling Smørgrav struct comm_reply* ATTR_UNUSED(reply_info)) 2537b7579f77SDag-Erling Smørgrav { 2538b7579f77SDag-Erling Smørgrav log_assert(0); 2539b7579f77SDag-Erling Smørgrav return 0; 2540b7579f77SDag-Erling Smørgrav } 2541b7579f77SDag-Erling Smørgrav 2542b7579f77SDag-Erling Smørgrav void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 2543b7579f77SDag-Erling Smørgrav uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 2544b7579f77SDag-Erling Smørgrav int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 2545b7579f77SDag-Erling Smørgrav { 2546b7579f77SDag-Erling Smørgrav log_assert(0); 2547b7579f77SDag-Erling Smørgrav } 2548b7579f77SDag-Erling Smørgrav 2549b7579f77SDag-Erling Smørgrav void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 255017d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 25514c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2552b7579f77SDag-Erling Smørgrav { 2553b7579f77SDag-Erling Smørgrav log_assert(0); 2554b7579f77SDag-Erling Smørgrav } 2555b7579f77SDag-Erling Smørgrav 2556b7579f77SDag-Erling Smørgrav void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 255717d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 25584c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 255917d15b25SDag-Erling Smørgrav { 256017d15b25SDag-Erling Smørgrav log_assert(0); 256117d15b25SDag-Erling Smørgrav } 256217d15b25SDag-Erling Smørgrav 256317d15b25SDag-Erling Smørgrav void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 256417d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 25654c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2566b7579f77SDag-Erling Smørgrav { 2567b7579f77SDag-Erling Smørgrav log_assert(0); 2568b7579f77SDag-Erling Smørgrav } 2569b7579f77SDag-Erling Smørgrav 2570b7579f77SDag-Erling Smørgrav int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2571b7579f77SDag-Erling Smørgrav { 2572b7579f77SDag-Erling Smørgrav log_assert(0); 2573b7579f77SDag-Erling Smørgrav return 0; 2574b7579f77SDag-Erling Smørgrav } 2575b7579f77SDag-Erling Smørgrav 2576b7579f77SDag-Erling Smørgrav int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 2577b7579f77SDag-Erling Smørgrav { 2578b7579f77SDag-Erling Smørgrav log_assert(0); 2579b7579f77SDag-Erling Smørgrav return 0; 2580b7579f77SDag-Erling Smørgrav } 2581b7579f77SDag-Erling Smørgrav 2582b7579f77SDag-Erling Smørgrav int codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2583b7579f77SDag-Erling Smørgrav { 2584b7579f77SDag-Erling Smørgrav log_assert(0); 2585b7579f77SDag-Erling Smørgrav return 0; 2586b7579f77SDag-Erling Smørgrav } 2587b7579f77SDag-Erling Smørgrav 258825039b37SCy Schubert #ifdef USE_DNSTAP 258925039b37SCy Schubert void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 259025039b37SCy Schubert void* ATTR_UNUSED(arg)) 259125039b37SCy Schubert { 259225039b37SCy Schubert log_assert(0); 259325039b37SCy Schubert } 259425039b37SCy Schubert #endif 259525039b37SCy Schubert 259625039b37SCy Schubert #ifdef USE_DNSTAP 259725039b37SCy Schubert void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 259825039b37SCy Schubert void* ATTR_UNUSED(arg)) 259925039b37SCy Schubert { 260025039b37SCy Schubert log_assert(0); 260125039b37SCy Schubert } 260225039b37SCy Schubert #endif 260346d2f618SCy Schubert 260446d2f618SCy Schubert #ifdef HAVE_NGTCP2 260546d2f618SCy Schubert void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 260646d2f618SCy Schubert void* ATTR_UNUSED(arg)) 260746d2f618SCy Schubert { 260846d2f618SCy Schubert log_assert(0); 260946d2f618SCy Schubert } 261046d2f618SCy Schubert #endif 261146d2f618SCy Schubert 261246d2f618SCy Schubert #ifdef HAVE_NGTCP2 261346d2f618SCy Schubert void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 261446d2f618SCy Schubert void* ATTR_UNUSED(arg)) 261546d2f618SCy Schubert { 261646d2f618SCy Schubert log_assert(0); 261746d2f618SCy Schubert } 261846d2f618SCy Schubert #endif 2619