1ae8c6e27Sflorian /* 2ae8c6e27Sflorian * services/mesh.c - deal with mesh of query states and handle events for that. 3ae8c6e27Sflorian * 4ae8c6e27Sflorian * Copyright (c) 2007, NLnet Labs. All rights reserved. 5ae8c6e27Sflorian * 6ae8c6e27Sflorian * This software is open source. 7ae8c6e27Sflorian * 8ae8c6e27Sflorian * Redistribution and use in source and binary forms, with or without 9ae8c6e27Sflorian * modification, are permitted provided that the following conditions 10ae8c6e27Sflorian * are met: 11ae8c6e27Sflorian * 12ae8c6e27Sflorian * Redistributions of source code must retain the above copyright notice, 13ae8c6e27Sflorian * this list of conditions and the following disclaimer. 14ae8c6e27Sflorian * 15ae8c6e27Sflorian * Redistributions in binary form must reproduce the above copyright notice, 16ae8c6e27Sflorian * this list of conditions and the following disclaimer in the documentation 17ae8c6e27Sflorian * and/or other materials provided with the distribution. 18ae8c6e27Sflorian * 19ae8c6e27Sflorian * Neither the name of the NLNET LABS nor the names of its contributors may 20ae8c6e27Sflorian * be used to endorse or promote products derived from this software without 21ae8c6e27Sflorian * specific prior written permission. 22ae8c6e27Sflorian * 23ae8c6e27Sflorian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24ae8c6e27Sflorian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25ae8c6e27Sflorian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26ae8c6e27Sflorian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27ae8c6e27Sflorian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28ae8c6e27Sflorian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29ae8c6e27Sflorian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30ae8c6e27Sflorian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31ae8c6e27Sflorian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32ae8c6e27Sflorian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33ae8c6e27Sflorian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34ae8c6e27Sflorian */ 35ae8c6e27Sflorian 36ae8c6e27Sflorian /** 37ae8c6e27Sflorian * \file 38ae8c6e27Sflorian * 39ae8c6e27Sflorian * This file contains functions to assist in dealing with a mesh of 40ae8c6e27Sflorian * query states. This mesh is supposed to be thread-specific. 41ae8c6e27Sflorian * It consists of query states (per qname, qtype, qclass) and connections 42ae8c6e27Sflorian * between query states and the super and subquery states, and replies to 43ae8c6e27Sflorian * send back to clients. 44ae8c6e27Sflorian */ 45ae8c6e27Sflorian #include "config.h" 46ae8c6e27Sflorian #include "services/mesh.h" 47ae8c6e27Sflorian #include "services/outbound_list.h" 48ae8c6e27Sflorian #include "services/cache/dns.h" 49d32eb43cSflorian #include "services/cache/rrset.h" 50096314feSflorian #include "services/cache/infra.h" 51ae8c6e27Sflorian #include "util/log.h" 52ae8c6e27Sflorian #include "util/net_help.h" 53ae8c6e27Sflorian #include "util/module.h" 54ae8c6e27Sflorian #include "util/regional.h" 55ae8c6e27Sflorian #include "util/data/msgencode.h" 56ae8c6e27Sflorian #include "util/timehist.h" 57ae8c6e27Sflorian #include "util/fptr_wlist.h" 58ae8c6e27Sflorian #include "util/alloc.h" 59ae8c6e27Sflorian #include "util/config_file.h" 60ae8c6e27Sflorian #include "util/edns.h" 61ae8c6e27Sflorian #include "sldns/sbuffer.h" 62ae8c6e27Sflorian #include "sldns/wire2str.h" 63ae8c6e27Sflorian #include "services/localzone.h" 64ae8c6e27Sflorian #include "util/data/dname.h" 65ae8c6e27Sflorian #include "respip/respip.h" 66e97c6e54Ssthen #include "services/listen_dnsport.h" 67d500c338Sflorian #include "util/timeval_func.h" 68ae8c6e27Sflorian 697a05b9dfSflorian #ifdef CLIENT_SUBNET 707a05b9dfSflorian #include "edns-subnet/subnetmod.h" 717a05b9dfSflorian #include "edns-subnet/edns-subnet.h" 727a05b9dfSflorian #endif 7354cc57acSflorian #ifdef HAVE_SYS_TYPES_H 7454cc57acSflorian # include <sys/types.h> 7554cc57acSflorian #endif 7654cc57acSflorian #ifdef HAVE_NETDB_H 7754cc57acSflorian #include <netdb.h> 7854cc57acSflorian #endif 797a05b9dfSflorian 80d32eb43cSflorian /** 81ae8c6e27Sflorian * Compare two response-ip client info entries for the purpose of mesh state 82ae8c6e27Sflorian * compare. It returns 0 if ci_a and ci_b are considered equal; otherwise 83ae8c6e27Sflorian * 1 or -1 (they mean 'ci_a is larger/smaller than ci_b', respectively, but 84ae8c6e27Sflorian * in practice it should be only used to mean they are different). 85ae8c6e27Sflorian * We cannot share the mesh state for two queries if different response-ip 86ae8c6e27Sflorian * actions can apply in the end, even if those queries are otherwise identical. 87ae8c6e27Sflorian * For this purpose we compare tag lists and tag action lists; they should be 88ae8c6e27Sflorian * identical to share the same state. 89ae8c6e27Sflorian * For tag data, we don't look into the data content, as it can be 90ae8c6e27Sflorian * expensive; unless tag data are not defined for both or they point to the 91ae8c6e27Sflorian * exact same data in memory (i.e., they come from the same ACL entry), we 92ae8c6e27Sflorian * consider these data different. 93ae8c6e27Sflorian * Likewise, if the client info is associated with views, we don't look into 94ae8c6e27Sflorian * the views. They are considered different unless they are exactly the same 95ae8c6e27Sflorian * even if the views only differ in the names. 96ae8c6e27Sflorian */ 97ae8c6e27Sflorian static int 98ae8c6e27Sflorian client_info_compare(const struct respip_client_info* ci_a, 99ae8c6e27Sflorian const struct respip_client_info* ci_b) 100ae8c6e27Sflorian { 101ae8c6e27Sflorian int cmp; 102ae8c6e27Sflorian 103ae8c6e27Sflorian if(!ci_a && !ci_b) 104ae8c6e27Sflorian return 0; 105ae8c6e27Sflorian if(ci_a && !ci_b) 106ae8c6e27Sflorian return -1; 107ae8c6e27Sflorian if(!ci_a && ci_b) 108ae8c6e27Sflorian return 1; 109ae8c6e27Sflorian if(ci_a->taglen != ci_b->taglen) 110ae8c6e27Sflorian return (ci_a->taglen < ci_b->taglen) ? -1 : 1; 111e47fef9eSflorian if(ci_a->taglist && !ci_b->taglist) 112e47fef9eSflorian return -1; 113e47fef9eSflorian if(!ci_a->taglist && ci_b->taglist) 114e47fef9eSflorian return 1; 115e47fef9eSflorian if(ci_a->taglist && ci_b->taglist) { 116ae8c6e27Sflorian cmp = memcmp(ci_a->taglist, ci_b->taglist, ci_a->taglen); 117ae8c6e27Sflorian if(cmp != 0) 118ae8c6e27Sflorian return cmp; 119e47fef9eSflorian } 120ae8c6e27Sflorian if(ci_a->tag_actions_size != ci_b->tag_actions_size) 121ae8c6e27Sflorian return (ci_a->tag_actions_size < ci_b->tag_actions_size) ? 122ae8c6e27Sflorian -1 : 1; 123e47fef9eSflorian if(ci_a->tag_actions && !ci_b->tag_actions) 124e47fef9eSflorian return -1; 125e47fef9eSflorian if(!ci_a->tag_actions && ci_b->tag_actions) 126e47fef9eSflorian return 1; 127e47fef9eSflorian if(ci_a->tag_actions && ci_b->tag_actions) { 128ae8c6e27Sflorian cmp = memcmp(ci_a->tag_actions, ci_b->tag_actions, 129ae8c6e27Sflorian ci_a->tag_actions_size); 130ae8c6e27Sflorian if(cmp != 0) 131ae8c6e27Sflorian return cmp; 132e47fef9eSflorian } 133ae8c6e27Sflorian if(ci_a->tag_datas != ci_b->tag_datas) 134ae8c6e27Sflorian return ci_a->tag_datas < ci_b->tag_datas ? -1 : 1; 135ae8c6e27Sflorian if(ci_a->view != ci_b->view) 136ae8c6e27Sflorian return ci_a->view < ci_b->view ? -1 : 1; 137ae8c6e27Sflorian /* For the unbound daemon these should be non-NULL and identical, 138ae8c6e27Sflorian * but we check that just in case. */ 139ae8c6e27Sflorian if(ci_a->respip_set != ci_b->respip_set) 140ae8c6e27Sflorian return ci_a->respip_set < ci_b->respip_set ? -1 : 1; 141ae8c6e27Sflorian return 0; 142ae8c6e27Sflorian } 143ae8c6e27Sflorian 144ae8c6e27Sflorian int 145ae8c6e27Sflorian mesh_state_compare(const void* ap, const void* bp) 146ae8c6e27Sflorian { 147ae8c6e27Sflorian struct mesh_state* a = (struct mesh_state*)ap; 148ae8c6e27Sflorian struct mesh_state* b = (struct mesh_state*)bp; 149ae8c6e27Sflorian int cmp; 150ae8c6e27Sflorian 151ae8c6e27Sflorian if(a->unique < b->unique) 152ae8c6e27Sflorian return -1; 153ae8c6e27Sflorian if(a->unique > b->unique) 154ae8c6e27Sflorian return 1; 155ae8c6e27Sflorian 156ae8c6e27Sflorian if(a->s.is_priming && !b->s.is_priming) 157ae8c6e27Sflorian return -1; 158ae8c6e27Sflorian if(!a->s.is_priming && b->s.is_priming) 159ae8c6e27Sflorian return 1; 160ae8c6e27Sflorian 161ae8c6e27Sflorian if(a->s.is_valrec && !b->s.is_valrec) 162ae8c6e27Sflorian return -1; 163ae8c6e27Sflorian if(!a->s.is_valrec && b->s.is_valrec) 164ae8c6e27Sflorian return 1; 165ae8c6e27Sflorian 166ae8c6e27Sflorian if((a->s.query_flags&BIT_RD) && !(b->s.query_flags&BIT_RD)) 167ae8c6e27Sflorian return -1; 168ae8c6e27Sflorian if(!(a->s.query_flags&BIT_RD) && (b->s.query_flags&BIT_RD)) 169ae8c6e27Sflorian return 1; 170ae8c6e27Sflorian 171ae8c6e27Sflorian if((a->s.query_flags&BIT_CD) && !(b->s.query_flags&BIT_CD)) 172ae8c6e27Sflorian return -1; 173ae8c6e27Sflorian if(!(a->s.query_flags&BIT_CD) && (b->s.query_flags&BIT_CD)) 174ae8c6e27Sflorian return 1; 175ae8c6e27Sflorian 176ae8c6e27Sflorian cmp = query_info_compare(&a->s.qinfo, &b->s.qinfo); 177ae8c6e27Sflorian if(cmp != 0) 178ae8c6e27Sflorian return cmp; 179ae8c6e27Sflorian return client_info_compare(a->s.client_info, b->s.client_info); 180ae8c6e27Sflorian } 181ae8c6e27Sflorian 182ae8c6e27Sflorian int 183ae8c6e27Sflorian mesh_state_ref_compare(const void* ap, const void* bp) 184ae8c6e27Sflorian { 185ae8c6e27Sflorian struct mesh_state_ref* a = (struct mesh_state_ref*)ap; 186ae8c6e27Sflorian struct mesh_state_ref* b = (struct mesh_state_ref*)bp; 187ae8c6e27Sflorian return mesh_state_compare(a->s, b->s); 188ae8c6e27Sflorian } 189ae8c6e27Sflorian 190ae8c6e27Sflorian struct mesh_area* 191ae8c6e27Sflorian mesh_create(struct module_stack* stack, struct module_env* env) 192ae8c6e27Sflorian { 193ae8c6e27Sflorian struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area)); 194ae8c6e27Sflorian if(!mesh) { 195ae8c6e27Sflorian log_err("mesh area alloc: out of memory"); 196ae8c6e27Sflorian return NULL; 197ae8c6e27Sflorian } 198ae8c6e27Sflorian mesh->histogram = timehist_setup(); 199ae8c6e27Sflorian mesh->qbuf_bak = sldns_buffer_new(env->cfg->msg_buffer_size); 200ae8c6e27Sflorian if(!mesh->histogram || !mesh->qbuf_bak) { 201ae8c6e27Sflorian free(mesh); 202ae8c6e27Sflorian log_err("mesh area alloc: out of memory"); 203ae8c6e27Sflorian return NULL; 204ae8c6e27Sflorian } 205ae8c6e27Sflorian mesh->mods = *stack; 206ae8c6e27Sflorian mesh->env = env; 207ae8c6e27Sflorian rbtree_init(&mesh->run, &mesh_state_compare); 208ae8c6e27Sflorian rbtree_init(&mesh->all, &mesh_state_compare); 209ae8c6e27Sflorian mesh->num_reply_addrs = 0; 210ae8c6e27Sflorian mesh->num_reply_states = 0; 211ae8c6e27Sflorian mesh->num_detached_states = 0; 212ae8c6e27Sflorian mesh->num_forever_states = 0; 213ae8c6e27Sflorian mesh->stats_jostled = 0; 214ae8c6e27Sflorian mesh->stats_dropped = 0; 215d32eb43cSflorian mesh->ans_expired = 0; 216d500c338Sflorian mesh->ans_cachedb = 0; 217ae8c6e27Sflorian mesh->max_reply_states = env->cfg->num_queries_per_thread; 218ae8c6e27Sflorian mesh->max_forever_states = (mesh->max_reply_states+1)/2; 219ae8c6e27Sflorian #ifndef S_SPLINT_S 220ae8c6e27Sflorian mesh->jostle_max.tv_sec = (time_t)(env->cfg->jostle_time / 1000); 221ae8c6e27Sflorian mesh->jostle_max.tv_usec = (time_t)((env->cfg->jostle_time % 1000) 222ae8c6e27Sflorian *1000); 223ae8c6e27Sflorian #endif 224ae8c6e27Sflorian return mesh; 225ae8c6e27Sflorian } 226ae8c6e27Sflorian 227ae8c6e27Sflorian /** help mesh delete delete mesh states */ 228ae8c6e27Sflorian static void 229ae8c6e27Sflorian mesh_delete_helper(rbnode_type* n) 230ae8c6e27Sflorian { 231ae8c6e27Sflorian struct mesh_state* mstate = (struct mesh_state*)n->key; 232ae8c6e27Sflorian /* perform a full delete, not only 'cleanup' routine, 233ae8c6e27Sflorian * because other callbacks expect a clean state in the mesh. 234ae8c6e27Sflorian * For 're-entrant' calls */ 235ae8c6e27Sflorian mesh_state_delete(&mstate->s); 236ae8c6e27Sflorian /* but because these delete the items from the tree, postorder 237ae8c6e27Sflorian * traversal and rbtree rebalancing do not work together */ 238ae8c6e27Sflorian } 239ae8c6e27Sflorian 240ae8c6e27Sflorian void 241ae8c6e27Sflorian mesh_delete(struct mesh_area* mesh) 242ae8c6e27Sflorian { 243ae8c6e27Sflorian if(!mesh) 244ae8c6e27Sflorian return; 245ae8c6e27Sflorian /* free all query states */ 246ae8c6e27Sflorian while(mesh->all.count) 247ae8c6e27Sflorian mesh_delete_helper(mesh->all.root); 248ae8c6e27Sflorian timehist_delete(mesh->histogram); 249ae8c6e27Sflorian sldns_buffer_free(mesh->qbuf_bak); 250ae8c6e27Sflorian free(mesh); 251ae8c6e27Sflorian } 252ae8c6e27Sflorian 253ae8c6e27Sflorian void 254ae8c6e27Sflorian mesh_delete_all(struct mesh_area* mesh) 255ae8c6e27Sflorian { 256ae8c6e27Sflorian /* free all query states */ 257ae8c6e27Sflorian while(mesh->all.count) 258ae8c6e27Sflorian mesh_delete_helper(mesh->all.root); 259ae8c6e27Sflorian mesh->stats_dropped += mesh->num_reply_addrs; 260ae8c6e27Sflorian /* clear mesh area references */ 261ae8c6e27Sflorian rbtree_init(&mesh->run, &mesh_state_compare); 262ae8c6e27Sflorian rbtree_init(&mesh->all, &mesh_state_compare); 263ae8c6e27Sflorian mesh->num_reply_addrs = 0; 264ae8c6e27Sflorian mesh->num_reply_states = 0; 265ae8c6e27Sflorian mesh->num_detached_states = 0; 266ae8c6e27Sflorian mesh->num_forever_states = 0; 267ae8c6e27Sflorian mesh->forever_first = NULL; 268ae8c6e27Sflorian mesh->forever_last = NULL; 269ae8c6e27Sflorian mesh->jostle_first = NULL; 270ae8c6e27Sflorian mesh->jostle_last = NULL; 271ae8c6e27Sflorian } 272ae8c6e27Sflorian 273ae8c6e27Sflorian int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf) 274ae8c6e27Sflorian { 275ae8c6e27Sflorian struct mesh_state* m = mesh->jostle_first; 276ae8c6e27Sflorian /* free space is available */ 277ae8c6e27Sflorian if(mesh->num_reply_states < mesh->max_reply_states) 278ae8c6e27Sflorian return 1; 279ae8c6e27Sflorian /* try to kick out a jostle-list item */ 280ae8c6e27Sflorian if(m && m->reply_list && m->list_select == mesh_jostle_list) { 281ae8c6e27Sflorian /* how old is it? */ 282ae8c6e27Sflorian struct timeval age; 283ae8c6e27Sflorian timeval_subtract(&age, mesh->env->now_tv, 284ae8c6e27Sflorian &m->reply_list->start_time); 285ae8c6e27Sflorian if(timeval_smaller(&mesh->jostle_max, &age)) { 286ae8c6e27Sflorian /* its a goner */ 287ae8c6e27Sflorian log_nametypeclass(VERB_ALGO, "query jostled out to " 288ae8c6e27Sflorian "make space for a new one", 289ae8c6e27Sflorian m->s.qinfo.qname, m->s.qinfo.qtype, 290ae8c6e27Sflorian m->s.qinfo.qclass); 291ae8c6e27Sflorian /* backup the query */ 292ae8c6e27Sflorian if(qbuf) sldns_buffer_copy(mesh->qbuf_bak, qbuf); 293ae8c6e27Sflorian /* notify supers */ 294ae8c6e27Sflorian if(m->super_set.count > 0) { 295ae8c6e27Sflorian verbose(VERB_ALGO, "notify supers of failure"); 296ae8c6e27Sflorian m->s.return_msg = NULL; 297ae8c6e27Sflorian m->s.return_rcode = LDNS_RCODE_SERVFAIL; 298ae8c6e27Sflorian mesh_walk_supers(mesh, m); 299ae8c6e27Sflorian } 300ae8c6e27Sflorian mesh->stats_jostled ++; 301ae8c6e27Sflorian mesh_state_delete(&m->s); 302ae8c6e27Sflorian /* restore the query - note that the qinfo ptr to 303ae8c6e27Sflorian * the querybuffer is then correct again. */ 304ae8c6e27Sflorian if(qbuf) sldns_buffer_copy(qbuf, mesh->qbuf_bak); 305ae8c6e27Sflorian return 1; 306ae8c6e27Sflorian } 307ae8c6e27Sflorian } 308ae8c6e27Sflorian /* no space for new item */ 309ae8c6e27Sflorian return 0; 310ae8c6e27Sflorian } 311ae8c6e27Sflorian 312d32eb43cSflorian struct dns_msg* 313d32eb43cSflorian mesh_serve_expired_lookup(struct module_qstate* qstate, 314d32eb43cSflorian struct query_info* lookup_qinfo) 315d32eb43cSflorian { 316d32eb43cSflorian hashvalue_type h; 317d32eb43cSflorian struct lruhash_entry* e; 318d32eb43cSflorian struct dns_msg* msg; 319d32eb43cSflorian struct reply_info* data; 320d32eb43cSflorian struct msgreply_entry* key; 321d32eb43cSflorian time_t timenow = *qstate->env->now; 322d32eb43cSflorian int must_validate = (!(qstate->query_flags&BIT_CD) 323d32eb43cSflorian || qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate; 324d32eb43cSflorian /* Lookup cache */ 325d32eb43cSflorian h = query_info_hash(lookup_qinfo, qstate->query_flags); 326d32eb43cSflorian e = slabhash_lookup(qstate->env->msg_cache, h, lookup_qinfo, 0); 327d32eb43cSflorian if(!e) return NULL; 328d32eb43cSflorian 329d32eb43cSflorian key = (struct msgreply_entry*)e->key; 330d32eb43cSflorian data = (struct reply_info*)e->data; 331d32eb43cSflorian msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow, 332d32eb43cSflorian qstate->env->cfg->serve_expired, qstate->env->scratch); 333d32eb43cSflorian if(!msg) 334d32eb43cSflorian goto bail_out; 335d32eb43cSflorian 336d32eb43cSflorian /* Check CNAME chain (if any) 337d32eb43cSflorian * This is part of tomsg above; no need to check now. */ 338d32eb43cSflorian 339d32eb43cSflorian /* Check security status of the cached answer. 340d32eb43cSflorian * tomsg above has a subset of these checks, so we are leaving 341d32eb43cSflorian * these as is. 342d32eb43cSflorian * In case of bogus or revalidation we don't care to reply here. */ 343d32eb43cSflorian if(must_validate && (msg->rep->security == sec_status_bogus || 344d32eb43cSflorian msg->rep->security == sec_status_secure_sentinel_fail)) { 345d32eb43cSflorian verbose(VERB_ALGO, "Serve expired: bogus answer found in cache"); 346d32eb43cSflorian goto bail_out; 347d32eb43cSflorian } else if(msg->rep->security == sec_status_unchecked && must_validate) { 348d32eb43cSflorian verbose(VERB_ALGO, "Serve expired: unchecked entry needs " 349d32eb43cSflorian "validation"); 350d32eb43cSflorian goto bail_out; /* need to validate cache entry first */ 351d32eb43cSflorian } else if(msg->rep->security == sec_status_secure && 352d32eb43cSflorian !reply_all_rrsets_secure(msg->rep) && must_validate) { 353d32eb43cSflorian verbose(VERB_ALGO, "Serve expired: secure entry" 354d32eb43cSflorian " changed status"); 355d32eb43cSflorian goto bail_out; /* rrset changed, re-verify */ 356d32eb43cSflorian } 357d32eb43cSflorian 358d32eb43cSflorian lock_rw_unlock(&e->lock); 359d32eb43cSflorian return msg; 360d32eb43cSflorian 361d32eb43cSflorian bail_out: 362d32eb43cSflorian lock_rw_unlock(&e->lock); 363d32eb43cSflorian return NULL; 364d32eb43cSflorian } 365d32eb43cSflorian 366d32eb43cSflorian 367d32eb43cSflorian /** Init the serve expired data structure */ 368d32eb43cSflorian static int 369d32eb43cSflorian mesh_serve_expired_init(struct mesh_state* mstate, int timeout) 370d32eb43cSflorian { 371d32eb43cSflorian struct timeval t; 372d32eb43cSflorian 373d32eb43cSflorian /* Create serve_expired_data if not there yet */ 374d32eb43cSflorian if(!mstate->s.serve_expired_data) { 375d32eb43cSflorian mstate->s.serve_expired_data = (struct serve_expired_data*) 376d32eb43cSflorian regional_alloc_zero( 377d32eb43cSflorian mstate->s.region, sizeof(struct serve_expired_data)); 378d32eb43cSflorian if(!mstate->s.serve_expired_data) 379d32eb43cSflorian return 0; 380d32eb43cSflorian } 381d32eb43cSflorian 382d32eb43cSflorian /* Don't overwrite the function if already set */ 383d32eb43cSflorian mstate->s.serve_expired_data->get_cached_answer = 384d32eb43cSflorian mstate->s.serve_expired_data->get_cached_answer? 385d32eb43cSflorian mstate->s.serve_expired_data->get_cached_answer: 386411c5950Sflorian &mesh_serve_expired_lookup; 387d32eb43cSflorian 388d32eb43cSflorian /* In case this timer already popped, start it again */ 389096314feSflorian if(!mstate->s.serve_expired_data->timer && timeout != -1) { 390d32eb43cSflorian mstate->s.serve_expired_data->timer = comm_timer_create( 391d32eb43cSflorian mstate->s.env->worker_base, mesh_serve_expired_callback, mstate); 392d32eb43cSflorian if(!mstate->s.serve_expired_data->timer) 393d32eb43cSflorian return 0; 394d32eb43cSflorian #ifndef S_SPLINT_S 395d32eb43cSflorian t.tv_sec = timeout/1000; 396d32eb43cSflorian t.tv_usec = (timeout%1000)*1000; 397d32eb43cSflorian #endif 398d32eb43cSflorian comm_timer_set(mstate->s.serve_expired_data->timer, &t); 399d32eb43cSflorian } 400d32eb43cSflorian return 1; 401d32eb43cSflorian } 402d32eb43cSflorian 403ae8c6e27Sflorian void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, 404ae8c6e27Sflorian struct respip_client_info* cinfo, uint16_t qflags, 4057a05b9dfSflorian struct edns_data* edns, struct comm_reply* rep, uint16_t qid, 4067a05b9dfSflorian int rpz_passthru) 407ae8c6e27Sflorian { 408ae8c6e27Sflorian struct mesh_state* s = NULL; 409a1a7ba80Sflorian int unique = unique_mesh_state(edns->opt_list_in, mesh->env); 410ae8c6e27Sflorian int was_detached = 0; 411ae8c6e27Sflorian int was_noreply = 0; 412ae8c6e27Sflorian int added = 0; 413d32eb43cSflorian int timeout = mesh->env->cfg->serve_expired? 414d32eb43cSflorian mesh->env->cfg->serve_expired_client_timeout:0; 4159b465e50Sflorian struct sldns_buffer* r_buffer = rep->c->buffer; 416*7037e34cSflorian uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD); 4179b465e50Sflorian if(rep->c->tcp_req_info) { 4189b465e50Sflorian r_buffer = rep->c->tcp_req_info->spool_buffer; 4199b465e50Sflorian } 420096314feSflorian if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep, 421096314feSflorian edns->cookie_valid, mesh->env->cfg)) { 422096314feSflorian verbose(VERB_ALGO, "Too many queries waiting from the IP. " 423096314feSflorian "dropping incoming query."); 424096314feSflorian comm_point_drop_reply(rep); 425096314feSflorian mesh->stats_dropped++; 426096314feSflorian return; 427096314feSflorian } 428ae8c6e27Sflorian if(!unique) 429*7037e34cSflorian s = mesh_area_find(mesh, cinfo, qinfo, mesh_flags, 0, 0); 430ae8c6e27Sflorian /* does this create a new reply state? */ 431ae8c6e27Sflorian if(!s || s->list_select == mesh_no_list) { 432ae8c6e27Sflorian if(!mesh_make_new_space(mesh, rep->c->buffer)) { 433ae8c6e27Sflorian verbose(VERB_ALGO, "Too many queries. dropping " 434ae8c6e27Sflorian "incoming query."); 435ae8c6e27Sflorian comm_point_drop_reply(rep); 436ae8c6e27Sflorian mesh->stats_dropped++; 437ae8c6e27Sflorian return; 438ae8c6e27Sflorian } 439ae8c6e27Sflorian /* for this new reply state, the reply address is free, 440ae8c6e27Sflorian * so the limit of reply addresses does not stop reply states*/ 441ae8c6e27Sflorian } else { 442ae8c6e27Sflorian /* protect our memory usage from storing reply addresses */ 443ae8c6e27Sflorian if(mesh->num_reply_addrs > mesh->max_reply_states*16) { 444ae8c6e27Sflorian verbose(VERB_ALGO, "Too many requests queued. " 445ae8c6e27Sflorian "dropping incoming query."); 446ae8c6e27Sflorian comm_point_drop_reply(rep); 447d32eb43cSflorian mesh->stats_dropped++; 448ae8c6e27Sflorian return; 449ae8c6e27Sflorian } 450ae8c6e27Sflorian } 451ae8c6e27Sflorian /* see if it already exists, if not, create one */ 452ae8c6e27Sflorian if(!s) { 453ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 454ae8c6e27Sflorian struct rbnode_type* n; 455ae8c6e27Sflorian #endif 456ae8c6e27Sflorian s = mesh_state_create(mesh->env, qinfo, cinfo, 457*7037e34cSflorian mesh_flags, 0, 0); 458ae8c6e27Sflorian if(!s) { 459ae8c6e27Sflorian log_err("mesh_state_create: out of memory; SERVFAIL"); 460ae8c6e27Sflorian if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, 461a8eaceedSflorian LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) 462a1a7ba80Sflorian edns->opt_list_inplace_cb_out = NULL; 4639b465e50Sflorian error_encode(r_buffer, LDNS_RCODE_SERVFAIL, 464ae8c6e27Sflorian qinfo, qid, qflags, edns); 465ae8c6e27Sflorian comm_point_send_reply(rep); 466ae8c6e27Sflorian return; 467ae8c6e27Sflorian } 468d500c338Sflorian /* set detached (it is now) */ 469d500c338Sflorian mesh->num_detached_states++; 470ae8c6e27Sflorian if(unique) 471ae8c6e27Sflorian mesh_state_make_unique(s); 4727a05b9dfSflorian s->s.rpz_passthru = rpz_passthru; 473ae8c6e27Sflorian /* copy the edns options we got from the front */ 474a1a7ba80Sflorian if(edns->opt_list_in) { 475a1a7ba80Sflorian s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in, 476ae8c6e27Sflorian s->s.region); 477ae8c6e27Sflorian if(!s->s.edns_opts_front_in) { 478d500c338Sflorian log_err("edns_opt_copy_region: out of memory; SERVFAIL"); 479ae8c6e27Sflorian if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, 480a8eaceedSflorian NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) 481a1a7ba80Sflorian edns->opt_list_inplace_cb_out = NULL; 4829b465e50Sflorian error_encode(r_buffer, LDNS_RCODE_SERVFAIL, 483ae8c6e27Sflorian qinfo, qid, qflags, edns); 484ae8c6e27Sflorian comm_point_send_reply(rep); 485d500c338Sflorian mesh_state_delete(&s->s); 486ae8c6e27Sflorian return; 487ae8c6e27Sflorian } 488ae8c6e27Sflorian } 489ae8c6e27Sflorian 490ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 491ae8c6e27Sflorian n = 492ae8c6e27Sflorian #else 493ae8c6e27Sflorian (void) 494ae8c6e27Sflorian #endif 495ae8c6e27Sflorian rbtree_insert(&mesh->all, &s->node); 496ae8c6e27Sflorian log_assert(n != NULL); 497ae8c6e27Sflorian added = 1; 498ae8c6e27Sflorian } 499d32eb43cSflorian if(!s->reply_list && !s->cb_list) { 500ae8c6e27Sflorian was_noreply = 1; 501d32eb43cSflorian if(s->super_set.count == 0) { 502d32eb43cSflorian was_detached = 1; 503d32eb43cSflorian } 504d32eb43cSflorian } 505ae8c6e27Sflorian /* add reply to s */ 506ae8c6e27Sflorian if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { 507ae8c6e27Sflorian log_err("mesh_new_client: out of memory; SERVFAIL"); 508d32eb43cSflorian goto servfail_mem; 509ae8c6e27Sflorian } 510e97c6e54Ssthen if(rep->c->tcp_req_info) { 511e97c6e54Ssthen if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) { 512e97c6e54Ssthen log_err("mesh_new_client: out of memory add tcpreqinfo"); 513e97c6e54Ssthen goto servfail_mem; 514e97c6e54Ssthen } 515e97c6e54Ssthen } 516f4f0f0ceSflorian if(rep->c->use_h2) { 517f4f0f0ceSflorian http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); 518f4f0f0ceSflorian } 519d32eb43cSflorian /* add serve expired timer if required and not already there */ 520d32eb43cSflorian if(timeout && !mesh_serve_expired_init(s, timeout)) { 521d32eb43cSflorian log_err("mesh_new_client: out of memory initializing serve expired"); 522d32eb43cSflorian goto servfail_mem; 523d32eb43cSflorian } 524096314feSflorian #ifdef USE_CACHEDB 525096314feSflorian if(!timeout && mesh->env->cfg->serve_expired && 526096314feSflorian !mesh->env->cfg->serve_expired_client_timeout && 527096314feSflorian (mesh->env->cachedb_enabled && 528096314feSflorian mesh->env->cfg->cachedb_check_when_serve_expired)) { 529096314feSflorian if(!mesh_serve_expired_init(s, -1)) { 530096314feSflorian log_err("mesh_new_client: out of memory initializing serve expired"); 531096314feSflorian goto servfail_mem; 532096314feSflorian } 533096314feSflorian } 534096314feSflorian #endif 535096314feSflorian infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now, 536096314feSflorian mesh->env->cfg); 537ae8c6e27Sflorian /* update statistics */ 538ae8c6e27Sflorian if(was_detached) { 539ae8c6e27Sflorian log_assert(mesh->num_detached_states > 0); 540ae8c6e27Sflorian mesh->num_detached_states--; 541ae8c6e27Sflorian } 542ae8c6e27Sflorian if(was_noreply) { 543ae8c6e27Sflorian mesh->num_reply_states ++; 544ae8c6e27Sflorian } 545ae8c6e27Sflorian mesh->num_reply_addrs++; 546ae8c6e27Sflorian if(s->list_select == mesh_no_list) { 547ae8c6e27Sflorian /* move to either the forever or the jostle_list */ 548ae8c6e27Sflorian if(mesh->num_forever_states < mesh->max_forever_states) { 549ae8c6e27Sflorian mesh->num_forever_states ++; 550ae8c6e27Sflorian mesh_list_insert(s, &mesh->forever_first, 551ae8c6e27Sflorian &mesh->forever_last); 552ae8c6e27Sflorian s->list_select = mesh_forever_list; 553ae8c6e27Sflorian } else { 554ae8c6e27Sflorian mesh_list_insert(s, &mesh->jostle_first, 555ae8c6e27Sflorian &mesh->jostle_last); 556ae8c6e27Sflorian s->list_select = mesh_jostle_list; 557ae8c6e27Sflorian } 558ae8c6e27Sflorian } 559ae8c6e27Sflorian if(added) 560ae8c6e27Sflorian mesh_run(mesh, s, module_event_new, NULL); 561d32eb43cSflorian return; 562d32eb43cSflorian 563d32eb43cSflorian servfail_mem: 564d32eb43cSflorian if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s, 565a8eaceedSflorian NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) 566a1a7ba80Sflorian edns->opt_list_inplace_cb_out = NULL; 567d32eb43cSflorian error_encode(r_buffer, LDNS_RCODE_SERVFAIL, 568d32eb43cSflorian qinfo, qid, qflags, edns); 569*7037e34cSflorian if(rep->c->use_h2) 570*7037e34cSflorian http2_stream_remove_mesh_state(rep->c->h2_stream); 571d32eb43cSflorian comm_point_send_reply(rep); 572d32eb43cSflorian if(added) 573d32eb43cSflorian mesh_state_delete(&s->s); 574d32eb43cSflorian return; 575ae8c6e27Sflorian } 576ae8c6e27Sflorian 577ae8c6e27Sflorian int 578ae8c6e27Sflorian mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, 579ae8c6e27Sflorian uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, 5807a05b9dfSflorian uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru) 581ae8c6e27Sflorian { 582ae8c6e27Sflorian struct mesh_state* s = NULL; 583a1a7ba80Sflorian int unique = unique_mesh_state(edns->opt_list_in, mesh->env); 584d32eb43cSflorian int timeout = mesh->env->cfg->serve_expired? 585d32eb43cSflorian mesh->env->cfg->serve_expired_client_timeout:0; 586ae8c6e27Sflorian int was_detached = 0; 587ae8c6e27Sflorian int was_noreply = 0; 588ae8c6e27Sflorian int added = 0; 589*7037e34cSflorian uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD); 590ae8c6e27Sflorian if(!unique) 591*7037e34cSflorian s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0); 592ae8c6e27Sflorian 593ae8c6e27Sflorian /* there are no limits on the number of callbacks */ 594ae8c6e27Sflorian 595ae8c6e27Sflorian /* see if it already exists, if not, create one */ 596ae8c6e27Sflorian if(!s) { 597ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 598ae8c6e27Sflorian struct rbnode_type* n; 599ae8c6e27Sflorian #endif 600ae8c6e27Sflorian s = mesh_state_create(mesh->env, qinfo, NULL, 601*7037e34cSflorian mesh_flags, 0, 0); 602ae8c6e27Sflorian if(!s) { 603ae8c6e27Sflorian return 0; 604ae8c6e27Sflorian } 605d500c338Sflorian /* set detached (it is now) */ 606d500c338Sflorian mesh->num_detached_states++; 607ae8c6e27Sflorian if(unique) 608ae8c6e27Sflorian mesh_state_make_unique(s); 6097a05b9dfSflorian s->s.rpz_passthru = rpz_passthru; 610a1a7ba80Sflorian if(edns->opt_list_in) { 611a1a7ba80Sflorian s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in, 612ae8c6e27Sflorian s->s.region); 613ae8c6e27Sflorian if(!s->s.edns_opts_front_in) { 614d500c338Sflorian mesh_state_delete(&s->s); 615ae8c6e27Sflorian return 0; 616ae8c6e27Sflorian } 617ae8c6e27Sflorian } 618ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 619ae8c6e27Sflorian n = 620ae8c6e27Sflorian #else 621ae8c6e27Sflorian (void) 622ae8c6e27Sflorian #endif 623ae8c6e27Sflorian rbtree_insert(&mesh->all, &s->node); 624ae8c6e27Sflorian log_assert(n != NULL); 625ae8c6e27Sflorian added = 1; 626ae8c6e27Sflorian } 627d32eb43cSflorian if(!s->reply_list && !s->cb_list) { 628ae8c6e27Sflorian was_noreply = 1; 629d32eb43cSflorian if(s->super_set.count == 0) { 630d32eb43cSflorian was_detached = 1; 631d32eb43cSflorian } 632d32eb43cSflorian } 633ae8c6e27Sflorian /* add reply to s */ 634ae8c6e27Sflorian if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) { 635ae8c6e27Sflorian if(added) 636ae8c6e27Sflorian mesh_state_delete(&s->s); 637ae8c6e27Sflorian return 0; 638ae8c6e27Sflorian } 639d32eb43cSflorian /* add serve expired timer if not already there */ 640d32eb43cSflorian if(timeout && !mesh_serve_expired_init(s, timeout)) { 641d500c338Sflorian if(added) 642d500c338Sflorian mesh_state_delete(&s->s); 643d32eb43cSflorian return 0; 644d32eb43cSflorian } 645096314feSflorian #ifdef USE_CACHEDB 646096314feSflorian if(!timeout && mesh->env->cfg->serve_expired && 647096314feSflorian !mesh->env->cfg->serve_expired_client_timeout && 648096314feSflorian (mesh->env->cachedb_enabled && 649096314feSflorian mesh->env->cfg->cachedb_check_when_serve_expired)) { 650096314feSflorian if(!mesh_serve_expired_init(s, -1)) { 651096314feSflorian if(added) 652096314feSflorian mesh_state_delete(&s->s); 653096314feSflorian return 0; 654096314feSflorian } 655096314feSflorian } 656096314feSflorian #endif 657ae8c6e27Sflorian /* update statistics */ 658ae8c6e27Sflorian if(was_detached) { 659ae8c6e27Sflorian log_assert(mesh->num_detached_states > 0); 660ae8c6e27Sflorian mesh->num_detached_states--; 661ae8c6e27Sflorian } 662ae8c6e27Sflorian if(was_noreply) { 663ae8c6e27Sflorian mesh->num_reply_states ++; 664ae8c6e27Sflorian } 665ae8c6e27Sflorian mesh->num_reply_addrs++; 666ae8c6e27Sflorian if(added) 667ae8c6e27Sflorian mesh_run(mesh, s, module_event_new, NULL); 668ae8c6e27Sflorian return 1; 669ae8c6e27Sflorian } 670ae8c6e27Sflorian 671ae8c6e27Sflorian /* Internal backend routine of mesh_new_prefetch(). It takes one additional 672ae8c6e27Sflorian * parameter, 'run', which controls whether to run the prefetch state 673ae8c6e27Sflorian * immediately. When this function is called internally 'run' could be 674ae8c6e27Sflorian * 0 (false), in which case the new state is only made runnable so it 675ae8c6e27Sflorian * will not be run recursively on top of the current state. */ 676ae8c6e27Sflorian static void mesh_schedule_prefetch(struct mesh_area* mesh, 6777a05b9dfSflorian struct query_info* qinfo, uint16_t qflags, time_t leeway, int run, 6787a05b9dfSflorian int rpz_passthru) 679ae8c6e27Sflorian { 680*7037e34cSflorian /* Explicitly set the BIT_RD regardless of the client's flags. This is 681*7037e34cSflorian * for a prefetch query (no client attached) but it needs to be treated 682*7037e34cSflorian * as a recursion query. */ 683*7037e34cSflorian uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD); 684ae8c6e27Sflorian struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo, 685*7037e34cSflorian mesh_flags, 0, 0); 686ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 687ae8c6e27Sflorian struct rbnode_type* n; 688ae8c6e27Sflorian #endif 689ae8c6e27Sflorian /* already exists, and for a different purpose perhaps. 690ae8c6e27Sflorian * if mesh_no_list, keep it that way. */ 691ae8c6e27Sflorian if(s) { 692ae8c6e27Sflorian /* make it ignore the cache from now on */ 693ae8c6e27Sflorian if(!s->s.blacklist) 694ae8c6e27Sflorian sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region); 695ae8c6e27Sflorian if(s->s.prefetch_leeway < leeway) 696ae8c6e27Sflorian s->s.prefetch_leeway = leeway; 697ae8c6e27Sflorian return; 698ae8c6e27Sflorian } 699ae8c6e27Sflorian if(!mesh_make_new_space(mesh, NULL)) { 700ae8c6e27Sflorian verbose(VERB_ALGO, "Too many queries. dropped prefetch."); 701ae8c6e27Sflorian mesh->stats_dropped ++; 702ae8c6e27Sflorian return; 703ae8c6e27Sflorian } 704ae8c6e27Sflorian 705*7037e34cSflorian s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0); 706ae8c6e27Sflorian if(!s) { 707ae8c6e27Sflorian log_err("prefetch mesh_state_create: out of memory"); 708ae8c6e27Sflorian return; 709ae8c6e27Sflorian } 710ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 711ae8c6e27Sflorian n = 712ae8c6e27Sflorian #else 713ae8c6e27Sflorian (void) 714ae8c6e27Sflorian #endif 715ae8c6e27Sflorian rbtree_insert(&mesh->all, &s->node); 716ae8c6e27Sflorian log_assert(n != NULL); 717ae8c6e27Sflorian /* set detached (it is now) */ 718ae8c6e27Sflorian mesh->num_detached_states++; 719ae8c6e27Sflorian /* make it ignore the cache */ 720ae8c6e27Sflorian sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region); 721ae8c6e27Sflorian s->s.prefetch_leeway = leeway; 722ae8c6e27Sflorian 723ae8c6e27Sflorian if(s->list_select == mesh_no_list) { 724ae8c6e27Sflorian /* move to either the forever or the jostle_list */ 725ae8c6e27Sflorian if(mesh->num_forever_states < mesh->max_forever_states) { 726ae8c6e27Sflorian mesh->num_forever_states ++; 727ae8c6e27Sflorian mesh_list_insert(s, &mesh->forever_first, 728ae8c6e27Sflorian &mesh->forever_last); 729ae8c6e27Sflorian s->list_select = mesh_forever_list; 730ae8c6e27Sflorian } else { 731ae8c6e27Sflorian mesh_list_insert(s, &mesh->jostle_first, 732ae8c6e27Sflorian &mesh->jostle_last); 733ae8c6e27Sflorian s->list_select = mesh_jostle_list; 734ae8c6e27Sflorian } 735ae8c6e27Sflorian } 7367a05b9dfSflorian s->s.rpz_passthru = rpz_passthru; 737ae8c6e27Sflorian 738ae8c6e27Sflorian if(!run) { 739ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 740ae8c6e27Sflorian n = 741ae8c6e27Sflorian #else 742ae8c6e27Sflorian (void) 743ae8c6e27Sflorian #endif 744ae8c6e27Sflorian rbtree_insert(&mesh->run, &s->run_node); 745ae8c6e27Sflorian log_assert(n != NULL); 746ae8c6e27Sflorian return; 747ae8c6e27Sflorian } 748ae8c6e27Sflorian 749ae8c6e27Sflorian mesh_run(mesh, s, module_event_new, NULL); 750ae8c6e27Sflorian } 751ae8c6e27Sflorian 7527a05b9dfSflorian #ifdef CLIENT_SUBNET 7537a05b9dfSflorian /* Same logic as mesh_schedule_prefetch but tailored to the subnet module logic 7547a05b9dfSflorian * like passing along the comm_reply info. This will be faked into an EDNS 7557a05b9dfSflorian * option for processing by the subnet module if the client has not already 7567a05b9dfSflorian * attached its own ECS data. */ 7577a05b9dfSflorian static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh, 7587a05b9dfSflorian struct query_info* qinfo, uint16_t qflags, time_t leeway, int run, 759d500c338Sflorian int rpz_passthru, struct sockaddr_storage* addr, struct edns_option* edns_list) 760d32eb43cSflorian { 7617a05b9dfSflorian struct mesh_state* s = NULL; 7627a05b9dfSflorian struct edns_option* opt = NULL; 7637a05b9dfSflorian #ifdef UNBOUND_DEBUG 7647a05b9dfSflorian struct rbnode_type* n; 7657a05b9dfSflorian #endif 766*7037e34cSflorian /* Explicitly set the BIT_RD regardless of the client's flags. This is 767*7037e34cSflorian * for a prefetch query (no client attached) but it needs to be treated 768*7037e34cSflorian * as a recursion query. */ 769*7037e34cSflorian uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD); 7707a05b9dfSflorian if(!mesh_make_new_space(mesh, NULL)) { 7717a05b9dfSflorian verbose(VERB_ALGO, "Too many queries. dropped prefetch."); 7727a05b9dfSflorian mesh->stats_dropped ++; 7737a05b9dfSflorian return; 7747a05b9dfSflorian } 7757a05b9dfSflorian 776*7037e34cSflorian s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0); 7777a05b9dfSflorian if(!s) { 7787a05b9dfSflorian log_err("prefetch_subnet mesh_state_create: out of memory"); 7797a05b9dfSflorian return; 7807a05b9dfSflorian } 7817a05b9dfSflorian mesh_state_make_unique(s); 7827a05b9dfSflorian 7837a05b9dfSflorian opt = edns_opt_list_find(edns_list, mesh->env->cfg->client_subnet_opcode); 7847a05b9dfSflorian if(opt) { 7857a05b9dfSflorian /* Use the client's ECS data */ 7867a05b9dfSflorian if(!edns_opt_list_append(&s->s.edns_opts_front_in, opt->opt_code, 7877a05b9dfSflorian opt->opt_len, opt->opt_data, s->s.region)) { 7887a05b9dfSflorian log_err("prefetch_subnet edns_opt_list_append: out of memory"); 7897a05b9dfSflorian return; 7907a05b9dfSflorian } 7917a05b9dfSflorian } else { 792d500c338Sflorian /* Store the client's address. Later in the subnet module, 793d500c338Sflorian * it is decided whether to include an ECS option or not. 794d500c338Sflorian */ 795d500c338Sflorian s->s.client_addr = *addr; 7967a05b9dfSflorian } 7977a05b9dfSflorian #ifdef UNBOUND_DEBUG 7987a05b9dfSflorian n = 7997a05b9dfSflorian #else 8007a05b9dfSflorian (void) 8017a05b9dfSflorian #endif 8027a05b9dfSflorian rbtree_insert(&mesh->all, &s->node); 8037a05b9dfSflorian log_assert(n != NULL); 8047a05b9dfSflorian /* set detached (it is now) */ 8057a05b9dfSflorian mesh->num_detached_states++; 8067a05b9dfSflorian /* make it ignore the cache */ 8077a05b9dfSflorian sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region); 8087a05b9dfSflorian s->s.prefetch_leeway = leeway; 8097a05b9dfSflorian 8107a05b9dfSflorian if(s->list_select == mesh_no_list) { 8117a05b9dfSflorian /* move to either the forever or the jostle_list */ 8127a05b9dfSflorian if(mesh->num_forever_states < mesh->max_forever_states) { 8137a05b9dfSflorian mesh->num_forever_states ++; 8147a05b9dfSflorian mesh_list_insert(s, &mesh->forever_first, 8157a05b9dfSflorian &mesh->forever_last); 8167a05b9dfSflorian s->list_select = mesh_forever_list; 8177a05b9dfSflorian } else { 8187a05b9dfSflorian mesh_list_insert(s, &mesh->jostle_first, 8197a05b9dfSflorian &mesh->jostle_last); 8207a05b9dfSflorian s->list_select = mesh_jostle_list; 8217a05b9dfSflorian } 8227a05b9dfSflorian } 8237a05b9dfSflorian s->s.rpz_passthru = rpz_passthru; 8247a05b9dfSflorian 8257a05b9dfSflorian if(!run) { 8267a05b9dfSflorian #ifdef UNBOUND_DEBUG 8277a05b9dfSflorian n = 8287a05b9dfSflorian #else 8297a05b9dfSflorian (void) 8307a05b9dfSflorian #endif 8317a05b9dfSflorian rbtree_insert(&mesh->run, &s->run_node); 8327a05b9dfSflorian log_assert(n != NULL); 8337a05b9dfSflorian return; 8347a05b9dfSflorian } 8357a05b9dfSflorian 8367a05b9dfSflorian mesh_run(mesh, s, module_event_new, NULL); 8377a05b9dfSflorian } 8387a05b9dfSflorian #endif /* CLIENT_SUBNET */ 8397a05b9dfSflorian 8407a05b9dfSflorian void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo, 8417a05b9dfSflorian uint16_t qflags, time_t leeway, int rpz_passthru, 842d500c338Sflorian struct sockaddr_storage* addr, struct edns_option* opt_list) 8437a05b9dfSflorian { 844d500c338Sflorian (void)addr; 8457a05b9dfSflorian (void)opt_list; 8467a05b9dfSflorian #ifdef CLIENT_SUBNET 847d500c338Sflorian if(addr) 8487a05b9dfSflorian mesh_schedule_prefetch_subnet(mesh, qinfo, qflags, leeway, 1, 849d500c338Sflorian rpz_passthru, addr, opt_list); 8507a05b9dfSflorian else 8517a05b9dfSflorian #endif 8527a05b9dfSflorian mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1, 8537a05b9dfSflorian rpz_passthru); 854d32eb43cSflorian } 855d32eb43cSflorian 856ae8c6e27Sflorian void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, 857ae8c6e27Sflorian struct comm_reply* reply, int what) 858ae8c6e27Sflorian { 859ae8c6e27Sflorian enum module_ev event = module_event_reply; 860ae8c6e27Sflorian e->qstate->reply = reply; 861ae8c6e27Sflorian if(what != NETEVENT_NOERROR) { 862ae8c6e27Sflorian event = module_event_noreply; 863ae8c6e27Sflorian if(what == NETEVENT_CAPSFAIL) 864ae8c6e27Sflorian event = module_event_capsfail; 865ae8c6e27Sflorian } 866ae8c6e27Sflorian mesh_run(mesh, e->qstate->mesh_info, event, e); 867ae8c6e27Sflorian } 868ae8c6e27Sflorian 869ae8c6e27Sflorian struct mesh_state* 870ae8c6e27Sflorian mesh_state_create(struct module_env* env, struct query_info* qinfo, 871ae8c6e27Sflorian struct respip_client_info* cinfo, uint16_t qflags, int prime, 872ae8c6e27Sflorian int valrec) 873ae8c6e27Sflorian { 874ae8c6e27Sflorian struct regional* region = alloc_reg_obtain(env->alloc); 875ae8c6e27Sflorian struct mesh_state* mstate; 876ae8c6e27Sflorian int i; 877ae8c6e27Sflorian if(!region) 878ae8c6e27Sflorian return NULL; 879ae8c6e27Sflorian mstate = (struct mesh_state*)regional_alloc(region, 880ae8c6e27Sflorian sizeof(struct mesh_state)); 881ae8c6e27Sflorian if(!mstate) { 882ae8c6e27Sflorian alloc_reg_release(env->alloc, region); 883ae8c6e27Sflorian return NULL; 884ae8c6e27Sflorian } 885ae8c6e27Sflorian memset(mstate, 0, sizeof(*mstate)); 886ae8c6e27Sflorian mstate->node = *RBTREE_NULL; 887ae8c6e27Sflorian mstate->run_node = *RBTREE_NULL; 888ae8c6e27Sflorian mstate->node.key = mstate; 889ae8c6e27Sflorian mstate->run_node.key = mstate; 890ae8c6e27Sflorian mstate->reply_list = NULL; 891ae8c6e27Sflorian mstate->list_select = mesh_no_list; 892ae8c6e27Sflorian mstate->replies_sent = 0; 893ae8c6e27Sflorian rbtree_init(&mstate->super_set, &mesh_state_ref_compare); 894ae8c6e27Sflorian rbtree_init(&mstate->sub_set, &mesh_state_ref_compare); 895ae8c6e27Sflorian mstate->num_activated = 0; 896ae8c6e27Sflorian mstate->unique = NULL; 897ae8c6e27Sflorian /* init module qstate */ 898ae8c6e27Sflorian mstate->s.qinfo.qtype = qinfo->qtype; 899ae8c6e27Sflorian mstate->s.qinfo.qclass = qinfo->qclass; 900ae8c6e27Sflorian mstate->s.qinfo.local_alias = NULL; 901ae8c6e27Sflorian mstate->s.qinfo.qname_len = qinfo->qname_len; 902ae8c6e27Sflorian mstate->s.qinfo.qname = regional_alloc_init(region, qinfo->qname, 903ae8c6e27Sflorian qinfo->qname_len); 904ae8c6e27Sflorian if(!mstate->s.qinfo.qname) { 905ae8c6e27Sflorian alloc_reg_release(env->alloc, region); 906ae8c6e27Sflorian return NULL; 907ae8c6e27Sflorian } 908ae8c6e27Sflorian if(cinfo) { 909ae8c6e27Sflorian mstate->s.client_info = regional_alloc_init(region, cinfo, 910ae8c6e27Sflorian sizeof(*cinfo)); 911ae8c6e27Sflorian if(!mstate->s.client_info) { 912ae8c6e27Sflorian alloc_reg_release(env->alloc, region); 913ae8c6e27Sflorian return NULL; 914ae8c6e27Sflorian } 915ae8c6e27Sflorian } 916ae8c6e27Sflorian /* remove all weird bits from qflags */ 917ae8c6e27Sflorian mstate->s.query_flags = (qflags & (BIT_RD|BIT_CD)); 918ae8c6e27Sflorian mstate->s.is_priming = prime; 919ae8c6e27Sflorian mstate->s.is_valrec = valrec; 920ae8c6e27Sflorian mstate->s.reply = NULL; 921ae8c6e27Sflorian mstate->s.region = region; 922ae8c6e27Sflorian mstate->s.curmod = 0; 923ae8c6e27Sflorian mstate->s.return_msg = 0; 924ae8c6e27Sflorian mstate->s.return_rcode = LDNS_RCODE_NOERROR; 925ae8c6e27Sflorian mstate->s.env = env; 926ae8c6e27Sflorian mstate->s.mesh_info = mstate; 927ae8c6e27Sflorian mstate->s.prefetch_leeway = 0; 928d32eb43cSflorian mstate->s.serve_expired_data = NULL; 929ae8c6e27Sflorian mstate->s.no_cache_lookup = 0; 930ae8c6e27Sflorian mstate->s.no_cache_store = 0; 931ae8c6e27Sflorian mstate->s.need_refetch = 0; 932ae8c6e27Sflorian mstate->s.was_ratelimited = 0; 9336d08cb1bSflorian mstate->s.qstarttime = *env->now; 934ae8c6e27Sflorian 935ae8c6e27Sflorian /* init modules */ 936ae8c6e27Sflorian for(i=0; i<env->mesh->mods.num; i++) { 937ae8c6e27Sflorian mstate->s.minfo[i] = NULL; 938ae8c6e27Sflorian mstate->s.ext_state[i] = module_state_initial; 939ae8c6e27Sflorian } 940ae8c6e27Sflorian /* init edns option lists */ 941ae8c6e27Sflorian mstate->s.edns_opts_front_in = NULL; 942ae8c6e27Sflorian mstate->s.edns_opts_back_out = NULL; 943ae8c6e27Sflorian mstate->s.edns_opts_back_in = NULL; 944ae8c6e27Sflorian mstate->s.edns_opts_front_out = NULL; 945ae8c6e27Sflorian 946ae8c6e27Sflorian return mstate; 947ae8c6e27Sflorian } 948ae8c6e27Sflorian 949ae8c6e27Sflorian void 950ae8c6e27Sflorian mesh_state_make_unique(struct mesh_state* mstate) 951ae8c6e27Sflorian { 952ae8c6e27Sflorian mstate->unique = mstate; 953ae8c6e27Sflorian } 954ae8c6e27Sflorian 955ae8c6e27Sflorian void 956ae8c6e27Sflorian mesh_state_cleanup(struct mesh_state* mstate) 957ae8c6e27Sflorian { 958ae8c6e27Sflorian struct mesh_area* mesh; 959ae8c6e27Sflorian int i; 960ae8c6e27Sflorian if(!mstate) 961ae8c6e27Sflorian return; 962ae8c6e27Sflorian mesh = mstate->s.env->mesh; 963d32eb43cSflorian /* Stop and delete the serve expired timer */ 964d32eb43cSflorian if(mstate->s.serve_expired_data && mstate->s.serve_expired_data->timer) { 965d32eb43cSflorian comm_timer_delete(mstate->s.serve_expired_data->timer); 966d32eb43cSflorian mstate->s.serve_expired_data->timer = NULL; 967d32eb43cSflorian } 968ae8c6e27Sflorian /* drop unsent replies */ 969ae8c6e27Sflorian if(!mstate->replies_sent) { 970e97c6e54Ssthen struct mesh_reply* rep = mstate->reply_list; 971ae8c6e27Sflorian struct mesh_cb* cb; 972e97c6e54Ssthen /* in tcp_req_info, the mstates linked are removed, but 973e97c6e54Ssthen * the reply_list is now NULL, so the remove-from-empty-list 974e97c6e54Ssthen * takes no time and also it does not do the mesh accounting */ 975e97c6e54Ssthen mstate->reply_list = NULL; 976e97c6e54Ssthen for(; rep; rep=rep->next) { 977096314feSflorian infra_wait_limit_dec(mesh->env->infra_cache, 978096314feSflorian &rep->query_reply, mesh->env->cfg); 979*7037e34cSflorian if(rep->query_reply.c->use_h2) 980*7037e34cSflorian http2_stream_remove_mesh_state(rep->h2_stream); 981ae8c6e27Sflorian comm_point_drop_reply(&rep->query_reply); 982d32eb43cSflorian log_assert(mesh->num_reply_addrs > 0); 983ae8c6e27Sflorian mesh->num_reply_addrs--; 984ae8c6e27Sflorian } 985ae8c6e27Sflorian while((cb = mstate->cb_list)!=NULL) { 986ae8c6e27Sflorian mstate->cb_list = cb->next; 987ae8c6e27Sflorian fptr_ok(fptr_whitelist_mesh_cb(cb->cb)); 988ae8c6e27Sflorian (*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL, 989ae8c6e27Sflorian sec_status_unchecked, NULL, 0); 990d32eb43cSflorian log_assert(mesh->num_reply_addrs > 0); 991ae8c6e27Sflorian mesh->num_reply_addrs--; 992ae8c6e27Sflorian } 993ae8c6e27Sflorian } 994ae8c6e27Sflorian 995ae8c6e27Sflorian /* de-init modules */ 996ae8c6e27Sflorian for(i=0; i<mesh->mods.num; i++) { 997ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_clear(mesh->mods.mod[i]->clear)); 998ae8c6e27Sflorian (*mesh->mods.mod[i]->clear)(&mstate->s, i); 999ae8c6e27Sflorian mstate->s.minfo[i] = NULL; 1000ae8c6e27Sflorian mstate->s.ext_state[i] = module_finished; 1001ae8c6e27Sflorian } 1002ae8c6e27Sflorian alloc_reg_release(mstate->s.env->alloc, mstate->s.region); 1003ae8c6e27Sflorian } 1004ae8c6e27Sflorian 1005ae8c6e27Sflorian void 1006ae8c6e27Sflorian mesh_state_delete(struct module_qstate* qstate) 1007ae8c6e27Sflorian { 1008ae8c6e27Sflorian struct mesh_area* mesh; 1009ae8c6e27Sflorian struct mesh_state_ref* super, ref; 1010ae8c6e27Sflorian struct mesh_state* mstate; 1011ae8c6e27Sflorian if(!qstate) 1012ae8c6e27Sflorian return; 1013ae8c6e27Sflorian mstate = qstate->mesh_info; 1014ae8c6e27Sflorian mesh = mstate->s.env->mesh; 1015ae8c6e27Sflorian mesh_detach_subs(&mstate->s); 1016ae8c6e27Sflorian if(mstate->list_select == mesh_forever_list) { 1017ae8c6e27Sflorian mesh->num_forever_states --; 1018ae8c6e27Sflorian mesh_list_remove(mstate, &mesh->forever_first, 1019ae8c6e27Sflorian &mesh->forever_last); 1020ae8c6e27Sflorian } else if(mstate->list_select == mesh_jostle_list) { 1021ae8c6e27Sflorian mesh_list_remove(mstate, &mesh->jostle_first, 1022ae8c6e27Sflorian &mesh->jostle_last); 1023ae8c6e27Sflorian } 1024ae8c6e27Sflorian if(!mstate->reply_list && !mstate->cb_list 1025ae8c6e27Sflorian && mstate->super_set.count == 0) { 1026ae8c6e27Sflorian log_assert(mesh->num_detached_states > 0); 1027ae8c6e27Sflorian mesh->num_detached_states--; 1028ae8c6e27Sflorian } 1029ae8c6e27Sflorian if(mstate->reply_list || mstate->cb_list) { 1030ae8c6e27Sflorian log_assert(mesh->num_reply_states > 0); 1031ae8c6e27Sflorian mesh->num_reply_states--; 1032ae8c6e27Sflorian } 1033ae8c6e27Sflorian ref.node.key = &ref; 1034ae8c6e27Sflorian ref.s = mstate; 1035ae8c6e27Sflorian RBTREE_FOR(super, struct mesh_state_ref*, &mstate->super_set) { 1036ae8c6e27Sflorian (void)rbtree_delete(&super->s->sub_set, &ref); 1037ae8c6e27Sflorian } 1038ae8c6e27Sflorian (void)rbtree_delete(&mesh->run, mstate); 1039ae8c6e27Sflorian (void)rbtree_delete(&mesh->all, mstate); 1040ae8c6e27Sflorian mesh_state_cleanup(mstate); 1041ae8c6e27Sflorian } 1042ae8c6e27Sflorian 1043ae8c6e27Sflorian /** helper recursive rbtree find routine */ 1044ae8c6e27Sflorian static int 1045ae8c6e27Sflorian find_in_subsub(struct mesh_state* m, struct mesh_state* tofind, size_t *c) 1046ae8c6e27Sflorian { 1047ae8c6e27Sflorian struct mesh_state_ref* r; 1048ae8c6e27Sflorian if((*c)++ > MESH_MAX_SUBSUB) 1049ae8c6e27Sflorian return 1; 1050ae8c6e27Sflorian RBTREE_FOR(r, struct mesh_state_ref*, &m->sub_set) { 1051ae8c6e27Sflorian if(r->s == tofind || find_in_subsub(r->s, tofind, c)) 1052ae8c6e27Sflorian return 1; 1053ae8c6e27Sflorian } 1054ae8c6e27Sflorian return 0; 1055ae8c6e27Sflorian } 1056ae8c6e27Sflorian 1057ae8c6e27Sflorian /** find cycle for already looked up mesh_state */ 1058ae8c6e27Sflorian static int 1059ae8c6e27Sflorian mesh_detect_cycle_found(struct module_qstate* qstate, struct mesh_state* dep_m) 1060ae8c6e27Sflorian { 1061ae8c6e27Sflorian struct mesh_state* cyc_m = qstate->mesh_info; 1062ae8c6e27Sflorian size_t counter = 0; 1063ae8c6e27Sflorian if(!dep_m) 1064ae8c6e27Sflorian return 0; 1065ae8c6e27Sflorian if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m, &counter)) { 1066ae8c6e27Sflorian if(counter > MESH_MAX_SUBSUB) 1067ae8c6e27Sflorian return 2; 1068ae8c6e27Sflorian return 1; 1069ae8c6e27Sflorian } 1070ae8c6e27Sflorian return 0; 1071ae8c6e27Sflorian } 1072ae8c6e27Sflorian 1073ae8c6e27Sflorian void mesh_detach_subs(struct module_qstate* qstate) 1074ae8c6e27Sflorian { 1075ae8c6e27Sflorian struct mesh_area* mesh = qstate->env->mesh; 1076ae8c6e27Sflorian struct mesh_state_ref* ref, lookup; 1077ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1078ae8c6e27Sflorian struct rbnode_type* n; 1079ae8c6e27Sflorian #endif 1080ae8c6e27Sflorian lookup.node.key = &lookup; 1081ae8c6e27Sflorian lookup.s = qstate->mesh_info; 1082ae8c6e27Sflorian RBTREE_FOR(ref, struct mesh_state_ref*, &qstate->mesh_info->sub_set) { 1083ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1084ae8c6e27Sflorian n = 1085ae8c6e27Sflorian #else 1086ae8c6e27Sflorian (void) 1087ae8c6e27Sflorian #endif 1088ae8c6e27Sflorian rbtree_delete(&ref->s->super_set, &lookup); 1089ae8c6e27Sflorian log_assert(n != NULL); /* must have been present */ 1090ae8c6e27Sflorian if(!ref->s->reply_list && !ref->s->cb_list 1091ae8c6e27Sflorian && ref->s->super_set.count == 0) { 1092ae8c6e27Sflorian mesh->num_detached_states++; 1093ae8c6e27Sflorian log_assert(mesh->num_detached_states + 1094ae8c6e27Sflorian mesh->num_reply_states <= mesh->all.count); 1095ae8c6e27Sflorian } 1096ae8c6e27Sflorian } 1097ae8c6e27Sflorian rbtree_init(&qstate->mesh_info->sub_set, &mesh_state_ref_compare); 1098ae8c6e27Sflorian } 1099ae8c6e27Sflorian 1100ae8c6e27Sflorian int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, 1101ae8c6e27Sflorian uint16_t qflags, int prime, int valrec, struct module_qstate** newq, 1102ae8c6e27Sflorian struct mesh_state** sub) 1103ae8c6e27Sflorian { 1104ae8c6e27Sflorian /* find it, if not, create it */ 1105ae8c6e27Sflorian struct mesh_area* mesh = qstate->env->mesh; 1106ae8c6e27Sflorian *sub = mesh_area_find(mesh, NULL, qinfo, qflags, 1107ae8c6e27Sflorian prime, valrec); 1108ae8c6e27Sflorian if(mesh_detect_cycle_found(qstate, *sub)) { 1109ae8c6e27Sflorian verbose(VERB_ALGO, "attach failed, cycle detected"); 1110ae8c6e27Sflorian return 0; 1111ae8c6e27Sflorian } 1112ae8c6e27Sflorian if(!*sub) { 1113ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1114ae8c6e27Sflorian struct rbnode_type* n; 1115ae8c6e27Sflorian #endif 1116ae8c6e27Sflorian /* create a new one */ 1117ae8c6e27Sflorian *sub = mesh_state_create(qstate->env, qinfo, NULL, qflags, prime, 1118ae8c6e27Sflorian valrec); 1119ae8c6e27Sflorian if(!*sub) { 1120ae8c6e27Sflorian log_err("mesh_attach_sub: out of memory"); 1121ae8c6e27Sflorian return 0; 1122ae8c6e27Sflorian } 1123ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1124ae8c6e27Sflorian n = 1125ae8c6e27Sflorian #else 1126ae8c6e27Sflorian (void) 1127ae8c6e27Sflorian #endif 1128ae8c6e27Sflorian rbtree_insert(&mesh->all, &(*sub)->node); 1129ae8c6e27Sflorian log_assert(n != NULL); 1130ae8c6e27Sflorian /* set detached (it is now) */ 1131ae8c6e27Sflorian mesh->num_detached_states++; 1132ae8c6e27Sflorian /* set new query state to run */ 1133ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1134ae8c6e27Sflorian n = 1135ae8c6e27Sflorian #else 1136ae8c6e27Sflorian (void) 1137ae8c6e27Sflorian #endif 1138ae8c6e27Sflorian rbtree_insert(&mesh->run, &(*sub)->run_node); 1139ae8c6e27Sflorian log_assert(n != NULL); 1140ae8c6e27Sflorian *newq = &(*sub)->s; 1141ae8c6e27Sflorian } else 1142ae8c6e27Sflorian *newq = NULL; 1143ae8c6e27Sflorian return 1; 1144ae8c6e27Sflorian } 1145ae8c6e27Sflorian 1146ae8c6e27Sflorian int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, 1147ae8c6e27Sflorian uint16_t qflags, int prime, int valrec, struct module_qstate** newq) 1148ae8c6e27Sflorian { 1149ae8c6e27Sflorian struct mesh_area* mesh = qstate->env->mesh; 1150ae8c6e27Sflorian struct mesh_state* sub = NULL; 1151ae8c6e27Sflorian int was_detached; 1152ae8c6e27Sflorian if(!mesh_add_sub(qstate, qinfo, qflags, prime, valrec, newq, &sub)) 1153ae8c6e27Sflorian return 0; 1154ae8c6e27Sflorian was_detached = (sub->super_set.count == 0); 1155ae8c6e27Sflorian if(!mesh_state_attachment(qstate->mesh_info, sub)) 1156ae8c6e27Sflorian return 0; 1157ae8c6e27Sflorian /* if it was a duplicate attachment, the count was not zero before */ 1158ae8c6e27Sflorian if(!sub->reply_list && !sub->cb_list && was_detached && 1159ae8c6e27Sflorian sub->super_set.count == 1) { 1160ae8c6e27Sflorian /* it used to be detached, before this one got added */ 1161ae8c6e27Sflorian log_assert(mesh->num_detached_states > 0); 1162ae8c6e27Sflorian mesh->num_detached_states--; 1163ae8c6e27Sflorian } 1164ae8c6e27Sflorian /* *newq will be run when inited after the current module stops */ 1165ae8c6e27Sflorian return 1; 1166ae8c6e27Sflorian } 1167ae8c6e27Sflorian 1168ae8c6e27Sflorian int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub) 1169ae8c6e27Sflorian { 1170ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1171ae8c6e27Sflorian struct rbnode_type* n; 1172ae8c6e27Sflorian #endif 1173ae8c6e27Sflorian struct mesh_state_ref* subref; /* points to sub, inserted in super */ 1174ae8c6e27Sflorian struct mesh_state_ref* superref; /* points to super, inserted in sub */ 1175ae8c6e27Sflorian if( !(subref = regional_alloc(super->s.region, 1176ae8c6e27Sflorian sizeof(struct mesh_state_ref))) || 1177ae8c6e27Sflorian !(superref = regional_alloc(sub->s.region, 1178ae8c6e27Sflorian sizeof(struct mesh_state_ref))) ) { 1179ae8c6e27Sflorian log_err("mesh_state_attachment: out of memory"); 1180ae8c6e27Sflorian return 0; 1181ae8c6e27Sflorian } 1182ae8c6e27Sflorian superref->node.key = superref; 1183ae8c6e27Sflorian superref->s = super; 1184ae8c6e27Sflorian subref->node.key = subref; 1185ae8c6e27Sflorian subref->s = sub; 1186ae8c6e27Sflorian if(!rbtree_insert(&sub->super_set, &superref->node)) { 1187ae8c6e27Sflorian /* this should not happen, iterator and validator do not 1188ae8c6e27Sflorian * attach subqueries that are identical. */ 1189ae8c6e27Sflorian /* already attached, we are done, nothing todo. 1190ae8c6e27Sflorian * since superref and subref already allocated in region, 1191ae8c6e27Sflorian * we cannot free them */ 1192ae8c6e27Sflorian return 1; 1193ae8c6e27Sflorian } 1194ae8c6e27Sflorian #ifdef UNBOUND_DEBUG 1195ae8c6e27Sflorian n = 1196ae8c6e27Sflorian #else 1197ae8c6e27Sflorian (void) 1198ae8c6e27Sflorian #endif 1199ae8c6e27Sflorian rbtree_insert(&super->sub_set, &subref->node); 1200ae8c6e27Sflorian log_assert(n != NULL); /* we checked above if statement, the reverse 1201ae8c6e27Sflorian administration should not fail now, unless they are out of sync */ 1202ae8c6e27Sflorian return 1; 1203ae8c6e27Sflorian } 1204ae8c6e27Sflorian 1205ae8c6e27Sflorian /** 1206ae8c6e27Sflorian * callback results to mesh cb entry 1207ae8c6e27Sflorian * @param m: mesh state to send it for. 1208ae8c6e27Sflorian * @param rcode: if not 0, error code. 1209ae8c6e27Sflorian * @param rep: reply to send (or NULL if rcode is set). 1210ae8c6e27Sflorian * @param r: callback entry 1211a8eaceedSflorian * @param start_time: the time to pass to callback functions, it is 0 or 1212a8eaceedSflorian * a value from one of the packets if the mesh state had packets. 1213ae8c6e27Sflorian */ 1214ae8c6e27Sflorian static void 1215ae8c6e27Sflorian mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, 1216a8eaceedSflorian struct mesh_cb* r, struct timeval* start_time) 1217ae8c6e27Sflorian { 1218ae8c6e27Sflorian int secure; 1219ae8c6e27Sflorian char* reason = NULL; 1220ae8c6e27Sflorian int was_ratelimited = m->s.was_ratelimited; 1221ae8c6e27Sflorian /* bogus messages are not made into servfail, sec_status passed 1222ae8c6e27Sflorian * to the callback function */ 1223ae8c6e27Sflorian if(rep && rep->security == sec_status_secure) 1224ae8c6e27Sflorian secure = 1; 1225ae8c6e27Sflorian else secure = 0; 1226ae8c6e27Sflorian if(!rep && rcode == LDNS_RCODE_NOERROR) 1227ae8c6e27Sflorian rcode = LDNS_RCODE_SERVFAIL; 1228d500c338Sflorian if(!rcode && rep && (rep->security == sec_status_bogus || 1229ae8c6e27Sflorian rep->security == sec_status_secure_sentinel_fail)) { 1230096314feSflorian if(!(reason = errinf_to_str_bogus(&m->s, NULL))) 1231ae8c6e27Sflorian rcode = LDNS_RCODE_SERVFAIL; 1232ae8c6e27Sflorian } 1233ae8c6e27Sflorian /* send the reply */ 1234ae8c6e27Sflorian if(rcode) { 1235ae8c6e27Sflorian if(rcode == LDNS_RCODE_SERVFAIL) { 1236ae8c6e27Sflorian if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, 1237a8eaceedSflorian rep, rcode, &r->edns, NULL, m->s.region, start_time)) 1238a1a7ba80Sflorian r->edns.opt_list_inplace_cb_out = NULL; 1239ae8c6e27Sflorian } else { 1240ae8c6e27Sflorian if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, 1241a8eaceedSflorian &r->edns, NULL, m->s.region, start_time)) 1242a1a7ba80Sflorian r->edns.opt_list_inplace_cb_out = NULL; 1243ae8c6e27Sflorian } 1244ae8c6e27Sflorian fptr_ok(fptr_whitelist_mesh_cb(r->cb)); 1245ae8c6e27Sflorian (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL, 1246ae8c6e27Sflorian was_ratelimited); 1247ae8c6e27Sflorian } else { 1248ae8c6e27Sflorian size_t udp_size = r->edns.udp_size; 1249ae8c6e27Sflorian sldns_buffer_clear(r->buf); 1250ae8c6e27Sflorian r->edns.edns_version = EDNS_ADVERTISED_VERSION; 1251ae8c6e27Sflorian r->edns.udp_size = EDNS_ADVERTISED_SIZE; 1252ae8c6e27Sflorian r->edns.ext_rcode = 0; 1253ae8c6e27Sflorian r->edns.bits &= EDNS_DO; 125454cc57acSflorian if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO)) 125554cc57acSflorian r->edns.edns_present = 0; 1256ae8c6e27Sflorian 1257ae8c6e27Sflorian if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, 1258a8eaceedSflorian LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region, start_time) || 1259ae8c6e27Sflorian !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 1260ae8c6e27Sflorian r->qflags, r->buf, 0, 1, 1261ae8c6e27Sflorian m->s.env->scratch, udp_size, &r->edns, 1262ae8c6e27Sflorian (int)(r->edns.bits & EDNS_DO), secure)) 1263ae8c6e27Sflorian { 1264ae8c6e27Sflorian fptr_ok(fptr_whitelist_mesh_cb(r->cb)); 1265ae8c6e27Sflorian (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, 1266ae8c6e27Sflorian sec_status_unchecked, NULL, 0); 1267ae8c6e27Sflorian } else { 1268ae8c6e27Sflorian fptr_ok(fptr_whitelist_mesh_cb(r->cb)); 1269ae8c6e27Sflorian (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, 1270d500c338Sflorian (rep?rep->security:sec_status_unchecked), 1271d500c338Sflorian reason, was_ratelimited); 1272ae8c6e27Sflorian } 1273ae8c6e27Sflorian } 1274ae8c6e27Sflorian free(reason); 1275d32eb43cSflorian log_assert(m->s.env->mesh->num_reply_addrs > 0); 1276ae8c6e27Sflorian m->s.env->mesh->num_reply_addrs--; 1277ae8c6e27Sflorian } 1278ae8c6e27Sflorian 1279a1a7ba80Sflorian static inline int 1280a1a7ba80Sflorian mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m) 1281a1a7ba80Sflorian { 1282a1a7ba80Sflorian struct respip_action_info const* respip_info = m->s.respip_action_info; 128354cc57acSflorian return (respip_info == NULL 1284a1a7ba80Sflorian ? 0 1285a1a7ba80Sflorian : (respip_info->rpz_used 1286a1a7ba80Sflorian && !respip_info->rpz_disabled 128754cc57acSflorian && respip_info->action == respip_truncate)) 128854cc57acSflorian || m->s.tcp_required; 1289a1a7ba80Sflorian } 1290a1a7ba80Sflorian 1291a1a7ba80Sflorian static inline int 1292d500c338Sflorian mesh_is_udp(struct mesh_reply const* r) 1293d500c338Sflorian { 1294a1a7ba80Sflorian return r->query_reply.c->type == comm_udp; 1295a1a7ba80Sflorian } 1296a1a7ba80Sflorian 1297d500c338Sflorian static inline void 1298d500c338Sflorian mesh_find_and_attach_ede_and_reason(struct mesh_state* m, 1299d500c338Sflorian struct reply_info* rep, struct mesh_reply* r) 1300d500c338Sflorian { 1301d500c338Sflorian /* OLD note: 1302d500c338Sflorian * During validation the EDE code can be received via two 1303d500c338Sflorian * code paths. One code path fills the reply_info EDE, and 1304d500c338Sflorian * the other fills it in the errinf_strlist. These paths 1305d500c338Sflorian * intersect at some points, but where is opaque due to 1306d500c338Sflorian * the complexity of the validator. At the time of writing 1307d500c338Sflorian * we make the choice to prefer the EDE from errinf_strlist 1308d500c338Sflorian * but a compelling reason to do otherwise is just as valid 1309d500c338Sflorian * NEW note: 1310d500c338Sflorian * The compelling reason is that with caching support, the value 1311d500c338Sflorian * in the reply_info is cached. 1312d500c338Sflorian * The reason members of the reply_info struct should be 1313d500c338Sflorian * updated as they are already cached. No reason to 1314d500c338Sflorian * try and find the EDE information in errinf anymore. 1315d500c338Sflorian */ 1316d500c338Sflorian if(rep->reason_bogus != LDNS_EDE_NONE) { 1317d500c338Sflorian edns_opt_list_append_ede(&r->edns.opt_list_out, 1318d500c338Sflorian m->s.region, rep->reason_bogus, rep->reason_bogus_str); 1319d500c338Sflorian } 1320d500c338Sflorian } 1321d500c338Sflorian 1322ae8c6e27Sflorian /** 1323ae8c6e27Sflorian * Send reply to mesh reply entry 1324ae8c6e27Sflorian * @param m: mesh state to send it for. 1325ae8c6e27Sflorian * @param rcode: if not 0, error code. 1326ae8c6e27Sflorian * @param rep: reply to send (or NULL if rcode is set). 1327ae8c6e27Sflorian * @param r: reply entry 1328e97c6e54Ssthen * @param r_buffer: buffer to use for reply entry. 1329ae8c6e27Sflorian * @param prev: previous reply, already has its answer encoded in buffer. 1330e97c6e54Ssthen * @param prev_buffer: buffer for previous reply. 1331ae8c6e27Sflorian */ 1332ae8c6e27Sflorian static void 1333ae8c6e27Sflorian mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, 1334e97c6e54Ssthen struct mesh_reply* r, struct sldns_buffer* r_buffer, 1335e97c6e54Ssthen struct mesh_reply* prev, struct sldns_buffer* prev_buffer) 1336ae8c6e27Sflorian { 1337ae8c6e27Sflorian struct timeval end_time; 1338ae8c6e27Sflorian struct timeval duration; 1339ae8c6e27Sflorian int secure; 1340853e076fSflorian /* briefly set the replylist to null in case the 1341853e076fSflorian * meshsendreply calls tcpreqinfo sendreply that 1342853e076fSflorian * comm_point_drops because of size, and then the 1343853e076fSflorian * null stops the mesh state remove and thus 1344853e076fSflorian * reply_list modification and accounting */ 1345853e076fSflorian struct mesh_reply* rlist = m->reply_list; 1346a1a7ba80Sflorian 1347a1a7ba80Sflorian /* rpz: apply actions */ 1348a1a7ba80Sflorian rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m) 1349a1a7ba80Sflorian ? (rcode|BIT_TC) : rcode; 1350a1a7ba80Sflorian 1351ae8c6e27Sflorian /* examine security status */ 1352ae8c6e27Sflorian if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) || 1353ae8c6e27Sflorian m->s.env->cfg->ignore_cd) && rep && 1354ae8c6e27Sflorian (rep->security <= sec_status_bogus || 1355ae8c6e27Sflorian rep->security == sec_status_secure_sentinel_fail)) { 1356ae8c6e27Sflorian rcode = LDNS_RCODE_SERVFAIL; 1357ae8c6e27Sflorian if(m->s.env->cfg->stat_extended) 1358ae8c6e27Sflorian m->s.env->mesh->ans_bogus++; 1359ae8c6e27Sflorian } 1360ae8c6e27Sflorian if(rep && rep->security == sec_status_secure) 1361ae8c6e27Sflorian secure = 1; 1362ae8c6e27Sflorian else secure = 0; 1363ae8c6e27Sflorian if(!rep && rcode == LDNS_RCODE_NOERROR) 1364ae8c6e27Sflorian rcode = LDNS_RCODE_SERVFAIL; 1365f4f0f0ceSflorian if(r->query_reply.c->use_h2) { 1366f4f0f0ceSflorian r->query_reply.c->h2_stream = r->h2_stream; 1367f4f0f0ceSflorian /* Mesh reply won't exist for long anymore. Make it impossible 1368f4f0f0ceSflorian * for HTTP/2 stream to refer to mesh state, in case 1369f4f0f0ceSflorian * connection gets cleanup before HTTP/2 stream close. */ 1370f4f0f0ceSflorian r->h2_stream->mesh_state = NULL; 1371f4f0f0ceSflorian } 1372ae8c6e27Sflorian /* send the reply */ 1373853e076fSflorian /* We don't reuse the encoded answer if: 1374853e076fSflorian * - either the previous or current response has a local alias. We could 1375853e076fSflorian * compare the alias records and still reuse the previous answer if they 1376853e076fSflorian * are the same, but that would be complicated and error prone for the 1377853e076fSflorian * relatively minor case. So we err on the side of safety. 1378853e076fSflorian * - there are registered callback functions for the given rcode, as these 1379853e076fSflorian * need to be called for each reply. */ 1380853e076fSflorian if(((rcode != LDNS_RCODE_SERVFAIL && 1381853e076fSflorian !m->s.env->inplace_cb_lists[inplace_cb_reply]) || 1382853e076fSflorian (rcode == LDNS_RCODE_SERVFAIL && 1383853e076fSflorian !m->s.env->inplace_cb_lists[inplace_cb_reply_servfail])) && 1384853e076fSflorian prev && prev_buffer && prev->qflags == r->qflags && 1385ae8c6e27Sflorian !prev->local_alias && !r->local_alias && 1386ae8c6e27Sflorian prev->edns.edns_present == r->edns.edns_present && 1387ae8c6e27Sflorian prev->edns.bits == r->edns.bits && 1388ae8c6e27Sflorian prev->edns.udp_size == r->edns.udp_size && 1389a1a7ba80Sflorian edns_opt_list_compare(prev->edns.opt_list_out, r->edns.opt_list_out) == 0 && 1390a1a7ba80Sflorian edns_opt_list_compare(prev->edns.opt_list_inplace_cb_out, r->edns.opt_list_inplace_cb_out) == 0 1391a1a7ba80Sflorian ) { 1392ae8c6e27Sflorian /* if the previous reply is identical to this one, fix ID */ 1393e97c6e54Ssthen if(prev_buffer != r_buffer) 1394e97c6e54Ssthen sldns_buffer_copy(r_buffer, prev_buffer); 1395e97c6e54Ssthen sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t)); 1396e97c6e54Ssthen sldns_buffer_write_at(r_buffer, 12, r->qname, 1397e97c6e54Ssthen m->s.qinfo.qname_len); 1398853e076fSflorian m->reply_list = NULL; 1399ae8c6e27Sflorian comm_point_send_reply(&r->query_reply); 1400853e076fSflorian m->reply_list = rlist; 1401ae8c6e27Sflorian } else if(rcode) { 1402ae8c6e27Sflorian m->s.qinfo.qname = r->qname; 1403ae8c6e27Sflorian m->s.qinfo.local_alias = r->local_alias; 1404ae8c6e27Sflorian if(rcode == LDNS_RCODE_SERVFAIL) { 1405ae8c6e27Sflorian if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, 1406a8eaceedSflorian rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time)) 1407a1a7ba80Sflorian r->edns.opt_list_inplace_cb_out = NULL; 1408ae8c6e27Sflorian } else { 1409ae8c6e27Sflorian if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, 1410a8eaceedSflorian &r->edns, &r->query_reply, m->s.region, &r->start_time)) 1411a1a7ba80Sflorian r->edns.opt_list_inplace_cb_out = NULL; 1412ae8c6e27Sflorian } 1413d500c338Sflorian /* Send along EDE EDNS0 option when SERVFAILing; usually 1414d500c338Sflorian * DNSSEC validation failures */ 1415d500c338Sflorian /* Since we are SERVFAILing here, CD bit and rep->security 1416d500c338Sflorian * is already handled. */ 1417d500c338Sflorian if(m->s.env->cfg->ede && rep) { 1418d500c338Sflorian mesh_find_and_attach_ede_and_reason(m, rep, r); 14197a05b9dfSflorian } 1420e97c6e54Ssthen error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, 1421e97c6e54Ssthen r->qflags, &r->edns); 1422853e076fSflorian m->reply_list = NULL; 1423ae8c6e27Sflorian comm_point_send_reply(&r->query_reply); 1424853e076fSflorian m->reply_list = rlist; 1425ae8c6e27Sflorian } else { 1426ae8c6e27Sflorian size_t udp_size = r->edns.udp_size; 1427ae8c6e27Sflorian r->edns.edns_version = EDNS_ADVERTISED_VERSION; 1428ae8c6e27Sflorian r->edns.udp_size = EDNS_ADVERTISED_SIZE; 1429ae8c6e27Sflorian r->edns.ext_rcode = 0; 1430ae8c6e27Sflorian r->edns.bits &= EDNS_DO; 143154cc57acSflorian if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO)) 143254cc57acSflorian r->edns.edns_present = 0; 1433ae8c6e27Sflorian m->s.qinfo.qname = r->qname; 1434ae8c6e27Sflorian m->s.qinfo.local_alias = r->local_alias; 1435d500c338Sflorian 1436d500c338Sflorian /* Attach EDE without SERVFAIL if the validation failed. 1437d500c338Sflorian * Need to explicitly check for rep->security otherwise failed 1438d500c338Sflorian * validation paths may attach to a secure answer. */ 1439d500c338Sflorian if(m->s.env->cfg->ede && rep && 1440d500c338Sflorian (rep->security <= sec_status_bogus || 1441d500c338Sflorian rep->security == sec_status_secure_sentinel_fail)) { 1442d500c338Sflorian mesh_find_and_attach_ede_and_reason(m, rep, r); 1443d500c338Sflorian } 1444d500c338Sflorian 1445ae8c6e27Sflorian if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, 1446a8eaceedSflorian LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) || 1447ae8c6e27Sflorian !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 1448e97c6e54Ssthen r->qflags, r_buffer, 0, 1, m->s.env->scratch, 1449e97c6e54Ssthen udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO), 1450e97c6e54Ssthen secure)) 1451ae8c6e27Sflorian { 1452ae8c6e27Sflorian if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, 1453a8eaceedSflorian rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time)) 1454a1a7ba80Sflorian r->edns.opt_list_inplace_cb_out = NULL; 14557a05b9dfSflorian /* internal server error (probably malloc failure) so no 14567a05b9dfSflorian * EDE (RFC8914) needed */ 1457e97c6e54Ssthen error_encode(r_buffer, LDNS_RCODE_SERVFAIL, 1458e97c6e54Ssthen &m->s.qinfo, r->qid, r->qflags, &r->edns); 1459ae8c6e27Sflorian } 1460853e076fSflorian m->reply_list = NULL; 1461ae8c6e27Sflorian comm_point_send_reply(&r->query_reply); 1462853e076fSflorian m->reply_list = rlist; 1463ae8c6e27Sflorian } 1464096314feSflorian infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply, 1465096314feSflorian m->s.env->cfg); 1466ae8c6e27Sflorian /* account */ 1467d32eb43cSflorian log_assert(m->s.env->mesh->num_reply_addrs > 0); 1468ae8c6e27Sflorian m->s.env->mesh->num_reply_addrs--; 1469ae8c6e27Sflorian end_time = *m->s.env->now_tv; 1470ae8c6e27Sflorian timeval_subtract(&duration, &end_time, &r->start_time); 1471ae8c6e27Sflorian verbose(VERB_ALGO, "query took " ARG_LL "d.%6.6d sec", 1472ae8c6e27Sflorian (long long)duration.tv_sec, (int)duration.tv_usec); 1473ae8c6e27Sflorian m->s.env->mesh->replies_sent++; 1474ae8c6e27Sflorian timeval_add(&m->s.env->mesh->replies_sum_wait, &duration); 1475ae8c6e27Sflorian timehist_insert(m->s.env->mesh->histogram, &duration); 1476ae8c6e27Sflorian if(m->s.env->cfg->stat_extended) { 1477e97c6e54Ssthen uint16_t rc = FLAGS_GET_RCODE(sldns_buffer_read_u16_at( 1478e97c6e54Ssthen r_buffer, 2)); 1479ae8c6e27Sflorian if(secure) m->s.env->mesh->ans_secure++; 1480ae8c6e27Sflorian m->s.env->mesh->ans_rcode[ rc ] ++; 1481e97c6e54Ssthen if(rc == 0 && LDNS_ANCOUNT(sldns_buffer_begin(r_buffer)) == 0) 1482ae8c6e27Sflorian m->s.env->mesh->ans_nodata++; 1483ae8c6e27Sflorian } 1484ae8c6e27Sflorian /* Log reply sent */ 1485ae8c6e27Sflorian if(m->s.env->cfg->log_replies) { 14865c45b740Sflorian log_reply_info(NO_VERBOSE, &m->s.qinfo, 14875c45b740Sflorian &r->query_reply.client_addr, 148854cc57acSflorian r->query_reply.client_addrlen, duration, 0, r_buffer, 1489096314feSflorian (m->s.env->cfg->log_destaddr?(void*)r->query_reply.c->socket->addr:NULL), 149054cc57acSflorian r->query_reply.c->type); 1491ae8c6e27Sflorian } 1492ae8c6e27Sflorian } 1493ae8c6e27Sflorian 1494ae8c6e27Sflorian void mesh_query_done(struct mesh_state* mstate) 1495ae8c6e27Sflorian { 1496e47fef9eSflorian struct mesh_reply* r; 1497ae8c6e27Sflorian struct mesh_reply* prev = NULL; 1498e97c6e54Ssthen struct sldns_buffer* prev_buffer = NULL; 1499ae8c6e27Sflorian struct mesh_cb* c; 1500ae8c6e27Sflorian struct reply_info* rep = (mstate->s.return_msg? 1501ae8c6e27Sflorian mstate->s.return_msg->rep:NULL); 1502a8eaceedSflorian struct timeval tv = {0, 0}; 1503d500c338Sflorian int i = 0; 1504d32eb43cSflorian /* No need for the serve expired timer anymore; we are going to reply. */ 1505d32eb43cSflorian if(mstate->s.serve_expired_data) { 1506d32eb43cSflorian comm_timer_delete(mstate->s.serve_expired_data->timer); 1507d32eb43cSflorian mstate->s.serve_expired_data->timer = NULL; 1508d32eb43cSflorian } 1509d32eb43cSflorian if(mstate->s.return_rcode == LDNS_RCODE_SERVFAIL || 1510d32eb43cSflorian (rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) { 1511a1a7ba80Sflorian /* we are SERVFAILing; check for expired answer here */ 1512d32eb43cSflorian mesh_serve_expired_callback(mstate); 1513d32eb43cSflorian if((mstate->reply_list || mstate->cb_list) 1514ae8c6e27Sflorian && mstate->s.env->cfg->log_servfail 1515ae8c6e27Sflorian && !mstate->s.env->cfg->val_log_squelch) { 1516ae8c6e27Sflorian char* err = errinf_to_str_servfail(&mstate->s); 1517096314feSflorian if(err) { log_err("%s", err); } 1518ae8c6e27Sflorian } 1519d32eb43cSflorian } 1520e47fef9eSflorian for(r = mstate->reply_list; r; r = r->next) { 1521096314feSflorian struct timeval old; 1522096314feSflorian timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); 1523096314feSflorian if(mstate->s.env->cfg->discard_timeout != 0 && 1524096314feSflorian ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > 1525096314feSflorian mstate->s.env->cfg->discard_timeout) { 1526096314feSflorian /* Drop the reply, it is too old */ 1527096314feSflorian /* briefly set the reply_list to NULL, so that the 1528096314feSflorian * tcp req info cleanup routine that calls the mesh 1529096314feSflorian * to deregister the meshstate for it is not done 1530096314feSflorian * because the list is NULL and also accounting is not 1531096314feSflorian * done there, but instead we do that here. */ 1532096314feSflorian struct mesh_reply* reply_list = mstate->reply_list; 1533096314feSflorian verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); 1534096314feSflorian infra_wait_limit_dec(mstate->s.env->infra_cache, 1535096314feSflorian &r->query_reply, mstate->s.env->cfg); 1536096314feSflorian mstate->reply_list = NULL; 1537*7037e34cSflorian if(r->query_reply.c->use_h2) 1538*7037e34cSflorian http2_stream_remove_mesh_state(r->h2_stream); 1539096314feSflorian comm_point_drop_reply(&r->query_reply); 1540096314feSflorian mstate->reply_list = reply_list; 1541096314feSflorian mstate->s.env->mesh->stats_dropped++; 1542096314feSflorian continue; 1543096314feSflorian } 1544096314feSflorian 1545d500c338Sflorian i++; 1546a8eaceedSflorian tv = r->start_time; 1547a8eaceedSflorian 1548ae8c6e27Sflorian /* if a response-ip address block has been stored the 1549ae8c6e27Sflorian * information should be logged for each client. */ 1550ae8c6e27Sflorian if(mstate->s.respip_action_info && 1551ae8c6e27Sflorian mstate->s.respip_action_info->addrinfo) { 1552d32eb43cSflorian respip_inform_print(mstate->s.respip_action_info, 1553ae8c6e27Sflorian r->qname, mstate->s.qinfo.qtype, 1554ae8c6e27Sflorian mstate->s.qinfo.qclass, r->local_alias, 15555c45b740Sflorian &r->query_reply.client_addr, 15565c45b740Sflorian r->query_reply.client_addrlen); 1557ae8c6e27Sflorian } 1558ae8c6e27Sflorian 1559ae8c6e27Sflorian /* if this query is determined to be dropped during the 1560ae8c6e27Sflorian * mesh processing, this is the point to take that action. */ 1561d32eb43cSflorian if(mstate->s.is_drop) { 1562e47fef9eSflorian /* briefly set the reply_list to NULL, so that the 1563e47fef9eSflorian * tcp req info cleanup routine that calls the mesh 1564e47fef9eSflorian * to deregister the meshstate for it is not done 1565e47fef9eSflorian * because the list is NULL and also accounting is not 1566e47fef9eSflorian * done there, but instead we do that here. */ 1567e47fef9eSflorian struct mesh_reply* reply_list = mstate->reply_list; 1568096314feSflorian infra_wait_limit_dec(mstate->s.env->infra_cache, 1569096314feSflorian &r->query_reply, mstate->s.env->cfg); 1570e47fef9eSflorian mstate->reply_list = NULL; 1571*7037e34cSflorian if(r->query_reply.c->use_h2) { 1572*7037e34cSflorian http2_stream_remove_mesh_state(r->h2_stream); 1573*7037e34cSflorian } 1574ae8c6e27Sflorian comm_point_drop_reply(&r->query_reply); 1575e47fef9eSflorian mstate->reply_list = reply_list; 1576d32eb43cSflorian } else { 1577e97c6e54Ssthen struct sldns_buffer* r_buffer = r->query_reply.c->buffer; 15789b465e50Sflorian if(r->query_reply.c->tcp_req_info) { 1579e97c6e54Ssthen r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; 15809b465e50Sflorian prev_buffer = NULL; 15819b465e50Sflorian } 1582ae8c6e27Sflorian mesh_send_reply(mstate, mstate->s.return_rcode, rep, 1583e97c6e54Ssthen r, r_buffer, prev, prev_buffer); 15849b465e50Sflorian if(r->query_reply.c->tcp_req_info) { 1585e97c6e54Ssthen tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); 15869b465e50Sflorian r_buffer = NULL; 15879b465e50Sflorian } 1588*7037e34cSflorian /* mesh_send_reply removed mesh state from 1589*7037e34cSflorian * http2_stream. */ 1590ae8c6e27Sflorian prev = r; 1591e97c6e54Ssthen prev_buffer = r_buffer; 1592ae8c6e27Sflorian } 1593ae8c6e27Sflorian } 1594d500c338Sflorian /* Account for each reply sent. */ 1595d500c338Sflorian if(i > 0 && mstate->s.respip_action_info && 1596d500c338Sflorian mstate->s.respip_action_info->addrinfo && 1597d500c338Sflorian mstate->s.env->cfg->stat_extended && 1598d500c338Sflorian mstate->s.respip_action_info->rpz_used) { 1599d500c338Sflorian if(mstate->s.respip_action_info->rpz_disabled) 1600d500c338Sflorian mstate->s.env->mesh->rpz_action[RPZ_DISABLED_ACTION] += i; 1601d500c338Sflorian if(mstate->s.respip_action_info->rpz_cname_override) 1602d500c338Sflorian mstate->s.env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION] += i; 1603d500c338Sflorian else 1604d500c338Sflorian mstate->s.env->mesh->rpz_action[respip_action_to_rpz_action( 1605d500c338Sflorian mstate->s.respip_action_info->action)] += i; 1606d500c338Sflorian } 1607d500c338Sflorian if(!mstate->s.is_drop && i > 0) { 1608d500c338Sflorian if(mstate->s.env->cfg->stat_extended 1609d500c338Sflorian && mstate->s.is_cachedb_answer) { 1610d500c338Sflorian mstate->s.env->mesh->ans_cachedb += i; 1611d500c338Sflorian } 1612d500c338Sflorian } 1613d500c338Sflorian 1614d500c338Sflorian /* Mesh area accounting */ 1615e47fef9eSflorian if(mstate->reply_list) { 1616e47fef9eSflorian mstate->reply_list = NULL; 1617e47fef9eSflorian if(!mstate->reply_list && !mstate->cb_list) { 1618e47fef9eSflorian /* was a reply state, not anymore */ 1619e47fef9eSflorian log_assert(mstate->s.env->mesh->num_reply_states > 0); 1620e47fef9eSflorian mstate->s.env->mesh->num_reply_states--; 1621e47fef9eSflorian } 1622e47fef9eSflorian if(!mstate->reply_list && !mstate->cb_list && 1623e47fef9eSflorian mstate->super_set.count == 0) 1624e47fef9eSflorian mstate->s.env->mesh->num_detached_states++; 1625e47fef9eSflorian } 1626ae8c6e27Sflorian mstate->replies_sent = 1; 1627d500c338Sflorian 1628ae8c6e27Sflorian while((c = mstate->cb_list) != NULL) { 1629ae8c6e27Sflorian /* take this cb off the list; so that the list can be 1630ae8c6e27Sflorian * changed, eg. by adds from the callback routine */ 1631ae8c6e27Sflorian if(!mstate->reply_list && mstate->cb_list && !c->next) { 1632ae8c6e27Sflorian /* was a reply state, not anymore */ 1633d32eb43cSflorian log_assert(mstate->s.env->mesh->num_reply_states > 0); 1634ae8c6e27Sflorian mstate->s.env->mesh->num_reply_states--; 1635ae8c6e27Sflorian } 1636ae8c6e27Sflorian mstate->cb_list = c->next; 1637ae8c6e27Sflorian if(!mstate->reply_list && !mstate->cb_list && 1638ae8c6e27Sflorian mstate->super_set.count == 0) 1639ae8c6e27Sflorian mstate->s.env->mesh->num_detached_states++; 1640a8eaceedSflorian mesh_do_callback(mstate, mstate->s.return_rcode, rep, c, &tv); 1641ae8c6e27Sflorian } 1642ae8c6e27Sflorian } 1643ae8c6e27Sflorian 1644ae8c6e27Sflorian void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate) 1645ae8c6e27Sflorian { 1646ae8c6e27Sflorian struct mesh_state_ref* ref; 1647ae8c6e27Sflorian RBTREE_FOR(ref, struct mesh_state_ref*, &mstate->super_set) 1648ae8c6e27Sflorian { 1649ae8c6e27Sflorian /* make super runnable */ 1650ae8c6e27Sflorian (void)rbtree_insert(&mesh->run, &ref->s->run_node); 1651ae8c6e27Sflorian /* callback the function to inform super of result */ 1652ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_inform_super( 1653ae8c6e27Sflorian mesh->mods.mod[ref->s->s.curmod]->inform_super)); 1654ae8c6e27Sflorian (*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s, 1655ae8c6e27Sflorian ref->s->s.curmod, &ref->s->s); 1656ae8c6e27Sflorian /* copy state that is always relevant to super */ 1657ae8c6e27Sflorian copy_state_to_super(&mstate->s, ref->s->s.curmod, &ref->s->s); 1658ae8c6e27Sflorian } 1659ae8c6e27Sflorian } 1660ae8c6e27Sflorian 1661ae8c6e27Sflorian struct mesh_state* mesh_area_find(struct mesh_area* mesh, 1662ae8c6e27Sflorian struct respip_client_info* cinfo, struct query_info* qinfo, 1663ae8c6e27Sflorian uint16_t qflags, int prime, int valrec) 1664ae8c6e27Sflorian { 1665ae8c6e27Sflorian struct mesh_state key; 1666ae8c6e27Sflorian struct mesh_state* result; 1667ae8c6e27Sflorian 1668ae8c6e27Sflorian key.node.key = &key; 1669ae8c6e27Sflorian key.s.is_priming = prime; 1670ae8c6e27Sflorian key.s.is_valrec = valrec; 1671ae8c6e27Sflorian key.s.qinfo = *qinfo; 1672ae8c6e27Sflorian key.s.query_flags = qflags; 1673ae8c6e27Sflorian /* We are searching for a similar mesh state when we DO want to 1674ae8c6e27Sflorian * aggregate the state. Thus unique is set to NULL. (default when we 1675ae8c6e27Sflorian * desire aggregation).*/ 1676ae8c6e27Sflorian key.unique = NULL; 1677ae8c6e27Sflorian key.s.client_info = cinfo; 1678ae8c6e27Sflorian 1679ae8c6e27Sflorian result = (struct mesh_state*)rbtree_search(&mesh->all, &key); 1680ae8c6e27Sflorian return result; 1681ae8c6e27Sflorian } 1682ae8c6e27Sflorian 1683ae8c6e27Sflorian int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, 1684ae8c6e27Sflorian sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, 1685ae8c6e27Sflorian uint16_t qid, uint16_t qflags) 1686ae8c6e27Sflorian { 1687ae8c6e27Sflorian struct mesh_cb* r = regional_alloc(s->s.region, 1688ae8c6e27Sflorian sizeof(struct mesh_cb)); 1689ae8c6e27Sflorian if(!r) 1690ae8c6e27Sflorian return 0; 1691ae8c6e27Sflorian r->buf = buf; 1692ae8c6e27Sflorian log_assert(fptr_whitelist_mesh_cb(cb)); /* early failure ifmissing*/ 1693ae8c6e27Sflorian r->cb = cb; 1694ae8c6e27Sflorian r->cb_arg = cb_arg; 1695ae8c6e27Sflorian r->edns = *edns; 1696a1a7ba80Sflorian if(edns->opt_list_in && !(r->edns.opt_list_in = 1697a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_in, s->s.region))) 1698ae8c6e27Sflorian return 0; 1699a1a7ba80Sflorian if(edns->opt_list_out && !(r->edns.opt_list_out = 1700a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_out, s->s.region))) 1701a1a7ba80Sflorian return 0; 1702a1a7ba80Sflorian if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out = 1703a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region))) 1704a1a7ba80Sflorian return 0; 1705ae8c6e27Sflorian r->qid = qid; 1706ae8c6e27Sflorian r->qflags = qflags; 1707ae8c6e27Sflorian r->next = s->cb_list; 1708ae8c6e27Sflorian s->cb_list = r; 1709ae8c6e27Sflorian return 1; 1710ae8c6e27Sflorian 1711ae8c6e27Sflorian } 1712ae8c6e27Sflorian 1713ae8c6e27Sflorian int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, 1714ae8c6e27Sflorian struct comm_reply* rep, uint16_t qid, uint16_t qflags, 1715ae8c6e27Sflorian const struct query_info* qinfo) 1716ae8c6e27Sflorian { 1717ae8c6e27Sflorian struct mesh_reply* r = regional_alloc(s->s.region, 1718ae8c6e27Sflorian sizeof(struct mesh_reply)); 1719ae8c6e27Sflorian if(!r) 1720ae8c6e27Sflorian return 0; 1721ae8c6e27Sflorian r->query_reply = *rep; 1722ae8c6e27Sflorian r->edns = *edns; 1723a1a7ba80Sflorian if(edns->opt_list_in && !(r->edns.opt_list_in = 1724a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_in, s->s.region))) 1725ae8c6e27Sflorian return 0; 1726a1a7ba80Sflorian if(edns->opt_list_out && !(r->edns.opt_list_out = 1727a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_out, s->s.region))) 1728a1a7ba80Sflorian return 0; 1729a1a7ba80Sflorian if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out = 1730a1a7ba80Sflorian edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region))) 1731a1a7ba80Sflorian return 0; 1732ae8c6e27Sflorian r->qid = qid; 1733ae8c6e27Sflorian r->qflags = qflags; 1734ae8c6e27Sflorian r->start_time = *s->s.env->now_tv; 1735ae8c6e27Sflorian r->next = s->reply_list; 1736ae8c6e27Sflorian r->qname = regional_alloc_init(s->s.region, qinfo->qname, 1737ae8c6e27Sflorian s->s.qinfo.qname_len); 1738ae8c6e27Sflorian if(!r->qname) 1739ae8c6e27Sflorian return 0; 1740f4f0f0ceSflorian if(rep->c->use_h2) 1741f4f0f0ceSflorian r->h2_stream = rep->c->h2_stream; 1742*7037e34cSflorian else r->h2_stream = NULL; 1743ae8c6e27Sflorian 1744ae8c6e27Sflorian /* Data related to local alias stored in 'qinfo' (if any) is ephemeral 1745ae8c6e27Sflorian * and can be different for different original queries (even if the 1746ae8c6e27Sflorian * replaced query name is the same). So we need to make a deep copy 1747ae8c6e27Sflorian * and store the copy for each reply info. */ 1748ae8c6e27Sflorian if(qinfo->local_alias) { 1749ae8c6e27Sflorian struct packed_rrset_data* d; 1750ae8c6e27Sflorian struct packed_rrset_data* dsrc; 1751ae8c6e27Sflorian r->local_alias = regional_alloc_zero(s->s.region, 1752ae8c6e27Sflorian sizeof(*qinfo->local_alias)); 1753ae8c6e27Sflorian if(!r->local_alias) 1754ae8c6e27Sflorian return 0; 1755ae8c6e27Sflorian r->local_alias->rrset = regional_alloc_init(s->s.region, 1756ae8c6e27Sflorian qinfo->local_alias->rrset, 1757ae8c6e27Sflorian sizeof(*qinfo->local_alias->rrset)); 1758ae8c6e27Sflorian if(!r->local_alias->rrset) 1759ae8c6e27Sflorian return 0; 1760ae8c6e27Sflorian dsrc = qinfo->local_alias->rrset->entry.data; 1761ae8c6e27Sflorian 1762ae8c6e27Sflorian /* In the current implementation, a local alias must be 1763ae8c6e27Sflorian * a single CNAME RR (see worker_handle_request()). */ 1764ae8c6e27Sflorian log_assert(!qinfo->local_alias->next && dsrc->count == 1 && 1765ae8c6e27Sflorian qinfo->local_alias->rrset->rk.type == 1766ae8c6e27Sflorian htons(LDNS_RR_TYPE_CNAME)); 1767da8c8390Sflorian /* we should make a local copy for the owner name of 1768da8c8390Sflorian * the RRset */ 1769da8c8390Sflorian r->local_alias->rrset->rk.dname_len = 1770da8c8390Sflorian qinfo->local_alias->rrset->rk.dname_len; 1771da8c8390Sflorian r->local_alias->rrset->rk.dname = regional_alloc_init( 1772da8c8390Sflorian s->s.region, qinfo->local_alias->rrset->rk.dname, 1773da8c8390Sflorian qinfo->local_alias->rrset->rk.dname_len); 1774da8c8390Sflorian if(!r->local_alias->rrset->rk.dname) 1775da8c8390Sflorian return 0; 1776ae8c6e27Sflorian 17779b465e50Sflorian /* the rrset is not packed, like in the cache, but it is 1778a1a7ba80Sflorian * individually allocated with an allocator from localzone. */ 17799b465e50Sflorian d = regional_alloc_zero(s->s.region, sizeof(*d)); 1780ae8c6e27Sflorian if(!d) 1781ae8c6e27Sflorian return 0; 1782ae8c6e27Sflorian r->local_alias->rrset->entry.data = d; 17839b465e50Sflorian if(!rrset_insert_rr(s->s.region, d, dsrc->rr_data[0], 17849b465e50Sflorian dsrc->rr_len[0], dsrc->rr_ttl[0], "CNAME local alias")) 1785ae8c6e27Sflorian return 0; 1786ae8c6e27Sflorian } else 1787ae8c6e27Sflorian r->local_alias = NULL; 1788ae8c6e27Sflorian 1789ae8c6e27Sflorian s->reply_list = r; 1790ae8c6e27Sflorian return 1; 1791ae8c6e27Sflorian } 1792ae8c6e27Sflorian 1793ae8c6e27Sflorian /* Extract the query info and flags from 'mstate' into '*qinfop' and '*qflags'. 1794ae8c6e27Sflorian * Since this is only used for internal refetch of otherwise-expired answer, 1795ae8c6e27Sflorian * we simply ignore the rare failure mode when memory allocation fails. */ 1796ae8c6e27Sflorian static void 1797ae8c6e27Sflorian mesh_copy_qinfo(struct mesh_state* mstate, struct query_info** qinfop, 1798ae8c6e27Sflorian uint16_t* qflags) 1799ae8c6e27Sflorian { 1800ae8c6e27Sflorian struct regional* region = mstate->s.env->scratch; 1801ae8c6e27Sflorian struct query_info* qinfo; 1802ae8c6e27Sflorian 1803ae8c6e27Sflorian qinfo = regional_alloc_init(region, &mstate->s.qinfo, sizeof(*qinfo)); 1804ae8c6e27Sflorian if(!qinfo) 1805ae8c6e27Sflorian return; 1806ae8c6e27Sflorian qinfo->qname = regional_alloc_init(region, qinfo->qname, 1807ae8c6e27Sflorian qinfo->qname_len); 1808ae8c6e27Sflorian if(!qinfo->qname) 1809ae8c6e27Sflorian return; 1810ae8c6e27Sflorian *qinfop = qinfo; 1811ae8c6e27Sflorian *qflags = mstate->s.query_flags; 1812ae8c6e27Sflorian } 1813ae8c6e27Sflorian 1814ae8c6e27Sflorian /** 1815ae8c6e27Sflorian * Continue processing the mesh state at another module. 1816ae8c6e27Sflorian * Handles module to modules transfer of control. 1817ae8c6e27Sflorian * Handles module finished. 1818ae8c6e27Sflorian * @param mesh: the mesh area. 1819ae8c6e27Sflorian * @param mstate: currently active mesh state. 1820ae8c6e27Sflorian * Deleted if finished, calls _done and _supers to 1821ae8c6e27Sflorian * send replies to clients and inform other mesh states. 1822ae8c6e27Sflorian * This in turn may create additional runnable mesh states. 1823ae8c6e27Sflorian * @param s: state at which the current module exited. 1824ae8c6e27Sflorian * @param ev: the event sent to the module. 1825ae8c6e27Sflorian * returned is the event to send to the next module. 1826ae8c6e27Sflorian * @return true if continue processing at the new module. 1827ae8c6e27Sflorian * false if not continued processing is needed. 1828ae8c6e27Sflorian */ 1829ae8c6e27Sflorian static int 1830ae8c6e27Sflorian mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate, 1831ae8c6e27Sflorian enum module_ext_state s, enum module_ev* ev) 1832ae8c6e27Sflorian { 1833ae8c6e27Sflorian mstate->num_activated++; 1834ae8c6e27Sflorian if(mstate->num_activated > MESH_MAX_ACTIVATION) { 1835ae8c6e27Sflorian /* module is looping. Stop it. */ 1836ae8c6e27Sflorian log_err("internal error: looping module (%s) stopped", 1837ae8c6e27Sflorian mesh->mods.mod[mstate->s.curmod]->name); 183857403691Sflorian log_query_info(NO_VERBOSE, "pass error for qstate", 1839ae8c6e27Sflorian &mstate->s.qinfo); 1840ae8c6e27Sflorian s = module_error; 1841ae8c6e27Sflorian } 1842ae8c6e27Sflorian if(s == module_wait_module || s == module_restart_next) { 1843ae8c6e27Sflorian /* start next module */ 1844ae8c6e27Sflorian mstate->s.curmod++; 1845ae8c6e27Sflorian if(mesh->mods.num == mstate->s.curmod) { 1846ae8c6e27Sflorian log_err("Cannot pass to next module; at last module"); 1847ae8c6e27Sflorian log_query_info(VERB_QUERY, "pass error for qstate", 1848ae8c6e27Sflorian &mstate->s.qinfo); 1849ae8c6e27Sflorian mstate->s.curmod--; 1850ae8c6e27Sflorian return mesh_continue(mesh, mstate, module_error, ev); 1851ae8c6e27Sflorian } 1852ae8c6e27Sflorian if(s == module_restart_next) { 1853ae8c6e27Sflorian int curmod = mstate->s.curmod; 1854ae8c6e27Sflorian for(; mstate->s.curmod < mesh->mods.num; 1855ae8c6e27Sflorian mstate->s.curmod++) { 1856ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_clear( 1857ae8c6e27Sflorian mesh->mods.mod[mstate->s.curmod]->clear)); 1858ae8c6e27Sflorian (*mesh->mods.mod[mstate->s.curmod]->clear) 1859ae8c6e27Sflorian (&mstate->s, mstate->s.curmod); 1860ae8c6e27Sflorian mstate->s.minfo[mstate->s.curmod] = NULL; 1861ae8c6e27Sflorian } 1862ae8c6e27Sflorian mstate->s.curmod = curmod; 1863ae8c6e27Sflorian } 1864ae8c6e27Sflorian *ev = module_event_pass; 1865ae8c6e27Sflorian return 1; 1866ae8c6e27Sflorian } 1867ae8c6e27Sflorian if(s == module_wait_subquery && mstate->sub_set.count == 0) { 1868ae8c6e27Sflorian log_err("module cannot wait for subquery, subquery list empty"); 1869ae8c6e27Sflorian log_query_info(VERB_QUERY, "pass error for qstate", 1870ae8c6e27Sflorian &mstate->s.qinfo); 1871ae8c6e27Sflorian s = module_error; 1872ae8c6e27Sflorian } 1873ae8c6e27Sflorian if(s == module_error && mstate->s.return_rcode == LDNS_RCODE_NOERROR) { 1874ae8c6e27Sflorian /* error is bad, handle pass back up below */ 1875ae8c6e27Sflorian mstate->s.return_rcode = LDNS_RCODE_SERVFAIL; 1876ae8c6e27Sflorian } 1877ae8c6e27Sflorian if(s == module_error) { 1878ae8c6e27Sflorian mesh_query_done(mstate); 1879ae8c6e27Sflorian mesh_walk_supers(mesh, mstate); 1880ae8c6e27Sflorian mesh_state_delete(&mstate->s); 1881ae8c6e27Sflorian return 0; 1882ae8c6e27Sflorian } 1883ae8c6e27Sflorian if(s == module_finished) { 1884ae8c6e27Sflorian if(mstate->s.curmod == 0) { 1885ae8c6e27Sflorian struct query_info* qinfo = NULL; 1886d500c338Sflorian struct edns_option* opt_list = NULL; 1887d500c338Sflorian struct sockaddr_storage addr; 1888ae8c6e27Sflorian uint16_t qflags; 18897a05b9dfSflorian int rpz_p = 0; 1890ae8c6e27Sflorian 1891d500c338Sflorian #ifdef CLIENT_SUBNET 1892d500c338Sflorian struct edns_option* ecs; 1893d500c338Sflorian if(mstate->s.need_refetch && mstate->reply_list && 1894d500c338Sflorian modstack_find(&mesh->mods, "subnetcache") != -1 && 1895d500c338Sflorian mstate->s.env->unique_mesh) { 1896d500c338Sflorian addr = mstate->reply_list->query_reply.client_addr; 1897d500c338Sflorian } else 1898d500c338Sflorian #endif 1899d500c338Sflorian memset(&addr, 0, sizeof(addr)); 1900d500c338Sflorian 1901ae8c6e27Sflorian mesh_query_done(mstate); 1902ae8c6e27Sflorian mesh_walk_supers(mesh, mstate); 1903ae8c6e27Sflorian 1904ae8c6e27Sflorian /* If the answer to the query needs to be refetched 1905ae8c6e27Sflorian * from an external DNS server, we'll need to schedule 1906ae8c6e27Sflorian * a prefetch after removing the current state, so 1907ae8c6e27Sflorian * we need to make a copy of the query info here. */ 19087a05b9dfSflorian if(mstate->s.need_refetch) { 1909ae8c6e27Sflorian mesh_copy_qinfo(mstate, &qinfo, &qflags); 1910d500c338Sflorian #ifdef CLIENT_SUBNET 1911d500c338Sflorian /* Make also a copy of the ecs option if any */ 1912d500c338Sflorian if((ecs = edns_opt_list_find( 1913d500c338Sflorian mstate->s.edns_opts_front_in, 1914d500c338Sflorian mstate->s.env->cfg->client_subnet_opcode)) != NULL) { 1915d500c338Sflorian (void)edns_opt_list_append(&opt_list, 1916d500c338Sflorian ecs->opt_code, ecs->opt_len, 1917d500c338Sflorian ecs->opt_data, 1918d500c338Sflorian mstate->s.env->scratch); 1919d500c338Sflorian } 1920d500c338Sflorian #endif 19217a05b9dfSflorian rpz_p = mstate->s.rpz_passthru; 19227a05b9dfSflorian } 1923ae8c6e27Sflorian 1924ae8c6e27Sflorian if(qinfo) { 1925d500c338Sflorian mesh_state_delete(&mstate->s); 1926d500c338Sflorian mesh_new_prefetch(mesh, qinfo, qflags, 0, 1927d500c338Sflorian rpz_p, 1928d500c338Sflorian addr.ss_family!=AF_UNSPEC?&addr:NULL, 1929d500c338Sflorian opt_list); 1930d500c338Sflorian } else { 1931d500c338Sflorian mesh_state_delete(&mstate->s); 1932ae8c6e27Sflorian } 1933ae8c6e27Sflorian return 0; 1934ae8c6e27Sflorian } 1935ae8c6e27Sflorian /* pass along the locus of control */ 1936ae8c6e27Sflorian mstate->s.curmod --; 1937ae8c6e27Sflorian *ev = module_event_moddone; 1938ae8c6e27Sflorian return 1; 1939ae8c6e27Sflorian } 1940ae8c6e27Sflorian return 0; 1941ae8c6e27Sflorian } 1942ae8c6e27Sflorian 1943ae8c6e27Sflorian void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate, 1944ae8c6e27Sflorian enum module_ev ev, struct outbound_entry* e) 1945ae8c6e27Sflorian { 1946ae8c6e27Sflorian enum module_ext_state s; 1947ae8c6e27Sflorian verbose(VERB_ALGO, "mesh_run: start"); 1948ae8c6e27Sflorian while(mstate) { 1949ae8c6e27Sflorian /* run the module */ 1950ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_operate( 1951ae8c6e27Sflorian mesh->mods.mod[mstate->s.curmod]->operate)); 1952ae8c6e27Sflorian (*mesh->mods.mod[mstate->s.curmod]->operate) 1953ae8c6e27Sflorian (&mstate->s, ev, mstate->s.curmod, e); 1954ae8c6e27Sflorian 1955ae8c6e27Sflorian /* examine results */ 1956ae8c6e27Sflorian mstate->s.reply = NULL; 1957ae8c6e27Sflorian regional_free_all(mstate->s.env->scratch); 1958ae8c6e27Sflorian s = mstate->s.ext_state[mstate->s.curmod]; 1959ae8c6e27Sflorian verbose(VERB_ALGO, "mesh_run: %s module exit state is %s", 1960ae8c6e27Sflorian mesh->mods.mod[mstate->s.curmod]->name, strextstate(s)); 1961ae8c6e27Sflorian e = NULL; 1962ae8c6e27Sflorian if(mesh_continue(mesh, mstate, s, &ev)) 1963ae8c6e27Sflorian continue; 1964ae8c6e27Sflorian 1965ae8c6e27Sflorian /* run more modules */ 1966ae8c6e27Sflorian ev = module_event_pass; 1967ae8c6e27Sflorian if(mesh->run.count > 0) { 1968ae8c6e27Sflorian /* pop random element off the runnable tree */ 1969ae8c6e27Sflorian mstate = (struct mesh_state*)mesh->run.root->key; 1970ae8c6e27Sflorian (void)rbtree_delete(&mesh->run, mstate); 1971ae8c6e27Sflorian } else mstate = NULL; 1972ae8c6e27Sflorian } 1973ae8c6e27Sflorian if(verbosity >= VERB_ALGO) { 1974ae8c6e27Sflorian mesh_stats(mesh, "mesh_run: end"); 1975ae8c6e27Sflorian mesh_log_list(mesh); 1976ae8c6e27Sflorian } 1977ae8c6e27Sflorian } 1978ae8c6e27Sflorian 1979ae8c6e27Sflorian void 1980ae8c6e27Sflorian mesh_log_list(struct mesh_area* mesh) 1981ae8c6e27Sflorian { 1982ae8c6e27Sflorian char buf[30]; 1983ae8c6e27Sflorian struct mesh_state* m; 1984ae8c6e27Sflorian int num = 0; 1985ae8c6e27Sflorian RBTREE_FOR(m, struct mesh_state*, &mesh->all) { 1986ae8c6e27Sflorian snprintf(buf, sizeof(buf), "%d%s%s%s%s%s%s mod%d %s%s", 1987ae8c6e27Sflorian num++, (m->s.is_priming)?"p":"", /* prime */ 1988ae8c6e27Sflorian (m->s.is_valrec)?"v":"", /* prime */ 1989ae8c6e27Sflorian (m->s.query_flags&BIT_RD)?"RD":"", 1990ae8c6e27Sflorian (m->s.query_flags&BIT_CD)?"CD":"", 1991ae8c6e27Sflorian (m->super_set.count==0)?"d":"", /* detached */ 1992ae8c6e27Sflorian (m->sub_set.count!=0)?"c":"", /* children */ 1993ae8c6e27Sflorian m->s.curmod, (m->reply_list)?"rep":"", /*hasreply*/ 1994ae8c6e27Sflorian (m->cb_list)?"cb":"" /* callbacks */ 1995ae8c6e27Sflorian ); 1996ae8c6e27Sflorian log_query_info(VERB_ALGO, buf, &m->s.qinfo); 1997ae8c6e27Sflorian } 1998ae8c6e27Sflorian } 1999ae8c6e27Sflorian 2000ae8c6e27Sflorian void 2001ae8c6e27Sflorian mesh_stats(struct mesh_area* mesh, const char* str) 2002ae8c6e27Sflorian { 2003ae8c6e27Sflorian verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, " 2004ae8c6e27Sflorian "%u detached), %u waiting replies, %u recursion replies " 2005ae8c6e27Sflorian "sent, %d replies dropped, %d states jostled out", 2006ae8c6e27Sflorian str, (unsigned)mesh->all.count, 2007ae8c6e27Sflorian (unsigned)mesh->num_reply_states, 2008ae8c6e27Sflorian (unsigned)mesh->num_detached_states, 2009ae8c6e27Sflorian (unsigned)mesh->num_reply_addrs, 2010ae8c6e27Sflorian (unsigned)mesh->replies_sent, 2011ae8c6e27Sflorian (unsigned)mesh->stats_dropped, 2012ae8c6e27Sflorian (unsigned)mesh->stats_jostled); 2013ae8c6e27Sflorian if(mesh->replies_sent > 0) { 2014ae8c6e27Sflorian struct timeval avg; 2015ae8c6e27Sflorian timeval_divide(&avg, &mesh->replies_sum_wait, 2016ae8c6e27Sflorian mesh->replies_sent); 2017ae8c6e27Sflorian log_info("average recursion processing time " 2018ae8c6e27Sflorian ARG_LL "d.%6.6d sec", 2019ae8c6e27Sflorian (long long)avg.tv_sec, (int)avg.tv_usec); 2020ae8c6e27Sflorian log_info("histogram of recursion processing times"); 2021ae8c6e27Sflorian timehist_log(mesh->histogram, "recursions"); 2022ae8c6e27Sflorian } 2023ae8c6e27Sflorian } 2024ae8c6e27Sflorian 2025ae8c6e27Sflorian void 2026ae8c6e27Sflorian mesh_stats_clear(struct mesh_area* mesh) 2027ae8c6e27Sflorian { 2028ae8c6e27Sflorian if(!mesh) 2029ae8c6e27Sflorian return; 2030ae8c6e27Sflorian mesh->replies_sent = 0; 2031ae8c6e27Sflorian mesh->replies_sum_wait.tv_sec = 0; 2032ae8c6e27Sflorian mesh->replies_sum_wait.tv_usec = 0; 2033ae8c6e27Sflorian mesh->stats_jostled = 0; 2034ae8c6e27Sflorian mesh->stats_dropped = 0; 2035ae8c6e27Sflorian timehist_clear(mesh->histogram); 2036ae8c6e27Sflorian mesh->ans_secure = 0; 2037ae8c6e27Sflorian mesh->ans_bogus = 0; 2038d32eb43cSflorian mesh->ans_expired = 0; 2039d500c338Sflorian mesh->ans_cachedb = 0; 2040d32eb43cSflorian memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*UB_STATS_RCODE_NUM); 2041d32eb43cSflorian memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM); 2042ae8c6e27Sflorian mesh->ans_nodata = 0; 2043ae8c6e27Sflorian } 2044ae8c6e27Sflorian 2045ae8c6e27Sflorian size_t 2046ae8c6e27Sflorian mesh_get_mem(struct mesh_area* mesh) 2047ae8c6e27Sflorian { 2048ae8c6e27Sflorian struct mesh_state* m; 2049ae8c6e27Sflorian size_t s = sizeof(*mesh) + sizeof(struct timehist) + 2050ae8c6e27Sflorian sizeof(struct th_buck)*mesh->histogram->num + 2051ae8c6e27Sflorian sizeof(sldns_buffer) + sldns_buffer_capacity(mesh->qbuf_bak); 2052ae8c6e27Sflorian RBTREE_FOR(m, struct mesh_state*, &mesh->all) { 2053ae8c6e27Sflorian /* all, including m itself allocated in qstate region */ 2054ae8c6e27Sflorian s += regional_get_mem(m->s.region); 2055ae8c6e27Sflorian } 2056ae8c6e27Sflorian return s; 2057ae8c6e27Sflorian } 2058ae8c6e27Sflorian 2059ae8c6e27Sflorian int 2060ae8c6e27Sflorian mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo, 2061ae8c6e27Sflorian uint16_t flags, int prime, int valrec) 2062ae8c6e27Sflorian { 2063ae8c6e27Sflorian struct mesh_area* mesh = qstate->env->mesh; 2064ae8c6e27Sflorian struct mesh_state* dep_m = NULL; 2065ae8c6e27Sflorian dep_m = mesh_area_find(mesh, NULL, qinfo, flags, prime, valrec); 2066ae8c6e27Sflorian return mesh_detect_cycle_found(qstate, dep_m); 2067ae8c6e27Sflorian } 2068ae8c6e27Sflorian 2069ae8c6e27Sflorian void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp, 2070ae8c6e27Sflorian struct mesh_state** lp) 2071ae8c6e27Sflorian { 2072ae8c6e27Sflorian /* insert as last element */ 2073ae8c6e27Sflorian m->prev = *lp; 2074ae8c6e27Sflorian m->next = NULL; 2075ae8c6e27Sflorian if(*lp) 2076ae8c6e27Sflorian (*lp)->next = m; 2077ae8c6e27Sflorian else *fp = m; 2078ae8c6e27Sflorian *lp = m; 2079ae8c6e27Sflorian } 2080ae8c6e27Sflorian 2081ae8c6e27Sflorian void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, 2082ae8c6e27Sflorian struct mesh_state** lp) 2083ae8c6e27Sflorian { 2084ae8c6e27Sflorian if(m->next) 2085ae8c6e27Sflorian m->next->prev = m->prev; 2086ae8c6e27Sflorian else *lp = m->prev; 2087ae8c6e27Sflorian if(m->prev) 2088ae8c6e27Sflorian m->prev->next = m->next; 2089ae8c6e27Sflorian else *fp = m->next; 2090ae8c6e27Sflorian } 2091e97c6e54Ssthen 2092e97c6e54Ssthen void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, 2093e97c6e54Ssthen struct comm_point* cp) 2094e97c6e54Ssthen { 2095e97c6e54Ssthen struct mesh_reply* n, *prev = NULL; 2096e97c6e54Ssthen n = m->reply_list; 2097e97c6e54Ssthen /* when in mesh_cleanup, it sets the reply_list to NULL, so that 2098e97c6e54Ssthen * there is no accounting twice */ 2099e97c6e54Ssthen if(!n) return; /* nothing to remove, also no accounting needed */ 2100e97c6e54Ssthen while(n) { 2101e97c6e54Ssthen if(n->query_reply.c == cp) { 2102e97c6e54Ssthen /* unlink it */ 2103e97c6e54Ssthen if(prev) prev->next = n->next; 2104e97c6e54Ssthen else m->reply_list = n->next; 2105e97c6e54Ssthen /* delete it, but allocated in m region */ 2106d32eb43cSflorian log_assert(mesh->num_reply_addrs > 0); 2107e97c6e54Ssthen mesh->num_reply_addrs--; 2108096314feSflorian infra_wait_limit_dec(mesh->env->infra_cache, 2109096314feSflorian &n->query_reply, mesh->env->cfg); 2110e97c6e54Ssthen 2111e97c6e54Ssthen /* prev = prev; */ 2112e97c6e54Ssthen n = n->next; 2113e97c6e54Ssthen continue; 2114e97c6e54Ssthen } 2115e97c6e54Ssthen prev = n; 2116e97c6e54Ssthen n = n->next; 2117e97c6e54Ssthen } 2118e97c6e54Ssthen /* it was not detached (because it had a reply list), could be now */ 2119e97c6e54Ssthen if(!m->reply_list && !m->cb_list 2120e97c6e54Ssthen && m->super_set.count == 0) { 2121e97c6e54Ssthen mesh->num_detached_states++; 2122e97c6e54Ssthen } 2123e97c6e54Ssthen /* if not replies any more in mstate, it is no longer a reply_state */ 2124e97c6e54Ssthen if(!m->reply_list && !m->cb_list) { 2125e97c6e54Ssthen log_assert(mesh->num_reply_states > 0); 2126e97c6e54Ssthen mesh->num_reply_states--; 2127e97c6e54Ssthen } 2128e97c6e54Ssthen } 2129d32eb43cSflorian 2130d32eb43cSflorian 2131d32eb43cSflorian static int 2132d32eb43cSflorian apply_respip_action(struct module_qstate* qstate, 2133d32eb43cSflorian const struct query_info* qinfo, struct respip_client_info* cinfo, 2134d32eb43cSflorian struct respip_action_info* actinfo, struct reply_info* rep, 2135d32eb43cSflorian struct ub_packed_rrset_key** alias_rrset, 2136d32eb43cSflorian struct reply_info** encode_repp, struct auth_zones* az) 2137d32eb43cSflorian { 2138d32eb43cSflorian if(qinfo->qtype != LDNS_RR_TYPE_A && 2139d32eb43cSflorian qinfo->qtype != LDNS_RR_TYPE_AAAA && 2140d32eb43cSflorian qinfo->qtype != LDNS_RR_TYPE_ANY) 2141d32eb43cSflorian return 1; 2142d32eb43cSflorian 2143d32eb43cSflorian if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo, 21447a05b9dfSflorian alias_rrset, 0, qstate->region, az, NULL)) 2145d32eb43cSflorian return 0; 2146d32eb43cSflorian 2147d32eb43cSflorian /* xxx_deny actions mean dropping the reply, unless the original reply 2148d32eb43cSflorian * was redirected to response-ip data. */ 2149d32eb43cSflorian if((actinfo->action == respip_deny || 2150d32eb43cSflorian actinfo->action == respip_inform_deny) && 2151d32eb43cSflorian *encode_repp == rep) 2152d32eb43cSflorian *encode_repp = NULL; 2153d32eb43cSflorian 2154d32eb43cSflorian return 1; 2155d32eb43cSflorian } 2156d32eb43cSflorian 2157d32eb43cSflorian void 2158d32eb43cSflorian mesh_serve_expired_callback(void* arg) 2159d32eb43cSflorian { 2160d32eb43cSflorian struct mesh_state* mstate = (struct mesh_state*) arg; 2161d32eb43cSflorian struct module_qstate* qstate = &mstate->s; 2162853e076fSflorian struct mesh_reply* r; 2163d32eb43cSflorian struct mesh_area* mesh = qstate->env->mesh; 2164d32eb43cSflorian struct dns_msg* msg; 2165d32eb43cSflorian struct mesh_cb* c; 2166d32eb43cSflorian struct mesh_reply* prev = NULL; 2167d32eb43cSflorian struct sldns_buffer* prev_buffer = NULL; 2168d32eb43cSflorian struct sldns_buffer* r_buffer = NULL; 2169d32eb43cSflorian struct reply_info* partial_rep = NULL; 2170d32eb43cSflorian struct ub_packed_rrset_key* alias_rrset = NULL; 2171d32eb43cSflorian struct reply_info* encode_rep = NULL; 2172d32eb43cSflorian struct respip_action_info actinfo; 2173d32eb43cSflorian struct query_info* lookup_qinfo = &qstate->qinfo; 2174d32eb43cSflorian struct query_info qinfo_tmp; 2175a8eaceedSflorian struct timeval tv = {0, 0}; 2176d32eb43cSflorian int must_validate = (!(qstate->query_flags&BIT_CD) 2177d32eb43cSflorian || qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate; 2178d500c338Sflorian int i = 0; 2179d32eb43cSflorian if(!qstate->serve_expired_data) return; 2180d32eb43cSflorian verbose(VERB_ALGO, "Serve expired: Trying to reply with expired data"); 2181d32eb43cSflorian comm_timer_delete(qstate->serve_expired_data->timer); 2182d32eb43cSflorian qstate->serve_expired_data->timer = NULL; 2183a8eaceedSflorian /* If is_drop or no_cache_lookup (modules that handle their own cache e.g., 2184a8eaceedSflorian * subnetmod) ignore stale data from the main cache. */ 2185a8eaceedSflorian if(qstate->no_cache_lookup || qstate->is_drop) { 2186d32eb43cSflorian verbose(VERB_ALGO, 2187d32eb43cSflorian "Serve expired: Not allowed to look into cache for stale"); 2188d32eb43cSflorian return; 2189d32eb43cSflorian } 2190d32eb43cSflorian /* The following while is used instead of the `goto lookup_cache` 2191d32eb43cSflorian * like in the worker. */ 2192d32eb43cSflorian while(1) { 2193d32eb43cSflorian fptr_ok(fptr_whitelist_serve_expired_lookup( 2194d32eb43cSflorian qstate->serve_expired_data->get_cached_answer)); 2195411c5950Sflorian msg = (*qstate->serve_expired_data->get_cached_answer)(qstate, 2196d32eb43cSflorian lookup_qinfo); 2197d32eb43cSflorian if(!msg) 2198d32eb43cSflorian return; 2199d32eb43cSflorian /* Reset these in case we pass a second time from here. */ 2200d32eb43cSflorian encode_rep = msg->rep; 2201d32eb43cSflorian memset(&actinfo, 0, sizeof(actinfo)); 2202d32eb43cSflorian actinfo.action = respip_none; 2203d32eb43cSflorian alias_rrset = NULL; 2204d32eb43cSflorian if((mesh->use_response_ip || mesh->use_rpz) && 2205d32eb43cSflorian !partial_rep && !apply_respip_action(qstate, &qstate->qinfo, 2206d32eb43cSflorian qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep, 2207d32eb43cSflorian qstate->env->auth_zones)) { 2208d32eb43cSflorian return; 2209d32eb43cSflorian } else if(partial_rep && 2210d32eb43cSflorian !respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, 2211d32eb43cSflorian qstate->client_info, must_validate, &encode_rep, qstate->region, 2212d32eb43cSflorian qstate->env->auth_zones)) { 2213d32eb43cSflorian return; 2214d32eb43cSflorian } 2215d32eb43cSflorian if(!encode_rep || alias_rrset) { 2216d32eb43cSflorian if(!encode_rep) { 2217d32eb43cSflorian /* Needs drop */ 2218d32eb43cSflorian return; 2219d32eb43cSflorian } else { 2220d32eb43cSflorian /* A partial CNAME chain is found. */ 2221d32eb43cSflorian partial_rep = encode_rep; 2222d32eb43cSflorian } 2223d32eb43cSflorian } 2224d32eb43cSflorian /* We've found a partial reply ending with an 2225d32eb43cSflorian * alias. Replace the lookup qinfo for the 2226d32eb43cSflorian * alias target and lookup the cache again to 2227d32eb43cSflorian * (possibly) complete the reply. As we're 2228d32eb43cSflorian * passing the "base" reply, there will be no 2229d32eb43cSflorian * more alias chasing. */ 2230d32eb43cSflorian if(partial_rep) { 2231d32eb43cSflorian memset(&qinfo_tmp, 0, sizeof(qinfo_tmp)); 2232d32eb43cSflorian get_cname_target(alias_rrset, &qinfo_tmp.qname, 2233d32eb43cSflorian &qinfo_tmp.qname_len); 2234d32eb43cSflorian if(!qinfo_tmp.qname) { 2235d32eb43cSflorian log_err("Serve expired: unexpected: invalid answer alias"); 2236d32eb43cSflorian return; 2237d32eb43cSflorian } 2238d32eb43cSflorian qinfo_tmp.qtype = qstate->qinfo.qtype; 2239d32eb43cSflorian qinfo_tmp.qclass = qstate->qinfo.qclass; 2240d32eb43cSflorian lookup_qinfo = &qinfo_tmp; 2241d32eb43cSflorian continue; 2242d32eb43cSflorian } 2243d32eb43cSflorian break; 2244d32eb43cSflorian } 2245d32eb43cSflorian 2246d32eb43cSflorian if(verbosity >= VERB_ALGO) 2247d32eb43cSflorian log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); 2248d32eb43cSflorian 2249e47fef9eSflorian for(r = mstate->reply_list; r; r = r->next) { 2250096314feSflorian struct timeval old; 2251096314feSflorian timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); 2252096314feSflorian if(mstate->s.env->cfg->discard_timeout != 0 && 2253096314feSflorian ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > 2254096314feSflorian mstate->s.env->cfg->discard_timeout) { 2255096314feSflorian /* Drop the reply, it is too old */ 2256096314feSflorian /* briefly set the reply_list to NULL, so that the 2257096314feSflorian * tcp req info cleanup routine that calls the mesh 2258096314feSflorian * to deregister the meshstate for it is not done 2259096314feSflorian * because the list is NULL and also accounting is not 2260096314feSflorian * done there, but instead we do that here. */ 2261096314feSflorian struct mesh_reply* reply_list = mstate->reply_list; 2262096314feSflorian verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); 2263096314feSflorian infra_wait_limit_dec(mstate->s.env->infra_cache, 2264096314feSflorian &r->query_reply, mstate->s.env->cfg); 2265096314feSflorian mstate->reply_list = NULL; 2266*7037e34cSflorian if(r->query_reply.c->use_h2) 2267*7037e34cSflorian http2_stream_remove_mesh_state(r->h2_stream); 2268096314feSflorian comm_point_drop_reply(&r->query_reply); 2269096314feSflorian mstate->reply_list = reply_list; 2270096314feSflorian mstate->s.env->mesh->stats_dropped++; 2271096314feSflorian continue; 2272096314feSflorian } 2273096314feSflorian 2274d500c338Sflorian i++; 2275a8eaceedSflorian tv = r->start_time; 2276a8eaceedSflorian 2277d32eb43cSflorian /* If address info is returned, it means the action should be an 2278d32eb43cSflorian * 'inform' variant and the information should be logged. */ 2279d32eb43cSflorian if(actinfo.addrinfo) { 2280d32eb43cSflorian respip_inform_print(&actinfo, r->qname, 2281d32eb43cSflorian qstate->qinfo.qtype, qstate->qinfo.qclass, 22825c45b740Sflorian r->local_alias, &r->query_reply.client_addr, 22835c45b740Sflorian r->query_reply.client_addrlen); 2284d32eb43cSflorian } 2285d32eb43cSflorian 22867a05b9dfSflorian /* Add EDE Stale Answer (RCF8914). Ignore global ede as this is 22877a05b9dfSflorian * warning instead of an error */ 22887a05b9dfSflorian if (r->edns.edns_present && qstate->env->cfg->ede_serve_expired && 22897a05b9dfSflorian qstate->env->cfg->ede) { 22907a05b9dfSflorian edns_opt_list_append_ede(&r->edns.opt_list_out, 22917a05b9dfSflorian mstate->s.region, LDNS_EDE_STALE_ANSWER, NULL); 22927a05b9dfSflorian } 22937a05b9dfSflorian 2294d32eb43cSflorian r_buffer = r->query_reply.c->buffer; 2295d32eb43cSflorian if(r->query_reply.c->tcp_req_info) 2296d32eb43cSflorian r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; 2297d32eb43cSflorian mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep, 2298d32eb43cSflorian r, r_buffer, prev, prev_buffer); 2299d32eb43cSflorian if(r->query_reply.c->tcp_req_info) 2300d32eb43cSflorian tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); 2301*7037e34cSflorian /* mesh_send_reply removed mesh state from http2_stream. */ 2302096314feSflorian infra_wait_limit_dec(mstate->s.env->infra_cache, 2303096314feSflorian &r->query_reply, mstate->s.env->cfg); 2304d32eb43cSflorian prev = r; 2305d32eb43cSflorian prev_buffer = r_buffer; 2306d32eb43cSflorian } 2307d500c338Sflorian /* Account for each reply sent. */ 2308d500c338Sflorian if(i > 0) { 2309d500c338Sflorian mesh->ans_expired += i; 2310d500c338Sflorian if(actinfo.addrinfo && qstate->env->cfg->stat_extended && 2311d500c338Sflorian actinfo.rpz_used) { 2312d500c338Sflorian if(actinfo.rpz_disabled) 2313d500c338Sflorian qstate->env->mesh->rpz_action[RPZ_DISABLED_ACTION] += i; 2314d500c338Sflorian if(actinfo.rpz_cname_override) 2315d500c338Sflorian qstate->env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION] += i; 2316d500c338Sflorian else 2317d500c338Sflorian qstate->env->mesh->rpz_action[ 2318d500c338Sflorian respip_action_to_rpz_action(actinfo.action)] += i; 2319d500c338Sflorian } 2320d500c338Sflorian } 2321d500c338Sflorian 2322d500c338Sflorian /* Mesh area accounting */ 2323e47fef9eSflorian if(mstate->reply_list) { 2324e47fef9eSflorian mstate->reply_list = NULL; 2325e47fef9eSflorian if(!mstate->reply_list && !mstate->cb_list) { 2326e47fef9eSflorian log_assert(mesh->num_reply_states > 0); 2327e47fef9eSflorian mesh->num_reply_states--; 2328e47fef9eSflorian if(mstate->super_set.count == 0) { 2329e47fef9eSflorian mesh->num_detached_states++; 2330e47fef9eSflorian } 2331e47fef9eSflorian } 2332e47fef9eSflorian } 2333d500c338Sflorian 2334d32eb43cSflorian while((c = mstate->cb_list) != NULL) { 2335d32eb43cSflorian /* take this cb off the list; so that the list can be 2336d32eb43cSflorian * changed, eg. by adds from the callback routine */ 2337d32eb43cSflorian if(!mstate->reply_list && mstate->cb_list && !c->next) { 2338d32eb43cSflorian /* was a reply state, not anymore */ 2339d32eb43cSflorian log_assert(qstate->env->mesh->num_reply_states > 0); 2340d32eb43cSflorian qstate->env->mesh->num_reply_states--; 2341d32eb43cSflorian } 2342d32eb43cSflorian mstate->cb_list = c->next; 2343d32eb43cSflorian if(!mstate->reply_list && !mstate->cb_list && 2344d32eb43cSflorian mstate->super_set.count == 0) 2345d32eb43cSflorian qstate->env->mesh->num_detached_states++; 2346a8eaceedSflorian mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv); 2347d32eb43cSflorian } 2348d32eb43cSflorian } 2349ab256815Sflorian 2350096314feSflorian void 2351096314feSflorian mesh_respond_serve_expired(struct mesh_state* mstate) 2352096314feSflorian { 2353096314feSflorian if(!mstate->s.serve_expired_data) 2354096314feSflorian mesh_serve_expired_init(mstate, -1); 2355096314feSflorian mesh_serve_expired_callback(mstate); 2356096314feSflorian } 2357096314feSflorian 2358ab256815Sflorian int mesh_jostle_exceeded(struct mesh_area* mesh) 2359ab256815Sflorian { 2360ab256815Sflorian if(mesh->all.count < mesh->max_reply_states) 2361ab256815Sflorian return 0; 2362ab256815Sflorian return 1; 2363ab256815Sflorian } 2364