1 /* 2 * libunbound/context.c - validating context for unbound internal use 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains the validator context structure. 40 */ 41 #include "config.h" 42 #include "libunbound/context.h" 43 #include "util/module.h" 44 #include "util/config_file.h" 45 #include "util/net_help.h" 46 #include "services/modstack.h" 47 #include "services/localzone.h" 48 #include "services/cache/rrset.h" 49 #include "services/cache/infra.h" 50 #include "services/authzone.h" 51 #include "services/listen_dnsport.h" 52 #include "util/data/msgreply.h" 53 #include "util/storage/slabhash.h" 54 #include "util/edns.h" 55 #include "sldns/sbuffer.h" 56 57 int 58 context_finalize(struct ub_ctx* ctx) 59 { 60 int is_rpz = 0; 61 struct config_file* cfg = ctx->env->cfg; 62 verbosity = cfg->verbosity; 63 if(ctx_logfile_overridden && !ctx->logfile_override) { 64 log_file(NULL); /* clear that override */ 65 ctx_logfile_overridden = 0; 66 } 67 if(ctx->logfile_override) { 68 ctx_logfile_overridden = 1; 69 log_file(ctx->log_out); 70 } else { 71 log_init(cfg->logfile, cfg->use_syslog, NULL); 72 } 73 cfg_apply_local_port_policy(cfg, 65536); 74 config_apply(cfg); 75 if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) 76 return UB_INITFAIL; 77 listen_setup_locks(); 78 log_edns_known_options(VERB_ALGO, ctx->env); 79 ctx->local_zones = local_zones_create(); 80 if(!ctx->local_zones) 81 return UB_NOMEM; 82 if(!local_zones_apply_cfg(ctx->local_zones, cfg)) 83 return UB_INITFAIL; 84 if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz, 85 ctx->env, &ctx->mods)) 86 return UB_INITFAIL; 87 if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg)) 88 return UB_INITFAIL; 89 if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, 90 cfg->msg_cache_slabs)) { 91 slabhash_delete(ctx->env->msg_cache); 92 ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, 93 HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, 94 msgreply_sizefunc, query_info_compare, 95 query_entry_delete, reply_info_delete, NULL); 96 if(!ctx->env->msg_cache) 97 return UB_NOMEM; 98 } 99 ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, 100 ctx->env->cfg, ctx->env->alloc); 101 if(!ctx->env->rrset_cache) 102 return UB_NOMEM; 103 ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); 104 if(!ctx->env->infra_cache) 105 return UB_NOMEM; 106 ctx->finalized = 1; 107 return UB_NOERROR; 108 } 109 110 int context_query_cmp(const void* a, const void* b) 111 { 112 if( *(int*)a < *(int*)b ) 113 return -1; 114 if( *(int*)a > *(int*)b ) 115 return 1; 116 return 0; 117 } 118 119 void 120 context_query_delete(struct ctx_query* q) 121 { 122 if(!q) return; 123 ub_resolve_free(q->res); 124 free(q->msg); 125 free(q); 126 } 127 128 /** How many times to try to find an unused query-id-number for async */ 129 #define NUM_ID_TRIES 100000 130 /** find next useful id number of 0 on error */ 131 static int 132 find_id(struct ub_ctx* ctx, int* id) 133 { 134 size_t tries = 0; 135 ctx->next_querynum++; 136 while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { 137 ctx->next_querynum++; /* numerical wraparound is fine */ 138 if(tries++ > NUM_ID_TRIES) 139 return 0; 140 } 141 *id = ctx->next_querynum; 142 return 1; 143 } 144 145 struct ctx_query* 146 context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 147 ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg) 148 { 149 struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 150 if(!q) return NULL; 151 lock_basic_lock(&ctx->cfglock); 152 if(!find_id(ctx, &q->querynum)) { 153 lock_basic_unlock(&ctx->cfglock); 154 free(q); 155 return NULL; 156 } 157 lock_basic_unlock(&ctx->cfglock); 158 q->node.key = &q->querynum; 159 q->async = (cb != NULL || cb_event != NULL); 160 q->cb = cb; 161 q->cb_event = cb_event; 162 q->cb_arg = cbarg; 163 q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 164 if(!q->res) { 165 free(q); 166 return NULL; 167 } 168 q->res->qname = strdup(name); 169 if(!q->res->qname) { 170 free(q->res); 171 free(q); 172 return NULL; 173 } 174 q->res->qtype = rrtype; 175 q->res->qclass = rrclass; 176 177 /* add to query list */ 178 lock_basic_lock(&ctx->cfglock); 179 if(q->async) 180 ctx->num_async ++; 181 (void)rbtree_insert(&ctx->queries, &q->node); 182 lock_basic_unlock(&ctx->cfglock); 183 return q; 184 } 185 186 struct alloc_cache* 187 context_obtain_alloc(struct ub_ctx* ctx, int locking) 188 { 189 struct alloc_cache* a; 190 int tnum = 0; 191 if(locking) { 192 lock_basic_lock(&ctx->cfglock); 193 } 194 a = ctx->alloc_list; 195 if(a) 196 ctx->alloc_list = a->super; /* snip off list */ 197 else tnum = ctx->thr_next_num++; 198 if(locking) { 199 lock_basic_unlock(&ctx->cfglock); 200 } 201 if(a) { 202 a->super = &ctx->superalloc; 203 return a; 204 } 205 a = (struct alloc_cache*)calloc(1, sizeof(*a)); 206 if(!a) 207 return NULL; 208 alloc_init(a, &ctx->superalloc, tnum); 209 return a; 210 } 211 212 void 213 context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, 214 int locking) 215 { 216 if(!ctx || !alloc) 217 return; 218 if(locking) { 219 lock_basic_lock(&ctx->cfglock); 220 } 221 alloc->super = ctx->alloc_list; 222 ctx->alloc_list = alloc; 223 if(locking) { 224 lock_basic_unlock(&ctx->cfglock); 225 } 226 } 227 228 uint8_t* 229 context_serialize_new_query(struct ctx_query* q, uint32_t* len) 230 { 231 /* format for new query is 232 * o uint32 cmd 233 * o uint32 id 234 * o uint32 type 235 * o uint32 class 236 * o rest queryname (string) 237 */ 238 uint8_t* p; 239 size_t slen = strlen(q->res->qname) + 1/*end of string*/; 240 *len = sizeof(uint32_t)*4 + slen; 241 p = (uint8_t*)malloc(*len); 242 if(!p) return NULL; 243 sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); 244 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 245 sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); 246 sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); 247 memmove(p+4*sizeof(uint32_t), q->res->qname, slen); 248 return p; 249 } 250 251 struct ctx_query* 252 context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 253 { 254 struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 255 if(!q) return NULL; 256 if(len < 4*sizeof(uint32_t)+1) { 257 free(q); 258 return NULL; 259 } 260 log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 261 q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 262 q->node.key = &q->querynum; 263 q->async = 1; 264 q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 265 if(!q->res) { 266 free(q); 267 return NULL; 268 } 269 q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 270 q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); 271 q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); 272 if(!q->res->qname) { 273 free(q->res); 274 free(q); 275 return NULL; 276 } 277 278 /** add to query list */ 279 ctx->num_async++; 280 (void)rbtree_insert(&ctx->queries, &q->node); 281 return q; 282 } 283 284 struct ctx_query* 285 context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 286 { 287 struct ctx_query* q; 288 int querynum; 289 if(len < 4*sizeof(uint32_t)+1) { 290 return NULL; 291 } 292 log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 293 querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 294 q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); 295 if(!q) { 296 return NULL; 297 } 298 log_assert(q->async); 299 return q; 300 } 301 302 uint8_t* 303 context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, 304 uint32_t* len) 305 { 306 /* answer format 307 * o uint32 cmd 308 * o uint32 id 309 * o uint32 error_code 310 * o uint32 msg_security 311 * o uint32 was_ratelimited 312 * o uint32 length of why_bogus string (+1 for eos); 0 absent. 313 * o why_bogus_string 314 * o the remainder is the answer msg from resolver lookup. 315 * remainder can be length 0. 316 */ 317 size_t size_of_uint32s = 6 * sizeof(uint32_t); 318 size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0; 319 size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0; 320 uint8_t* p; 321 *len = size_of_uint32s + pkt_len + wlen; 322 p = (uint8_t*)malloc(*len); 323 if(!p) return NULL; 324 sldns_write_uint32(p, UB_LIBCMD_ANSWER); 325 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 326 sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); 327 sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); 328 sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited); 329 sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen); 330 if(wlen > 0) 331 memmove(p+size_of_uint32s, q->res->why_bogus, wlen); 332 if(pkt_len > 0) 333 memmove(p+size_of_uint32s+wlen, 334 sldns_buffer_begin(pkt), pkt_len); 335 return p; 336 } 337 338 struct ctx_query* 339 context_deserialize_answer(struct ub_ctx* ctx, 340 uint8_t* p, uint32_t len, int* err) 341 { 342 size_t size_of_uint32s = 6 * sizeof(uint32_t); 343 struct ctx_query* q = NULL ; 344 int id; 345 size_t wlen; 346 if(len < size_of_uint32s) return NULL; 347 log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER); 348 id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 349 q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 350 if(!q) return NULL; 351 *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 352 q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t)); 353 q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t)); 354 wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t)); 355 if(len > size_of_uint32s && wlen > 0) { 356 if(len >= size_of_uint32s+wlen) 357 q->res->why_bogus = (char*)memdup( 358 p+size_of_uint32s, wlen); 359 if(!q->res->why_bogus) { 360 /* pass malloc failure to the user callback */ 361 q->msg_len = 0; 362 *err = UB_NOMEM; 363 return q; 364 } 365 q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */ 366 } 367 if(len > size_of_uint32s+wlen) { 368 q->msg_len = len - size_of_uint32s - wlen; 369 q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen, 370 q->msg_len); 371 if(!q->msg) { 372 /* pass malloc failure to the user callback */ 373 q->msg_len = 0; 374 *err = UB_NOMEM; 375 return q; 376 } 377 } 378 return q; 379 } 380 381 uint8_t* 382 context_serialize_cancel(struct ctx_query* q, uint32_t* len) 383 { 384 /* format of cancel: 385 * o uint32 cmd 386 * o uint32 async-id */ 387 uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); 388 if(!p) return NULL; 389 *len = 2*sizeof(uint32_t); 390 sldns_write_uint32(p, UB_LIBCMD_CANCEL); 391 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 392 return p; 393 } 394 395 struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, 396 uint8_t* p, uint32_t len) 397 { 398 struct ctx_query* q; 399 int id; 400 if(len != 2*sizeof(uint32_t)) return NULL; 401 log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); 402 id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 403 q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 404 return q; 405 } 406 407 uint8_t* 408 context_serialize_quit(uint32_t* len) 409 { 410 uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t)); 411 if(!p) 412 return NULL; 413 *len = sizeof(uint32_t); 414 sldns_write_uint32(p, UB_LIBCMD_QUIT); 415 return (uint8_t*)p; 416 } 417 418 enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) 419 { 420 uint32_t v; 421 if((size_t)len < sizeof(v)) 422 return UB_LIBCMD_QUIT; 423 v = sldns_read_uint32(p); 424 return v; 425 } 426