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 374b7579f77SDag-Erling Smørgrav void 375b7579f77SDag-Erling Smørgrav worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, 376b7579f77SDag-Erling Smørgrav size_t len, int error, void* arg) 377b7579f77SDag-Erling Smørgrav { 378b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 379b7579f77SDag-Erling Smørgrav enum worker_commands cmd; 380b7579f77SDag-Erling Smørgrav if(error != NETEVENT_NOERROR) { 381b7579f77SDag-Erling Smørgrav free(msg); 382b7579f77SDag-Erling Smørgrav if(error == NETEVENT_CLOSED) 383b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 384b7579f77SDag-Erling Smørgrav else log_info("control event: %d", error); 385b7579f77SDag-Erling Smørgrav return; 386b7579f77SDag-Erling Smørgrav } 387b7579f77SDag-Erling Smørgrav if(len != sizeof(uint32_t)) { 388b7579f77SDag-Erling Smørgrav fatal_exit("bad control msg length %d", (int)len); 389b7579f77SDag-Erling Smørgrav } 39017d15b25SDag-Erling Smørgrav cmd = sldns_read_uint32(msg); 391b7579f77SDag-Erling Smørgrav free(msg); 392b7579f77SDag-Erling Smørgrav switch(cmd) { 393b7579f77SDag-Erling Smørgrav case worker_cmd_quit: 394b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd quit"); 395b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 396b7579f77SDag-Erling Smørgrav break; 397b7579f77SDag-Erling Smørgrav case worker_cmd_stats: 398b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd stats"); 399b7579f77SDag-Erling Smørgrav server_stats_reply(worker, 1); 400b7579f77SDag-Erling Smørgrav break; 401b7579f77SDag-Erling Smørgrav case worker_cmd_stats_noreset: 402b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd stats_noreset"); 403b7579f77SDag-Erling Smørgrav server_stats_reply(worker, 0); 404b7579f77SDag-Erling Smørgrav break; 405b7579f77SDag-Erling Smørgrav case worker_cmd_remote: 406b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "got control cmd remote"); 407b7579f77SDag-Erling Smørgrav daemon_remote_exec(worker); 408b7579f77SDag-Erling Smørgrav break; 409b7579f77SDag-Erling Smørgrav default: 410b7579f77SDag-Erling Smørgrav log_err("bad command %d", (int)cmd); 411b7579f77SDag-Erling Smørgrav break; 412b7579f77SDag-Erling Smørgrav } 413b7579f77SDag-Erling Smørgrav } 414b7579f77SDag-Erling Smørgrav 415b7579f77SDag-Erling Smørgrav /** check if a delegation is secure */ 416b7579f77SDag-Erling Smørgrav static enum sec_status 417b7579f77SDag-Erling Smørgrav check_delegation_secure(struct reply_info *rep) 418b7579f77SDag-Erling Smørgrav { 419b7579f77SDag-Erling Smørgrav /* return smallest security status */ 420b7579f77SDag-Erling Smørgrav size_t i; 421b7579f77SDag-Erling Smørgrav enum sec_status sec = sec_status_secure; 422b7579f77SDag-Erling Smørgrav enum sec_status s; 423b7579f77SDag-Erling Smørgrav size_t num = rep->an_numrrsets + rep->ns_numrrsets; 424b7579f77SDag-Erling Smørgrav /* check if answer and authority are OK */ 425b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) { 426b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 427b7579f77SDag-Erling Smørgrav ->security; 428b7579f77SDag-Erling Smørgrav if(s < sec) 429b7579f77SDag-Erling Smørgrav sec = s; 430b7579f77SDag-Erling Smørgrav } 431b7579f77SDag-Erling Smørgrav /* in additional, only unchecked triggers revalidation */ 432b7579f77SDag-Erling Smørgrav for(i=num; i<rep->rrset_count; i++) { 433b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 434b7579f77SDag-Erling Smørgrav ->security; 435b7579f77SDag-Erling Smørgrav if(s == sec_status_unchecked) 436b7579f77SDag-Erling Smørgrav return s; 437b7579f77SDag-Erling Smørgrav } 438b7579f77SDag-Erling Smørgrav return sec; 439b7579f77SDag-Erling Smørgrav } 440b7579f77SDag-Erling Smørgrav 441b7579f77SDag-Erling Smørgrav /** remove nonsecure from a delegation referral additional section */ 442b7579f77SDag-Erling Smørgrav static void 443b7579f77SDag-Erling Smørgrav deleg_remove_nonsecure_additional(struct reply_info* rep) 444b7579f77SDag-Erling Smørgrav { 445b7579f77SDag-Erling Smørgrav /* we can simply edit it, since we are working in the scratch region */ 446b7579f77SDag-Erling Smørgrav size_t i; 447b7579f77SDag-Erling Smørgrav enum sec_status s; 448b7579f77SDag-Erling Smørgrav 449b7579f77SDag-Erling Smørgrav for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { 450b7579f77SDag-Erling Smørgrav s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 451b7579f77SDag-Erling Smørgrav ->security; 452b7579f77SDag-Erling Smørgrav if(s != sec_status_secure) { 453b7579f77SDag-Erling Smørgrav memmove(rep->rrsets+i, rep->rrsets+i+1, 454b7579f77SDag-Erling Smørgrav sizeof(struct ub_packed_rrset_key*)* 455b7579f77SDag-Erling Smørgrav (rep->rrset_count - i - 1)); 456b7579f77SDag-Erling Smørgrav rep->ar_numrrsets--; 457b7579f77SDag-Erling Smørgrav rep->rrset_count--; 458b7579f77SDag-Erling Smørgrav i--; 459b7579f77SDag-Erling Smørgrav } 460b7579f77SDag-Erling Smørgrav } 461b7579f77SDag-Erling Smørgrav } 462b7579f77SDag-Erling Smørgrav 463b7579f77SDag-Erling Smørgrav /** answer nonrecursive query from the cache */ 464b7579f77SDag-Erling Smørgrav static int 465b7579f77SDag-Erling Smørgrav answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, 466b7579f77SDag-Erling Smørgrav uint16_t id, uint16_t flags, struct comm_reply* repinfo, 467b7579f77SDag-Erling Smørgrav struct edns_data* edns) 468b7579f77SDag-Erling Smørgrav { 469b7579f77SDag-Erling Smørgrav /* for a nonrecursive query return either: 470b7579f77SDag-Erling Smørgrav * o an error (servfail; we try to avoid this) 471b7579f77SDag-Erling Smørgrav * o a delegation (closest we have; this routine tries that) 472b7579f77SDag-Erling Smørgrav * o the answer (checked by answer_from_cache) 473b7579f77SDag-Erling Smørgrav * 474b7579f77SDag-Erling Smørgrav * So, grab a delegation from the rrset cache. 475b7579f77SDag-Erling Smørgrav * Then check if it needs validation, if so, this routine fails, 476b7579f77SDag-Erling Smørgrav * so that iterator can prime and validator can verify rrsets. 477b7579f77SDag-Erling Smørgrav */ 478b7579f77SDag-Erling Smørgrav uint16_t udpsize = edns->udp_size; 479b7579f77SDag-Erling Smørgrav int secure = 0; 48017d15b25SDag-Erling Smørgrav time_t timenow = *worker->env.now; 4818f76bb7dSCy Schubert int has_cd_bit = (flags&BIT_CD); 4828f76bb7dSCy Schubert int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd) 483b7579f77SDag-Erling Smørgrav && worker->env.need_to_validate; 484b7579f77SDag-Erling Smørgrav struct dns_msg *msg = NULL; 485b7579f77SDag-Erling Smørgrav struct delegpt *dp; 486b7579f77SDag-Erling Smørgrav 487b7579f77SDag-Erling Smørgrav dp = dns_cache_find_delegation(&worker->env, qinfo->qname, 488b7579f77SDag-Erling Smørgrav qinfo->qname_len, qinfo->qtype, qinfo->qclass, 489790c6b24SCy Schubert worker->scratchpad, &msg, timenow, 0, NULL, 0); 490b7579f77SDag-Erling Smørgrav if(!dp) { /* no delegation, need to reprime */ 491b7579f77SDag-Erling Smørgrav return 0; 492b7579f77SDag-Erling Smørgrav } 493bc892140SDag-Erling Smørgrav /* In case we have a local alias, copy it into the delegation message. 494bc892140SDag-Erling Smørgrav * Shallow copy should be fine, as we'll be done with msg in this 495bc892140SDag-Erling Smørgrav * function. */ 496bc892140SDag-Erling Smørgrav msg->qinfo.local_alias = qinfo->local_alias; 497b7579f77SDag-Erling Smørgrav if(must_validate) { 498b7579f77SDag-Erling Smørgrav switch(check_delegation_secure(msg->rep)) { 499b7579f77SDag-Erling Smørgrav case sec_status_unchecked: 500b7579f77SDag-Erling Smørgrav /* some rrsets have not been verified yet, go and 501b7579f77SDag-Erling Smørgrav * let validator do that */ 502b7579f77SDag-Erling Smørgrav return 0; 503b7579f77SDag-Erling Smørgrav case sec_status_bogus: 5040fb34990SDag-Erling Smørgrav case sec_status_secure_sentinel_fail: 505b7579f77SDag-Erling Smørgrav /* some rrsets are bogus, reply servfail */ 506b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 507b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 508b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 509b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 510bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, 511f44e67d1SCy Schubert msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 512f44e67d1SCy Schubert worker->env.now_tv)) 513e2d15004SDag-Erling Smørgrav return 0; 5148f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) */ 5158f76bb7dSCy Schubert if(worker->env.cfg->ede && 5168f76bb7dSCy Schubert msg->rep->reason_bogus != LDNS_EDE_NONE) { 5178f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 5188f76bb7dSCy Schubert worker->scratchpad, msg->rep->reason_bogus, 5198f76bb7dSCy Schubert msg->rep->reason_bogus_str); 520a39a5a69SCy Schubert } 521b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 522b7579f77SDag-Erling Smørgrav &msg->qinfo, id, flags, edns); 523b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 524b7579f77SDag-Erling Smørgrav worker->stats.ans_bogus++; 525b7579f77SDag-Erling Smørgrav worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++; 526b7579f77SDag-Erling Smørgrav } 527b7579f77SDag-Erling Smørgrav return 1; 528b7579f77SDag-Erling Smørgrav case sec_status_secure: 529b7579f77SDag-Erling Smørgrav /* all rrsets are secure */ 530b7579f77SDag-Erling Smørgrav /* remove non-secure rrsets from the add. section*/ 531b7579f77SDag-Erling Smørgrav if(worker->env.cfg->val_clean_additional) 532b7579f77SDag-Erling Smørgrav deleg_remove_nonsecure_additional(msg->rep); 533b7579f77SDag-Erling Smørgrav secure = 1; 534b7579f77SDag-Erling Smørgrav break; 535b7579f77SDag-Erling Smørgrav case sec_status_indeterminate: 536b7579f77SDag-Erling Smørgrav case sec_status_insecure: 537b7579f77SDag-Erling Smørgrav default: 538b7579f77SDag-Erling Smørgrav /* not secure */ 539b7579f77SDag-Erling Smørgrav secure = 0; 540b7579f77SDag-Erling Smørgrav break; 541b7579f77SDag-Erling Smørgrav } 542b7579f77SDag-Erling Smørgrav } 543b7579f77SDag-Erling Smørgrav /* return this delegation from the cache */ 544b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 545b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 546b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 547b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 548103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 549103ba509SCy Schubert edns->edns_present = 0; 550bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep, 551f44e67d1SCy Schubert (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad, 552f44e67d1SCy Schubert worker->env.now_tv)) 553e2d15004SDag-Erling Smørgrav return 0; 554b7579f77SDag-Erling Smørgrav msg->rep->flags |= BIT_QR|BIT_RA; 5558f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) if CD bit is set and the answer is 5568f76bb7dSCy Schubert * bogus. */ 5578f76bb7dSCy Schubert if(worker->env.cfg->ede && has_cd_bit && 5588f76bb7dSCy Schubert (check_delegation_secure(msg->rep) == sec_status_bogus || 5598f76bb7dSCy Schubert check_delegation_secure(msg->rep) == sec_status_secure_sentinel_fail) && 5608f76bb7dSCy Schubert msg->rep->reason_bogus != LDNS_EDE_NONE) { 5618f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 5628f76bb7dSCy Schubert worker->scratchpad, msg->rep->reason_bogus, 5638f76bb7dSCy Schubert msg->rep->reason_bogus_str); 5648f76bb7dSCy Schubert } 56524e36522SCy Schubert if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags, 566b7579f77SDag-Erling Smørgrav repinfo->c->buffer, 0, 1, worker->scratchpad, 567b7579f77SDag-Erling Smørgrav udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { 568bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, 569f44e67d1SCy Schubert LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 570f44e67d1SCy Schubert worker->env.now_tv)) 57124e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 572b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 573b7579f77SDag-Erling Smørgrav &msg->qinfo, id, flags, edns); 574b7579f77SDag-Erling Smørgrav } 575b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 576b7579f77SDag-Erling Smørgrav if(secure) worker->stats.ans_secure++; 577b7579f77SDag-Erling Smørgrav server_stats_insrcode(&worker->stats, repinfo->c->buffer); 578b7579f77SDag-Erling Smørgrav } 579b7579f77SDag-Erling Smørgrav return 1; 580b7579f77SDag-Erling Smørgrav } 581b7579f77SDag-Erling Smørgrav 58265b390aaSDag-Erling Smørgrav /** Apply, if applicable, a response IP action to a cached answer. 58365b390aaSDag-Erling Smørgrav * If the answer is rewritten as a result of an action, '*encode_repp' will 58465b390aaSDag-Erling Smørgrav * point to the reply info containing the modified answer. '*encode_repp' will 58565b390aaSDag-Erling Smørgrav * be intact otherwise. 58665b390aaSDag-Erling Smørgrav * It returns 1 on success, 0 otherwise. */ 58765b390aaSDag-Erling Smørgrav static int 58865b390aaSDag-Erling Smørgrav apply_respip_action(struct worker* worker, const struct query_info* qinfo, 58965b390aaSDag-Erling Smørgrav struct respip_client_info* cinfo, struct reply_info* rep, 590865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, 591865f46b2SCy Schubert struct ub_packed_rrset_key** alias_rrset, 592091e9e46SCy Schubert struct reply_info** encode_repp, struct auth_zones* az) 59365b390aaSDag-Erling Smørgrav { 594369c6923SCy Schubert struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; 595091e9e46SCy Schubert actinfo.action = respip_none; 59665b390aaSDag-Erling Smørgrav 59765b390aaSDag-Erling Smørgrav if(qinfo->qtype != LDNS_RR_TYPE_A && 59865b390aaSDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_AAAA && 59965b390aaSDag-Erling Smørgrav qinfo->qtype != LDNS_RR_TYPE_ANY) 60065b390aaSDag-Erling Smørgrav return 1; 60165b390aaSDag-Erling Smørgrav 60265b390aaSDag-Erling Smørgrav if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, 603a39a5a69SCy Schubert alias_rrset, 0, worker->scratchpad, az, NULL)) 60465b390aaSDag-Erling Smørgrav return 0; 60565b390aaSDag-Erling Smørgrav 60665b390aaSDag-Erling Smørgrav /* xxx_deny actions mean dropping the reply, unless the original reply 60765b390aaSDag-Erling Smørgrav * was redirected to response-ip data. */ 6088f76bb7dSCy Schubert if(actinfo.action == respip_always_deny || 6098f76bb7dSCy Schubert ((actinfo.action == respip_deny || 61065b390aaSDag-Erling Smørgrav actinfo.action == respip_inform_deny) && 6118f76bb7dSCy Schubert *encode_repp == rep)) 61265b390aaSDag-Erling Smørgrav *encode_repp = NULL; 61365b390aaSDag-Erling Smørgrav 61465b390aaSDag-Erling Smørgrav /* If address info is returned, it means the action should be an 61565b390aaSDag-Erling Smørgrav * 'inform' variant and the information should be logged. */ 61665b390aaSDag-Erling Smørgrav if(actinfo.addrinfo) { 617091e9e46SCy Schubert respip_inform_print(&actinfo, qinfo->qname, 61865b390aaSDag-Erling Smørgrav qinfo->qtype, qinfo->qclass, qinfo->local_alias, 619865f46b2SCy Schubert addr, addrlen); 620091e9e46SCy Schubert 621091e9e46SCy Schubert if(worker->stats.extended && actinfo.rpz_used) { 622091e9e46SCy Schubert if(actinfo.rpz_disabled) 623091e9e46SCy Schubert worker->stats.rpz_action[RPZ_DISABLED_ACTION]++; 624091e9e46SCy Schubert if(actinfo.rpz_cname_override) 625091e9e46SCy Schubert worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++; 626091e9e46SCy Schubert else 627091e9e46SCy Schubert worker->stats.rpz_action[ 628091e9e46SCy Schubert respip_action_to_rpz_action(actinfo.action)]++; 629091e9e46SCy Schubert } 63065b390aaSDag-Erling Smørgrav } 63165b390aaSDag-Erling Smørgrav 63265b390aaSDag-Erling Smørgrav return 1; 63365b390aaSDag-Erling Smørgrav } 63465b390aaSDag-Erling Smørgrav 63565b390aaSDag-Erling Smørgrav /** answer query from the cache. 63665b390aaSDag-Erling Smørgrav * Normally, the answer message will be built in repinfo->c->buffer; if the 63765b390aaSDag-Erling Smørgrav * answer is supposed to be suppressed or the answer is supposed to be an 63865b390aaSDag-Erling Smørgrav * incomplete CNAME chain, the buffer is explicitly cleared to signal the 63965b390aaSDag-Erling Smørgrav * caller as such. In the latter case *partial_rep will point to the incomplete 64065b390aaSDag-Erling Smørgrav * reply, and this function is (possibly) supposed to be called again with that 64165b390aaSDag-Erling Smørgrav * *partial_rep value to complete the chain. In addition, if the query should 64265b390aaSDag-Erling Smørgrav * be completely dropped, '*need_drop' will be set to 1. */ 643b7579f77SDag-Erling Smørgrav static int 644b7579f77SDag-Erling Smørgrav answer_from_cache(struct worker* worker, struct query_info* qinfo, 645091e9e46SCy Schubert struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer, 646091e9e46SCy Schubert int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset, 64765b390aaSDag-Erling Smørgrav struct reply_info** partial_repp, 648b7579f77SDag-Erling Smørgrav struct reply_info* rep, uint16_t id, uint16_t flags, 649b7579f77SDag-Erling Smørgrav struct comm_reply* repinfo, struct edns_data* edns) 650b7579f77SDag-Erling Smørgrav { 65117d15b25SDag-Erling Smørgrav time_t timenow = *worker->env.now; 652b7579f77SDag-Erling Smørgrav uint16_t udpsize = edns->udp_size; 65365b390aaSDag-Erling Smørgrav struct reply_info* encode_rep = rep; 65465b390aaSDag-Erling Smørgrav struct reply_info* partial_rep = *partial_repp; 6558f76bb7dSCy Schubert int has_cd_bit = (flags&BIT_CD); 6568f76bb7dSCy Schubert int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd) 657b7579f77SDag-Erling Smørgrav && worker->env.need_to_validate; 65865b390aaSDag-Erling Smørgrav *partial_repp = NULL; /* avoid accidental further pass */ 659091e9e46SCy Schubert 660091e9e46SCy Schubert /* Check TTL */ 661091e9e46SCy Schubert if(rep->ttl < timenow) { 662091e9e46SCy Schubert /* Check if we need to serve expired now */ 663091e9e46SCy Schubert if(worker->env.cfg->serve_expired && 664*46d2f618SCy Schubert /* if serve-expired-client-timeout is set, serve 665*46d2f618SCy Schubert * an expired record without attempting recursion 666*46d2f618SCy Schubert * if the serve_expired_norec_ttl is set for the record 667*46d2f618SCy Schubert * as we know that recursion is currently failing. */ 668*46d2f618SCy Schubert (!worker->env.cfg->serve_expired_client_timeout || 669*46d2f618SCy Schubert timenow < rep->serve_expired_norec_ttl) 670335c7cdaSCy Schubert #ifdef USE_CACHEDB 671335c7cdaSCy Schubert && !(worker->env.cachedb_enabled && 672335c7cdaSCy Schubert worker->env.cfg->cachedb_check_when_serve_expired) 673335c7cdaSCy Schubert #endif 674335c7cdaSCy Schubert ) { 675*46d2f618SCy Schubert if(!reply_info_can_answer_expired(rep, timenow)) 6761838dec3SCy Schubert return 0; 677bc892140SDag-Erling Smørgrav if(!rrset_array_lock(rep->ref, rep->rrset_count, 0)) 678bc892140SDag-Erling Smørgrav return 0; 679091e9e46SCy Schubert *is_expired_answer = 1; 680bc892140SDag-Erling Smørgrav } else { 681b7579f77SDag-Erling Smørgrav /* the rrsets may have been updated in the meantime. 682b7579f77SDag-Erling Smørgrav * we will refetch the message format from the 683b7579f77SDag-Erling Smørgrav * authoritative server 684b7579f77SDag-Erling Smørgrav */ 685b7579f77SDag-Erling Smørgrav return 0; 686b7579f77SDag-Erling Smørgrav } 687091e9e46SCy Schubert } else { 688b7579f77SDag-Erling Smørgrav if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) 689b7579f77SDag-Erling Smørgrav return 0; 690bc892140SDag-Erling Smørgrav } 691091e9e46SCy Schubert /* locked and ids and ttls are OK. */ 692091e9e46SCy Schubert 693b7579f77SDag-Erling Smørgrav /* check CNAME chain (if any) */ 694b7579f77SDag-Erling Smørgrav if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == 695b7579f77SDag-Erling Smørgrav htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == 696b7579f77SDag-Erling Smørgrav htons(LDNS_RR_TYPE_DNAME))) { 69709a3aaf3SDag-Erling Smørgrav if(!reply_check_cname_chain(qinfo, rep)) { 698b7579f77SDag-Erling Smørgrav /* cname chain invalid, redo iterator steps */ 699b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: cname chain broken"); 700e86b9096SDag-Erling Smørgrav goto bail_out; 701b7579f77SDag-Erling Smørgrav } 702b7579f77SDag-Erling Smørgrav } 703b7579f77SDag-Erling Smørgrav /* check security status of the cached answer */ 7040fb34990SDag-Erling Smørgrav if(must_validate && (rep->security == sec_status_bogus || 7050fb34990SDag-Erling Smørgrav rep->security == sec_status_secure_sentinel_fail)) { 706b7579f77SDag-Erling Smørgrav /* BAD cached */ 707b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 708b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 709b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 710b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 711103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 712103ba509SCy Schubert edns->edns_present = 0; 713bc892140SDag-Erling Smørgrav if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, 714f44e67d1SCy Schubert LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, 715f44e67d1SCy Schubert worker->env.now_tv)) 7163005e0a3SDag-Erling Smørgrav goto bail_out; 7178f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) */ 7188f76bb7dSCy Schubert if(worker->env.cfg->ede && rep->reason_bogus != LDNS_EDE_NONE) { 7198f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 7208f76bb7dSCy Schubert worker->scratchpad, rep->reason_bogus, 7218f76bb7dSCy Schubert rep->reason_bogus_str); 722a39a5a69SCy Schubert } 723b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 724b7579f77SDag-Erling Smørgrav qinfo, id, flags, edns); 725b7579f77SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, 726b7579f77SDag-Erling Smørgrav worker->scratchpad, rep->ref, rep->rrset_count); 727b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 728b7579f77SDag-Erling Smørgrav worker->stats.ans_bogus ++; 729b7579f77SDag-Erling Smørgrav worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; 730b7579f77SDag-Erling Smørgrav } 731b7579f77SDag-Erling Smørgrav return 1; 732b7579f77SDag-Erling Smørgrav } else if(rep->security == sec_status_unchecked && must_validate) { 733b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: unchecked entry needs " 734b7579f77SDag-Erling Smørgrav "validation"); 735b7579f77SDag-Erling Smørgrav goto bail_out; /* need to validate cache entry first */ 736b7579f77SDag-Erling Smørgrav } else if(rep->security == sec_status_secure) { 737091e9e46SCy Schubert if(reply_all_rrsets_secure(rep)) { 738091e9e46SCy Schubert *is_secure_answer = 1; 739091e9e46SCy Schubert } else { 740b7579f77SDag-Erling Smørgrav if(must_validate) { 741b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Cache reply: secure entry" 742b7579f77SDag-Erling Smørgrav " changed status"); 743b7579f77SDag-Erling Smørgrav goto bail_out; /* rrset changed, re-verify */ 744b7579f77SDag-Erling Smørgrav } 745091e9e46SCy Schubert *is_secure_answer = 0; 746b7579f77SDag-Erling Smørgrav } 747091e9e46SCy Schubert } else *is_secure_answer = 0; 748b7579f77SDag-Erling Smørgrav 749b7579f77SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 750b7579f77SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 751b7579f77SDag-Erling Smørgrav edns->ext_rcode = 0; 752b7579f77SDag-Erling Smørgrav edns->bits &= EDNS_DO; 753103ba509SCy Schubert if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) 754103ba509SCy Schubert edns->edns_present = 0; 75565b390aaSDag-Erling Smørgrav *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ 756091e9e46SCy Schubert if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && 757091e9e46SCy Schubert !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep, 758865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, alias_rrset, 759091e9e46SCy Schubert &encode_rep, worker->env.auth_zones)) { 76065b390aaSDag-Erling Smørgrav goto bail_out; 76165b390aaSDag-Erling Smørgrav } else if(partial_rep && 76265b390aaSDag-Erling Smørgrav !respip_merge_cname(partial_rep, qinfo, rep, cinfo, 763091e9e46SCy Schubert must_validate, &encode_rep, worker->scratchpad, 764091e9e46SCy Schubert worker->env.auth_zones)) { 76565b390aaSDag-Erling Smørgrav goto bail_out; 76665b390aaSDag-Erling Smørgrav } 767091e9e46SCy Schubert if(encode_rep != rep) { 768091e9e46SCy Schubert /* if rewritten, it can't be considered "secure" */ 769091e9e46SCy Schubert *is_secure_answer = 0; 770091e9e46SCy Schubert } 77165b390aaSDag-Erling Smørgrav if(!encode_rep || *alias_rrset) { 77265b390aaSDag-Erling Smørgrav if(!encode_rep) 77365b390aaSDag-Erling Smørgrav *need_drop = 1; 77465b390aaSDag-Erling Smørgrav else { 77565b390aaSDag-Erling Smørgrav /* If a partial CNAME chain is found, we first need to 77665b390aaSDag-Erling Smørgrav * make a copy of the reply in the scratchpad so we 77765b390aaSDag-Erling Smørgrav * can release the locks and lookup the cache again. */ 77865b390aaSDag-Erling Smørgrav *partial_repp = reply_info_copy(encode_rep, NULL, 77965b390aaSDag-Erling Smørgrav worker->scratchpad); 78065b390aaSDag-Erling Smørgrav if(!*partial_repp) 78165b390aaSDag-Erling Smørgrav goto bail_out; 78265b390aaSDag-Erling Smørgrav } 783a39a5a69SCy Schubert } else { 784a39a5a69SCy Schubert if(*is_expired_answer == 1 && 785a39a5a69SCy Schubert worker->env.cfg->ede_serve_expired && worker->env.cfg->ede) { 786a39a5a69SCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out, 787a39a5a69SCy Schubert worker->scratchpad, LDNS_EDE_STALE_ANSWER, ""); 788a39a5a69SCy Schubert } 7898f76bb7dSCy Schubert /* Attach the cached EDE (RFC8914) if CD bit is set and the 7908f76bb7dSCy Schubert * answer is bogus. */ 7918f76bb7dSCy Schubert if(*is_secure_answer == 0 && 7928f76bb7dSCy Schubert worker->env.cfg->ede && has_cd_bit && 7938f76bb7dSCy Schubert encode_rep->reason_bogus != LDNS_EDE_NONE) { 7948f76bb7dSCy Schubert edns_opt_list_append_ede(&edns->opt_list_out, 7958f76bb7dSCy Schubert worker->scratchpad, encode_rep->reason_bogus, 7968f76bb7dSCy Schubert encode_rep->reason_bogus_str); 7978f76bb7dSCy Schubert } 7988f76bb7dSCy Schubert if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, encode_rep, 7998f76bb7dSCy Schubert (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad, 8008f76bb7dSCy Schubert worker->env.now_tv)) 8018f76bb7dSCy Schubert goto bail_out; 802a39a5a69SCy Schubert if(!reply_info_answer_encode(qinfo, encode_rep, id, flags, 803b7579f77SDag-Erling Smørgrav repinfo->c->buffer, timenow, 1, worker->scratchpad, 804a39a5a69SCy Schubert udpsize, edns, (int)(edns->bits & EDNS_DO), 805a39a5a69SCy Schubert *is_secure_answer)) { 806a39a5a69SCy Schubert if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, 807a39a5a69SCy Schubert NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, 808a39a5a69SCy Schubert worker->scratchpad, worker->env.now_tv)) 80924e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 810b7579f77SDag-Erling Smørgrav error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 811b7579f77SDag-Erling Smørgrav qinfo, id, flags, edns); 812b7579f77SDag-Erling Smørgrav } 813a39a5a69SCy Schubert } 814b7579f77SDag-Erling Smørgrav /* cannot send the reply right now, because blocking network syscall 815b7579f77SDag-Erling Smørgrav * is bad while holding locks. */ 816b7579f77SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, 817b7579f77SDag-Erling Smørgrav rep->ref, rep->rrset_count); 818b7579f77SDag-Erling Smørgrav /* go and return this buffer to the client */ 819b7579f77SDag-Erling Smørgrav return 1; 820e86b9096SDag-Erling Smørgrav 821e86b9096SDag-Erling Smørgrav bail_out: 822e86b9096SDag-Erling Smørgrav rrset_array_unlock_touch(worker->env.rrset_cache, 823e86b9096SDag-Erling Smørgrav worker->scratchpad, rep->ref, rep->rrset_count); 824e86b9096SDag-Erling Smørgrav return 0; 825b7579f77SDag-Erling Smørgrav } 826b7579f77SDag-Erling Smørgrav 8270eefd307SCy Schubert /** Reply to client and perform prefetch to keep cache up to date. */ 828b7579f77SDag-Erling Smørgrav static void 829b7579f77SDag-Erling Smørgrav reply_and_prefetch(struct worker* worker, struct query_info* qinfo, 830a39a5a69SCy Schubert uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply, 831a39a5a69SCy Schubert int rpz_passthru, struct edns_option* opt_list) 832b7579f77SDag-Erling Smørgrav { 833a39a5a69SCy Schubert (void)opt_list; 834b7579f77SDag-Erling Smørgrav /* first send answer to client to keep its latency 835b7579f77SDag-Erling Smørgrav * as small as a cachereply */ 8360eefd307SCy Schubert if(!noreply) { 837e86b9096SDag-Erling Smørgrav if(repinfo->c->tcp_req_info) { 838e86b9096SDag-Erling Smørgrav sldns_buffer_copy( 839e86b9096SDag-Erling Smørgrav repinfo->c->tcp_req_info->spool_buffer, 840e86b9096SDag-Erling Smørgrav repinfo->c->buffer); 841e86b9096SDag-Erling Smørgrav } 842b7579f77SDag-Erling Smørgrav comm_point_send_reply(repinfo); 843e86b9096SDag-Erling Smørgrav } 844b7579f77SDag-Erling Smørgrav server_stats_prefetch(&worker->stats, worker); 845a39a5a69SCy Schubert #ifdef CLIENT_SUBNET 846a39a5a69SCy Schubert /* Check if the subnet module is enabled. In that case pass over the 847a39a5a69SCy Schubert * comm_reply information for ECS generation later. The mesh states are 848a39a5a69SCy Schubert * unique when subnet is enabled. */ 849a39a5a69SCy Schubert if(modstack_find(&worker->env.mesh->mods, "subnetcache") != -1 850a39a5a69SCy Schubert && worker->env.unique_mesh) { 851a39a5a69SCy Schubert mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 8528f76bb7dSCy Schubert PREFETCH_EXPIRY_ADD, rpz_passthru, 8538f76bb7dSCy Schubert &repinfo->client_addr, opt_list); 854a39a5a69SCy Schubert return; 855a39a5a69SCy Schubert } 856a39a5a69SCy Schubert #endif 857b7579f77SDag-Erling Smørgrav /* create the prefetch in the mesh as a normal lookup without 858b7579f77SDag-Erling Smørgrav * client addrs waiting, which has the cache blacklisted (to bypass 859b7579f77SDag-Erling Smørgrav * the cache and go to the network for the data). */ 860b7579f77SDag-Erling Smørgrav /* this (potentially) runs the mesh for the new query */ 861b7579f77SDag-Erling Smørgrav mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 862a39a5a69SCy Schubert PREFETCH_EXPIRY_ADD, rpz_passthru, NULL, NULL); 863b7579f77SDag-Erling Smørgrav } 864b7579f77SDag-Erling Smørgrav 865b7579f77SDag-Erling Smørgrav /** 866b7579f77SDag-Erling Smørgrav * Fill CH class answer into buffer. Keeps query. 867b7579f77SDag-Erling Smørgrav * @param pkt: buffer 868b7579f77SDag-Erling Smørgrav * @param str: string to put into text record (<255). 86965b390aaSDag-Erling Smørgrav * array of strings, every string becomes a text record. 87065b390aaSDag-Erling Smørgrav * @param num: number of strings in array. 871b7579f77SDag-Erling Smørgrav * @param edns: edns reply information. 872e2d15004SDag-Erling Smørgrav * @param worker: worker with scratch region. 8734c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 874b7579f77SDag-Erling Smørgrav */ 875b7579f77SDag-Erling Smørgrav static void 87665b390aaSDag-Erling Smørgrav chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, 8774c75e3aaSDag-Erling Smørgrav struct worker* worker, struct comm_reply* repinfo) 878b7579f77SDag-Erling Smørgrav { 87965b390aaSDag-Erling Smørgrav int i; 88017d15b25SDag-Erling Smørgrav unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); 88117d15b25SDag-Erling Smørgrav unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); 88224e36522SCy Schubert size_t udpsize = edns->udp_size; 88324e36522SCy Schubert edns->edns_version = EDNS_ADVERTISED_VERSION; 88424e36522SCy Schubert edns->udp_size = EDNS_ADVERTISED_SIZE; 88524e36522SCy Schubert edns->bits &= EDNS_DO; 88624e36522SCy Schubert if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, 88724e36522SCy Schubert LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad, 88824e36522SCy Schubert worker->env.now_tv)) 88924e36522SCy Schubert edns->opt_list_inplace_cb_out = NULL; 89017d15b25SDag-Erling Smørgrav sldns_buffer_clear(pkt); 89117d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ 89217d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); 89317d15b25SDag-Erling Smørgrav if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); 89417d15b25SDag-Erling Smørgrav if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); 89517d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 1); /* qdcount */ 89665b390aaSDag-Erling Smørgrav sldns_buffer_write_u16(pkt, (uint16_t)num); /* ancount */ 89717d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0); /* nscount */ 89817d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0); /* arcount */ 899b7579f77SDag-Erling Smørgrav (void)query_dname_len(pkt); /* skip qname */ 90017d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 90117d15b25SDag-Erling Smørgrav sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 90265b390aaSDag-Erling Smørgrav for(i=0; i<num; i++) { 90365b390aaSDag-Erling Smørgrav size_t len = strlen(str[i]); 90465b390aaSDag-Erling Smørgrav if(len>255) len=255; /* cap size of TXT record */ 90524e36522SCy Schubert if(sldns_buffer_position(pkt)+2+2+2+4+2+1+len+ 90624e36522SCy Schubert calc_edns_field_size(edns) > udpsize) { 90724e36522SCy Schubert sldns_buffer_write_u16_at(pkt, 6, i); /* ANCOUNT */ 90824e36522SCy Schubert LDNS_TC_SET(sldns_buffer_begin(pkt)); 90924e36522SCy Schubert break; 91024e36522SCy Schubert } 91117d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ 91217d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); 91317d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); 91417d15b25SDag-Erling Smørgrav sldns_buffer_write_u32(pkt, 0); /* TTL */ 91517d15b25SDag-Erling Smørgrav sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); 91617d15b25SDag-Erling Smørgrav sldns_buffer_write_u8(pkt, len); 91765b390aaSDag-Erling Smørgrav sldns_buffer_write(pkt, str[i], len); 91865b390aaSDag-Erling Smørgrav } 91917d15b25SDag-Erling Smørgrav sldns_buffer_flip(pkt); 920c7f4d7adSDag-Erling Smørgrav if(sldns_buffer_capacity(pkt) >= 921c7f4d7adSDag-Erling Smørgrav sldns_buffer_limit(pkt)+calc_edns_field_size(edns)) 922b7579f77SDag-Erling Smørgrav attach_edns_record(pkt, edns); 923b7579f77SDag-Erling Smørgrav } 924b7579f77SDag-Erling Smørgrav 92565b390aaSDag-Erling Smørgrav /** Reply with one string */ 92665b390aaSDag-Erling Smørgrav static void 92765b390aaSDag-Erling Smørgrav chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns, 9284c75e3aaSDag-Erling Smørgrav struct worker* worker, struct comm_reply* repinfo) 92965b390aaSDag-Erling Smørgrav { 9304c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, (char**)&str, 1, edns, worker, repinfo); 93165b390aaSDag-Erling Smørgrav } 93265b390aaSDag-Erling Smørgrav 93365b390aaSDag-Erling Smørgrav /** 93465b390aaSDag-Erling Smørgrav * Create CH class trustanchor answer. 93565b390aaSDag-Erling Smørgrav * @param pkt: buffer 93665b390aaSDag-Erling Smørgrav * @param edns: edns reply information. 93765b390aaSDag-Erling Smørgrav * @param w: worker with scratch region. 9384c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 93965b390aaSDag-Erling Smørgrav */ 94065b390aaSDag-Erling Smørgrav static void 9414c75e3aaSDag-Erling Smørgrav chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w, 9424c75e3aaSDag-Erling Smørgrav struct comm_reply* repinfo) 94365b390aaSDag-Erling Smørgrav { 94465b390aaSDag-Erling Smørgrav #define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */ 94565b390aaSDag-Erling Smørgrav #define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */ 94665b390aaSDag-Erling Smørgrav char* str_array[TA_RESPONSE_MAX_TXT]; 94765b390aaSDag-Erling Smørgrav uint16_t tags[TA_RESPONSE_MAX_TAGS]; 94865b390aaSDag-Erling Smørgrav int num = 0; 94965b390aaSDag-Erling Smørgrav struct trust_anchor* ta; 95065b390aaSDag-Erling Smørgrav 95165b390aaSDag-Erling Smørgrav if(!w->env.need_to_validate) { 95265b390aaSDag-Erling Smørgrav /* no validator module, reply no trustanchors */ 9534c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, NULL, 0, edns, w, repinfo); 95465b390aaSDag-Erling Smørgrav return; 95565b390aaSDag-Erling Smørgrav } 95665b390aaSDag-Erling Smørgrav 95765b390aaSDag-Erling Smørgrav /* fill the string with contents */ 95865b390aaSDag-Erling Smørgrav lock_basic_lock(&w->env.anchors->lock); 95965b390aaSDag-Erling Smørgrav RBTREE_FOR(ta, struct trust_anchor*, w->env.anchors->tree) { 96065b390aaSDag-Erling Smørgrav char* str; 96165b390aaSDag-Erling Smørgrav size_t i, numtag, str_len = 255; 96265b390aaSDag-Erling Smørgrav if(num == TA_RESPONSE_MAX_TXT) continue; 96365b390aaSDag-Erling Smørgrav str = (char*)regional_alloc(w->scratchpad, str_len); 96465b390aaSDag-Erling Smørgrav if(!str) continue; 96565b390aaSDag-Erling Smørgrav lock_basic_lock(&ta->lock); 96665b390aaSDag-Erling Smørgrav numtag = anchor_list_keytags(ta, tags, TA_RESPONSE_MAX_TAGS); 96765b390aaSDag-Erling Smørgrav if(numtag == 0) { 96865b390aaSDag-Erling Smørgrav /* empty, insecure point */ 96965b390aaSDag-Erling Smørgrav lock_basic_unlock(&ta->lock); 97065b390aaSDag-Erling Smørgrav continue; 97165b390aaSDag-Erling Smørgrav } 97265b390aaSDag-Erling Smørgrav str_array[num] = str; 97365b390aaSDag-Erling Smørgrav num++; 97465b390aaSDag-Erling Smørgrav 97565b390aaSDag-Erling Smørgrav /* spool name of anchor */ 97665b390aaSDag-Erling Smørgrav (void)sldns_wire2str_dname_buf(ta->name, ta->namelen, str, str_len); 97765b390aaSDag-Erling Smørgrav str_len -= strlen(str); str += strlen(str); 97865b390aaSDag-Erling Smørgrav /* spool tags */ 97965b390aaSDag-Erling Smørgrav for(i=0; i<numtag; i++) { 98065b390aaSDag-Erling Smørgrav snprintf(str, str_len, " %u", (unsigned)tags[i]); 98165b390aaSDag-Erling Smørgrav str_len -= strlen(str); str += strlen(str); 98265b390aaSDag-Erling Smørgrav } 98365b390aaSDag-Erling Smørgrav lock_basic_unlock(&ta->lock); 98465b390aaSDag-Erling Smørgrav } 98565b390aaSDag-Erling Smørgrav lock_basic_unlock(&w->env.anchors->lock); 98665b390aaSDag-Erling Smørgrav 9874c75e3aaSDag-Erling Smørgrav chaos_replystr(pkt, str_array, num, edns, w, repinfo); 98865b390aaSDag-Erling Smørgrav regional_free_all(w->scratchpad); 98965b390aaSDag-Erling Smørgrav } 99065b390aaSDag-Erling Smørgrav 991b7579f77SDag-Erling Smørgrav /** 992b7579f77SDag-Erling Smørgrav * Answer CH class queries. 993b7579f77SDag-Erling Smørgrav * @param w: worker 994b7579f77SDag-Erling Smørgrav * @param qinfo: query info. Pointer into packet buffer. 995b7579f77SDag-Erling Smørgrav * @param edns: edns info from query. 9964c75e3aaSDag-Erling Smørgrav * @param repinfo: reply information for a communication point. 997b7579f77SDag-Erling Smørgrav * @param pkt: packet buffer. 998b7579f77SDag-Erling Smørgrav * @return: true if a reply is to be sent. 999b7579f77SDag-Erling Smørgrav */ 1000b7579f77SDag-Erling Smørgrav static int 1001b7579f77SDag-Erling Smørgrav answer_chaos(struct worker* w, struct query_info* qinfo, 10024c75e3aaSDag-Erling Smørgrav struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* pkt) 1003b7579f77SDag-Erling Smørgrav { 1004b7579f77SDag-Erling Smørgrav struct config_file* cfg = w->env.cfg; 1005b7579f77SDag-Erling Smørgrav if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) 1006b7579f77SDag-Erling Smørgrav return 0; 1007b7579f77SDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 1008b7579f77SDag-Erling Smørgrav (uint8_t*)"\002id\006server") == 0 || 1009b7579f77SDag-Erling Smørgrav query_dname_compare(qinfo->qname, 1010b7579f77SDag-Erling Smørgrav (uint8_t*)"\010hostname\004bind") == 0) 1011b7579f77SDag-Erling Smørgrav { 1012b7579f77SDag-Erling Smørgrav if(cfg->hide_identity) 1013b7579f77SDag-Erling Smørgrav return 0; 1014b7579f77SDag-Erling Smørgrav if(cfg->identity==NULL || cfg->identity[0]==0) { 1015b7579f77SDag-Erling Smørgrav char buf[MAXHOSTNAMELEN+1]; 1016b7579f77SDag-Erling Smørgrav if (gethostname(buf, MAXHOSTNAMELEN) == 0) { 1017b7579f77SDag-Erling Smørgrav buf[MAXHOSTNAMELEN] = 0; 10184c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, buf, edns, w, repinfo); 1019b7579f77SDag-Erling Smørgrav } else { 1020b7579f77SDag-Erling Smørgrav log_err("gethostname: %s", strerror(errno)); 10214c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, "no hostname", edns, w, repinfo); 1022b7579f77SDag-Erling Smørgrav } 1023b7579f77SDag-Erling Smørgrav } 10244c75e3aaSDag-Erling Smørgrav else chaos_replyonestr(pkt, cfg->identity, edns, w, repinfo); 1025b7579f77SDag-Erling Smørgrav return 1; 1026b7579f77SDag-Erling Smørgrav } 1027b7579f77SDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 1028b7579f77SDag-Erling Smørgrav (uint8_t*)"\007version\006server") == 0 || 1029b7579f77SDag-Erling Smørgrav query_dname_compare(qinfo->qname, 1030b7579f77SDag-Erling Smørgrav (uint8_t*)"\007version\004bind") == 0) 1031b7579f77SDag-Erling Smørgrav { 1032b7579f77SDag-Erling Smørgrav if(cfg->hide_version) 1033b7579f77SDag-Erling Smørgrav return 0; 1034b7579f77SDag-Erling Smørgrav if(cfg->version==NULL || cfg->version[0]==0) 10354c75e3aaSDag-Erling Smørgrav chaos_replyonestr(pkt, PACKAGE_STRING, edns, w, repinfo); 10364c75e3aaSDag-Erling Smørgrav else chaos_replyonestr(pkt, cfg->version, edns, w, repinfo); 1037b7579f77SDag-Erling Smørgrav return 1; 1038b7579f77SDag-Erling Smørgrav } 103965b390aaSDag-Erling Smørgrav if(query_dname_compare(qinfo->qname, 104065b390aaSDag-Erling Smørgrav (uint8_t*)"\013trustanchor\007unbound") == 0) 104165b390aaSDag-Erling Smørgrav { 104265b390aaSDag-Erling Smørgrav if(cfg->hide_trustanchor) 104365b390aaSDag-Erling Smørgrav return 0; 10444c75e3aaSDag-Erling Smørgrav chaos_trustanchor(pkt, edns, w, repinfo); 104565b390aaSDag-Erling Smørgrav return 1; 104665b390aaSDag-Erling Smørgrav } 104765b390aaSDag-Erling Smørgrav 1048b7579f77SDag-Erling Smørgrav return 0; 1049b7579f77SDag-Erling Smørgrav } 1050b7579f77SDag-Erling Smørgrav 10510fb34990SDag-Erling Smørgrav /** 10520fb34990SDag-Erling Smørgrav * Answer notify queries. These are notifies for authoritative zones, 10530fb34990SDag-Erling Smørgrav * the reply is an ack that the notify has been received. We need to check 10540fb34990SDag-Erling Smørgrav * access permission here. 10550fb34990SDag-Erling Smørgrav * @param w: worker 10560fb34990SDag-Erling Smørgrav * @param qinfo: query info. Pointer into packet buffer. 10570fb34990SDag-Erling Smørgrav * @param edns: edns info from query. 1058865f46b2SCy Schubert * @param addr: client address. 1059865f46b2SCy Schubert * @param addrlen: client address length. 10600fb34990SDag-Erling Smørgrav * @param pkt: packet buffer. 10610fb34990SDag-Erling Smørgrav */ 10620fb34990SDag-Erling Smørgrav static void 10630fb34990SDag-Erling Smørgrav answer_notify(struct worker* w, struct query_info* qinfo, 1064865f46b2SCy Schubert struct edns_data* edns, sldns_buffer* pkt, 1065865f46b2SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen) 10660fb34990SDag-Erling Smørgrav { 10670fb34990SDag-Erling Smørgrav int refused = 0; 10680fb34990SDag-Erling Smørgrav int rcode = LDNS_RCODE_NOERROR; 10690fb34990SDag-Erling Smørgrav uint32_t serial = 0; 10700fb34990SDag-Erling Smørgrav int has_serial; 10710fb34990SDag-Erling Smørgrav if(!w->env.auth_zones) return; 10720fb34990SDag-Erling Smørgrav has_serial = auth_zone_parse_notify_serial(pkt, &serial); 10730fb34990SDag-Erling Smørgrav if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname, 1074865f46b2SCy Schubert qinfo->qname_len, qinfo->qclass, addr, 1075865f46b2SCy Schubert addrlen, has_serial, serial, &refused)) { 10760fb34990SDag-Erling Smørgrav rcode = LDNS_RCODE_NOERROR; 10770fb34990SDag-Erling Smørgrav } else { 10780fb34990SDag-Erling Smørgrav if(refused) 10790fb34990SDag-Erling Smørgrav rcode = LDNS_RCODE_REFUSED; 10800fb34990SDag-Erling Smørgrav else rcode = LDNS_RCODE_SERVFAIL; 10810fb34990SDag-Erling Smørgrav } 10820fb34990SDag-Erling Smørgrav 10830fb34990SDag-Erling Smørgrav if(verbosity >= VERB_DETAIL) { 10840fb34990SDag-Erling Smørgrav char buf[380]; 10850fb34990SDag-Erling Smørgrav char zname[255+1]; 10860fb34990SDag-Erling Smørgrav char sr[25]; 10870fb34990SDag-Erling Smørgrav dname_str(qinfo->qname, zname); 10880fb34990SDag-Erling Smørgrav sr[0]=0; 10890fb34990SDag-Erling Smørgrav if(has_serial) 10900fb34990SDag-Erling Smørgrav snprintf(sr, sizeof(sr), "serial %u ", 10910fb34990SDag-Erling Smørgrav (unsigned)serial); 10920fb34990SDag-Erling Smørgrav if(rcode == LDNS_RCODE_REFUSED) 10930fb34990SDag-Erling Smørgrav snprintf(buf, sizeof(buf), 10940fb34990SDag-Erling Smørgrav "refused NOTIFY %sfor %s from", sr, zname); 10950fb34990SDag-Erling Smørgrav else if(rcode == LDNS_RCODE_SERVFAIL) 10960fb34990SDag-Erling Smørgrav snprintf(buf, sizeof(buf), 10970fb34990SDag-Erling Smørgrav "servfail for NOTIFY %sfor %s from", sr, zname); 10980fb34990SDag-Erling Smørgrav else snprintf(buf, sizeof(buf), 10990fb34990SDag-Erling Smørgrav "received NOTIFY %sfor %s from", sr, zname); 1100865f46b2SCy Schubert log_addr(VERB_DETAIL, buf, addr, addrlen); 11010fb34990SDag-Erling Smørgrav } 11020fb34990SDag-Erling Smørgrav edns->edns_version = EDNS_ADVERTISED_VERSION; 11030fb34990SDag-Erling Smørgrav edns->udp_size = EDNS_ADVERTISED_SIZE; 11040fb34990SDag-Erling Smørgrav edns->ext_rcode = 0; 11050fb34990SDag-Erling Smørgrav edns->bits &= EDNS_DO; 11060fb34990SDag-Erling Smørgrav error_encode(pkt, rcode, qinfo, 11070fb34990SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(pkt), 11080fb34990SDag-Erling Smørgrav sldns_buffer_read_u16_at(pkt, 2), edns); 11090fb34990SDag-Erling Smørgrav LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY); 11100fb34990SDag-Erling Smørgrav } 11110fb34990SDag-Erling Smørgrav 111217d15b25SDag-Erling Smørgrav static int 111317d15b25SDag-Erling Smørgrav deny_refuse(struct comm_point* c, enum acl_access acl, 111417d15b25SDag-Erling Smørgrav enum acl_access deny, enum acl_access refuse, 1115a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 11168f76bb7dSCy Schubert struct acl_addr* acladdr, int ede, 11178f76bb7dSCy Schubert struct check_request_result* check_result) 111817d15b25SDag-Erling Smørgrav { 111917d15b25SDag-Erling Smørgrav if(acl == deny) { 1120a39a5a69SCy Schubert if(verbosity >= VERB_ALGO) { 1121865f46b2SCy Schubert log_acl_action("dropped", &repinfo->client_addr, 1122865f46b2SCy Schubert repinfo->client_addrlen, acl, acladdr); 1123a39a5a69SCy Schubert log_buf(VERB_ALGO, "dropped", c->buffer); 1124a39a5a69SCy Schubert } 112517d15b25SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 112617d15b25SDag-Erling Smørgrav if(worker->stats.extended) 112717d15b25SDag-Erling Smørgrav worker->stats.unwanted_queries++; 112817d15b25SDag-Erling Smørgrav return 0; 112917d15b25SDag-Erling Smørgrav } else if(acl == refuse) { 1130a39a5a69SCy Schubert size_t opt_rr_mark; 1131a39a5a69SCy Schubert 1132a39a5a69SCy Schubert if(verbosity >= VERB_ALGO) { 1133865f46b2SCy Schubert log_acl_action("refused", &repinfo->client_addr, 1134865f46b2SCy Schubert repinfo->client_addrlen, acl, acladdr); 113517d15b25SDag-Erling Smørgrav log_buf(VERB_ALGO, "refuse", c->buffer); 1136a39a5a69SCy Schubert } 1137a39a5a69SCy Schubert 113817d15b25SDag-Erling Smørgrav if(worker->stats.extended) 113917d15b25SDag-Erling Smørgrav worker->stats.unwanted_queries++; 11408f76bb7dSCy Schubert worker_check_request(c->buffer, worker, check_result); 11418f76bb7dSCy Schubert if(check_result->value != 0) { 11428f76bb7dSCy Schubert if(check_result->value != -1) { 11438f76bb7dSCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 11448f76bb7dSCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 11458f76bb7dSCy Schubert check_result->value); 11468f76bb7dSCy Schubert return 1; 11478f76bb7dSCy Schubert } 114817d15b25SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 11498f76bb7dSCy Schubert return 0; 115017d15b25SDag-Erling Smørgrav } 1151a39a5a69SCy Schubert /* worker_check_request() above guarantees that the buffer contains at 1152a39a5a69SCy Schubert * least a header and that qdcount == 1 1153a39a5a69SCy Schubert */ 1154a39a5a69SCy Schubert log_assert(sldns_buffer_limit(c->buffer) >= LDNS_HEADER_SIZE 1155a39a5a69SCy Schubert && LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1); 1156a39a5a69SCy Schubert 1157b7c0c8c1SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); /* skip header */ 1158a39a5a69SCy Schubert 1159a39a5a69SCy Schubert /* check additional section is present and that we respond with EDEs */ 1160a39a5a69SCy Schubert if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1 1161a39a5a69SCy Schubert || !ede) { 1162a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1163a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1164a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1165a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 116617d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 116717d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 116817d15b25SDag-Erling Smørgrav LDNS_RCODE_REFUSED); 1169b7c0c8c1SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1170a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1171a39a5a69SCy Schubert return 1; 1172a39a5a69SCy Schubert } 1173a39a5a69SCy Schubert 1174a39a5a69SCy Schubert if (!query_dname_len(c->buffer)) { 1175a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1176a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1177a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1178a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1179a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1180a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1181a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1182b5663de9SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1183b5663de9SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 118417d15b25SDag-Erling Smørgrav return 1; 118517d15b25SDag-Erling Smørgrav } 1186a39a5a69SCy Schubert /* space available for query type and class? */ 1187a39a5a69SCy Schubert if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) { 1188a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1189a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1190a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1191a39a5a69SCy Schubert LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1192a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1193a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1194a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1195a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 1196a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1197a39a5a69SCy Schubert return 1; 1198a39a5a69SCy Schubert } 1199a39a5a69SCy Schubert LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 1200a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1201a39a5a69SCy Schubert LDNS_RCODE_REFUSED); 1202a39a5a69SCy Schubert 1203a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */ 1204a39a5a69SCy Schubert 1205a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qclass */ 1206a39a5a69SCy Schubert 1207a39a5a69SCy Schubert /* The OPT RR to be returned should come directly after 1208a39a5a69SCy Schubert * the query, so mark this spot. 1209a39a5a69SCy Schubert */ 1210a39a5a69SCy Schubert opt_rr_mark = sldns_buffer_position(c->buffer); 1211a39a5a69SCy Schubert 1212a39a5a69SCy Schubert /* Skip through the RR records */ 1213a39a5a69SCy Schubert if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 || 1214a39a5a69SCy Schubert LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) { 1215a39a5a69SCy Schubert if(!skip_pkt_rrs(c->buffer, 1216a39a5a69SCy Schubert ((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+ 1217a39a5a69SCy Schubert ((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) { 1218a39a5a69SCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1219a39a5a69SCy Schubert LDNS_RCODE_FORMERR); 1220a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1221a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1222a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1223a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1224a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1225a39a5a69SCy Schubert return 1; 1226a39a5a69SCy Schubert } 1227a39a5a69SCy Schubert } 1228a39a5a69SCy Schubert /* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */ 1229a39a5a69SCy Schubert /* domain name must be the root of length 1. */ 1230a39a5a69SCy Schubert if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) { 1231a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1232a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1233a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1234a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1235a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1236a39a5a69SCy Schubert return 1; 1237a39a5a69SCy Schubert } else { 1238a39a5a69SCy Schubert sldns_buffer_skip(c->buffer, 1); /* skip root label */ 1239a39a5a69SCy Schubert } 1240a39a5a69SCy Schubert if(sldns_buffer_remaining(c->buffer) < 2 || 1241a39a5a69SCy Schubert sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) { 1242a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1243a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1244a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1245a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1246a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1247a39a5a69SCy Schubert return 1; 1248a39a5a69SCy Schubert } 1249a39a5a69SCy Schubert /* Write OPT RR directly after the query, 1250a39a5a69SCy Schubert * so without the (possibly skipped) Answer and NS RRs 1251a39a5a69SCy Schubert */ 1252a39a5a69SCy Schubert LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1253a39a5a69SCy Schubert LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1254a39a5a69SCy Schubert sldns_buffer_clear(c->buffer); /* reset write limit */ 1255a39a5a69SCy Schubert sldns_buffer_set_position(c->buffer, opt_rr_mark); 1256a39a5a69SCy Schubert 1257a39a5a69SCy Schubert /* Check if OPT record can be written 1258a39a5a69SCy Schubert * 17 == root label (1) + RR type (2) + UDP Size (2) 1259a39a5a69SCy Schubert * + Fields (4) + rdata len (2) + EDE Option code (2) 1260a39a5a69SCy Schubert * + EDE Option length (2) + EDE info-code (2) 1261a39a5a69SCy Schubert */ 1262a39a5a69SCy Schubert if (sldns_buffer_available(c->buffer, 17) == 0) { 1263a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0); 1264a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1265a39a5a69SCy Schubert return 1; 1266a39a5a69SCy Schubert } 1267a39a5a69SCy Schubert 1268a39a5a69SCy Schubert LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1); 1269a39a5a69SCy Schubert 1270a39a5a69SCy Schubert /* root label */ 1271a39a5a69SCy Schubert sldns_buffer_write_u8(c->buffer, 0); 1272a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT); 1273a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE); 1274a39a5a69SCy Schubert 1275a39a5a69SCy Schubert /* write OPT Record TTL Field */ 1276a39a5a69SCy Schubert sldns_buffer_write_u32(c->buffer, 0); 1277a39a5a69SCy Schubert 1278a39a5a69SCy Schubert /* write rdata len: EDE option + length + info-code */ 1279a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, 6); 1280a39a5a69SCy Schubert 1281a39a5a69SCy Schubert /* write OPTIONS; add EDE option code */ 1282a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE); 1283a39a5a69SCy Schubert 1284a39a5a69SCy Schubert /* write single EDE option length (for just 1 info-code) */ 1285a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, 2); 1286a39a5a69SCy Schubert 1287a39a5a69SCy Schubert /* write single EDE info-code */ 1288a39a5a69SCy Schubert sldns_buffer_write_u16(c->buffer, LDNS_EDE_PROHIBITED); 1289a39a5a69SCy Schubert 1290a39a5a69SCy Schubert sldns_buffer_flip(c->buffer); 1291a39a5a69SCy Schubert 1292a39a5a69SCy Schubert verbose(VERB_ALGO, "attached EDE code: %d", LDNS_EDE_PROHIBITED); 1293a39a5a69SCy Schubert 1294a39a5a69SCy Schubert return 1; 1295a39a5a69SCy Schubert 1296a39a5a69SCy Schubert } 129717d15b25SDag-Erling Smørgrav 129817d15b25SDag-Erling Smørgrav return -1; 129917d15b25SDag-Erling Smørgrav } 130017d15b25SDag-Erling Smørgrav 130117d15b25SDag-Erling Smørgrav static int 1302865f46b2SCy Schubert deny_refuse_all(struct comm_point* c, enum acl_access* acl, 1303a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 13048f76bb7dSCy Schubert struct acl_addr** acladdr, int ede, int check_proxy, 13058f76bb7dSCy Schubert struct check_request_result* check_result) 130617d15b25SDag-Erling Smørgrav { 1307865f46b2SCy Schubert if(check_proxy) { 1308865f46b2SCy Schubert *acladdr = acl_addr_lookup(worker->daemon->acl, 1309865f46b2SCy Schubert &repinfo->remote_addr, repinfo->remote_addrlen); 1310865f46b2SCy Schubert } else { 1311865f46b2SCy Schubert *acladdr = acl_addr_lookup(worker->daemon->acl, 1312865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1313865f46b2SCy Schubert } 1314865f46b2SCy Schubert /* If there is no ACL based on client IP use the interface ACL. */ 1315865f46b2SCy Schubert if(!(*acladdr) && c->socket) { 1316865f46b2SCy Schubert *acladdr = c->socket->acl; 1317865f46b2SCy Schubert } 1318865f46b2SCy Schubert *acl = acl_get_control(*acladdr); 1319865f46b2SCy Schubert return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo, 13208f76bb7dSCy Schubert *acladdr, ede, check_result); 132117d15b25SDag-Erling Smørgrav } 132217d15b25SDag-Erling Smørgrav 132317d15b25SDag-Erling Smørgrav static int 132417d15b25SDag-Erling Smørgrav deny_refuse_non_local(struct comm_point* c, enum acl_access acl, 1325a39a5a69SCy Schubert struct worker* worker, struct comm_reply* repinfo, 13268f76bb7dSCy Schubert struct acl_addr* acladdr, int ede, 13278f76bb7dSCy Schubert struct check_request_result* check_result) 132817d15b25SDag-Erling Smørgrav { 1329a39a5a69SCy Schubert return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, 13308f76bb7dSCy Schubert worker, repinfo, acladdr, ede, check_result); 13318f76bb7dSCy Schubert } 13328f76bb7dSCy Schubert 13338f76bb7dSCy Schubert /* Check if the query is blocked by source IP rate limiting. 13348f76bb7dSCy Schubert * Returns 1 if it passes the check, 0 otherwise. */ 13358f76bb7dSCy Schubert static int 13368f76bb7dSCy Schubert check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr, 13378f76bb7dSCy Schubert socklen_t addrlen, int has_cookie, sldns_buffer* pkt) 13388f76bb7dSCy Schubert { 13398f76bb7dSCy Schubert if(!infra_ip_ratelimit_inc(worker->env.infra_cache, addr, addrlen, 13408f76bb7dSCy Schubert *worker->env.now, has_cookie, 13418f76bb7dSCy Schubert worker->env.cfg->ip_ratelimit_backoff, pkt)) { 13428f76bb7dSCy Schubert /* See if we can pass through with slip factor */ 13438f76bb7dSCy Schubert if(!has_cookie && worker->env.cfg->ip_ratelimit_factor != 0 && 13448f76bb7dSCy Schubert ub_random_max(worker->env.rnd, 13458f76bb7dSCy Schubert worker->env.cfg->ip_ratelimit_factor) == 0) { 13468f76bb7dSCy Schubert char addrbuf[128]; 13478f76bb7dSCy Schubert addr_to_str(addr, addrlen, addrbuf, sizeof(addrbuf)); 13488f76bb7dSCy Schubert verbose(VERB_QUERY, "ip_ratelimit allowed through for " 13498f76bb7dSCy Schubert "ip address %s because of slip in " 13508f76bb7dSCy Schubert "ip_ratelimit_factor", addrbuf); 13518f76bb7dSCy Schubert return 1; 13528f76bb7dSCy Schubert } 13538f76bb7dSCy Schubert return 0; 13548f76bb7dSCy Schubert } 13558f76bb7dSCy Schubert return 1; 135617d15b25SDag-Erling Smørgrav } 135717d15b25SDag-Erling Smørgrav 1358b7579f77SDag-Erling Smørgrav int 1359b7579f77SDag-Erling Smørgrav worker_handle_request(struct comm_point* c, void* arg, int error, 1360b7579f77SDag-Erling Smørgrav struct comm_reply* repinfo) 1361b7579f77SDag-Erling Smørgrav { 1362b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 1363b7579f77SDag-Erling Smørgrav int ret; 13643005e0a3SDag-Erling Smørgrav hashvalue_type h; 1365b7579f77SDag-Erling Smørgrav struct lruhash_entry* e; 1366b7579f77SDag-Erling Smørgrav struct query_info qinfo; 1367b7579f77SDag-Erling Smørgrav struct edns_data edns; 1368a39a5a69SCy Schubert struct edns_option* original_edns_list = NULL; 1369b7579f77SDag-Erling Smørgrav enum acl_access acl; 1370b5663de9SDag-Erling Smørgrav struct acl_addr* acladdr; 13718f76bb7dSCy Schubert int pre_edns_ip_ratelimit = 1; 1372ff825849SDag-Erling Smørgrav int rc = 0; 137365b390aaSDag-Erling Smørgrav int need_drop = 0; 1374091e9e46SCy Schubert int is_expired_answer = 0; 1375091e9e46SCy Schubert int is_secure_answer = 0; 1376a39a5a69SCy Schubert int rpz_passthru = 0; 13778f76bb7dSCy Schubert long long wait_queue_time = 0; 137865b390aaSDag-Erling Smørgrav /* We might have to chase a CNAME chain internally, in which case 137965b390aaSDag-Erling Smørgrav * we'll have up to two replies and combine them to build a complete 138065b390aaSDag-Erling Smørgrav * answer. These variables control this case. */ 138165b390aaSDag-Erling Smørgrav struct ub_packed_rrset_key* alias_rrset = NULL; 138265b390aaSDag-Erling Smørgrav struct reply_info* partial_rep = NULL; 138365b390aaSDag-Erling Smørgrav struct query_info* lookup_qinfo = &qinfo; 1384e86b9096SDag-Erling Smørgrav struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */ 138565b390aaSDag-Erling Smørgrav struct respip_client_info* cinfo = NULL, cinfo_tmp; 13868f76bb7dSCy Schubert struct timeval wait_time; 13878f76bb7dSCy Schubert struct check_request_result check_result = {0,0}; 1388971980c3SDag-Erling Smørgrav memset(&qinfo, 0, sizeof(qinfo)); 1389b7579f77SDag-Erling Smørgrav 1390c0caa2e2SCy Schubert if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) { 1391b7579f77SDag-Erling Smørgrav /* some bad tcp query DNS formats give these error calls */ 1392b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "handle request called with err=%d", error); 1393b7579f77SDag-Erling Smørgrav return 0; 1394b7579f77SDag-Erling Smørgrav } 13958f76bb7dSCy Schubert 13968f76bb7dSCy Schubert if (worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv)) { 13978f76bb7dSCy Schubert timeval_subtract(&wait_time, worker->env.now_tv, &c->recv_tv); 13988f76bb7dSCy Schubert wait_queue_time = wait_time.tv_sec * 1000000 + wait_time.tv_usec; 13998f76bb7dSCy Schubert if (worker->stats.max_query_time_us < wait_queue_time) 14008f76bb7dSCy Schubert worker->stats.max_query_time_us = wait_queue_time; 14018f76bb7dSCy Schubert if(wait_queue_time > 14028f76bb7dSCy Schubert (long long)(worker->env.cfg->sock_queue_timeout * 1000000)) { 14038f76bb7dSCy Schubert /* count and drop queries that were sitting in the socket queue too long */ 14048f76bb7dSCy Schubert worker->stats.num_queries_timed_out++; 14058f76bb7dSCy Schubert return 0; 14068f76bb7dSCy Schubert } 14078f76bb7dSCy Schubert } 14088f76bb7dSCy Schubert 140965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 141065b390aaSDag-Erling Smørgrav repinfo->max_udp_size = worker->daemon->cfg->max_udp_size; 141165b390aaSDag-Erling Smørgrav if(!dnsc_handle_curved_request(worker->daemon->dnscenv, repinfo)) { 141265b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_crypted_malformed++; 141365b390aaSDag-Erling Smørgrav return 0; 141465b390aaSDag-Erling Smørgrav } 141565b390aaSDag-Erling Smørgrav if(c->dnscrypt && !repinfo->is_dnscrypted) { 141665b390aaSDag-Erling Smørgrav char buf[LDNS_MAX_DOMAINLEN+1]; 1417c7f4d7adSDag-Erling Smørgrav /* Check if this is unencrypted and asking for certs */ 14188f76bb7dSCy Schubert worker_check_request(c->buffer, worker, &check_result); 14198f76bb7dSCy Schubert if(check_result.value != 0) { 1420c7f4d7adSDag-Erling Smørgrav verbose(VERB_ALGO, 1421c7f4d7adSDag-Erling Smørgrav "dnscrypt: worker check request: bad query."); 1422865f46b2SCy Schubert log_addr(VERB_CLIENT,"from",&repinfo->client_addr, 1423865f46b2SCy Schubert repinfo->client_addrlen); 142465b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 142565b390aaSDag-Erling Smørgrav return 0; 142665b390aaSDag-Erling Smørgrav } 142765b390aaSDag-Erling Smørgrav if(!query_info_parse(&qinfo, c->buffer)) { 1428c7f4d7adSDag-Erling Smørgrav verbose(VERB_ALGO, 1429c7f4d7adSDag-Erling Smørgrav "dnscrypt: worker parse request: formerror."); 1430865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1431865f46b2SCy Schubert repinfo->client_addrlen); 143265b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 143365b390aaSDag-Erling Smørgrav return 0; 143465b390aaSDag-Erling Smørgrav } 143565b390aaSDag-Erling Smørgrav dname_str(qinfo.qname, buf); 143665b390aaSDag-Erling Smørgrav if(!(qinfo.qtype == LDNS_RR_TYPE_TXT && 1437c7f4d7adSDag-Erling Smørgrav strcasecmp(buf, 1438c7f4d7adSDag-Erling Smørgrav worker->daemon->dnscenv->provider_name) == 0)) { 143965b390aaSDag-Erling Smørgrav verbose(VERB_ALGO, 144057bddd21SDag-Erling Smørgrav "dnscrypt: not TXT \"%s\". Received: %s \"%s\"", 144165b390aaSDag-Erling Smørgrav worker->daemon->dnscenv->provider_name, 144265b390aaSDag-Erling Smørgrav sldns_rr_descript(qinfo.qtype)->_name, 144365b390aaSDag-Erling Smørgrav buf); 144465b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 144565b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_cleartext++; 144665b390aaSDag-Erling Smørgrav return 0; 144765b390aaSDag-Erling Smørgrav } 144865b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_cert++; 144965b390aaSDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 145065b390aaSDag-Erling Smørgrav } else if(c->dnscrypt && repinfo->is_dnscrypted) { 145165b390aaSDag-Erling Smørgrav worker->stats.num_query_dnscrypt_crypted++; 145265b390aaSDag-Erling Smørgrav } 145365b390aaSDag-Erling Smørgrav #endif 1454ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 14555469a995SCy Schubert /* 14565469a995SCy Schubert * sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler 14575469a995SCy Schubert */ 14585469a995SCy Schubert if(worker->dtenv.log_client_query_messages) { 1459865f46b2SCy Schubert log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen); 1460335c7cdaSCy Schubert log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen); 1461335c7cdaSCy Schubert dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer, 14628f76bb7dSCy Schubert ((worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv))?&c->recv_tv:NULL)); 14635469a995SCy Schubert } 1464ff825849SDag-Erling Smørgrav #endif 1465865f46b2SCy Schubert /* Check deny/refuse ACLs */ 1466865f46b2SCy Schubert if(repinfo->is_proxied) { 1467865f46b2SCy Schubert if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, 14688f76bb7dSCy Schubert worker->env.cfg->ede, 1, &check_result)) != -1) { 14698cee2ebaSCy Schubert if(ret == 1) 14708cee2ebaSCy Schubert goto send_reply; 14718cee2ebaSCy Schubert return ret; 14728cee2ebaSCy Schubert } 1473865f46b2SCy Schubert } 1474865f46b2SCy Schubert if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr, 14758f76bb7dSCy Schubert worker->env.cfg->ede, 0, &check_result)) != -1) { 1476865f46b2SCy Schubert if(ret == 1) 1477865f46b2SCy Schubert goto send_reply; 1478865f46b2SCy Schubert return ret; 1479865f46b2SCy Schubert } 1480865f46b2SCy Schubert 14818f76bb7dSCy Schubert worker_check_request(c->buffer, worker, &check_result); 14828f76bb7dSCy Schubert if(check_result.value != 0) { 1483b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker check request: bad query."); 1484865f46b2SCy Schubert log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen); 14858f76bb7dSCy Schubert if(check_result.value != -1) { 148617d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 14878f76bb7dSCy Schubert LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 14888f76bb7dSCy Schubert check_result.value); 1489b7579f77SDag-Erling Smørgrav return 1; 1490b7579f77SDag-Erling Smørgrav } 1491b7579f77SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 1492b7579f77SDag-Erling Smørgrav return 0; 1493b7579f77SDag-Erling Smørgrav } 14943005e0a3SDag-Erling Smørgrav 1495b7579f77SDag-Erling Smørgrav worker->stats.num_queries++; 1496b7c0c8c1SCy Schubert pre_edns_ip_ratelimit = !worker->env.cfg->do_answer_cookie 1497b7c0c8c1SCy Schubert || sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE 1498b7c0c8c1SCy Schubert || LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) == 0; 14993005e0a3SDag-Erling Smørgrav 15008f76bb7dSCy Schubert /* If the IP rate limiting check needs extra EDNS information (e.g., 15018f76bb7dSCy Schubert * DNS Cookies) postpone the check until after EDNS is parsed. */ 15028f76bb7dSCy Schubert if(pre_edns_ip_ratelimit) { 15038f76bb7dSCy Schubert /* NOTE: we always check the repinfo->client_address. 15048f76bb7dSCy Schubert * IP ratelimiting is implicitly disabled for proxies. */ 15058f76bb7dSCy Schubert if(!check_ip_ratelimit(worker, &repinfo->client_addr, 15068f76bb7dSCy Schubert repinfo->client_addrlen, 0, c->buffer)) { 15073005e0a3SDag-Erling Smørgrav worker->stats.num_queries_ip_ratelimited++; 15083005e0a3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 15093005e0a3SDag-Erling Smørgrav return 0; 15103005e0a3SDag-Erling Smørgrav } 15113005e0a3SDag-Erling Smørgrav } 15123005e0a3SDag-Erling Smørgrav 1513b7579f77SDag-Erling Smørgrav if(!query_info_parse(&qinfo, c->buffer)) { 1514b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker parse request: formerror."); 1515865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1516865f46b2SCy Schubert repinfo->client_addrlen); 1517971980c3SDag-Erling Smørgrav memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */ 151809a3aaf3SDag-Erling Smørgrav if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { 151909a3aaf3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 152009a3aaf3SDag-Erling Smørgrav return 0; 152109a3aaf3SDag-Erling Smørgrav } 152217d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 152317d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 152417d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1525b7579f77SDag-Erling Smørgrav LDNS_RCODE_FORMERR); 1526ff825849SDag-Erling Smørgrav goto send_reply; 1527b7579f77SDag-Erling Smørgrav } 1528b7579f77SDag-Erling Smørgrav if(worker->env.cfg->log_queries) { 1529b7579f77SDag-Erling Smørgrav char ip[128]; 1530865f46b2SCy Schubert addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip)); 1531e86b9096SDag-Erling Smørgrav log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass); 1532b7579f77SDag-Erling Smørgrav } 1533b7579f77SDag-Erling Smørgrav if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 1534b7579f77SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_IXFR) { 1535b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: refused zone transfer."); 1536865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1537865f46b2SCy Schubert repinfo->client_addrlen); 153817d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 153917d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 154017d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1541b7579f77SDag-Erling Smørgrav LDNS_RCODE_REFUSED); 1542b7579f77SDag-Erling Smørgrav if(worker->stats.extended) { 1543b7579f77SDag-Erling Smørgrav worker->stats.qtype[qinfo.qtype]++; 1544b7579f77SDag-Erling Smørgrav } 1545ff825849SDag-Erling Smørgrav goto send_reply; 1546b7579f77SDag-Erling Smørgrav } 15473005e0a3SDag-Erling Smørgrav if(qinfo.qtype == LDNS_RR_TYPE_OPT || 15483005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_TSIG || 15493005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_TKEY || 15503005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_MAILA || 15513005e0a3SDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_MAILB || 15523005e0a3SDag-Erling Smørgrav (qinfo.qtype >= 128 && qinfo.qtype <= 248)) { 15533005e0a3SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: formerror for meta-type."); 1554865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1555865f46b2SCy Schubert repinfo->client_addrlen); 15563005e0a3SDag-Erling Smørgrav if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { 15573005e0a3SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 15583005e0a3SDag-Erling Smørgrav return 0; 15593005e0a3SDag-Erling Smørgrav } 15603005e0a3SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 15613005e0a3SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 15623005e0a3SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 15633005e0a3SDag-Erling Smørgrav LDNS_RCODE_FORMERR); 15643005e0a3SDag-Erling Smørgrav if(worker->stats.extended) { 15653005e0a3SDag-Erling Smørgrav worker->stats.qtype[qinfo.qtype]++; 15663005e0a3SDag-Erling Smørgrav } 15673005e0a3SDag-Erling Smørgrav goto send_reply; 15683005e0a3SDag-Erling Smørgrav } 15698f76bb7dSCy Schubert if((ret=parse_edns_from_query_pkt( 15708f76bb7dSCy Schubert c->buffer, &edns, worker->env.cfg, c, repinfo, 15718f76bb7dSCy Schubert (worker->env.now ? *worker->env.now : time(NULL)), 157256850988SCy Schubert worker->scratchpad, 157356850988SCy Schubert worker->daemon->cookie_secrets)) != 0) { 157405ab2901SDag-Erling Smørgrav struct edns_data reply_edns; 1575b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker parse edns: formerror."); 1576865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1577865f46b2SCy Schubert repinfo->client_addrlen); 157805ab2901SDag-Erling Smørgrav memset(&reply_edns, 0, sizeof(reply_edns)); 157905ab2901SDag-Erling Smørgrav reply_edns.edns_present = 1; 158005ab2901SDag-Erling Smørgrav error_encode(c->buffer, ret, &qinfo, 158105ab2901SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 158205ab2901SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); 1583e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1584ff825849SDag-Erling Smørgrav goto send_reply; 1585b7579f77SDag-Erling Smørgrav } 15864c75e3aaSDag-Erling Smørgrav if(edns.edns_present) { 15874c75e3aaSDag-Erling Smørgrav if(edns.edns_version != 0) { 158824e36522SCy Schubert edns.opt_list_in = NULL; 158924e36522SCy Schubert edns.opt_list_out = NULL; 159024e36522SCy Schubert edns.opt_list_inplace_cb_out = NULL; 1591b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "query with bad edns version."); 1592865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1593865f46b2SCy Schubert repinfo->client_addrlen); 15948f76bb7dSCy Schubert extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo, 159517d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 15968f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns); 1597e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1598ff825849SDag-Erling Smørgrav goto send_reply; 1599b7579f77SDag-Erling Smørgrav } 16004c75e3aaSDag-Erling Smørgrav if(edns.udp_size < NORMAL_UDP_SIZE && 1601b7579f77SDag-Erling Smørgrav worker->daemon->cfg->harden_short_bufsize) { 1602b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored", 1603b7579f77SDag-Erling Smørgrav (int)edns.udp_size); 1604865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1605865f46b2SCy Schubert repinfo->client_addrlen); 1606b7579f77SDag-Erling Smørgrav edns.udp_size = NORMAL_UDP_SIZE; 1607b7579f77SDag-Erling Smørgrav } 16084c75e3aaSDag-Erling Smørgrav } 16098f76bb7dSCy Schubert 16108f76bb7dSCy Schubert /* Get stats for cookies */ 16118f76bb7dSCy Schubert server_stats_downstream_cookie(&worker->stats, &edns); 16128f76bb7dSCy Schubert 16138f76bb7dSCy Schubert /* If the IP rate limiting check was postponed, check now. */ 16148f76bb7dSCy Schubert if(!pre_edns_ip_ratelimit) { 16158f76bb7dSCy Schubert /* NOTE: we always check the repinfo->client_address. 16168f76bb7dSCy Schubert * IP ratelimiting is implicitly disabled for proxies. */ 16178f76bb7dSCy Schubert if(!check_ip_ratelimit(worker, &repinfo->client_addr, 16188f76bb7dSCy Schubert repinfo->client_addrlen, edns.cookie_valid, 16198f76bb7dSCy Schubert c->buffer)) { 16208f76bb7dSCy Schubert worker->stats.num_queries_ip_ratelimited++; 16218f76bb7dSCy Schubert comm_point_drop_reply(repinfo); 16228f76bb7dSCy Schubert return 0; 16238f76bb7dSCy Schubert } 16248f76bb7dSCy Schubert } 16258f76bb7dSCy Schubert 16268f76bb7dSCy Schubert /* "if, else if" sequence below deals with downstream DNS Cookies */ 16278f76bb7dSCy Schubert if(acl != acl_allow_cookie) 16288f76bb7dSCy Schubert ; /* pass; No cookie downstream processing whatsoever */ 16298f76bb7dSCy Schubert 16308f76bb7dSCy Schubert else if(edns.cookie_valid) 16318f76bb7dSCy Schubert ; /* pass; Valid cookie is good! */ 16328f76bb7dSCy Schubert 16338f76bb7dSCy Schubert else if(c->type != comm_udp) 16348f76bb7dSCy Schubert ; /* pass; Stateful transport */ 16358f76bb7dSCy Schubert 16368f76bb7dSCy Schubert else if(edns.cookie_present) { 16378f76bb7dSCy Schubert /* Cookie present, but not valid: Cookie was bad! */ 16388f76bb7dSCy Schubert extended_error_encode(c->buffer, 16398f76bb7dSCy Schubert LDNS_EXT_RCODE_BADCOOKIE, &qinfo, 16408f76bb7dSCy Schubert *(uint16_t*)(void *) 16418f76bb7dSCy Schubert sldns_buffer_begin(c->buffer), 16428f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 16438f76bb7dSCy Schubert 0, &edns); 16448f76bb7dSCy Schubert regional_free_all(worker->scratchpad); 16458f76bb7dSCy Schubert goto send_reply; 16468f76bb7dSCy Schubert } else { 16478f76bb7dSCy Schubert /* Cookie required, but no cookie present on UDP */ 16488f76bb7dSCy Schubert verbose(VERB_ALGO, "worker request: " 16498f76bb7dSCy Schubert "need cookie or stateful transport"); 16508f76bb7dSCy Schubert log_addr(VERB_ALGO, "from",&repinfo->remote_addr 16518f76bb7dSCy Schubert , repinfo->remote_addrlen); 16528f76bb7dSCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, 16538f76bb7dSCy Schubert worker->scratchpad, LDNS_EDE_OTHER, 16548f76bb7dSCy Schubert "DNS Cookie needed for UDP replies"); 16558f76bb7dSCy Schubert error_encode(c->buffer, 16568f76bb7dSCy Schubert (LDNS_RCODE_REFUSED|BIT_TC), &qinfo, 16578f76bb7dSCy Schubert *(uint16_t*)(void *) 16588f76bb7dSCy Schubert sldns_buffer_begin(c->buffer), 16598f76bb7dSCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), 16608f76bb7dSCy Schubert &edns); 16618f76bb7dSCy Schubert regional_free_all(worker->scratchpad); 16628f76bb7dSCy Schubert goto send_reply; 16638f76bb7dSCy Schubert } 16648f76bb7dSCy Schubert 166517d15b25SDag-Erling Smørgrav if(edns.udp_size > worker->daemon->cfg->max_udp_size && 166617d15b25SDag-Erling Smørgrav c->type == comm_udp) { 166717d15b25SDag-Erling Smørgrav verbose(VERB_QUERY, 166817d15b25SDag-Erling Smørgrav "worker request: max UDP reply size modified" 166917d15b25SDag-Erling Smørgrav " (%d to max-udp-size)", (int)edns.udp_size); 1670865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1671865f46b2SCy Schubert repinfo->client_addrlen); 167217d15b25SDag-Erling Smørgrav edns.udp_size = worker->daemon->cfg->max_udp_size; 167317d15b25SDag-Erling Smørgrav } 167417d15b25SDag-Erling Smørgrav if(edns.udp_size < LDNS_HEADER_SIZE) { 1675b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "worker request: edns is too small."); 1676865f46b2SCy Schubert log_addr(VERB_CLIENT, "from", &repinfo->client_addr, 1677865f46b2SCy Schubert repinfo->client_addrlen); 167817d15b25SDag-Erling Smørgrav LDNS_QR_SET(sldns_buffer_begin(c->buffer)); 167917d15b25SDag-Erling Smørgrav LDNS_TC_SET(sldns_buffer_begin(c->buffer)); 168017d15b25SDag-Erling Smørgrav LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 1681b7579f77SDag-Erling Smørgrav LDNS_RCODE_SERVFAIL); 168217d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); 168317d15b25SDag-Erling Smørgrav sldns_buffer_write_at(c->buffer, 4, 1684b7579f77SDag-Erling Smørgrav (uint8_t*)"\0\0\0\0\0\0\0\0", 8); 168517d15b25SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 1686e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1687ff825849SDag-Erling Smørgrav goto send_reply; 1688b7579f77SDag-Erling Smørgrav } 1689b7579f77SDag-Erling Smørgrav if(worker->stats.extended) 1690b7579f77SDag-Erling Smørgrav server_stats_insquery(&worker->stats, c, qinfo.qtype, 1691b7579f77SDag-Erling Smørgrav qinfo.qclass, &edns, repinfo); 1692b7579f77SDag-Erling Smørgrav if(c->type != comm_udp) 1693b7579f77SDag-Erling Smørgrav edns.udp_size = 65535; /* max size for TCP replies */ 1694b7579f77SDag-Erling Smørgrav if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, 16954c75e3aaSDag-Erling Smørgrav &edns, repinfo, c->buffer)) { 1696e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1697ff825849SDag-Erling Smørgrav goto send_reply; 1698b7579f77SDag-Erling Smørgrav } 16990fb34990SDag-Erling Smørgrav if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) == 17000fb34990SDag-Erling Smørgrav LDNS_PACKET_NOTIFY) { 1701865f46b2SCy Schubert answer_notify(worker, &qinfo, &edns, c->buffer, 1702865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 17030fb34990SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 17040fb34990SDag-Erling Smørgrav goto send_reply; 17050fb34990SDag-Erling Smørgrav } 1706bc892140SDag-Erling Smørgrav if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo, 1707bc892140SDag-Erling Smørgrav &edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist, 1708bc892140SDag-Erling Smørgrav acladdr->taglen, acladdr->tag_actions, 1709b5663de9SDag-Erling Smørgrav acladdr->tag_actions_size, acladdr->tag_datas, 1710b5663de9SDag-Erling Smørgrav acladdr->tag_datas_size, worker->daemon->cfg->tagname, 1711bc892140SDag-Erling Smørgrav worker->daemon->cfg->num_tags, acladdr->view)) { 1712b7579f77SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 171317d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) == 0) { 1714b7579f77SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 1715b7579f77SDag-Erling Smørgrav return 0; 1716b7579f77SDag-Erling Smørgrav } 1717ff825849SDag-Erling Smørgrav goto send_reply; 1718b7579f77SDag-Erling Smørgrav } 171957bddd21SDag-Erling Smørgrav if(worker->env.auth_zones && 172024e36522SCy Schubert rpz_callback_from_worker_request(worker->env.auth_zones, 1721091e9e46SCy Schubert &worker->env, &qinfo, &edns, c->buffer, worker->scratchpad, 1722a39a5a69SCy Schubert repinfo, acladdr->taglist, acladdr->taglen, &worker->stats, 1723a39a5a69SCy Schubert &rpz_passthru)) { 1724091e9e46SCy Schubert regional_free_all(worker->scratchpad); 1725091e9e46SCy Schubert if(sldns_buffer_limit(c->buffer) == 0) { 1726091e9e46SCy Schubert comm_point_drop_reply(repinfo); 1727091e9e46SCy Schubert return 0; 1728091e9e46SCy Schubert } 1729091e9e46SCy Schubert goto send_reply; 1730091e9e46SCy Schubert } 1731091e9e46SCy Schubert if(worker->env.auth_zones && 173257bddd21SDag-Erling Smørgrav auth_zones_answer(worker->env.auth_zones, &worker->env, 17334c75e3aaSDag-Erling Smørgrav &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) { 173457bddd21SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 173557bddd21SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) == 0) { 173657bddd21SDag-Erling Smørgrav comm_point_drop_reply(repinfo); 173757bddd21SDag-Erling Smørgrav return 0; 173857bddd21SDag-Erling Smørgrav } 173957bddd21SDag-Erling Smørgrav /* set RA for everyone that can have recursion (based on 174057bddd21SDag-Erling Smørgrav * access control list) */ 174157bddd21SDag-Erling Smørgrav if(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer)) && 174257bddd21SDag-Erling Smørgrav acl != acl_deny_non_local && acl != acl_refuse_non_local) 174357bddd21SDag-Erling Smørgrav LDNS_RA_SET(sldns_buffer_begin(c->buffer)); 174457bddd21SDag-Erling Smørgrav goto send_reply; 174557bddd21SDag-Erling Smørgrav } 174617d15b25SDag-Erling Smørgrav 174717d15b25SDag-Erling Smørgrav /* We've looked in our local zones. If the answer isn't there, we 174817d15b25SDag-Erling Smørgrav * might need to bail out based on ACLs now. */ 1749a39a5a69SCy Schubert if((ret=deny_refuse_non_local(c, acl, worker, repinfo, acladdr, 17508f76bb7dSCy Schubert worker->env.cfg->ede, &check_result)) != -1) 175117d15b25SDag-Erling Smørgrav { 1752e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1753ff825849SDag-Erling Smørgrav if(ret == 1) 1754ff825849SDag-Erling Smørgrav goto send_reply; 175517d15b25SDag-Erling Smørgrav return ret; 175617d15b25SDag-Erling Smørgrav } 175717d15b25SDag-Erling Smørgrav 175817d15b25SDag-Erling Smørgrav /* If this request does not have the recursion bit set, verify 17593bd4df0aSDag-Erling Smørgrav * ACLs allow the recursion bit to be treated as set. */ 17603bd4df0aSDag-Erling Smørgrav if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 17613bd4df0aSDag-Erling Smørgrav acl == acl_allow_setrd ) { 17623bd4df0aSDag-Erling Smørgrav LDNS_RD_SET(sldns_buffer_begin(c->buffer)); 17633bd4df0aSDag-Erling Smørgrav } 17643bd4df0aSDag-Erling Smørgrav 17653bd4df0aSDag-Erling Smørgrav /* If this request does not have the recursion bit set, verify 176617d15b25SDag-Erling Smørgrav * ACLs allow the snooping. */ 176717d15b25SDag-Erling Smørgrav if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) && 1768b7579f77SDag-Erling Smørgrav acl != acl_allow_snoop ) { 1769a39a5a69SCy Schubert if(worker->env.cfg->ede) { 1770a39a5a69SCy Schubert EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, 1771a39a5a69SCy Schubert worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, ""); 1772a39a5a69SCy Schubert } 177357bddd21SDag-Erling Smørgrav error_encode(c->buffer, LDNS_RCODE_REFUSED, &qinfo, 177457bddd21SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 1775a39a5a69SCy Schubert sldns_buffer_read_u16_at(c->buffer, 2), &edns); 1776e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1777b7579f77SDag-Erling Smørgrav log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", 1778865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1779a39a5a69SCy Schubert 1780ff825849SDag-Erling Smørgrav goto send_reply; 1781b7579f77SDag-Erling Smørgrav } 1782bc892140SDag-Erling Smørgrav 1783bc892140SDag-Erling Smørgrav /* If we've found a local alias, replace the qname with the alias 1784bc892140SDag-Erling Smørgrav * target before resolving it. */ 1785bc892140SDag-Erling Smørgrav if(qinfo.local_alias) { 1786bc892140SDag-Erling Smørgrav struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset; 1787bc892140SDag-Erling Smørgrav struct packed_rrset_data* d = rrset->entry.data; 1788bc892140SDag-Erling Smørgrav 1789bc892140SDag-Erling Smørgrav /* Sanity check: our current implementation only supports 1790bc892140SDag-Erling Smørgrav * a single CNAME RRset as a local alias. */ 1791bc892140SDag-Erling Smørgrav if(qinfo.local_alias->next || 1792bc892140SDag-Erling Smørgrav rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) || 1793bc892140SDag-Erling Smørgrav d->count != 1) { 1794bc892140SDag-Erling Smørgrav log_err("assumption failure: unexpected local alias"); 1795bc892140SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1796bc892140SDag-Erling Smørgrav return 0; /* drop it */ 1797bc892140SDag-Erling Smørgrav } 1798bc892140SDag-Erling Smørgrav qinfo.qname = d->rr_data[0] + 2; 1799bc892140SDag-Erling Smørgrav qinfo.qname_len = d->rr_len[0] - 2; 1800bc892140SDag-Erling Smørgrav } 1801bc892140SDag-Erling Smørgrav 180265b390aaSDag-Erling Smørgrav /* If we may apply IP-based actions to the answer, build the client 180365b390aaSDag-Erling Smørgrav * information. As this can be expensive, skip it if there is 180465b390aaSDag-Erling Smørgrav * absolutely no possibility of it. */ 1805091e9e46SCy Schubert if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && 180665b390aaSDag-Erling Smørgrav (qinfo.qtype == LDNS_RR_TYPE_A || 180765b390aaSDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_AAAA || 180865b390aaSDag-Erling Smørgrav qinfo.qtype == LDNS_RR_TYPE_ANY)) { 180965b390aaSDag-Erling Smørgrav cinfo_tmp.taglist = acladdr->taglist; 181065b390aaSDag-Erling Smørgrav cinfo_tmp.taglen = acladdr->taglen; 181165b390aaSDag-Erling Smørgrav cinfo_tmp.tag_actions = acladdr->tag_actions; 181265b390aaSDag-Erling Smørgrav cinfo_tmp.tag_actions_size = acladdr->tag_actions_size; 181365b390aaSDag-Erling Smørgrav cinfo_tmp.tag_datas = acladdr->tag_datas; 181465b390aaSDag-Erling Smørgrav cinfo_tmp.tag_datas_size = acladdr->tag_datas_size; 181565b390aaSDag-Erling Smørgrav cinfo_tmp.view = acladdr->view; 181665b390aaSDag-Erling Smørgrav cinfo_tmp.respip_set = worker->daemon->respip_set; 181765b390aaSDag-Erling Smørgrav cinfo = &cinfo_tmp; 181865b390aaSDag-Erling Smørgrav } 181965b390aaSDag-Erling Smørgrav 1820a39a5a69SCy Schubert /* Keep the original edns list around. The pointer could change if there is 1821a39a5a69SCy Schubert * a cached answer (through the inplace callback function there). 1822a39a5a69SCy Schubert * No need to actually copy the contents as they shouldn't change. 1823a39a5a69SCy Schubert * Used while prefetching and subnet is enabled. */ 1824a39a5a69SCy Schubert original_edns_list = edns.opt_list_in; 182565b390aaSDag-Erling Smørgrav lookup_cache: 182665b390aaSDag-Erling Smørgrav /* Lookup the cache. In case we chase an intermediate CNAME chain 182765b390aaSDag-Erling Smørgrav * this is a two-pass operation, and lookup_qinfo is different for 182865b390aaSDag-Erling Smørgrav * each pass. We should still pass the original qinfo to 182965b390aaSDag-Erling Smørgrav * answer_from_cache(), however, since it's used to build the reply. */ 183024e36522SCy Schubert if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) { 1831091e9e46SCy Schubert is_expired_answer = 0; 1832091e9e46SCy Schubert is_secure_answer = 0; 183365b390aaSDag-Erling Smørgrav h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); 183465b390aaSDag-Erling Smørgrav if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) { 18350a92a9fcSCy Schubert struct reply_info* rep = (struct reply_info*)e->data; 1836b7579f77SDag-Erling Smørgrav /* answer from cache - we have acquired a readlock on it */ 18370a92a9fcSCy Schubert if(answer_from_cache(worker, &qinfo, cinfo, &need_drop, 18380a92a9fcSCy Schubert &is_expired_answer, &is_secure_answer, 18390a92a9fcSCy Schubert &alias_rrset, &partial_rep, rep, 184017d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 184117d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 1842b7579f77SDag-Erling Smørgrav &edns)) { 184365b390aaSDag-Erling Smørgrav /* prefetch it if the prefetch TTL expired. 184465b390aaSDag-Erling Smørgrav * Note that if there is more than one pass 184565b390aaSDag-Erling Smørgrav * its qname must be that used for cache 184665b390aaSDag-Erling Smørgrav * lookup. */ 18470a92a9fcSCy Schubert if((worker->env.cfg->prefetch && 18480a92a9fcSCy Schubert *worker->env.now >= rep->prefetch_ttl) || 1849091e9e46SCy Schubert (worker->env.cfg->serve_expired && 18500a92a9fcSCy Schubert *worker->env.now > rep->ttl)) { 1851091e9e46SCy Schubert 18520a92a9fcSCy Schubert time_t leeway = rep->ttl - *worker->env.now; 18530a92a9fcSCy Schubert if(rep->ttl < *worker->env.now) 1854bc892140SDag-Erling Smørgrav leeway = 0; 1855b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1856a39a5a69SCy Schubert 185765b390aaSDag-Erling Smørgrav reply_and_prefetch(worker, lookup_qinfo, 185817d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), 18590eefd307SCy Schubert repinfo, leeway, 1860a39a5a69SCy Schubert (partial_rep || need_drop), 1861a39a5a69SCy Schubert rpz_passthru, 1862a39a5a69SCy Schubert original_edns_list); 186365b390aaSDag-Erling Smørgrav if(!partial_rep) { 1864ff825849SDag-Erling Smørgrav rc = 0; 1865e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1866ff825849SDag-Erling Smørgrav goto send_reply_rc; 1867b7579f77SDag-Erling Smørgrav } 186865b390aaSDag-Erling Smørgrav } else if(!partial_rep) { 1869b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1870e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1871ff825849SDag-Erling Smørgrav goto send_reply; 1872971980c3SDag-Erling Smørgrav } else { 1873971980c3SDag-Erling Smørgrav /* Note that we've already released the 1874971980c3SDag-Erling Smørgrav * lock if we're here after prefetch. */ 1875971980c3SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1876b7579f77SDag-Erling Smørgrav } 187765b390aaSDag-Erling Smørgrav /* We've found a partial reply ending with an 187865b390aaSDag-Erling Smørgrav * alias. Replace the lookup qinfo for the 187965b390aaSDag-Erling Smørgrav * alias target and lookup the cache again to 188065b390aaSDag-Erling Smørgrav * (possibly) complete the reply. As we're 188165b390aaSDag-Erling Smørgrav * passing the "base" reply, there will be no 188265b390aaSDag-Erling Smørgrav * more alias chasing. */ 188365b390aaSDag-Erling Smørgrav memset(&qinfo_tmp, 0, sizeof(qinfo_tmp)); 188465b390aaSDag-Erling Smørgrav get_cname_target(alias_rrset, &qinfo_tmp.qname, 188565b390aaSDag-Erling Smørgrav &qinfo_tmp.qname_len); 188665b390aaSDag-Erling Smørgrav if(!qinfo_tmp.qname) { 188765b390aaSDag-Erling Smørgrav log_err("unexpected: invalid answer alias"); 188865b390aaSDag-Erling Smørgrav regional_free_all(worker->scratchpad); 188965b390aaSDag-Erling Smørgrav return 0; /* drop query */ 189065b390aaSDag-Erling Smørgrav } 189165b390aaSDag-Erling Smørgrav qinfo_tmp.qtype = qinfo.qtype; 189265b390aaSDag-Erling Smørgrav qinfo_tmp.qclass = qinfo.qclass; 189365b390aaSDag-Erling Smørgrav lookup_qinfo = &qinfo_tmp; 189465b390aaSDag-Erling Smørgrav goto lookup_cache; 189565b390aaSDag-Erling Smørgrav } 1896b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "answer from the cache failed"); 1897b7579f77SDag-Erling Smørgrav lock_rw_unlock(&e->lock); 1898b7579f77SDag-Erling Smørgrav } 1899a39a5a69SCy Schubert 190017d15b25SDag-Erling Smørgrav if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { 1901b7579f77SDag-Erling Smørgrav if(answer_norec_from_cache(worker, &qinfo, 190217d15b25SDag-Erling Smørgrav *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 190317d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), repinfo, 1904b7579f77SDag-Erling Smørgrav &edns)) { 1905e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1906ff825849SDag-Erling Smørgrav goto send_reply; 1907b7579f77SDag-Erling Smørgrav } 1908b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "answer norec from cache -- " 1909b7579f77SDag-Erling Smørgrav "need to validate or not primed"); 1910b7579f77SDag-Erling Smørgrav } 1911bc892140SDag-Erling Smørgrav } 191217d15b25SDag-Erling Smørgrav sldns_buffer_rewind(c->buffer); 1913b7579f77SDag-Erling Smørgrav server_stats_querymiss(&worker->stats, worker); 1914b7579f77SDag-Erling Smørgrav 1915b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_CLIENT) { 1916b7579f77SDag-Erling Smørgrav if(c->type == comm_udp) 1917b7579f77SDag-Erling Smørgrav log_addr(VERB_CLIENT, "udp request from", 1918865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1919b7579f77SDag-Erling Smørgrav else log_addr(VERB_CLIENT, "tcp request from", 1920865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen); 1921b7579f77SDag-Erling Smørgrav } 1922b7579f77SDag-Erling Smørgrav 1923b7579f77SDag-Erling Smørgrav /* grab a work request structure for this new request */ 192465b390aaSDag-Erling Smørgrav mesh_new_client(worker->env.mesh, &qinfo, cinfo, 192517d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 2), 1926a39a5a69SCy Schubert &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), 1927a39a5a69SCy Schubert rpz_passthru); 1928e2d15004SDag-Erling Smørgrav regional_free_all(worker->scratchpad); 1929b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 1930b7579f77SDag-Erling Smørgrav return 0; 1931ff825849SDag-Erling Smørgrav 1932ff825849SDag-Erling Smørgrav send_reply: 1933ff825849SDag-Erling Smørgrav rc = 1; 1934ff825849SDag-Erling Smørgrav send_reply_rc: 193565b390aaSDag-Erling Smørgrav if(need_drop) { 193665b390aaSDag-Erling Smørgrav comm_point_drop_reply(repinfo); 193765b390aaSDag-Erling Smørgrav return 0; 193865b390aaSDag-Erling Smørgrav } 1939091e9e46SCy Schubert if(is_expired_answer) { 1940091e9e46SCy Schubert worker->stats.ans_expired++; 1941091e9e46SCy Schubert } 1942c0caa2e2SCy Schubert server_stats_insrcode(&worker->stats, c->buffer); 1943091e9e46SCy Schubert if(worker->stats.extended) { 1944091e9e46SCy Schubert if(is_secure_answer) worker->stats.ans_secure++; 1945091e9e46SCy Schubert } 1946ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 19475469a995SCy Schubert /* 19485469a995SCy Schubert * sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.) 19495469a995SCy Schubert */ 1950335c7cdaSCy Schubert if(worker->dtenv.log_client_response_messages && rc !=0) { 1951335c7cdaSCy Schubert log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen); 1952865f46b2SCy Schubert log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen); 1953335c7cdaSCy Schubert dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer); 19545469a995SCy Schubert } 1955ff825849SDag-Erling Smørgrav #endif 19563005e0a3SDag-Erling Smørgrav if(worker->env.cfg->log_replies) 19573005e0a3SDag-Erling Smørgrav { 19580eefd307SCy Schubert struct timeval tv; 19590eefd307SCy Schubert memset(&tv, 0, sizeof(tv)); 1960e86b9096SDag-Erling Smørgrav if(qinfo.local_alias && qinfo.local_alias->rrset && 1961e86b9096SDag-Erling Smørgrav qinfo.local_alias->rrset->rk.dname) { 1962e86b9096SDag-Erling Smørgrav /* log original qname, before the local alias was 1963e86b9096SDag-Erling Smørgrav * used to resolve that CNAME to something else */ 1964e86b9096SDag-Erling Smørgrav qinfo.qname = qinfo.local_alias->rrset->rk.dname; 1965865f46b2SCy Schubert log_reply_info(NO_VERBOSE, &qinfo, 1966865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, 1967b7c0c8c1SCy Schubert tv, 1, c->buffer, 1968335c7cdaSCy Schubert (worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL), 1969b7c0c8c1SCy Schubert c->type); 1970e86b9096SDag-Erling Smørgrav } else { 1971865f46b2SCy Schubert log_reply_info(NO_VERBOSE, &qinfo, 1972865f46b2SCy Schubert &repinfo->client_addr, repinfo->client_addrlen, 1973b7c0c8c1SCy Schubert tv, 1, c->buffer, 1974335c7cdaSCy Schubert (worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL), 1975b7c0c8c1SCy Schubert c->type); 1976e86b9096SDag-Erling Smørgrav } 19773005e0a3SDag-Erling Smørgrav } 197865b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 197965b390aaSDag-Erling Smørgrav if(!dnsc_handle_uncurved_request(repinfo)) { 198065b390aaSDag-Erling Smørgrav return 0; 198165b390aaSDag-Erling Smørgrav } 198265b390aaSDag-Erling Smørgrav #endif 1983ff825849SDag-Erling Smørgrav return rc; 1984b7579f77SDag-Erling Smørgrav } 1985b7579f77SDag-Erling Smørgrav 1986b7579f77SDag-Erling Smørgrav void 1987b7579f77SDag-Erling Smørgrav worker_sighandler(int sig, void* arg) 1988b7579f77SDag-Erling Smørgrav { 1989ff825849SDag-Erling Smørgrav /* note that log, print, syscalls here give race conditions. 1990ff825849SDag-Erling Smørgrav * And cause hangups if the log-lock is held by the application. */ 1991b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 1992b7579f77SDag-Erling Smørgrav switch(sig) { 1993b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 1994b7579f77SDag-Erling Smørgrav case SIGHUP: 1995b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 1996b7579f77SDag-Erling Smørgrav break; 1997b7579f77SDag-Erling Smørgrav #endif 1998a39a5a69SCy Schubert #ifdef SIGBREAK 1999a39a5a69SCy Schubert case SIGBREAK: 2000a39a5a69SCy Schubert #endif 2001b7579f77SDag-Erling Smørgrav case SIGINT: 2002b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2003b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2004b7579f77SDag-Erling Smørgrav break; 2005b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2006b7579f77SDag-Erling Smørgrav case SIGQUIT: 2007b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2008b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2009b7579f77SDag-Erling Smørgrav break; 2010b7579f77SDag-Erling Smørgrav #endif 2011b7579f77SDag-Erling Smørgrav case SIGTERM: 2012b7579f77SDag-Erling Smørgrav worker->need_to_exit = 1; 2013b7579f77SDag-Erling Smørgrav comm_base_exit(worker->base); 2014b7579f77SDag-Erling Smørgrav break; 2015b7579f77SDag-Erling Smørgrav default: 2016ff825849SDag-Erling Smørgrav /* unknown signal, ignored */ 2017b7579f77SDag-Erling Smørgrav break; 2018b7579f77SDag-Erling Smørgrav } 2019b7579f77SDag-Erling Smørgrav } 2020b7579f77SDag-Erling Smørgrav 2021b7579f77SDag-Erling Smørgrav /** restart statistics timer for worker, if enabled */ 2022b7579f77SDag-Erling Smørgrav static void 2023b7579f77SDag-Erling Smørgrav worker_restart_timer(struct worker* worker) 2024b7579f77SDag-Erling Smørgrav { 2025b7579f77SDag-Erling Smørgrav if(worker->env.cfg->stat_interval > 0) { 2026b7579f77SDag-Erling Smørgrav struct timeval tv; 2027b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 2028b7579f77SDag-Erling Smørgrav tv.tv_sec = worker->env.cfg->stat_interval; 2029b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2030b7579f77SDag-Erling Smørgrav #endif 2031b7579f77SDag-Erling Smørgrav comm_timer_set(worker->stat_timer, &tv); 2032b7579f77SDag-Erling Smørgrav } 2033b7579f77SDag-Erling Smørgrav } 2034b7579f77SDag-Erling Smørgrav 2035b7579f77SDag-Erling Smørgrav void worker_stat_timer_cb(void* arg) 2036b7579f77SDag-Erling Smørgrav { 2037b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2038b7579f77SDag-Erling Smørgrav server_stats_log(&worker->stats, worker, worker->thread_num); 2039b7579f77SDag-Erling Smørgrav mesh_stats(worker->env.mesh, "mesh has"); 2040b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 204165b390aaSDag-Erling Smørgrav /* SHM is enabled, process data to SHM */ 204265b390aaSDag-Erling Smørgrav if (worker->daemon->cfg->shm_enable) { 204365b390aaSDag-Erling Smørgrav shm_main_run(worker); 204465b390aaSDag-Erling Smørgrav } 2045b7579f77SDag-Erling Smørgrav if(!worker->daemon->cfg->stat_cumulative) { 2046b7579f77SDag-Erling Smørgrav worker_stats_clear(worker); 2047b7579f77SDag-Erling Smørgrav } 2048b7579f77SDag-Erling Smørgrav /* start next timer */ 2049b7579f77SDag-Erling Smørgrav worker_restart_timer(worker); 2050b7579f77SDag-Erling Smørgrav } 2051b7579f77SDag-Erling Smørgrav 2052b7579f77SDag-Erling Smørgrav void worker_probe_timer_cb(void* arg) 2053b7579f77SDag-Erling Smørgrav { 2054b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2055b7579f77SDag-Erling Smørgrav struct timeval tv; 2056b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 2057b7579f77SDag-Erling Smørgrav tv.tv_sec = (time_t)autr_probe_timer(&worker->env); 2058b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2059b7579f77SDag-Erling Smørgrav #endif 2060b7579f77SDag-Erling Smørgrav if(tv.tv_sec != 0) 2061b7579f77SDag-Erling Smørgrav comm_timer_set(worker->env.probe_timer, &tv); 2062b7579f77SDag-Erling Smørgrav } 2063b7579f77SDag-Erling Smørgrav 2064b7579f77SDag-Erling Smørgrav struct worker* 2065b7579f77SDag-Erling Smørgrav worker_create(struct daemon* daemon, int id, int* ports, int n) 2066b7579f77SDag-Erling Smørgrav { 2067b7579f77SDag-Erling Smørgrav unsigned int seed; 2068b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)calloc(1, 2069b7579f77SDag-Erling Smørgrav sizeof(struct worker)); 2070b7579f77SDag-Erling Smørgrav if(!worker) 2071b7579f77SDag-Erling Smørgrav return NULL; 2072b7579f77SDag-Erling Smørgrav worker->numports = n; 2073b7579f77SDag-Erling Smørgrav worker->ports = (int*)memdup(ports, sizeof(int)*n); 2074b7579f77SDag-Erling Smørgrav if(!worker->ports) { 2075b7579f77SDag-Erling Smørgrav free(worker); 2076b7579f77SDag-Erling Smørgrav return NULL; 2077b7579f77SDag-Erling Smørgrav } 2078b7579f77SDag-Erling Smørgrav worker->daemon = daemon; 2079b7579f77SDag-Erling Smørgrav worker->thread_num = id; 2080b7579f77SDag-Erling Smørgrav if(!(worker->cmd = tube_create())) { 2081b7579f77SDag-Erling Smørgrav free(worker->ports); 2082b7579f77SDag-Erling Smørgrav free(worker); 2083b7579f77SDag-Erling Smørgrav return NULL; 2084b7579f77SDag-Erling Smørgrav } 2085b7579f77SDag-Erling Smørgrav /* create random state here to avoid locking trouble in RAND_bytes */ 20860eefd307SCy Schubert if(!(worker->rndstate = ub_initstate(daemon->rand))) { 2087b7579f77SDag-Erling Smørgrav log_err("could not init random numbers."); 2088b7579f77SDag-Erling Smørgrav tube_delete(worker->cmd); 2089b7579f77SDag-Erling Smørgrav free(worker->ports); 2090b7579f77SDag-Erling Smørgrav free(worker); 2091b7579f77SDag-Erling Smørgrav return NULL; 2092b7579f77SDag-Erling Smørgrav } 2093a755b6f6SDag-Erling Smørgrav explicit_bzero(&seed, sizeof(seed)); 2094b7579f77SDag-Erling Smørgrav return worker; 2095b7579f77SDag-Erling Smørgrav } 2096b7579f77SDag-Erling Smørgrav 2097b7579f77SDag-Erling Smørgrav int 2098b7579f77SDag-Erling Smørgrav worker_init(struct worker* worker, struct config_file *cfg, 2099b7579f77SDag-Erling Smørgrav struct listen_port* ports, int do_sigs) 2100b7579f77SDag-Erling Smørgrav { 2101ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2102ff825849SDag-Erling Smørgrav struct dt_env* dtenv = &worker->dtenv; 2103ff825849SDag-Erling Smørgrav #else 2104ff825849SDag-Erling Smørgrav void* dtenv = NULL; 2105ff825849SDag-Erling Smørgrav #endif 2106865f46b2SCy Schubert #ifdef HAVE_GETTID 2107865f46b2SCy Schubert worker->thread_tid = gettid(); 2108865f46b2SCy Schubert #endif 2109b7579f77SDag-Erling Smørgrav worker->need_to_exit = 0; 2110b7579f77SDag-Erling Smørgrav worker->base = comm_base_create(do_sigs); 2111b7579f77SDag-Erling Smørgrav if(!worker->base) { 2112b7579f77SDag-Erling Smørgrav log_err("could not create event handling base"); 2113b7579f77SDag-Erling Smørgrav worker_delete(worker); 2114b7579f77SDag-Erling Smørgrav return 0; 2115b7579f77SDag-Erling Smørgrav } 2116b7579f77SDag-Erling Smørgrav comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept, 2117b7579f77SDag-Erling Smørgrav &worker_start_accept, worker); 2118b7579f77SDag-Erling Smørgrav if(do_sigs) { 2119b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 2120b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGHUP); 2121b7579f77SDag-Erling Smørgrav #endif 2122a39a5a69SCy Schubert #ifdef SIGBREAK 2123a39a5a69SCy Schubert ub_thread_sig_unblock(SIGBREAK); 2124a39a5a69SCy Schubert #endif 2125b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGINT); 2126b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2127b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGQUIT); 2128b7579f77SDag-Erling Smørgrav #endif 2129b7579f77SDag-Erling Smørgrav ub_thread_sig_unblock(SIGTERM); 2130b7579f77SDag-Erling Smørgrav #ifndef LIBEVENT_SIGNAL_PROBLEM 2131b7579f77SDag-Erling Smørgrav worker->comsig = comm_signal_create(worker->base, 2132b7579f77SDag-Erling Smørgrav worker_sighandler, worker); 2133b7579f77SDag-Erling Smørgrav if(!worker->comsig 2134b7579f77SDag-Erling Smørgrav #ifdef SIGHUP 2135b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGHUP) 2136b7579f77SDag-Erling Smørgrav #endif 2137b7579f77SDag-Erling Smørgrav #ifdef SIGQUIT 2138b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGQUIT) 2139b7579f77SDag-Erling Smørgrav #endif 2140b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGTERM) 2141a39a5a69SCy Schubert #ifdef SIGBREAK 2142a39a5a69SCy Schubert || !comm_signal_bind(worker->comsig, SIGBREAK) 2143a39a5a69SCy Schubert #endif 2144b7579f77SDag-Erling Smørgrav || !comm_signal_bind(worker->comsig, SIGINT)) { 2145b7579f77SDag-Erling Smørgrav log_err("could not create signal handlers"); 2146b7579f77SDag-Erling Smørgrav worker_delete(worker); 2147b7579f77SDag-Erling Smørgrav return 0; 2148b7579f77SDag-Erling Smørgrav } 2149b7579f77SDag-Erling Smørgrav #endif /* LIBEVENT_SIGNAL_PROBLEM */ 2150b7579f77SDag-Erling Smørgrav if(!daemon_remote_open_accept(worker->daemon->rc, 2151b7579f77SDag-Erling Smørgrav worker->daemon->rc_ports, worker)) { 2152b7579f77SDag-Erling Smørgrav worker_delete(worker); 2153b7579f77SDag-Erling Smørgrav return 0; 2154b7579f77SDag-Erling Smørgrav } 2155b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 2156b7579f77SDag-Erling Smørgrav wsvc_setup_worker(worker); 2157b7579f77SDag-Erling Smørgrav #endif /* UB_ON_WINDOWS */ 2158b7579f77SDag-Erling Smørgrav } else { /* !do_sigs */ 2159b7579f77SDag-Erling Smørgrav worker->comsig = NULL; 2160b7579f77SDag-Erling Smørgrav } 2161c0caa2e2SCy Schubert #ifdef USE_DNSTAP 2162c0caa2e2SCy Schubert if(cfg->dnstap) { 2163c0caa2e2SCy Schubert log_assert(worker->daemon->dtenv != NULL); 2164c0caa2e2SCy Schubert memcpy(&worker->dtenv, worker->daemon->dtenv, sizeof(struct dt_env)); 2165c0caa2e2SCy Schubert if(!dt_init(&worker->dtenv, worker->base)) 2166c0caa2e2SCy Schubert fatal_exit("dt_init failed"); 2167c0caa2e2SCy Schubert } 2168c0caa2e2SCy Schubert #endif 2169b7579f77SDag-Erling Smørgrav worker->front = listen_create(worker->base, ports, 2170b7579f77SDag-Erling Smørgrav cfg->msg_buffer_size, (int)cfg->incoming_num_tcp, 21714c75e3aaSDag-Erling Smørgrav cfg->do_tcp_keepalive 21724c75e3aaSDag-Erling Smørgrav ? cfg->tcp_keepalive_timeout 21734c75e3aaSDag-Erling Smørgrav : cfg->tcp_idle_timeout, 2174c0caa2e2SCy Schubert cfg->harden_large_queries, cfg->http_max_streams, 2175369c6923SCy Schubert cfg->http_endpoint, cfg->http_notls_downstream, 2176369c6923SCy Schubert worker->daemon->tcl, worker->daemon->listen_sslctx, 2177*46d2f618SCy Schubert dtenv, worker->daemon->doq_table, worker->env.rnd, 2178*46d2f618SCy Schubert cfg->ssl_service_key, cfg->ssl_service_pem, cfg, 2179*46d2f618SCy Schubert worker_handle_request, worker); 2180b7579f77SDag-Erling Smørgrav if(!worker->front) { 2181b7579f77SDag-Erling Smørgrav log_err("could not create listening sockets"); 2182b7579f77SDag-Erling Smørgrav worker_delete(worker); 2183b7579f77SDag-Erling Smørgrav return 0; 2184b7579f77SDag-Erling Smørgrav } 2185b7579f77SDag-Erling Smørgrav worker->back = outside_network_create(worker->base, 2186b7579f77SDag-Erling Smørgrav cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, 2187b7579f77SDag-Erling Smørgrav cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 218825039b37SCy Schubert cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, 2189b7579f77SDag-Erling Smørgrav worker->daemon->env->infra_cache, worker->rndstate, 2190b7579f77SDag-Erling Smørgrav cfg->use_caps_bits_for_id, worker->ports, worker->numports, 2191f61ef7f6SDag-Erling Smørgrav cfg->unwanted_threshold, cfg->outgoing_tcp_mss, 2192f61ef7f6SDag-Erling Smørgrav &worker_alloc_cleanup, worker, 21938a384985SDag-Erling Smørgrav cfg->do_udp || cfg->udp_upstream_without_downstream, 21948a384985SDag-Erling Smørgrav worker->daemon->connect_sslctx, cfg->delay_close, 21955469a995SCy Schubert cfg->tls_use_sni, dtenv, cfg->udp_connect, 21965469a995SCy Schubert cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, 21975469a995SCy Schubert cfg->tcp_auth_query_timeout); 2198b7579f77SDag-Erling Smørgrav if(!worker->back) { 2199b7579f77SDag-Erling Smørgrav log_err("could not create outgoing sockets"); 2200b7579f77SDag-Erling Smørgrav worker_delete(worker); 2201b7579f77SDag-Erling Smørgrav return 0; 2202b7579f77SDag-Erling Smørgrav } 22035469a995SCy Schubert iterator_set_ip46_support(&worker->daemon->mods, worker->daemon->env, 22045469a995SCy Schubert worker->back); 2205b7579f77SDag-Erling Smørgrav /* start listening to commands */ 2206b7579f77SDag-Erling Smørgrav if(!tube_setup_bg_listen(worker->cmd, worker->base, 2207b7579f77SDag-Erling Smørgrav &worker_handle_control_cmd, worker)) { 2208b7579f77SDag-Erling Smørgrav log_err("could not create control compt."); 2209b7579f77SDag-Erling Smørgrav worker_delete(worker); 2210b7579f77SDag-Erling Smørgrav return 0; 2211b7579f77SDag-Erling Smørgrav } 2212b7579f77SDag-Erling Smørgrav worker->stat_timer = comm_timer_create(worker->base, 2213b7579f77SDag-Erling Smørgrav worker_stat_timer_cb, worker); 2214b7579f77SDag-Erling Smørgrav if(!worker->stat_timer) { 2215b7579f77SDag-Erling Smørgrav log_err("could not create statistics timer"); 2216b7579f77SDag-Erling Smørgrav } 2217b7579f77SDag-Erling Smørgrav 2218b7579f77SDag-Erling Smørgrav /* we use the msg_buffer_size as a good estimate for what the 2219b7579f77SDag-Erling Smørgrav * user wants for memory usage sizes */ 2220b7579f77SDag-Erling Smørgrav worker->scratchpad = regional_create_custom(cfg->msg_buffer_size); 2221b7579f77SDag-Erling Smørgrav if(!worker->scratchpad) { 2222b7579f77SDag-Erling Smørgrav log_err("malloc failure"); 2223b7579f77SDag-Erling Smørgrav worker_delete(worker); 2224b7579f77SDag-Erling Smørgrav return 0; 2225b7579f77SDag-Erling Smørgrav } 2226b7579f77SDag-Erling Smørgrav 2227b7579f77SDag-Erling Smørgrav server_stats_init(&worker->stats, cfg); 22281838dec3SCy Schubert worker->alloc = worker->daemon->worker_allocs[worker->thread_num]; 22291838dec3SCy Schubert alloc_set_id_cleanup(worker->alloc, &worker_alloc_cleanup, worker); 2230b7579f77SDag-Erling Smørgrav worker->env = *worker->daemon->env; 2231b7579f77SDag-Erling Smørgrav comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); 2232b7579f77SDag-Erling Smørgrav worker->env.worker = worker; 223357bddd21SDag-Erling Smørgrav worker->env.worker_base = worker->base; 2234b7579f77SDag-Erling Smørgrav worker->env.send_query = &worker_send_query; 22351838dec3SCy Schubert worker->env.alloc = worker->alloc; 223657bddd21SDag-Erling Smørgrav worker->env.outnet = worker->back; 2237b7579f77SDag-Erling Smørgrav worker->env.rnd = worker->rndstate; 2238971980c3SDag-Erling Smørgrav /* If case prefetch is triggered, the corresponding mesh will clear 2239971980c3SDag-Erling Smørgrav * the scratchpad for the module env in the middle of request handling. 2240971980c3SDag-Erling Smørgrav * It would be prone to a use-after-free kind of bug, so we avoid 2241971980c3SDag-Erling Smørgrav * sharing it with worker's own scratchpad at the cost of having 2242971980c3SDag-Erling Smørgrav * one more pad per worker. */ 2243971980c3SDag-Erling Smørgrav worker->env.scratch = regional_create_custom(cfg->msg_buffer_size); 2244971980c3SDag-Erling Smørgrav if(!worker->env.scratch) { 2245971980c3SDag-Erling Smørgrav log_err("malloc failure"); 2246971980c3SDag-Erling Smørgrav worker_delete(worker); 2247971980c3SDag-Erling Smørgrav return 0; 2248971980c3SDag-Erling Smørgrav } 2249b7579f77SDag-Erling Smørgrav worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); 22505469a995SCy Schubert if(!worker->env.mesh) { 22515469a995SCy Schubert log_err("malloc failure"); 22525469a995SCy Schubert worker_delete(worker); 22535469a995SCy Schubert return 0; 22545469a995SCy Schubert } 2255091e9e46SCy Schubert /* Pass on daemon variables that we would need in the mesh area */ 2256091e9e46SCy Schubert worker->env.mesh->use_response_ip = worker->daemon->use_response_ip; 2257091e9e46SCy Schubert worker->env.mesh->use_rpz = worker->daemon->use_rpz; 2258091e9e46SCy Schubert 2259b7579f77SDag-Erling Smørgrav worker->env.detach_subs = &mesh_detach_subs; 2260b7579f77SDag-Erling Smørgrav worker->env.attach_sub = &mesh_attach_sub; 2261c7f4d7adSDag-Erling Smørgrav worker->env.add_sub = &mesh_add_sub; 2262b7579f77SDag-Erling Smørgrav worker->env.kill_sub = &mesh_state_delete; 2263b7579f77SDag-Erling Smørgrav worker->env.detect_cycle = &mesh_detect_cycle; 226417d15b25SDag-Erling Smørgrav worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); 22655469a995SCy Schubert if(!worker->env.scratch_buffer) { 22665469a995SCy Schubert log_err("malloc failure"); 22675469a995SCy Schubert worker_delete(worker); 22685469a995SCy Schubert return 0; 22695469a995SCy Schubert } 2270b7579f77SDag-Erling Smørgrav /* one probe timer per process -- if we have 5011 anchors */ 2271b7579f77SDag-Erling Smørgrav if(autr_get_num_anchors(worker->env.anchors) > 0 2272b7579f77SDag-Erling Smørgrav #ifndef THREADS_DISABLED 2273b7579f77SDag-Erling Smørgrav && worker->thread_num == 0 2274b7579f77SDag-Erling Smørgrav #endif 2275b7579f77SDag-Erling Smørgrav ) { 2276b7579f77SDag-Erling Smørgrav struct timeval tv; 2277b7579f77SDag-Erling Smørgrav tv.tv_sec = 0; 2278b7579f77SDag-Erling Smørgrav tv.tv_usec = 0; 2279b7579f77SDag-Erling Smørgrav worker->env.probe_timer = comm_timer_create(worker->base, 2280b7579f77SDag-Erling Smørgrav worker_probe_timer_cb, worker); 2281b7579f77SDag-Erling Smørgrav if(!worker->env.probe_timer) { 2282b7579f77SDag-Erling Smørgrav log_err("could not create 5011-probe timer"); 2283b7579f77SDag-Erling Smørgrav } else { 2284b7579f77SDag-Erling Smørgrav /* let timer fire, then it can reset itself */ 2285b7579f77SDag-Erling Smørgrav comm_timer_set(worker->env.probe_timer, &tv); 2286b7579f77SDag-Erling Smørgrav } 2287b7579f77SDag-Erling Smørgrav } 228857bddd21SDag-Erling Smørgrav /* zone transfer tasks, setup once per process, if any */ 228957bddd21SDag-Erling Smørgrav if(worker->env.auth_zones 229057bddd21SDag-Erling Smørgrav #ifndef THREADS_DISABLED 229157bddd21SDag-Erling Smørgrav && worker->thread_num == 0 229257bddd21SDag-Erling Smørgrav #endif 229357bddd21SDag-Erling Smørgrav ) { 229457bddd21SDag-Erling Smørgrav auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env); 22955469a995SCy Schubert auth_zones_pickup_zonemd_verify(worker->env.auth_zones, 22965469a995SCy Schubert &worker->env); 229757bddd21SDag-Erling Smørgrav } 229825039b37SCy Schubert #ifdef USE_DNSTAP 229925039b37SCy Schubert if(worker->daemon->cfg->dnstap 230025039b37SCy Schubert #ifndef THREADS_DISABLED 230125039b37SCy Schubert && worker->thread_num == 0 230225039b37SCy Schubert #endif 230325039b37SCy Schubert ) { 230425039b37SCy Schubert if(!dt_io_thread_start(dtenv->dtio, comm_base_internal( 230525039b37SCy Schubert worker->base), worker->daemon->num)) { 230625039b37SCy Schubert log_err("could not start dnstap io thread"); 230725039b37SCy Schubert worker_delete(worker); 230825039b37SCy Schubert return 0; 230925039b37SCy Schubert } 231025039b37SCy Schubert } 231125039b37SCy Schubert #endif /* USE_DNSTAP */ 2312b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 2313b7579f77SDag-Erling Smørgrav /* if statistics enabled start timer */ 2314b7579f77SDag-Erling Smørgrav if(worker->env.cfg->stat_interval > 0) { 2315b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "set statistics interval %d secs", 2316b7579f77SDag-Erling Smørgrav worker->env.cfg->stat_interval); 2317b7579f77SDag-Erling Smørgrav worker_restart_timer(worker); 2318b7579f77SDag-Erling Smørgrav } 2319103ba509SCy Schubert pp_init(&sldns_write_uint16, &sldns_write_uint32); 2320b7579f77SDag-Erling Smørgrav return 1; 2321b7579f77SDag-Erling Smørgrav } 2322b7579f77SDag-Erling Smørgrav 2323b7579f77SDag-Erling Smørgrav void 2324b7579f77SDag-Erling Smørgrav worker_work(struct worker* worker) 2325b7579f77SDag-Erling Smørgrav { 2326b7579f77SDag-Erling Smørgrav comm_base_dispatch(worker->base); 2327b7579f77SDag-Erling Smørgrav } 2328b7579f77SDag-Erling Smørgrav 2329b7579f77SDag-Erling Smørgrav void 2330b7579f77SDag-Erling Smørgrav worker_delete(struct worker* worker) 2331b7579f77SDag-Erling Smørgrav { 2332b7579f77SDag-Erling Smørgrav if(!worker) 2333b7579f77SDag-Erling Smørgrav return; 2334b7579f77SDag-Erling Smørgrav if(worker->env.mesh && verbosity >= VERB_OPS) { 2335b7579f77SDag-Erling Smørgrav server_stats_log(&worker->stats, worker, worker->thread_num); 2336b7579f77SDag-Erling Smørgrav mesh_stats(worker->env.mesh, "mesh has"); 2337b7579f77SDag-Erling Smørgrav worker_mem_report(worker, NULL); 2338b7579f77SDag-Erling Smørgrav } 2339b7579f77SDag-Erling Smørgrav outside_network_quit_prepare(worker->back); 2340b7579f77SDag-Erling Smørgrav mesh_delete(worker->env.mesh); 234117d15b25SDag-Erling Smørgrav sldns_buffer_free(worker->env.scratch_buffer); 2342b7579f77SDag-Erling Smørgrav listen_delete(worker->front); 2343b7579f77SDag-Erling Smørgrav outside_network_delete(worker->back); 2344b7579f77SDag-Erling Smørgrav comm_signal_delete(worker->comsig); 2345b7579f77SDag-Erling Smørgrav tube_delete(worker->cmd); 2346b7579f77SDag-Erling Smørgrav comm_timer_delete(worker->stat_timer); 2347b7579f77SDag-Erling Smørgrav comm_timer_delete(worker->env.probe_timer); 2348b7579f77SDag-Erling Smørgrav free(worker->ports); 2349b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) { 2350b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 2351b7579f77SDag-Erling Smørgrav wsvc_desetup_worker(worker); 2352b7579f77SDag-Erling Smørgrav #endif /* UB_ON_WINDOWS */ 2353b7579f77SDag-Erling Smørgrav } 235425039b37SCy Schubert #ifdef USE_DNSTAP 235525039b37SCy Schubert if(worker->daemon->cfg->dnstap 235625039b37SCy Schubert #ifndef THREADS_DISABLED 235725039b37SCy Schubert && worker->thread_num == 0 235825039b37SCy Schubert #endif 235925039b37SCy Schubert ) { 236025039b37SCy Schubert dt_io_thread_stop(worker->dtenv.dtio); 236125039b37SCy Schubert } 236225039b37SCy Schubert dt_deinit(&worker->dtenv); 236325039b37SCy Schubert #endif /* USE_DNSTAP */ 2364b7579f77SDag-Erling Smørgrav comm_base_delete(worker->base); 2365b7579f77SDag-Erling Smørgrav ub_randfree(worker->rndstate); 23661838dec3SCy Schubert /* don't touch worker->alloc, as it's maintained in daemon */ 2367971980c3SDag-Erling Smørgrav regional_destroy(worker->env.scratch); 2368b7579f77SDag-Erling Smørgrav regional_destroy(worker->scratchpad); 2369b7579f77SDag-Erling Smørgrav free(worker); 2370b7579f77SDag-Erling Smørgrav } 2371b7579f77SDag-Erling Smørgrav 2372b7579f77SDag-Erling Smørgrav struct outbound_entry* 2373bc892140SDag-Erling Smørgrav worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec, 23749cf5bc93SCy Schubert int want_dnssec, int nocaps, int check_ratelimit, 23759cf5bc93SCy Schubert struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, 23769cf5bc93SCy Schubert size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name, 23779cf5bc93SCy Schubert struct module_qstate* q, int* was_ratelimited) 2378b7579f77SDag-Erling Smørgrav { 2379b7579f77SDag-Erling Smørgrav struct worker* worker = q->env->worker; 2380b7579f77SDag-Erling Smørgrav struct outbound_entry* e = (struct outbound_entry*)regional_alloc( 2381b7579f77SDag-Erling Smørgrav q->region, sizeof(*e)); 2382b7579f77SDag-Erling Smørgrav if(!e) 2383b7579f77SDag-Erling Smørgrav return NULL; 2384b7579f77SDag-Erling Smørgrav e->qstate = q; 2385bc892140SDag-Erling Smørgrav e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec, 23869cf5bc93SCy Schubert want_dnssec, nocaps, check_ratelimit, tcp_upstream, 23870fb34990SDag-Erling Smørgrav ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q, 23889cf5bc93SCy Schubert worker_handle_service_reply, e, worker->back->udp_buff, q->env, 23899cf5bc93SCy Schubert was_ratelimited); 2390b7579f77SDag-Erling Smørgrav if(!e->qsent) { 2391b7579f77SDag-Erling Smørgrav return NULL; 2392b7579f77SDag-Erling Smørgrav } 2393b7579f77SDag-Erling Smørgrav return e; 2394b7579f77SDag-Erling Smørgrav } 2395b7579f77SDag-Erling Smørgrav 2396b7579f77SDag-Erling Smørgrav void 2397b7579f77SDag-Erling Smørgrav worker_alloc_cleanup(void* arg) 2398b7579f77SDag-Erling Smørgrav { 2399b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2400b7579f77SDag-Erling Smørgrav slabhash_clear(&worker->env.rrset_cache->table); 2401b7579f77SDag-Erling Smørgrav slabhash_clear(worker->env.msg_cache); 2402b7579f77SDag-Erling Smørgrav } 2403b7579f77SDag-Erling Smørgrav 2404b7579f77SDag-Erling Smørgrav void worker_stats_clear(struct worker* worker) 2405b7579f77SDag-Erling Smørgrav { 2406b7579f77SDag-Erling Smørgrav server_stats_init(&worker->stats, worker->env.cfg); 2407b7579f77SDag-Erling Smørgrav mesh_stats_clear(worker->env.mesh); 2408b7579f77SDag-Erling Smørgrav worker->back->unwanted_replies = 0; 2409ff825849SDag-Erling Smørgrav worker->back->num_tcp_outgoing = 0; 24100a92a9fcSCy Schubert worker->back->num_udp_outgoing = 0; 2411b7579f77SDag-Erling Smørgrav } 2412b7579f77SDag-Erling Smørgrav 2413b7579f77SDag-Erling Smørgrav void worker_start_accept(void* arg) 2414b7579f77SDag-Erling Smørgrav { 2415b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2416b7579f77SDag-Erling Smørgrav listen_start_accept(worker->front); 2417b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) 2418b7579f77SDag-Erling Smørgrav daemon_remote_start_accept(worker->daemon->rc); 2419b7579f77SDag-Erling Smørgrav } 2420b7579f77SDag-Erling Smørgrav 2421b7579f77SDag-Erling Smørgrav void worker_stop_accept(void* arg) 2422b7579f77SDag-Erling Smørgrav { 2423b7579f77SDag-Erling Smørgrav struct worker* worker = (struct worker*)arg; 2424b7579f77SDag-Erling Smørgrav listen_stop_accept(worker->front); 2425b7579f77SDag-Erling Smørgrav if(worker->thread_num == 0) 2426b7579f77SDag-Erling Smørgrav daemon_remote_stop_accept(worker->daemon->rc); 2427b7579f77SDag-Erling Smørgrav } 2428b7579f77SDag-Erling Smørgrav 2429b7579f77SDag-Erling Smørgrav /* --- fake callbacks for fptr_wlist to work --- */ 2430bc892140SDag-Erling Smørgrav struct outbound_entry* libworker_send_query( 2431bc892140SDag-Erling Smørgrav struct query_info* ATTR_UNUSED(qinfo), 2432bc892140SDag-Erling Smørgrav uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), 2433bc892140SDag-Erling Smørgrav int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), 24349cf5bc93SCy Schubert int ATTR_UNUSED(check_ratelimit), 2435bc892140SDag-Erling Smørgrav struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), 243624e36522SCy Schubert uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), 24370fb34990SDag-Erling Smørgrav int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name), 24389cf5bc93SCy Schubert struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited)) 2439b7579f77SDag-Erling Smørgrav { 2440b7579f77SDag-Erling Smørgrav log_assert(0); 2441b7579f77SDag-Erling Smørgrav return 0; 2442b7579f77SDag-Erling Smørgrav } 2443b7579f77SDag-Erling Smørgrav 2444b7579f77SDag-Erling Smørgrav int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), 2445b7579f77SDag-Erling Smørgrav void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), 2446b7579f77SDag-Erling Smørgrav struct comm_reply* ATTR_UNUSED(reply_info)) 2447b7579f77SDag-Erling Smørgrav { 2448b7579f77SDag-Erling Smørgrav log_assert(0); 2449b7579f77SDag-Erling Smørgrav return 0; 2450b7579f77SDag-Erling Smørgrav } 2451b7579f77SDag-Erling Smørgrav 2452b7579f77SDag-Erling Smørgrav void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 2453b7579f77SDag-Erling Smørgrav uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), 2454b7579f77SDag-Erling Smørgrav int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) 2455b7579f77SDag-Erling Smørgrav { 2456b7579f77SDag-Erling Smørgrav log_assert(0); 2457b7579f77SDag-Erling Smørgrav } 2458b7579f77SDag-Erling Smørgrav 2459b7579f77SDag-Erling Smørgrav void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 246017d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 24614c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2462b7579f77SDag-Erling Smørgrav { 2463b7579f77SDag-Erling Smørgrav log_assert(0); 2464b7579f77SDag-Erling Smørgrav } 2465b7579f77SDag-Erling Smørgrav 2466b7579f77SDag-Erling Smørgrav void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 246717d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 24684c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 246917d15b25SDag-Erling Smørgrav { 247017d15b25SDag-Erling Smørgrav log_assert(0); 247117d15b25SDag-Erling Smørgrav } 247217d15b25SDag-Erling Smørgrav 247317d15b25SDag-Erling Smørgrav void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), 247417d15b25SDag-Erling Smørgrav sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), 24754c75e3aaSDag-Erling Smørgrav char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) 2476b7579f77SDag-Erling Smørgrav { 2477b7579f77SDag-Erling Smørgrav log_assert(0); 2478b7579f77SDag-Erling Smørgrav } 2479b7579f77SDag-Erling Smørgrav 2480b7579f77SDag-Erling Smørgrav int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2481b7579f77SDag-Erling Smørgrav { 2482b7579f77SDag-Erling Smørgrav log_assert(0); 2483b7579f77SDag-Erling Smørgrav return 0; 2484b7579f77SDag-Erling Smørgrav } 2485b7579f77SDag-Erling Smørgrav 2486b7579f77SDag-Erling Smørgrav int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2)) 2487b7579f77SDag-Erling Smørgrav { 2488b7579f77SDag-Erling Smørgrav log_assert(0); 2489b7579f77SDag-Erling Smørgrav return 0; 2490b7579f77SDag-Erling Smørgrav } 2491b7579f77SDag-Erling Smørgrav 2492b7579f77SDag-Erling Smørgrav int codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 2493b7579f77SDag-Erling Smørgrav { 2494b7579f77SDag-Erling Smørgrav log_assert(0); 2495b7579f77SDag-Erling Smørgrav return 0; 2496b7579f77SDag-Erling Smørgrav } 2497b7579f77SDag-Erling Smørgrav 249825039b37SCy Schubert #ifdef USE_DNSTAP 249925039b37SCy Schubert void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 250025039b37SCy Schubert void* ATTR_UNUSED(arg)) 250125039b37SCy Schubert { 250225039b37SCy Schubert log_assert(0); 250325039b37SCy Schubert } 250425039b37SCy Schubert #endif 250525039b37SCy Schubert 250625039b37SCy Schubert #ifdef USE_DNSTAP 250725039b37SCy Schubert void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 250825039b37SCy Schubert void* ATTR_UNUSED(arg)) 250925039b37SCy Schubert { 251025039b37SCy Schubert log_assert(0); 251125039b37SCy Schubert } 251225039b37SCy Schubert #endif 2513*46d2f618SCy Schubert 2514*46d2f618SCy Schubert #ifdef HAVE_NGTCP2 2515*46d2f618SCy Schubert void doq_client_event_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 2516*46d2f618SCy Schubert void* ATTR_UNUSED(arg)) 2517*46d2f618SCy Schubert { 2518*46d2f618SCy Schubert log_assert(0); 2519*46d2f618SCy Schubert } 2520*46d2f618SCy Schubert #endif 2521*46d2f618SCy Schubert 2522*46d2f618SCy Schubert #ifdef HAVE_NGTCP2 2523*46d2f618SCy Schubert void doq_client_timer_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), 2524*46d2f618SCy Schubert void* ATTR_UNUSED(arg)) 2525*46d2f618SCy Schubert { 2526*46d2f618SCy Schubert log_assert(0); 2527*46d2f618SCy Schubert } 2528*46d2f618SCy Schubert #endif 2529