1238106Sdes/* 2238106Sdes * libunbound/context.c - validating context for unbound internal use 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains the validator context structure. 40238106Sdes */ 41238106Sdes#include "config.h" 42238106Sdes#include "libunbound/context.h" 43238106Sdes#include "util/module.h" 44238106Sdes#include "util/config_file.h" 45238106Sdes#include "util/net_help.h" 46238106Sdes#include "services/modstack.h" 47238106Sdes#include "services/localzone.h" 48238106Sdes#include "services/cache/rrset.h" 49238106Sdes#include "services/cache/infra.h" 50238106Sdes#include "util/data/msgreply.h" 51238106Sdes#include "util/storage/slabhash.h" 52291767Sdes#include "sldns/sbuffer.h" 53238106Sdes 54238106Sdesint 55238106Sdescontext_finalize(struct ub_ctx* ctx) 56238106Sdes{ 57238106Sdes struct config_file* cfg = ctx->env->cfg; 58238106Sdes verbosity = cfg->verbosity; 59238106Sdes if(ctx->logfile_override) 60238106Sdes log_file(ctx->log_out); 61238106Sdes else log_init(cfg->logfile, cfg->use_syslog, NULL); 62238106Sdes config_apply(cfg); 63238106Sdes if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) 64238106Sdes return UB_INITFAIL; 65238106Sdes ctx->local_zones = local_zones_create(); 66238106Sdes if(!ctx->local_zones) 67238106Sdes return UB_NOMEM; 68238106Sdes if(!local_zones_apply_cfg(ctx->local_zones, cfg)) 69238106Sdes return UB_INITFAIL; 70238106Sdes if(!ctx->env->msg_cache || 71238106Sdes cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) || 72238106Sdes cfg->msg_cache_slabs != ctx->env->msg_cache->size) { 73238106Sdes slabhash_delete(ctx->env->msg_cache); 74238106Sdes ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, 75238106Sdes HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, 76238106Sdes msgreply_sizefunc, query_info_compare, 77238106Sdes query_entry_delete, reply_info_delete, NULL); 78238106Sdes if(!ctx->env->msg_cache) 79238106Sdes return UB_NOMEM; 80238106Sdes } 81238106Sdes ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, 82238106Sdes ctx->env->cfg, ctx->env->alloc); 83238106Sdes if(!ctx->env->rrset_cache) 84238106Sdes return UB_NOMEM; 85238106Sdes ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); 86238106Sdes if(!ctx->env->infra_cache) 87238106Sdes return UB_NOMEM; 88238106Sdes ctx->finalized = 1; 89238106Sdes return UB_NOERROR; 90238106Sdes} 91238106Sdes 92238106Sdesint context_query_cmp(const void* a, const void* b) 93238106Sdes{ 94238106Sdes if( *(int*)a < *(int*)b ) 95238106Sdes return -1; 96238106Sdes if( *(int*)a > *(int*)b ) 97238106Sdes return 1; 98238106Sdes return 0; 99238106Sdes} 100238106Sdes 101238106Sdesvoid 102238106Sdescontext_query_delete(struct ctx_query* q) 103238106Sdes{ 104238106Sdes if(!q) return; 105238106Sdes ub_resolve_free(q->res); 106238106Sdes free(q->msg); 107238106Sdes free(q); 108238106Sdes} 109238106Sdes 110238106Sdes/** How many times to try to find an unused query-id-number for async */ 111238106Sdes#define NUM_ID_TRIES 100000 112238106Sdes/** find next useful id number of 0 on error */ 113238106Sdesstatic int 114238106Sdesfind_id(struct ub_ctx* ctx, int* id) 115238106Sdes{ 116238106Sdes size_t tries = 0; 117238106Sdes ctx->next_querynum++; 118238106Sdes while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { 119238106Sdes ctx->next_querynum++; /* numerical wraparound is fine */ 120238106Sdes if(tries++ > NUM_ID_TRIES) 121238106Sdes return 0; 122238106Sdes } 123238106Sdes *id = ctx->next_querynum; 124238106Sdes return 1; 125238106Sdes} 126238106Sdes 127238106Sdesstruct ctx_query* 128269257Sdescontext_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 129238106Sdes ub_callback_t cb, void* cbarg) 130238106Sdes{ 131238106Sdes struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 132238106Sdes if(!q) return NULL; 133238106Sdes lock_basic_lock(&ctx->cfglock); 134238106Sdes if(!find_id(ctx, &q->querynum)) { 135238106Sdes lock_basic_unlock(&ctx->cfglock); 136238106Sdes free(q); 137238106Sdes return NULL; 138238106Sdes } 139238106Sdes lock_basic_unlock(&ctx->cfglock); 140238106Sdes q->node.key = &q->querynum; 141238106Sdes q->async = (cb != NULL); 142238106Sdes q->cb = cb; 143238106Sdes q->cb_arg = cbarg; 144238106Sdes q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 145238106Sdes if(!q->res) { 146238106Sdes free(q); 147238106Sdes return NULL; 148238106Sdes } 149238106Sdes q->res->qname = strdup(name); 150238106Sdes if(!q->res->qname) { 151238106Sdes free(q->res); 152238106Sdes free(q); 153238106Sdes return NULL; 154238106Sdes } 155238106Sdes q->res->qtype = rrtype; 156238106Sdes q->res->qclass = rrclass; 157238106Sdes 158238106Sdes /* add to query list */ 159238106Sdes lock_basic_lock(&ctx->cfglock); 160238106Sdes if(q->async) 161238106Sdes ctx->num_async ++; 162238106Sdes (void)rbtree_insert(&ctx->queries, &q->node); 163238106Sdes lock_basic_unlock(&ctx->cfglock); 164238106Sdes return q; 165238106Sdes} 166238106Sdes 167238106Sdesstruct alloc_cache* 168238106Sdescontext_obtain_alloc(struct ub_ctx* ctx, int locking) 169238106Sdes{ 170238106Sdes struct alloc_cache* a; 171238106Sdes int tnum = 0; 172238106Sdes if(locking) { 173238106Sdes lock_basic_lock(&ctx->cfglock); 174238106Sdes } 175238106Sdes a = ctx->alloc_list; 176238106Sdes if(a) 177238106Sdes ctx->alloc_list = a->super; /* snip off list */ 178238106Sdes else tnum = ctx->thr_next_num++; 179238106Sdes if(locking) { 180238106Sdes lock_basic_unlock(&ctx->cfglock); 181238106Sdes } 182238106Sdes if(a) { 183238106Sdes a->super = &ctx->superalloc; 184238106Sdes return a; 185238106Sdes } 186238106Sdes a = (struct alloc_cache*)calloc(1, sizeof(*a)); 187238106Sdes if(!a) 188238106Sdes return NULL; 189238106Sdes alloc_init(a, &ctx->superalloc, tnum); 190238106Sdes return a; 191238106Sdes} 192238106Sdes 193238106Sdesvoid 194238106Sdescontext_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, 195238106Sdes int locking) 196238106Sdes{ 197238106Sdes if(!ctx || !alloc) 198238106Sdes return; 199238106Sdes if(locking) { 200238106Sdes lock_basic_lock(&ctx->cfglock); 201238106Sdes } 202238106Sdes alloc->super = ctx->alloc_list; 203238106Sdes ctx->alloc_list = alloc; 204238106Sdes if(locking) { 205238106Sdes lock_basic_unlock(&ctx->cfglock); 206238106Sdes } 207238106Sdes} 208238106Sdes 209238106Sdesuint8_t* 210238106Sdescontext_serialize_new_query(struct ctx_query* q, uint32_t* len) 211238106Sdes{ 212238106Sdes /* format for new query is 213238106Sdes * o uint32 cmd 214238106Sdes * o uint32 id 215238106Sdes * o uint32 type 216238106Sdes * o uint32 class 217238106Sdes * o rest queryname (string) 218238106Sdes */ 219238106Sdes uint8_t* p; 220238106Sdes size_t slen = strlen(q->res->qname) + 1/*end of string*/; 221238106Sdes *len = sizeof(uint32_t)*4 + slen; 222238106Sdes p = (uint8_t*)malloc(*len); 223238106Sdes if(!p) return NULL; 224269257Sdes sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); 225269257Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 226269257Sdes sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); 227269257Sdes sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); 228238106Sdes memmove(p+4*sizeof(uint32_t), q->res->qname, slen); 229238106Sdes return p; 230238106Sdes} 231238106Sdes 232238106Sdesstruct ctx_query* 233238106Sdescontext_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 234238106Sdes{ 235238106Sdes struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 236238106Sdes if(!q) return NULL; 237238106Sdes if(len < 4*sizeof(uint32_t)+1) { 238238106Sdes free(q); 239238106Sdes return NULL; 240238106Sdes } 241269257Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 242269257Sdes q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 243238106Sdes q->node.key = &q->querynum; 244238106Sdes q->async = 1; 245238106Sdes q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 246238106Sdes if(!q->res) { 247238106Sdes free(q); 248238106Sdes return NULL; 249238106Sdes } 250269257Sdes q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 251269257Sdes q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); 252238106Sdes q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); 253238106Sdes if(!q->res->qname) { 254238106Sdes free(q->res); 255238106Sdes free(q); 256238106Sdes return NULL; 257238106Sdes } 258238106Sdes 259238106Sdes /** add to query list */ 260238106Sdes ctx->num_async++; 261238106Sdes (void)rbtree_insert(&ctx->queries, &q->node); 262238106Sdes return q; 263238106Sdes} 264238106Sdes 265238106Sdesstruct ctx_query* 266238106Sdescontext_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 267238106Sdes{ 268238106Sdes struct ctx_query* q; 269238106Sdes int querynum; 270238106Sdes if(len < 4*sizeof(uint32_t)+1) { 271238106Sdes return NULL; 272238106Sdes } 273269257Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 274269257Sdes querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 275238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); 276238106Sdes if(!q) { 277238106Sdes return NULL; 278238106Sdes } 279238106Sdes log_assert(q->async); 280238106Sdes return q; 281238106Sdes} 282238106Sdes 283238106Sdesuint8_t* 284269257Sdescontext_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, 285238106Sdes uint32_t* len) 286238106Sdes{ 287238106Sdes /* answer format 288238106Sdes * o uint32 cmd 289238106Sdes * o uint32 id 290238106Sdes * o uint32 error_code 291238106Sdes * o uint32 msg_security 292238106Sdes * o uint32 length of why_bogus string (+1 for eos); 0 absent. 293238106Sdes * o why_bogus_string 294238106Sdes * o the remainder is the answer msg from resolver lookup. 295238106Sdes * remainder can be length 0. 296238106Sdes */ 297269257Sdes size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0; 298238106Sdes size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0; 299238106Sdes uint8_t* p; 300238106Sdes *len = sizeof(uint32_t)*5 + pkt_len + wlen; 301238106Sdes p = (uint8_t*)malloc(*len); 302238106Sdes if(!p) return NULL; 303269257Sdes sldns_write_uint32(p, UB_LIBCMD_ANSWER); 304269257Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 305269257Sdes sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); 306269257Sdes sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); 307269257Sdes sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen); 308238106Sdes if(wlen > 0) 309238106Sdes memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen); 310238106Sdes if(pkt_len > 0) 311238106Sdes memmove(p+5*sizeof(uint32_t)+wlen, 312269257Sdes sldns_buffer_begin(pkt), pkt_len); 313238106Sdes return p; 314238106Sdes} 315238106Sdes 316238106Sdesstruct ctx_query* 317238106Sdescontext_deserialize_answer(struct ub_ctx* ctx, 318238106Sdes uint8_t* p, uint32_t len, int* err) 319238106Sdes{ 320238106Sdes struct ctx_query* q = NULL ; 321238106Sdes int id; 322238106Sdes size_t wlen; 323238106Sdes if(len < 5*sizeof(uint32_t)) return NULL; 324269257Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER); 325269257Sdes id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 326238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 327238106Sdes if(!q) return NULL; 328269257Sdes *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 329269257Sdes q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t)); 330269257Sdes wlen = (size_t)sldns_read_uint32(p+4*sizeof(uint32_t)); 331238106Sdes if(len > 5*sizeof(uint32_t) && wlen > 0) { 332238106Sdes if(len >= 5*sizeof(uint32_t)+wlen) 333238106Sdes q->res->why_bogus = (char*)memdup( 334238106Sdes p+5*sizeof(uint32_t), wlen); 335238106Sdes if(!q->res->why_bogus) { 336238106Sdes /* pass malloc failure to the user callback */ 337238106Sdes q->msg_len = 0; 338238106Sdes *err = UB_NOMEM; 339238106Sdes return q; 340238106Sdes } 341238106Sdes q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */ 342238106Sdes } 343238106Sdes if(len > 5*sizeof(uint32_t)+wlen) { 344238106Sdes q->msg_len = len - 5*sizeof(uint32_t) - wlen; 345238106Sdes q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen, 346238106Sdes q->msg_len); 347238106Sdes if(!q->msg) { 348238106Sdes /* pass malloc failure to the user callback */ 349238106Sdes q->msg_len = 0; 350238106Sdes *err = UB_NOMEM; 351238106Sdes return q; 352238106Sdes } 353238106Sdes } 354238106Sdes return q; 355238106Sdes} 356238106Sdes 357238106Sdesuint8_t* 358238106Sdescontext_serialize_cancel(struct ctx_query* q, uint32_t* len) 359238106Sdes{ 360238106Sdes /* format of cancel: 361238106Sdes * o uint32 cmd 362238106Sdes * o uint32 async-id */ 363291767Sdes uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); 364238106Sdes if(!p) return NULL; 365238106Sdes *len = 2*sizeof(uint32_t); 366269257Sdes sldns_write_uint32(p, UB_LIBCMD_CANCEL); 367269257Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 368238106Sdes return p; 369238106Sdes} 370238106Sdes 371238106Sdesstruct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, 372238106Sdes uint8_t* p, uint32_t len) 373238106Sdes{ 374238106Sdes struct ctx_query* q; 375238106Sdes int id; 376238106Sdes if(len != 2*sizeof(uint32_t)) return NULL; 377269257Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); 378269257Sdes id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 379238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 380238106Sdes return q; 381238106Sdes} 382238106Sdes 383238106Sdesuint8_t* 384238106Sdescontext_serialize_quit(uint32_t* len) 385238106Sdes{ 386238106Sdes uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t)); 387238106Sdes if(!p) 388238106Sdes return NULL; 389238106Sdes *len = sizeof(uint32_t); 390269257Sdes sldns_write_uint32(p, UB_LIBCMD_QUIT); 391238106Sdes return p; 392238106Sdes} 393238106Sdes 394238106Sdesenum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) 395238106Sdes{ 396238106Sdes uint32_t v; 397238106Sdes if((size_t)len < sizeof(v)) 398238106Sdes return UB_LIBCMD_QUIT; 399269257Sdes v = sldns_read_uint32(p); 400238106Sdes return v; 401238106Sdes} 402