1933707f3Ssthen /* 2933707f3Ssthen * services/mesh.h - deal with mesh of query states and handle events for that. 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains functions to assist in dealing with a mesh of 40933707f3Ssthen * query states. This mesh is supposed to be thread-specific. 41933707f3Ssthen * It consists of query states (per qname, qtype, qclass) and connections 42933707f3Ssthen * between query states and the super and subquery states, and replies to 43933707f3Ssthen * send back to clients. 44933707f3Ssthen */ 45933707f3Ssthen 46933707f3Ssthen #ifndef SERVICES_MESH_H 47933707f3Ssthen #define SERVICES_MESH_H 48933707f3Ssthen 49933707f3Ssthen #include "util/rbtree.h" 50933707f3Ssthen #include "util/netevent.h" 51933707f3Ssthen #include "util/data/msgparse.h" 52933707f3Ssthen #include "util/module.h" 53933707f3Ssthen #include "services/modstack.h" 54eaf2578eSsthen #include "services/rpz.h" 55eaf2578eSsthen #include "libunbound/unbound.h" 565d76a658Ssthen struct sldns_buffer; 57933707f3Ssthen struct mesh_state; 58933707f3Ssthen struct mesh_reply; 59933707f3Ssthen struct mesh_cb; 60933707f3Ssthen struct query_info; 61933707f3Ssthen struct reply_info; 62933707f3Ssthen struct outbound_entry; 63933707f3Ssthen struct timehist; 642be9e038Ssthen struct respip_client_info; 65933707f3Ssthen 66933707f3Ssthen /** 67933707f3Ssthen * Maximum number of mesh state activations. Any more is likely an 68933707f3Ssthen * infinite loop in the module. It is then terminated. 69933707f3Ssthen */ 70f6b99bafSsthen #define MESH_MAX_ACTIVATION 10000 71933707f3Ssthen 72933707f3Ssthen /** 73933707f3Ssthen * Max number of references-to-references-to-references.. search size. 74933707f3Ssthen * Any more is treated like 'too large', and the creation of a new 75933707f3Ssthen * dependency is failed (so that no loops can be created). 76933707f3Ssthen */ 77933707f3Ssthen #define MESH_MAX_SUBSUB 1024 78933707f3Ssthen 79933707f3Ssthen /** 80933707f3Ssthen * Mesh of query states 81933707f3Ssthen */ 82933707f3Ssthen struct mesh_area { 83933707f3Ssthen /** active module stack */ 84933707f3Ssthen struct module_stack mods; 85933707f3Ssthen /** environment for new states */ 86933707f3Ssthen struct module_env* env; 87933707f3Ssthen 88933707f3Ssthen /** set of runnable queries (mesh_state.run_node) */ 8977079be7Ssthen rbtree_type run; 90933707f3Ssthen /** rbtree of all current queries (mesh_state.node)*/ 9177079be7Ssthen rbtree_type all; 92933707f3Ssthen 93933707f3Ssthen /** count of the total number of mesh_reply entries */ 94933707f3Ssthen size_t num_reply_addrs; 95933707f3Ssthen /** count of the number of mesh_states that have mesh_replies 96933707f3Ssthen * Because a state can send results to multiple reply addresses, 97933707f3Ssthen * this number must be equal or lower than num_reply_addrs. */ 98933707f3Ssthen size_t num_reply_states; 99933707f3Ssthen /** number of mesh_states that have no mesh_replies, and also 100933707f3Ssthen * an empty set of super-states, thus are 'toplevel' or detached 101933707f3Ssthen * internal opportunistic queries */ 102933707f3Ssthen size_t num_detached_states; 103933707f3Ssthen /** number of reply states in the forever list */ 104933707f3Ssthen size_t num_forever_states; 105933707f3Ssthen 106933707f3Ssthen /** max total number of reply states to have */ 107933707f3Ssthen size_t max_reply_states; 108933707f3Ssthen /** max forever number of reply states to have */ 109933707f3Ssthen size_t max_forever_states; 110933707f3Ssthen 111933707f3Ssthen /** stats, cumulative number of reply states jostled out */ 112933707f3Ssthen size_t stats_jostled; 113933707f3Ssthen /** stats, cumulative number of incoming client msgs dropped */ 114933707f3Ssthen size_t stats_dropped; 115eaf2578eSsthen /** stats, number of expired replies sent */ 116eaf2578eSsthen size_t ans_expired; 1178b7325afSsthen /** stats, number of cached replies from cachedb */ 1188b7325afSsthen size_t ans_cachedb; 119933707f3Ssthen /** number of replies sent */ 120933707f3Ssthen size_t replies_sent; 121933707f3Ssthen /** sum of waiting times for the replies */ 122933707f3Ssthen struct timeval replies_sum_wait; 123933707f3Ssthen /** histogram of time values */ 124933707f3Ssthen struct timehist* histogram; 125933707f3Ssthen /** (extended stats) secure replies */ 126933707f3Ssthen size_t ans_secure; 127933707f3Ssthen /** (extended stats) bogus replies */ 128933707f3Ssthen size_t ans_bogus; 129933707f3Ssthen /** (extended stats) rcodes in replies */ 130eaf2578eSsthen size_t ans_rcode[UB_STATS_RCODE_NUM]; 131933707f3Ssthen /** (extended stats) rcode nodata in replies */ 132933707f3Ssthen size_t ans_nodata; 133eaf2578eSsthen /** (extended stats) type of applied RPZ action */ 134eaf2578eSsthen size_t rpz_action[UB_STATS_RPZ_ACTION_NUM]; 135933707f3Ssthen 136933707f3Ssthen /** backup of query if other operations recurse and need the 137933707f3Ssthen * network buffers */ 1385d76a658Ssthen struct sldns_buffer* qbuf_bak; 139933707f3Ssthen 140933707f3Ssthen /** double linked list of the run-to-completion query states. 141933707f3Ssthen * These are query states with a reply */ 142933707f3Ssthen struct mesh_state* forever_first; 143933707f3Ssthen /** last entry in run forever list */ 144933707f3Ssthen struct mesh_state* forever_last; 145933707f3Ssthen 146933707f3Ssthen /** double linked list of the query states that can be jostled out 147933707f3Ssthen * by new queries if too old. These are query states with a reply */ 148933707f3Ssthen struct mesh_state* jostle_first; 149933707f3Ssthen /** last entry in jostle list - this is the entry that is newest */ 150933707f3Ssthen struct mesh_state* jostle_last; 151933707f3Ssthen /** timeout for jostling. if age is lower, it does not get jostled. */ 152933707f3Ssthen struct timeval jostle_max; 153eaf2578eSsthen 154eaf2578eSsthen /** If we need to use response ip (value passed from daemon)*/ 155eaf2578eSsthen int use_response_ip; 156eaf2578eSsthen /** If we need to use RPZ (value passed from daemon) */ 157eaf2578eSsthen int use_rpz; 158933707f3Ssthen }; 159933707f3Ssthen 160933707f3Ssthen /** 161933707f3Ssthen * A mesh query state 162933707f3Ssthen * Unique per qname, qtype, qclass (from the qstate). 163933707f3Ssthen * And RD / CD flag; in case a client turns it off. 164933707f3Ssthen * And priming queries are different from ordinary queries (because of hints). 165933707f3Ssthen * 166933707f3Ssthen * The entire structure is allocated in a region, this region is the qstate 167933707f3Ssthen * region. All parts (rbtree nodes etc) are also allocated in the region. 168933707f3Ssthen */ 169933707f3Ssthen struct mesh_state { 170933707f3Ssthen /** node in mesh_area all tree, key is this struct. Must be first. */ 17177079be7Ssthen rbnode_type node; 172933707f3Ssthen /** node in mesh_area runnable tree, key is this struct */ 17377079be7Ssthen rbnode_type run_node; 174933707f3Ssthen /** the query state. Note that the qinfo and query_flags 175933707f3Ssthen * may not change. */ 176933707f3Ssthen struct module_qstate s; 177933707f3Ssthen /** the list of replies to clients for the results */ 178933707f3Ssthen struct mesh_reply* reply_list; 179933707f3Ssthen /** the list of callbacks for the results */ 180933707f3Ssthen struct mesh_cb* cb_list; 181933707f3Ssthen /** set of superstates (that want this state's result) 182933707f3Ssthen * contains struct mesh_state_ref* */ 18377079be7Ssthen rbtree_type super_set; 184933707f3Ssthen /** set of substates (that this state needs to continue) 185933707f3Ssthen * contains struct mesh_state_ref* */ 18677079be7Ssthen rbtree_type sub_set; 187933707f3Ssthen /** number of activations for the mesh state */ 188933707f3Ssthen size_t num_activated; 189933707f3Ssthen 190933707f3Ssthen /** previous in linked list for reply states */ 191933707f3Ssthen struct mesh_state* prev; 192933707f3Ssthen /** next in linked list for reply states */ 193933707f3Ssthen struct mesh_state* next; 194933707f3Ssthen /** if this state is in the forever list, jostle list, or neither */ 195933707f3Ssthen enum mesh_list_select { mesh_no_list, mesh_forever_list, 196933707f3Ssthen mesh_jostle_list } list_select; 19777079be7Ssthen /** pointer to this state for uniqueness or NULL */ 19877079be7Ssthen struct mesh_state* unique; 199933707f3Ssthen 200933707f3Ssthen /** true if replies have been sent out (at end for alignment) */ 201933707f3Ssthen uint8_t replies_sent; 202933707f3Ssthen }; 203933707f3Ssthen 204933707f3Ssthen /** 205933707f3Ssthen * Rbtree reference to a mesh_state. 206933707f3Ssthen * Used in super_set and sub_set. 207933707f3Ssthen */ 208933707f3Ssthen struct mesh_state_ref { 209933707f3Ssthen /** node in rbtree for set, key is this structure */ 21077079be7Ssthen rbnode_type node; 211933707f3Ssthen /** the mesh state */ 212933707f3Ssthen struct mesh_state* s; 213933707f3Ssthen }; 214933707f3Ssthen 215933707f3Ssthen /** 216933707f3Ssthen * Reply to a client 217933707f3Ssthen */ 218933707f3Ssthen struct mesh_reply { 219933707f3Ssthen /** next in reply list */ 220933707f3Ssthen struct mesh_reply* next; 221933707f3Ssthen /** the query reply destination, packet buffer and where to send. */ 222933707f3Ssthen struct comm_reply query_reply; 223933707f3Ssthen /** edns data from query */ 224933707f3Ssthen struct edns_data edns; 225933707f3Ssthen /** the time when request was entered */ 226933707f3Ssthen struct timeval start_time; 227933707f3Ssthen /** id of query, in network byteorder. */ 228933707f3Ssthen uint16_t qid; 229933707f3Ssthen /** flags of query, for reply flags */ 230933707f3Ssthen uint16_t qflags; 231933707f3Ssthen /** qname from this query. len same as mesh qinfo. */ 232933707f3Ssthen uint8_t* qname; 23377079be7Ssthen /** same as that in query_info. */ 23477079be7Ssthen struct local_rrset* local_alias; 2352c144df0Ssthen /** send query to this http2 stream, if set */ 2362c144df0Ssthen struct http2_stream* h2_stream; 237933707f3Ssthen }; 238933707f3Ssthen 239933707f3Ssthen /** 240933707f3Ssthen * Mesh result callback func. 2412308e98cSsthen * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus, 2422308e98cSsthen * was_ratelimited); 243933707f3Ssthen */ 2442308e98cSsthen typedef void (*mesh_cb_func_type)(void* cb_arg, int rcode, struct sldns_buffer*, 2452308e98cSsthen enum sec_status, char* why_bogus, int was_ratelimited); 246933707f3Ssthen 247933707f3Ssthen /** 248933707f3Ssthen * Callback to result routine 249933707f3Ssthen */ 250933707f3Ssthen struct mesh_cb { 251933707f3Ssthen /** next in list */ 252933707f3Ssthen struct mesh_cb* next; 253933707f3Ssthen /** edns data from query */ 254933707f3Ssthen struct edns_data edns; 255933707f3Ssthen /** id of query, in network byteorder. */ 256933707f3Ssthen uint16_t qid; 257933707f3Ssthen /** flags of query, for reply flags */ 258933707f3Ssthen uint16_t qflags; 259933707f3Ssthen /** buffer for reply */ 2605d76a658Ssthen struct sldns_buffer* buf; 261933707f3Ssthen /** callback routine for results. if rcode != 0 buf has message. 2622308e98cSsthen * called as cb(cb_arg, rcode, buf, sec_state, why_bogus, was_ratelimited); 263933707f3Ssthen */ 26477079be7Ssthen mesh_cb_func_type cb; 265933707f3Ssthen /** user arg for callback */ 266933707f3Ssthen void* cb_arg; 267933707f3Ssthen }; 268933707f3Ssthen 269933707f3Ssthen /* ------------------- Functions for worker -------------------- */ 270933707f3Ssthen 271933707f3Ssthen /** 272933707f3Ssthen * Allocate mesh, to empty. 273933707f3Ssthen * @param stack: module stack to activate, copied (as readonly reference). 274933707f3Ssthen * @param env: environment for new queries. 275933707f3Ssthen * @return mesh: the new mesh or NULL on error. 276933707f3Ssthen */ 277933707f3Ssthen struct mesh_area* mesh_create(struct module_stack* stack, 278933707f3Ssthen struct module_env* env); 279933707f3Ssthen 280933707f3Ssthen /** 281933707f3Ssthen * Delete mesh, and all query states and replies in it. 282933707f3Ssthen * @param mesh: the mesh to delete. 283933707f3Ssthen */ 284933707f3Ssthen void mesh_delete(struct mesh_area* mesh); 285933707f3Ssthen 286933707f3Ssthen /** 287933707f3Ssthen * New query incoming from clients. Create new query state if needed, and 288933707f3Ssthen * add mesh_reply to it. Returns error to client on malloc failures. 289933707f3Ssthen * Will run the mesh area queries to process if a new query state is created. 290933707f3Ssthen * 291933707f3Ssthen * @param mesh: the mesh. 292933707f3Ssthen * @param qinfo: query from client. 2932be9e038Ssthen * @param cinfo: additional information associated with the query client. 2942be9e038Ssthen * 'cinfo' itself is ephemeral but data pointed to by its members 2952be9e038Ssthen * can be assumed to be valid and unchanged until the query processing is 2962be9e038Ssthen * completed. 297933707f3Ssthen * @param qflags: flags from client query. 298933707f3Ssthen * @param edns: edns data from client query. 299933707f3Ssthen * @param rep: where to reply to. 300933707f3Ssthen * @param qid: query id to reply with. 3010bdb4f62Ssthen * @param rpz_passthru: if true, the rpz passthru was previously found and 3020bdb4f62Ssthen * further rpz processing is stopped. 303933707f3Ssthen */ 304933707f3Ssthen void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, 3052be9e038Ssthen struct respip_client_info* cinfo, uint16_t qflags, 3060bdb4f62Ssthen struct edns_data* edns, struct comm_reply* rep, uint16_t qid, 3070bdb4f62Ssthen int rpz_passthru); 308933707f3Ssthen 309933707f3Ssthen /** 310933707f3Ssthen * New query with callback. Create new query state if needed, and 311933707f3Ssthen * add mesh_cb to it. 312933707f3Ssthen * Will run the mesh area queries to process if a new query state is created. 313933707f3Ssthen * 314933707f3Ssthen * @param mesh: the mesh. 315933707f3Ssthen * @param qinfo: query from client. 316933707f3Ssthen * @param qflags: flags from client query. 317933707f3Ssthen * @param edns: edns data from client query. 318933707f3Ssthen * @param buf: buffer for reply contents. 319933707f3Ssthen * @param qid: query id to reply with. 320933707f3Ssthen * @param cb: callback function. 321933707f3Ssthen * @param cb_arg: callback user arg. 3220bdb4f62Ssthen * @param rpz_passthru: if true, the rpz passthru was previously found and 3230bdb4f62Ssthen * further rpz processing is stopped. 324933707f3Ssthen * @return 0 on error. 325933707f3Ssthen */ 326933707f3Ssthen int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, 3275d76a658Ssthen uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, 3280bdb4f62Ssthen uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru); 329933707f3Ssthen 330933707f3Ssthen /** 331933707f3Ssthen * New prefetch message. Create new query state if needed. 332933707f3Ssthen * Will run the mesh area queries to process if a new query state is created. 333933707f3Ssthen * 334933707f3Ssthen * @param mesh: the mesh. 335933707f3Ssthen * @param qinfo: query from client. 336933707f3Ssthen * @param qflags: flags from client query. 337933707f3Ssthen * @param leeway: TTL leeway what to expire earlier for this update. 3380bdb4f62Ssthen * @param rpz_passthru: if true, the rpz passthru was previously found and 3390bdb4f62Ssthen * further rpz processing is stopped. 3408b7325afSsthen * @param addr: sockaddr_storage for the client; to be used with subnet. 3410bdb4f62Ssthen * @param opt_list: edns opt_list from the client; to be used when subnet is 3420bdb4f62Ssthen * enabled. 343933707f3Ssthen */ 344933707f3Ssthen void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo, 3450bdb4f62Ssthen uint16_t qflags, time_t leeway, int rpz_passthru, 3468b7325afSsthen struct sockaddr_storage* addr, struct edns_option* opt_list); 347933707f3Ssthen 348933707f3Ssthen /** 349933707f3Ssthen * Handle new event from the wire. A serviced query has returned. 350933707f3Ssthen * The query state will be made runnable, and the mesh_area will process 351933707f3Ssthen * query states until processing is complete. 352933707f3Ssthen * 353933707f3Ssthen * @param mesh: the query mesh. 354933707f3Ssthen * @param e: outbound entry, with query state to run and reply pointer. 355933707f3Ssthen * @param reply: the comm point reply info. 356933707f3Ssthen * @param what: NETEVENT_* error code (if not 0, what is wrong, TIMEOUT). 357933707f3Ssthen */ 358933707f3Ssthen void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, 359933707f3Ssthen struct comm_reply* reply, int what); 360933707f3Ssthen 361933707f3Ssthen /* ------------------- Functions for module environment --------------- */ 362933707f3Ssthen 363933707f3Ssthen /** 364933707f3Ssthen * Detach-subqueries. 365933707f3Ssthen * Remove all sub-query references from this query state. 366933707f3Ssthen * Keeps super-references of those sub-queries correct. 367933707f3Ssthen * Updates stat items in mesh_area structure. 368933707f3Ssthen * @param qstate: used to find mesh state. 369933707f3Ssthen */ 370933707f3Ssthen void mesh_detach_subs(struct module_qstate* qstate); 371933707f3Ssthen 372933707f3Ssthen /** 373933707f3Ssthen * Attach subquery. 374933707f3Ssthen * Creates it if it does not exist already. 375933707f3Ssthen * Keeps sub and super references correct. 376933707f3Ssthen * Performs a cycle detection - for double check - and fails if there is one. 377933707f3Ssthen * Also fails if the sub-sub-references become too large. 378933707f3Ssthen * Updates stat items in mesh_area structure. 379933707f3Ssthen * Pass if it is priming query or not. 380933707f3Ssthen * return: 381933707f3Ssthen * o if error (malloc) happened. 382933707f3Ssthen * o need to initialise the new state (module init; it is a new state). 383933707f3Ssthen * so that the next run of the query with this module is successful. 384933707f3Ssthen * o no init needed, attachment successful. 385933707f3Ssthen * 386933707f3Ssthen * @param qstate: the state to find mesh state, and that wants to receive 387933707f3Ssthen * the results from the new subquery. 388933707f3Ssthen * @param qinfo: what to query for (copied). 389933707f3Ssthen * @param qflags: what flags to use (RD / CD flag or not). 390933707f3Ssthen * @param prime: if it is a (stub) priming query. 39157dceb2aSbrad * @param valrec: if it is a validation recursion query (lookup of key, DS). 392933707f3Ssthen * @param newq: If the new subquery needs initialisation, it is returned, 393933707f3Ssthen * otherwise NULL is returned. 394933707f3Ssthen * @return: false on error, true if success (and init may be needed). 395933707f3Ssthen */ 396933707f3Ssthen int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, 39757dceb2aSbrad uint16_t qflags, int prime, int valrec, struct module_qstate** newq); 398933707f3Ssthen 399933707f3Ssthen /** 4002be9e038Ssthen * Add detached query. 4012be9e038Ssthen * Creates it if it does not exist already. 4022be9e038Ssthen * Does not make super/sub references. 4032be9e038Ssthen * Performs a cycle detection - for double check - and fails if there is one. 4042be9e038Ssthen * Updates stat items in mesh_area structure. 4052be9e038Ssthen * Pass if it is priming query or not. 4062be9e038Ssthen * return: 4072be9e038Ssthen * o if error (malloc) happened. 4082be9e038Ssthen * o need to initialise the new state (module init; it is a new state). 4092be9e038Ssthen * so that the next run of the query with this module is successful. 4102be9e038Ssthen * o no init needed, attachment successful. 4112be9e038Ssthen * o added subquery, created if it did not exist already. 4122be9e038Ssthen * 4132be9e038Ssthen * @param qstate: the state to find mesh state, and that wants to receive 4142be9e038Ssthen * the results from the new subquery. 4152be9e038Ssthen * @param qinfo: what to query for (copied). 4162be9e038Ssthen * @param qflags: what flags to use (RD / CD flag or not). 4172be9e038Ssthen * @param prime: if it is a (stub) priming query. 4182be9e038Ssthen * @param valrec: if it is a validation recursion query (lookup of key, DS). 4192be9e038Ssthen * @param newq: If the new subquery needs initialisation, it is returned, 4202be9e038Ssthen * otherwise NULL is returned. 4212be9e038Ssthen * @param sub: The added mesh state, created if it did not exist already. 4222be9e038Ssthen * @return: false on error, true if success (and init may be needed). 4232be9e038Ssthen */ 4242be9e038Ssthen int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo, 4252be9e038Ssthen uint16_t qflags, int prime, int valrec, struct module_qstate** newq, 4262be9e038Ssthen struct mesh_state** sub); 4272be9e038Ssthen 4282be9e038Ssthen /** 429933707f3Ssthen * Query state is done, send messages to reply entries. 430933707f3Ssthen * Encode messages using reply entry values and the querystate (with original 431933707f3Ssthen * qinfo), using given reply_info. 432933707f3Ssthen * Pass errcode != 0 if an error reply is needed. 433933707f3Ssthen * If no reply entries, nothing is done. 434933707f3Ssthen * Must be called before a module can module_finished or return module_error. 435933707f3Ssthen * The module must handle the super query states itself as well. 436933707f3Ssthen * 437933707f3Ssthen * @param mstate: mesh state that is done. return_rcode and return_msg 438933707f3Ssthen * are used for replies. 439933707f3Ssthen * return_rcode: if not 0 (NOERROR) an error is sent back (and 440933707f3Ssthen * return_msg is ignored). 441933707f3Ssthen * return_msg: reply to encode and send back to clients. 442933707f3Ssthen */ 443933707f3Ssthen void mesh_query_done(struct mesh_state* mstate); 444933707f3Ssthen 445933707f3Ssthen /** 446933707f3Ssthen * Call inform_super for the super query states that are interested in the 447933707f3Ssthen * results from this query state. These can then be changed for error 448933707f3Ssthen * or results. 449933707f3Ssthen * Called when a module is module_finished or returns module_error. 450933707f3Ssthen * The super query states become runnable with event module_event_pass, 451933707f3Ssthen * it calls the current module for the super with the inform_super event. 452933707f3Ssthen * 453933707f3Ssthen * @param mesh: mesh area to add newly runnable modules to. 454933707f3Ssthen * @param mstate: the state that has results, used to find mesh state. 455933707f3Ssthen */ 456933707f3Ssthen void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate); 457933707f3Ssthen 458933707f3Ssthen /** 459933707f3Ssthen * Delete mesh state, cleanup and also rbtrees and so on. 460933707f3Ssthen * Will detach from all super/subnodes. 461933707f3Ssthen * @param qstate: to remove. 462933707f3Ssthen */ 463933707f3Ssthen void mesh_state_delete(struct module_qstate* qstate); 464933707f3Ssthen 465933707f3Ssthen /* ------------------- Functions for mesh -------------------- */ 466933707f3Ssthen 467933707f3Ssthen /** 468933707f3Ssthen * Create and initialize a new mesh state and its query state 469933707f3Ssthen * Does not put the mesh state into rbtrees and so on. 470933707f3Ssthen * @param env: module environment to set. 471933707f3Ssthen * @param qinfo: query info that the mesh is for. 4722be9e038Ssthen * @param cinfo: control info for the query client (can be NULL). 473933707f3Ssthen * @param qflags: flags for query (RD / CD flag). 474933707f3Ssthen * @param prime: if true, it is a priming query, set is_priming on mesh state. 47557dceb2aSbrad * @param valrec: if true, it is a validation recursion query, and sets 47657dceb2aSbrad * is_valrec on the mesh state. 477933707f3Ssthen * @return: new mesh state or NULL on allocation error. 478933707f3Ssthen */ 479933707f3Ssthen struct mesh_state* mesh_state_create(struct module_env* env, 4802be9e038Ssthen struct query_info* qinfo, struct respip_client_info* cinfo, 4812be9e038Ssthen uint16_t qflags, int prime, int valrec); 482933707f3Ssthen 483933707f3Ssthen /** 48477079be7Ssthen * Make a mesh state unique. 48577079be7Ssthen * A unique mesh state uses it's unique member to point to itself. 48677079be7Ssthen * @param mstate: mesh state to check. 48777079be7Ssthen */ 48877079be7Ssthen void mesh_state_make_unique(struct mesh_state* mstate); 48977079be7Ssthen 49077079be7Ssthen /** 491933707f3Ssthen * Cleanup a mesh state and its query state. Does not do rbtree or 492933707f3Ssthen * reference cleanup. 493933707f3Ssthen * @param mstate: mesh state to cleanup. Its pointer may no longer be used 494933707f3Ssthen * afterwards. Cleanup rbtrees before calling this function. 495933707f3Ssthen */ 496933707f3Ssthen void mesh_state_cleanup(struct mesh_state* mstate); 497933707f3Ssthen 498933707f3Ssthen /** 499933707f3Ssthen * Delete all mesh states from the mesh. 500933707f3Ssthen * @param mesh: the mesh area to clear 501933707f3Ssthen */ 502933707f3Ssthen void mesh_delete_all(struct mesh_area* mesh); 503933707f3Ssthen 504933707f3Ssthen /** 505933707f3Ssthen * Find a mesh state in the mesh area. Pass relevant flags. 506933707f3Ssthen * 507933707f3Ssthen * @param mesh: the mesh area to look in. 5082be9e038Ssthen * @param cinfo: if non-NULL client specific info that may affect IP-based 5092be9e038Ssthen * actions that apply to the query result. 510933707f3Ssthen * @param qinfo: what query 511933707f3Ssthen * @param qflags: if RD / CD bit is set or not. 512933707f3Ssthen * @param prime: if it is a priming query. 51357dceb2aSbrad * @param valrec: if it is a validation-recursion query. 514933707f3Ssthen * @return: mesh state or NULL if not found. 515933707f3Ssthen */ 516933707f3Ssthen struct mesh_state* mesh_area_find(struct mesh_area* mesh, 5172be9e038Ssthen struct respip_client_info* cinfo, struct query_info* qinfo, 5182be9e038Ssthen uint16_t qflags, int prime, int valrec); 519933707f3Ssthen 520933707f3Ssthen /** 521933707f3Ssthen * Setup attachment super/sub relation between super and sub mesh state. 522933707f3Ssthen * The relation must not be present when calling the function. 523933707f3Ssthen * Does not update stat items in mesh_area. 524933707f3Ssthen * @param super: super state. 525933707f3Ssthen * @param sub: sub state. 526933707f3Ssthen * @return: 0 on alloc error. 527933707f3Ssthen */ 528933707f3Ssthen int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub); 529933707f3Ssthen 530933707f3Ssthen /** 531933707f3Ssthen * Create new reply structure and attach it to a mesh state. 532933707f3Ssthen * Does not update stat items in mesh area. 533933707f3Ssthen * @param s: the mesh state. 534933707f3Ssthen * @param edns: edns data for reply (bufsize). 535933707f3Ssthen * @param rep: comm point reply info. 536933707f3Ssthen * @param qid: ID of reply. 537933707f3Ssthen * @param qflags: original query flags. 53877079be7Ssthen * @param qinfo: original query info. 539933707f3Ssthen * @return: 0 on alloc error. 540933707f3Ssthen */ 541933707f3Ssthen int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, 54277079be7Ssthen struct comm_reply* rep, uint16_t qid, uint16_t qflags, 54377079be7Ssthen const struct query_info* qinfo); 544933707f3Ssthen 545933707f3Ssthen /** 546933707f3Ssthen * Create new callback structure and attach it to a mesh state. 547933707f3Ssthen * Does not update stat items in mesh area. 548933707f3Ssthen * @param s: the mesh state. 549933707f3Ssthen * @param edns: edns data for reply (bufsize). 550933707f3Ssthen * @param buf: buffer for reply 551933707f3Ssthen * @param cb: callback to call with results. 552933707f3Ssthen * @param cb_arg: callback user arg. 553933707f3Ssthen * @param qid: ID of reply. 554933707f3Ssthen * @param qflags: original query flags. 555933707f3Ssthen * @return: 0 on alloc error. 556933707f3Ssthen */ 557933707f3Ssthen int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, 55877079be7Ssthen struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, 55977079be7Ssthen uint16_t qid, uint16_t qflags); 560933707f3Ssthen 561933707f3Ssthen /** 562933707f3Ssthen * Run the mesh. Run all runnable mesh states. Which can create new 563933707f3Ssthen * runnable mesh states. Until completion. Automatically called by 564933707f3Ssthen * mesh_report_reply and mesh_new_client as needed. 565933707f3Ssthen * @param mesh: mesh area. 566933707f3Ssthen * @param mstate: first mesh state to run. 567933707f3Ssthen * @param ev: event the mstate. Others get event_pass. 568933707f3Ssthen * @param e: if a reply, its outbound entry. 569933707f3Ssthen */ 570933707f3Ssthen void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate, 571933707f3Ssthen enum module_ev ev, struct outbound_entry* e); 572933707f3Ssthen 573933707f3Ssthen /** 574933707f3Ssthen * Print some stats about the mesh to the log. 575933707f3Ssthen * @param mesh: the mesh to print it for. 576933707f3Ssthen * @param str: descriptive string to go with it. 577933707f3Ssthen */ 578933707f3Ssthen void mesh_stats(struct mesh_area* mesh, const char* str); 579933707f3Ssthen 580933707f3Ssthen /** 581933707f3Ssthen * Clear the stats that the mesh keeps (number of queries serviced) 582933707f3Ssthen * @param mesh: the mesh 583933707f3Ssthen */ 584933707f3Ssthen void mesh_stats_clear(struct mesh_area* mesh); 585933707f3Ssthen 586933707f3Ssthen /** 587933707f3Ssthen * Print all the states in the mesh to the log. 588933707f3Ssthen * @param mesh: the mesh to print all states of. 589933707f3Ssthen */ 590933707f3Ssthen void mesh_log_list(struct mesh_area* mesh); 591933707f3Ssthen 592933707f3Ssthen /** 593933707f3Ssthen * Calculate memory size in use by mesh and all queries inside it. 594933707f3Ssthen * @param mesh: the mesh to examine. 595933707f3Ssthen * @return size in bytes. 596933707f3Ssthen */ 597933707f3Ssthen size_t mesh_get_mem(struct mesh_area* mesh); 598933707f3Ssthen 599933707f3Ssthen /** 600933707f3Ssthen * Find cycle; see if the given mesh is in the targets sub, or sub-sub, ... 601933707f3Ssthen * trees. 602933707f3Ssthen * If the sub-sub structure is too large, it returns 'a cycle'=2. 603933707f3Ssthen * @param qstate: given mesh querystate. 604933707f3Ssthen * @param qinfo: query info for dependency. 605933707f3Ssthen * @param flags: query flags of dependency. 606933707f3Ssthen * @param prime: if dependency is a priming query or not. 60757dceb2aSbrad * @param valrec: if it is a validation recursion query (lookup of key, DS). 608933707f3Ssthen * @return true if the name,type,class exists and the given qstate mesh exists 609933707f3Ssthen * as a dependency of that name. Thus if qstate becomes dependent on 610933707f3Ssthen * name,type,class then a cycle is created, this is return value 1. 611933707f3Ssthen * Too large to search is value 2 (also true). 612933707f3Ssthen */ 613933707f3Ssthen int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo, 61457dceb2aSbrad uint16_t flags, int prime, int valrec); 615933707f3Ssthen 616933707f3Ssthen /** compare two mesh_states */ 617933707f3Ssthen int mesh_state_compare(const void* ap, const void* bp); 618933707f3Ssthen 619933707f3Ssthen /** compare two mesh references */ 620933707f3Ssthen int mesh_state_ref_compare(const void* ap, const void* bp); 621933707f3Ssthen 622933707f3Ssthen /** 623933707f3Ssthen * Make space for another recursion state for a reply in the mesh 624933707f3Ssthen * @param mesh: mesh area 625933707f3Ssthen * @param qbuf: query buffer to save if recursion is invoked to make space. 626933707f3Ssthen * This buffer is necessary, because the following sequence in calls 627933707f3Ssthen * can result in an overwrite of the incoming query: 628933707f3Ssthen * delete_other_mesh_query - iter_clean - serviced_delete - waiting 629933707f3Ssthen * udp query is sent - on error callback - callback sends SERVFAIL reply 630933707f3Ssthen * over the same network channel, and shared UDP buffer is overwritten. 631933707f3Ssthen * You can pass NULL if there is no buffer that must be backed up. 632933707f3Ssthen * @return false if no space is available. 633933707f3Ssthen */ 6345d76a658Ssthen int mesh_make_new_space(struct mesh_area* mesh, struct sldns_buffer* qbuf); 635933707f3Ssthen 636933707f3Ssthen /** 637933707f3Ssthen * Insert mesh state into a double linked list. Inserted at end. 638933707f3Ssthen * @param m: mesh state. 639933707f3Ssthen * @param fp: pointer to the first-elem-pointer of the list. 640933707f3Ssthen * @param lp: pointer to the last-elem-pointer of the list. 641933707f3Ssthen */ 642933707f3Ssthen void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp, 643933707f3Ssthen struct mesh_state** lp); 644933707f3Ssthen 645933707f3Ssthen /** 646933707f3Ssthen * Remove mesh state from a double linked list. Remove from any position. 647933707f3Ssthen * @param m: mesh state. 648933707f3Ssthen * @param fp: pointer to the first-elem-pointer of the list. 649933707f3Ssthen * @param lp: pointer to the last-elem-pointer of the list. 650933707f3Ssthen */ 651933707f3Ssthen void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp, 652933707f3Ssthen struct mesh_state** lp); 653933707f3Ssthen 654f6b99bafSsthen /** 655f6b99bafSsthen * Remove mesh reply entry from the reply entry list. Searches for 656f6b99bafSsthen * the comm_point pointer. 657f6b99bafSsthen * @param mesh: to update the counters. 658f6b99bafSsthen * @param m: the mesh state. 659f6b99bafSsthen * @param cp: the comm_point to remove from the list. 660f6b99bafSsthen */ 661f6b99bafSsthen void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, 662f6b99bafSsthen struct comm_point* cp); 663f6b99bafSsthen 664eaf2578eSsthen /** Callback for when the serve expired client timer has run out. Tries to 665eaf2578eSsthen * find an expired answer in the cache and reply that to the client. 666eaf2578eSsthen * @param arg: the argument passed to the callback. 667eaf2578eSsthen */ 668eaf2578eSsthen void mesh_serve_expired_callback(void* arg); 669eaf2578eSsthen 670eaf2578eSsthen /** 671eaf2578eSsthen * Try to get a (expired) cached answer. 672eaf2578eSsthen * This needs to behave like the worker's answer_from_cache() in order to have 673eaf2578eSsthen * the same behavior as when replying from cache. 674eaf2578eSsthen * @param qstate: the module qstate. 675eaf2578eSsthen * @param lookup_qinfo: the query info to look for in the cache. 676eaf2578eSsthen * @return dns_msg if a cached answer was found, otherwise NULL. 677eaf2578eSsthen */ 678eaf2578eSsthen struct dns_msg* 679eaf2578eSsthen mesh_serve_expired_lookup(struct module_qstate* qstate, 680eaf2578eSsthen struct query_info* lookup_qinfo); 681eaf2578eSsthen 6827dd170e2Ssthen /** 6837dd170e2Ssthen * See if the mesh has space for more queries. You can allocate queries 6847dd170e2Ssthen * anyway, but this checks for the allocated space. 6857dd170e2Ssthen * @param mesh: mesh area. 6867dd170e2Ssthen * @return true if the query list is full. 6877dd170e2Ssthen * It checks the number of all queries, not just number of reply states, 6887dd170e2Ssthen * that have a client address. So that spawned queries count too, 6897dd170e2Ssthen * that were created by the iterator, or other modules. 6907dd170e2Ssthen */ 6917dd170e2Ssthen int mesh_jostle_exceeded(struct mesh_area* mesh); 6927dd170e2Ssthen 693*2bdc0ed1Ssthen /** 694*2bdc0ed1Ssthen * Give the serve expired responses. 695*2bdc0ed1Ssthen * @param mstate: mesh state for query that has serve_expired_data. 696*2bdc0ed1Ssthen */ 697*2bdc0ed1Ssthen void mesh_respond_serve_expired(struct mesh_state* mstate); 698*2bdc0ed1Ssthen 699933707f3Ssthen #endif /* SERVICES_MESH_H */ 700