1933707f3Ssthen /* 2933707f3Ssthen * libunbound/context.c - validating context for unbound internal use 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 the validator context structure. 40933707f3Ssthen */ 41933707f3Ssthen #include "config.h" 42933707f3Ssthen #include "libunbound/context.h" 43933707f3Ssthen #include "util/module.h" 44933707f3Ssthen #include "util/config_file.h" 45933707f3Ssthen #include "util/net_help.h" 46933707f3Ssthen #include "services/modstack.h" 47933707f3Ssthen #include "services/localzone.h" 48933707f3Ssthen #include "services/cache/rrset.h" 49933707f3Ssthen #include "services/cache/infra.h" 50938a3a5eSflorian #include "services/authzone.h" 51e21c60efSsthen #include "services/listen_dnsport.h" 52933707f3Ssthen #include "util/data/msgreply.h" 53933707f3Ssthen #include "util/storage/slabhash.h" 542c144df0Ssthen #include "util/edns.h" 55fdfb4ba6Ssthen #include "sldns/sbuffer.h" 562bdc0ed1Ssthen #include "iterator/iter_fwd.h" 572bdc0ed1Ssthen #include "iterator/iter_hints.h" 58933707f3Ssthen 59933707f3Ssthen int 60933707f3Ssthen context_finalize(struct ub_ctx* ctx) 61933707f3Ssthen { 62eaf2578eSsthen int is_rpz = 0; 63933707f3Ssthen struct config_file* cfg = ctx->env->cfg; 64933707f3Ssthen verbosity = cfg->verbosity; 658240c1b9Ssthen if(ctx_logfile_overridden && !ctx->logfile_override) { 668240c1b9Ssthen log_file(NULL); /* clear that override */ 678240c1b9Ssthen ctx_logfile_overridden = 0; 688240c1b9Ssthen } 698240c1b9Ssthen if(ctx->logfile_override) { 708240c1b9Ssthen ctx_logfile_overridden = 1; 71933707f3Ssthen log_file(ctx->log_out); 728240c1b9Ssthen } else { 738240c1b9Ssthen log_init(cfg->logfile, cfg->use_syslog, NULL); 748240c1b9Ssthen } 758b7325afSsthen ctx->pipe_pid = getpid(); 76191f22c6Ssthen cfg_apply_local_port_policy(cfg, 65536); 77933707f3Ssthen config_apply(cfg); 78*98bc733bSsthen if(!modstack_call_startup(&ctx->mods, cfg->module_conf, ctx->env)) 79*98bc733bSsthen return UB_INITFAIL; 80*98bc733bSsthen if(!modstack_call_init(&ctx->mods, cfg->module_conf, ctx->env)) 81933707f3Ssthen return UB_INITFAIL; 82e21c60efSsthen listen_setup_locks(); 8377079be7Ssthen log_edns_known_options(VERB_ALGO, ctx->env); 84933707f3Ssthen ctx->local_zones = local_zones_create(); 85933707f3Ssthen if(!ctx->local_zones) 86933707f3Ssthen return UB_NOMEM; 87933707f3Ssthen if(!local_zones_apply_cfg(ctx->local_zones, cfg)) 88933707f3Ssthen return UB_INITFAIL; 89191f22c6Ssthen if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz, 90191f22c6Ssthen ctx->env, &ctx->mods)) 91938a3a5eSflorian return UB_INITFAIL; 922bdc0ed1Ssthen if(!(ctx->env->fwds = forwards_create()) || 932bdc0ed1Ssthen !forwards_apply_cfg(ctx->env->fwds, cfg)) 942bdc0ed1Ssthen return UB_INITFAIL; 952bdc0ed1Ssthen if(!(ctx->env->hints = hints_create()) || 962bdc0ed1Ssthen !hints_apply_cfg(ctx->env->hints, cfg)) 972bdc0ed1Ssthen return UB_INITFAIL; 98eba819a2Ssthen if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg)) 992c144df0Ssthen return UB_INITFAIL; 1002308e98cSsthen if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, 1012308e98cSsthen cfg->msg_cache_slabs)) { 102933707f3Ssthen slabhash_delete(ctx->env->msg_cache); 103933707f3Ssthen ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, 104933707f3Ssthen HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, 105933707f3Ssthen msgreply_sizefunc, query_info_compare, 106933707f3Ssthen query_entry_delete, reply_info_delete, NULL); 107933707f3Ssthen if(!ctx->env->msg_cache) 108933707f3Ssthen return UB_NOMEM; 109933707f3Ssthen } 110933707f3Ssthen ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, 111933707f3Ssthen ctx->env->cfg, ctx->env->alloc); 112933707f3Ssthen if(!ctx->env->rrset_cache) 113933707f3Ssthen return UB_NOMEM; 114933707f3Ssthen ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); 115933707f3Ssthen if(!ctx->env->infra_cache) 116933707f3Ssthen return UB_NOMEM; 117933707f3Ssthen ctx->finalized = 1; 118933707f3Ssthen return UB_NOERROR; 119933707f3Ssthen } 120933707f3Ssthen 121933707f3Ssthen int context_query_cmp(const void* a, const void* b) 122933707f3Ssthen { 123933707f3Ssthen if( *(int*)a < *(int*)b ) 124933707f3Ssthen return -1; 125933707f3Ssthen if( *(int*)a > *(int*)b ) 126933707f3Ssthen return 1; 127933707f3Ssthen return 0; 128933707f3Ssthen } 129933707f3Ssthen 130933707f3Ssthen void 131933707f3Ssthen context_query_delete(struct ctx_query* q) 132933707f3Ssthen { 133933707f3Ssthen if(!q) return; 134933707f3Ssthen ub_resolve_free(q->res); 135933707f3Ssthen free(q->msg); 136933707f3Ssthen free(q); 137933707f3Ssthen } 138933707f3Ssthen 139933707f3Ssthen /** How many times to try to find an unused query-id-number for async */ 140933707f3Ssthen #define NUM_ID_TRIES 100000 141933707f3Ssthen /** find next useful id number of 0 on error */ 142933707f3Ssthen static int 143933707f3Ssthen find_id(struct ub_ctx* ctx, int* id) 144933707f3Ssthen { 145933707f3Ssthen size_t tries = 0; 146933707f3Ssthen ctx->next_querynum++; 147933707f3Ssthen while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { 148933707f3Ssthen ctx->next_querynum++; /* numerical wraparound is fine */ 149933707f3Ssthen if(tries++ > NUM_ID_TRIES) 150933707f3Ssthen return 0; 151933707f3Ssthen } 152933707f3Ssthen *id = ctx->next_querynum; 153933707f3Ssthen return 1; 154933707f3Ssthen } 155933707f3Ssthen 156933707f3Ssthen struct ctx_query* 157229e174cSsthen context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 15820237c55Ssthen ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg) 159933707f3Ssthen { 160933707f3Ssthen struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 161933707f3Ssthen if(!q) return NULL; 162933707f3Ssthen lock_basic_lock(&ctx->cfglock); 163933707f3Ssthen if(!find_id(ctx, &q->querynum)) { 164933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 165933707f3Ssthen free(q); 166933707f3Ssthen return NULL; 167933707f3Ssthen } 168933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 169933707f3Ssthen q->node.key = &q->querynum; 17020237c55Ssthen q->async = (cb != NULL || cb_event != NULL); 171933707f3Ssthen q->cb = cb; 17220237c55Ssthen q->cb_event = cb_event; 173933707f3Ssthen q->cb_arg = cbarg; 174933707f3Ssthen q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 175933707f3Ssthen if(!q->res) { 176933707f3Ssthen free(q); 177933707f3Ssthen return NULL; 178933707f3Ssthen } 179933707f3Ssthen q->res->qname = strdup(name); 180933707f3Ssthen if(!q->res->qname) { 181933707f3Ssthen free(q->res); 182933707f3Ssthen free(q); 183933707f3Ssthen return NULL; 184933707f3Ssthen } 185933707f3Ssthen q->res->qtype = rrtype; 186933707f3Ssthen q->res->qclass = rrclass; 187933707f3Ssthen 188933707f3Ssthen /* add to query list */ 189933707f3Ssthen lock_basic_lock(&ctx->cfglock); 190933707f3Ssthen if(q->async) 191933707f3Ssthen ctx->num_async ++; 192933707f3Ssthen (void)rbtree_insert(&ctx->queries, &q->node); 193933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 194933707f3Ssthen return q; 195933707f3Ssthen } 196933707f3Ssthen 197933707f3Ssthen struct alloc_cache* 198933707f3Ssthen context_obtain_alloc(struct ub_ctx* ctx, int locking) 199933707f3Ssthen { 200933707f3Ssthen struct alloc_cache* a; 201933707f3Ssthen int tnum = 0; 202933707f3Ssthen if(locking) { 203933707f3Ssthen lock_basic_lock(&ctx->cfglock); 204933707f3Ssthen } 205933707f3Ssthen a = ctx->alloc_list; 206933707f3Ssthen if(a) 207933707f3Ssthen ctx->alloc_list = a->super; /* snip off list */ 208933707f3Ssthen else tnum = ctx->thr_next_num++; 209933707f3Ssthen if(locking) { 210933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 211933707f3Ssthen } 212933707f3Ssthen if(a) { 213933707f3Ssthen a->super = &ctx->superalloc; 214933707f3Ssthen return a; 215933707f3Ssthen } 216933707f3Ssthen a = (struct alloc_cache*)calloc(1, sizeof(*a)); 217933707f3Ssthen if(!a) 218933707f3Ssthen return NULL; 219933707f3Ssthen alloc_init(a, &ctx->superalloc, tnum); 220933707f3Ssthen return a; 221933707f3Ssthen } 222933707f3Ssthen 223933707f3Ssthen void 224933707f3Ssthen context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, 225933707f3Ssthen int locking) 226933707f3Ssthen { 227933707f3Ssthen if(!ctx || !alloc) 228933707f3Ssthen return; 229933707f3Ssthen if(locking) { 230933707f3Ssthen lock_basic_lock(&ctx->cfglock); 231933707f3Ssthen } 232933707f3Ssthen alloc->super = ctx->alloc_list; 233933707f3Ssthen ctx->alloc_list = alloc; 234933707f3Ssthen if(locking) { 235933707f3Ssthen lock_basic_unlock(&ctx->cfglock); 236933707f3Ssthen } 237933707f3Ssthen } 238933707f3Ssthen 239933707f3Ssthen uint8_t* 240933707f3Ssthen context_serialize_new_query(struct ctx_query* q, uint32_t* len) 241933707f3Ssthen { 242933707f3Ssthen /* format for new query is 243933707f3Ssthen * o uint32 cmd 244933707f3Ssthen * o uint32 id 245933707f3Ssthen * o uint32 type 246933707f3Ssthen * o uint32 class 247933707f3Ssthen * o rest queryname (string) 248933707f3Ssthen */ 249933707f3Ssthen uint8_t* p; 250933707f3Ssthen size_t slen = strlen(q->res->qname) + 1/*end of string*/; 251933707f3Ssthen *len = sizeof(uint32_t)*4 + slen; 252933707f3Ssthen p = (uint8_t*)malloc(*len); 253933707f3Ssthen if(!p) return NULL; 2545d76a658Ssthen sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); 2555d76a658Ssthen sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 2565d76a658Ssthen sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); 2575d76a658Ssthen sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); 258933707f3Ssthen memmove(p+4*sizeof(uint32_t), q->res->qname, slen); 259933707f3Ssthen return p; 260933707f3Ssthen } 261933707f3Ssthen 262933707f3Ssthen struct ctx_query* 263933707f3Ssthen context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 264933707f3Ssthen { 265933707f3Ssthen struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 266933707f3Ssthen if(!q) return NULL; 267933707f3Ssthen if(len < 4*sizeof(uint32_t)+1) { 268933707f3Ssthen free(q); 269933707f3Ssthen return NULL; 270933707f3Ssthen } 2715d76a658Ssthen log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 2725d76a658Ssthen q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 273933707f3Ssthen q->node.key = &q->querynum; 274933707f3Ssthen q->async = 1; 275933707f3Ssthen q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 276933707f3Ssthen if(!q->res) { 277933707f3Ssthen free(q); 278933707f3Ssthen return NULL; 279933707f3Ssthen } 2805d76a658Ssthen q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 2815d76a658Ssthen q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); 282933707f3Ssthen q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); 283933707f3Ssthen if(!q->res->qname) { 284933707f3Ssthen free(q->res); 285933707f3Ssthen free(q); 286933707f3Ssthen return NULL; 287933707f3Ssthen } 288933707f3Ssthen 289933707f3Ssthen /** add to query list */ 290933707f3Ssthen ctx->num_async++; 291933707f3Ssthen (void)rbtree_insert(&ctx->queries, &q->node); 292933707f3Ssthen return q; 293933707f3Ssthen } 294933707f3Ssthen 295933707f3Ssthen struct ctx_query* 296933707f3Ssthen context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 297933707f3Ssthen { 298933707f3Ssthen struct ctx_query* q; 299933707f3Ssthen int querynum; 300933707f3Ssthen if(len < 4*sizeof(uint32_t)+1) { 301933707f3Ssthen return NULL; 302933707f3Ssthen } 3035d76a658Ssthen log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 3045d76a658Ssthen querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 305933707f3Ssthen q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); 306933707f3Ssthen if(!q) { 307933707f3Ssthen return NULL; 308933707f3Ssthen } 309933707f3Ssthen log_assert(q->async); 310933707f3Ssthen return q; 311933707f3Ssthen } 312933707f3Ssthen 313933707f3Ssthen uint8_t* 3145d76a658Ssthen context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, 315933707f3Ssthen uint32_t* len) 316933707f3Ssthen { 317933707f3Ssthen /* answer format 318933707f3Ssthen * o uint32 cmd 319933707f3Ssthen * o uint32 id 320933707f3Ssthen * o uint32 error_code 321933707f3Ssthen * o uint32 msg_security 3222308e98cSsthen * o uint32 was_ratelimited 323933707f3Ssthen * o uint32 length of why_bogus string (+1 for eos); 0 absent. 324933707f3Ssthen * o why_bogus_string 325933707f3Ssthen * o the remainder is the answer msg from resolver lookup. 326933707f3Ssthen * remainder can be length 0. 327933707f3Ssthen */ 3282308e98cSsthen size_t size_of_uint32s = 6 * sizeof(uint32_t); 3295d76a658Ssthen size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0; 330933707f3Ssthen size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0; 331933707f3Ssthen uint8_t* p; 3322308e98cSsthen *len = size_of_uint32s + pkt_len + wlen; 333933707f3Ssthen p = (uint8_t*)malloc(*len); 334933707f3Ssthen if(!p) return NULL; 3355d76a658Ssthen sldns_write_uint32(p, UB_LIBCMD_ANSWER); 3365d76a658Ssthen sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 3375d76a658Ssthen sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); 3385d76a658Ssthen sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); 3392308e98cSsthen sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited); 3402308e98cSsthen sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen); 341933707f3Ssthen if(wlen > 0) 3422308e98cSsthen memmove(p+size_of_uint32s, q->res->why_bogus, wlen); 343933707f3Ssthen if(pkt_len > 0) 3442308e98cSsthen memmove(p+size_of_uint32s+wlen, 3455d76a658Ssthen sldns_buffer_begin(pkt), pkt_len); 346933707f3Ssthen return p; 347933707f3Ssthen } 348933707f3Ssthen 349933707f3Ssthen struct ctx_query* 350933707f3Ssthen context_deserialize_answer(struct ub_ctx* ctx, 351933707f3Ssthen uint8_t* p, uint32_t len, int* err) 352933707f3Ssthen { 3532308e98cSsthen size_t size_of_uint32s = 6 * sizeof(uint32_t); 354933707f3Ssthen struct ctx_query* q = NULL ; 355933707f3Ssthen int id; 356933707f3Ssthen size_t wlen; 3572308e98cSsthen if(len < size_of_uint32s) return NULL; 3585d76a658Ssthen log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER); 3595d76a658Ssthen id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 360933707f3Ssthen q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 361933707f3Ssthen if(!q) return NULL; 3625d76a658Ssthen *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 3635d76a658Ssthen q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t)); 3642308e98cSsthen q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t)); 3652308e98cSsthen wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t)); 3662308e98cSsthen if(len > size_of_uint32s && wlen > 0) { 3672308e98cSsthen if(len >= size_of_uint32s+wlen) 368933707f3Ssthen q->res->why_bogus = (char*)memdup( 3692308e98cSsthen p+size_of_uint32s, wlen); 370933707f3Ssthen if(!q->res->why_bogus) { 371933707f3Ssthen /* pass malloc failure to the user callback */ 372933707f3Ssthen q->msg_len = 0; 373933707f3Ssthen *err = UB_NOMEM; 374933707f3Ssthen return q; 375933707f3Ssthen } 376933707f3Ssthen q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */ 377933707f3Ssthen } 3782308e98cSsthen if(len > size_of_uint32s+wlen) { 3792308e98cSsthen q->msg_len = len - size_of_uint32s - wlen; 3802308e98cSsthen q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen, 381933707f3Ssthen q->msg_len); 382933707f3Ssthen if(!q->msg) { 383933707f3Ssthen /* pass malloc failure to the user callback */ 384933707f3Ssthen q->msg_len = 0; 385933707f3Ssthen *err = UB_NOMEM; 386933707f3Ssthen return q; 387933707f3Ssthen } 388933707f3Ssthen } 389933707f3Ssthen return q; 390933707f3Ssthen } 391933707f3Ssthen 392933707f3Ssthen uint8_t* 393933707f3Ssthen context_serialize_cancel(struct ctx_query* q, uint32_t* len) 394933707f3Ssthen { 395933707f3Ssthen /* format of cancel: 396933707f3Ssthen * o uint32 cmd 397933707f3Ssthen * o uint32 async-id */ 398fdfb4ba6Ssthen uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); 399933707f3Ssthen if(!p) return NULL; 400933707f3Ssthen *len = 2*sizeof(uint32_t); 4015d76a658Ssthen sldns_write_uint32(p, UB_LIBCMD_CANCEL); 4025d76a658Ssthen sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 403933707f3Ssthen return p; 404933707f3Ssthen } 405933707f3Ssthen 406933707f3Ssthen struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, 407933707f3Ssthen uint8_t* p, uint32_t len) 408933707f3Ssthen { 409933707f3Ssthen struct ctx_query* q; 410933707f3Ssthen int id; 411933707f3Ssthen if(len != 2*sizeof(uint32_t)) return NULL; 4125d76a658Ssthen log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); 4135d76a658Ssthen id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 414933707f3Ssthen q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 415933707f3Ssthen return q; 416933707f3Ssthen } 417933707f3Ssthen 418933707f3Ssthen uint8_t* 419933707f3Ssthen context_serialize_quit(uint32_t* len) 420933707f3Ssthen { 421452a1548Ssthen uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t)); 422933707f3Ssthen if(!p) 423933707f3Ssthen return NULL; 424933707f3Ssthen *len = sizeof(uint32_t); 4255d76a658Ssthen sldns_write_uint32(p, UB_LIBCMD_QUIT); 426452a1548Ssthen return (uint8_t*)p; 427933707f3Ssthen } 428933707f3Ssthen 429933707f3Ssthen enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) 430933707f3Ssthen { 431933707f3Ssthen uint32_t v; 432933707f3Ssthen if((size_t)len < sizeof(v)) 433933707f3Ssthen return UB_LIBCMD_QUIT; 4345d76a658Ssthen v = sldns_read_uint32(p); 435933707f3Ssthen return v; 436933707f3Ssthen } 437