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 24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33266114Sdes * 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" 50356345Scy#include "services/authzone.h" 51238106Sdes#include "util/data/msgreply.h" 52238106Sdes#include "util/storage/slabhash.h" 53368129Scy#include "util/edns.h" 54287917Sdes#include "sldns/sbuffer.h" 55238106Sdes 56238106Sdesint 57238106Sdescontext_finalize(struct ub_ctx* ctx) 58238106Sdes{ 59361435Scy int is_rpz = 0; 60238106Sdes struct config_file* cfg = ctx->env->cfg; 61238106Sdes verbosity = cfg->verbosity; 62356345Scy if(ctx_logfile_overridden && !ctx->logfile_override) { 63356345Scy log_file(NULL); /* clear that override */ 64356345Scy ctx_logfile_overridden = 0; 65356345Scy } 66356345Scy if(ctx->logfile_override) { 67356345Scy ctx_logfile_overridden = 1; 68238106Sdes log_file(ctx->log_out); 69356345Scy } else { 70356345Scy log_init(cfg->logfile, cfg->use_syslog, NULL); 71356345Scy } 72238106Sdes config_apply(cfg); 73238106Sdes if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) 74238106Sdes return UB_INITFAIL; 75356345Scy log_edns_known_options(VERB_ALGO, ctx->env); 76238106Sdes ctx->local_zones = local_zones_create(); 77238106Sdes if(!ctx->local_zones) 78238106Sdes return UB_NOMEM; 79238106Sdes if(!local_zones_apply_cfg(ctx->local_zones, cfg)) 80238106Sdes return UB_INITFAIL; 81361435Scy if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz)) 82356345Scy return UB_INITFAIL; 83368693Scy if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg)) 84368129Scy return UB_INITFAIL; 85356345Scy if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, 86356345Scy cfg->msg_cache_slabs)) { 87238106Sdes slabhash_delete(ctx->env->msg_cache); 88238106Sdes ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, 89238106Sdes HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, 90238106Sdes msgreply_sizefunc, query_info_compare, 91238106Sdes query_entry_delete, reply_info_delete, NULL); 92238106Sdes if(!ctx->env->msg_cache) 93238106Sdes return UB_NOMEM; 94238106Sdes } 95238106Sdes ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, 96238106Sdes ctx->env->cfg, ctx->env->alloc); 97238106Sdes if(!ctx->env->rrset_cache) 98238106Sdes return UB_NOMEM; 99238106Sdes ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); 100238106Sdes if(!ctx->env->infra_cache) 101238106Sdes return UB_NOMEM; 102238106Sdes ctx->finalized = 1; 103238106Sdes return UB_NOERROR; 104238106Sdes} 105238106Sdes 106238106Sdesint context_query_cmp(const void* a, const void* b) 107238106Sdes{ 108238106Sdes if( *(int*)a < *(int*)b ) 109238106Sdes return -1; 110238106Sdes if( *(int*)a > *(int*)b ) 111238106Sdes return 1; 112238106Sdes return 0; 113238106Sdes} 114238106Sdes 115238106Sdesvoid 116238106Sdescontext_query_delete(struct ctx_query* q) 117238106Sdes{ 118238106Sdes if(!q) return; 119238106Sdes ub_resolve_free(q->res); 120238106Sdes free(q->msg); 121238106Sdes free(q); 122238106Sdes} 123238106Sdes 124238106Sdes/** How many times to try to find an unused query-id-number for async */ 125238106Sdes#define NUM_ID_TRIES 100000 126238106Sdes/** find next useful id number of 0 on error */ 127238106Sdesstatic int 128238106Sdesfind_id(struct ub_ctx* ctx, int* id) 129238106Sdes{ 130238106Sdes size_t tries = 0; 131238106Sdes ctx->next_querynum++; 132238106Sdes while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { 133238106Sdes ctx->next_querynum++; /* numerical wraparound is fine */ 134238106Sdes if(tries++ > NUM_ID_TRIES) 135238106Sdes return 0; 136238106Sdes } 137238106Sdes *id = ctx->next_querynum; 138238106Sdes return 1; 139238106Sdes} 140238106Sdes 141238106Sdesstruct ctx_query* 142266114Sdescontext_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 143356345Scy ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg) 144238106Sdes{ 145238106Sdes struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 146238106Sdes if(!q) return NULL; 147238106Sdes lock_basic_lock(&ctx->cfglock); 148238106Sdes if(!find_id(ctx, &q->querynum)) { 149238106Sdes lock_basic_unlock(&ctx->cfglock); 150238106Sdes free(q); 151238106Sdes return NULL; 152238106Sdes } 153238106Sdes lock_basic_unlock(&ctx->cfglock); 154238106Sdes q->node.key = &q->querynum; 155356345Scy q->async = (cb != NULL || cb_event != NULL); 156238106Sdes q->cb = cb; 157356345Scy q->cb_event = cb_event; 158238106Sdes q->cb_arg = cbarg; 159238106Sdes q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 160238106Sdes if(!q->res) { 161238106Sdes free(q); 162238106Sdes return NULL; 163238106Sdes } 164238106Sdes q->res->qname = strdup(name); 165238106Sdes if(!q->res->qname) { 166238106Sdes free(q->res); 167238106Sdes free(q); 168238106Sdes return NULL; 169238106Sdes } 170238106Sdes q->res->qtype = rrtype; 171238106Sdes q->res->qclass = rrclass; 172238106Sdes 173238106Sdes /* add to query list */ 174238106Sdes lock_basic_lock(&ctx->cfglock); 175238106Sdes if(q->async) 176238106Sdes ctx->num_async ++; 177238106Sdes (void)rbtree_insert(&ctx->queries, &q->node); 178238106Sdes lock_basic_unlock(&ctx->cfglock); 179238106Sdes return q; 180238106Sdes} 181238106Sdes 182238106Sdesstruct alloc_cache* 183238106Sdescontext_obtain_alloc(struct ub_ctx* ctx, int locking) 184238106Sdes{ 185238106Sdes struct alloc_cache* a; 186238106Sdes int tnum = 0; 187238106Sdes if(locking) { 188238106Sdes lock_basic_lock(&ctx->cfglock); 189238106Sdes } 190238106Sdes a = ctx->alloc_list; 191238106Sdes if(a) 192238106Sdes ctx->alloc_list = a->super; /* snip off list */ 193238106Sdes else tnum = ctx->thr_next_num++; 194238106Sdes if(locking) { 195238106Sdes lock_basic_unlock(&ctx->cfglock); 196238106Sdes } 197238106Sdes if(a) { 198238106Sdes a->super = &ctx->superalloc; 199238106Sdes return a; 200238106Sdes } 201238106Sdes a = (struct alloc_cache*)calloc(1, sizeof(*a)); 202238106Sdes if(!a) 203238106Sdes return NULL; 204238106Sdes alloc_init(a, &ctx->superalloc, tnum); 205238106Sdes return a; 206238106Sdes} 207238106Sdes 208238106Sdesvoid 209238106Sdescontext_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, 210238106Sdes int locking) 211238106Sdes{ 212238106Sdes if(!ctx || !alloc) 213238106Sdes return; 214238106Sdes if(locking) { 215238106Sdes lock_basic_lock(&ctx->cfglock); 216238106Sdes } 217238106Sdes alloc->super = ctx->alloc_list; 218238106Sdes ctx->alloc_list = alloc; 219238106Sdes if(locking) { 220238106Sdes lock_basic_unlock(&ctx->cfglock); 221238106Sdes } 222238106Sdes} 223238106Sdes 224238106Sdesuint8_t* 225238106Sdescontext_serialize_new_query(struct ctx_query* q, uint32_t* len) 226238106Sdes{ 227238106Sdes /* format for new query is 228238106Sdes * o uint32 cmd 229238106Sdes * o uint32 id 230238106Sdes * o uint32 type 231238106Sdes * o uint32 class 232238106Sdes * o rest queryname (string) 233238106Sdes */ 234238106Sdes uint8_t* p; 235238106Sdes size_t slen = strlen(q->res->qname) + 1/*end of string*/; 236238106Sdes *len = sizeof(uint32_t)*4 + slen; 237238106Sdes p = (uint8_t*)malloc(*len); 238238106Sdes if(!p) return NULL; 239266114Sdes sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); 240266114Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 241266114Sdes sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); 242266114Sdes sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); 243238106Sdes memmove(p+4*sizeof(uint32_t), q->res->qname, slen); 244238106Sdes return p; 245238106Sdes} 246238106Sdes 247238106Sdesstruct ctx_query* 248238106Sdescontext_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 249238106Sdes{ 250238106Sdes struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 251238106Sdes if(!q) return NULL; 252238106Sdes if(len < 4*sizeof(uint32_t)+1) { 253238106Sdes free(q); 254238106Sdes return NULL; 255238106Sdes } 256266114Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 257266114Sdes q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 258238106Sdes q->node.key = &q->querynum; 259238106Sdes q->async = 1; 260238106Sdes q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 261238106Sdes if(!q->res) { 262238106Sdes free(q); 263238106Sdes return NULL; 264238106Sdes } 265266114Sdes q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 266266114Sdes q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); 267238106Sdes q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); 268238106Sdes if(!q->res->qname) { 269238106Sdes free(q->res); 270238106Sdes free(q); 271238106Sdes return NULL; 272238106Sdes } 273238106Sdes 274238106Sdes /** add to query list */ 275238106Sdes ctx->num_async++; 276238106Sdes (void)rbtree_insert(&ctx->queries, &q->node); 277238106Sdes return q; 278238106Sdes} 279238106Sdes 280238106Sdesstruct ctx_query* 281238106Sdescontext_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 282238106Sdes{ 283238106Sdes struct ctx_query* q; 284238106Sdes int querynum; 285238106Sdes if(len < 4*sizeof(uint32_t)+1) { 286238106Sdes return NULL; 287238106Sdes } 288266114Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 289266114Sdes querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 290238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); 291238106Sdes if(!q) { 292238106Sdes return NULL; 293238106Sdes } 294238106Sdes log_assert(q->async); 295238106Sdes return q; 296238106Sdes} 297238106Sdes 298238106Sdesuint8_t* 299266114Sdescontext_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, 300238106Sdes uint32_t* len) 301238106Sdes{ 302238106Sdes /* answer format 303238106Sdes * o uint32 cmd 304238106Sdes * o uint32 id 305238106Sdes * o uint32 error_code 306238106Sdes * o uint32 msg_security 307356345Scy * o uint32 was_ratelimited 308238106Sdes * o uint32 length of why_bogus string (+1 for eos); 0 absent. 309238106Sdes * o why_bogus_string 310238106Sdes * o the remainder is the answer msg from resolver lookup. 311238106Sdes * remainder can be length 0. 312238106Sdes */ 313356345Scy size_t size_of_uint32s = 6 * sizeof(uint32_t); 314266114Sdes size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0; 315238106Sdes size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0; 316238106Sdes uint8_t* p; 317356345Scy *len = size_of_uint32s + pkt_len + wlen; 318238106Sdes p = (uint8_t*)malloc(*len); 319238106Sdes if(!p) return NULL; 320266114Sdes sldns_write_uint32(p, UB_LIBCMD_ANSWER); 321266114Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 322266114Sdes sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); 323266114Sdes sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); 324356345Scy sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited); 325356345Scy sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen); 326238106Sdes if(wlen > 0) 327356345Scy memmove(p+size_of_uint32s, q->res->why_bogus, wlen); 328238106Sdes if(pkt_len > 0) 329356345Scy memmove(p+size_of_uint32s+wlen, 330266114Sdes sldns_buffer_begin(pkt), pkt_len); 331238106Sdes return p; 332238106Sdes} 333238106Sdes 334238106Sdesstruct ctx_query* 335238106Sdescontext_deserialize_answer(struct ub_ctx* ctx, 336238106Sdes uint8_t* p, uint32_t len, int* err) 337238106Sdes{ 338356345Scy size_t size_of_uint32s = 6 * sizeof(uint32_t); 339238106Sdes struct ctx_query* q = NULL ; 340238106Sdes int id; 341238106Sdes size_t wlen; 342356345Scy if(len < size_of_uint32s) return NULL; 343266114Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER); 344266114Sdes id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 345238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 346238106Sdes if(!q) return NULL; 347266114Sdes *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 348266114Sdes q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t)); 349356345Scy q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t)); 350356345Scy wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t)); 351356345Scy if(len > size_of_uint32s && wlen > 0) { 352356345Scy if(len >= size_of_uint32s+wlen) 353238106Sdes q->res->why_bogus = (char*)memdup( 354356345Scy p+size_of_uint32s, wlen); 355238106Sdes if(!q->res->why_bogus) { 356238106Sdes /* pass malloc failure to the user callback */ 357238106Sdes q->msg_len = 0; 358238106Sdes *err = UB_NOMEM; 359238106Sdes return q; 360238106Sdes } 361238106Sdes q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */ 362238106Sdes } 363356345Scy if(len > size_of_uint32s+wlen) { 364356345Scy q->msg_len = len - size_of_uint32s - wlen; 365356345Scy q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen, 366238106Sdes q->msg_len); 367238106Sdes if(!q->msg) { 368238106Sdes /* pass malloc failure to the user callback */ 369238106Sdes q->msg_len = 0; 370238106Sdes *err = UB_NOMEM; 371238106Sdes return q; 372238106Sdes } 373238106Sdes } 374238106Sdes return q; 375238106Sdes} 376238106Sdes 377238106Sdesuint8_t* 378238106Sdescontext_serialize_cancel(struct ctx_query* q, uint32_t* len) 379238106Sdes{ 380238106Sdes /* format of cancel: 381238106Sdes * o uint32 cmd 382238106Sdes * o uint32 async-id */ 383287917Sdes uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); 384238106Sdes if(!p) return NULL; 385238106Sdes *len = 2*sizeof(uint32_t); 386266114Sdes sldns_write_uint32(p, UB_LIBCMD_CANCEL); 387266114Sdes sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 388238106Sdes return p; 389238106Sdes} 390238106Sdes 391238106Sdesstruct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, 392238106Sdes uint8_t* p, uint32_t len) 393238106Sdes{ 394238106Sdes struct ctx_query* q; 395238106Sdes int id; 396238106Sdes if(len != 2*sizeof(uint32_t)) return NULL; 397266114Sdes log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); 398266114Sdes id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 399238106Sdes q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 400238106Sdes return q; 401238106Sdes} 402238106Sdes 403238106Sdesuint8_t* 404238106Sdescontext_serialize_quit(uint32_t* len) 405238106Sdes{ 406356345Scy uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t)); 407238106Sdes if(!p) 408238106Sdes return NULL; 409238106Sdes *len = sizeof(uint32_t); 410266114Sdes sldns_write_uint32(p, UB_LIBCMD_QUIT); 411356345Scy return (uint8_t*)p; 412238106Sdes} 413238106Sdes 414238106Sdesenum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) 415238106Sdes{ 416238106Sdes uint32_t v; 417238106Sdes if((size_t)len < sizeof(v)) 418238106Sdes return UB_LIBCMD_QUIT; 419266114Sdes v = sldns_read_uint32(p); 420238106Sdes return v; 421238106Sdes} 422