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 "util/data/msgreply.h" 51 #include "util/storage/slabhash.h" 52 #include "sldns/sbuffer.h" 53 54 int 55 context_finalize(struct ub_ctx* ctx) 56 { 57 struct config_file* cfg = ctx->env->cfg; 58 verbosity = cfg->verbosity; 59 if(ctx->logfile_override) 60 log_file(ctx->log_out); 61 else log_init(cfg->logfile, cfg->use_syslog, NULL); 62 config_apply(cfg); 63 if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) 64 return UB_INITFAIL; 65 log_edns_known_options(VERB_ALGO, ctx->env); 66 ctx->local_zones = local_zones_create(); 67 if(!ctx->local_zones) 68 return UB_NOMEM; 69 if(!local_zones_apply_cfg(ctx->local_zones, cfg)) 70 return UB_INITFAIL; 71 if(!ctx->env->msg_cache || 72 cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) || 73 cfg->msg_cache_slabs != ctx->env->msg_cache->size) { 74 slabhash_delete(ctx->env->msg_cache); 75 ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs, 76 HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size, 77 msgreply_sizefunc, query_info_compare, 78 query_entry_delete, reply_info_delete, NULL); 79 if(!ctx->env->msg_cache) 80 return UB_NOMEM; 81 } 82 ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache, 83 ctx->env->cfg, ctx->env->alloc); 84 if(!ctx->env->rrset_cache) 85 return UB_NOMEM; 86 ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); 87 if(!ctx->env->infra_cache) 88 return UB_NOMEM; 89 ctx->finalized = 1; 90 return UB_NOERROR; 91 } 92 93 int context_query_cmp(const void* a, const void* b) 94 { 95 if( *(int*)a < *(int*)b ) 96 return -1; 97 if( *(int*)a > *(int*)b ) 98 return 1; 99 return 0; 100 } 101 102 void 103 context_query_delete(struct ctx_query* q) 104 { 105 if(!q) return; 106 ub_resolve_free(q->res); 107 free(q->msg); 108 free(q); 109 } 110 111 /** How many times to try to find an unused query-id-number for async */ 112 #define NUM_ID_TRIES 100000 113 /** find next useful id number of 0 on error */ 114 static int 115 find_id(struct ub_ctx* ctx, int* id) 116 { 117 size_t tries = 0; 118 ctx->next_querynum++; 119 while(rbtree_search(&ctx->queries, &ctx->next_querynum)) { 120 ctx->next_querynum++; /* numerical wraparound is fine */ 121 if(tries++ > NUM_ID_TRIES) 122 return 0; 123 } 124 *id = ctx->next_querynum; 125 return 1; 126 } 127 128 struct ctx_query* 129 context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, 130 ub_callback_type cb, void* cbarg) 131 { 132 struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 133 if(!q) return NULL; 134 lock_basic_lock(&ctx->cfglock); 135 if(!find_id(ctx, &q->querynum)) { 136 lock_basic_unlock(&ctx->cfglock); 137 free(q); 138 return NULL; 139 } 140 lock_basic_unlock(&ctx->cfglock); 141 q->node.key = &q->querynum; 142 q->async = (cb != NULL); 143 q->cb = cb; 144 q->cb_arg = cbarg; 145 q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 146 if(!q->res) { 147 free(q); 148 return NULL; 149 } 150 q->res->qname = strdup(name); 151 if(!q->res->qname) { 152 free(q->res); 153 free(q); 154 return NULL; 155 } 156 q->res->qtype = rrtype; 157 q->res->qclass = rrclass; 158 159 /* add to query list */ 160 lock_basic_lock(&ctx->cfglock); 161 if(q->async) 162 ctx->num_async ++; 163 (void)rbtree_insert(&ctx->queries, &q->node); 164 lock_basic_unlock(&ctx->cfglock); 165 return q; 166 } 167 168 struct alloc_cache* 169 context_obtain_alloc(struct ub_ctx* ctx, int locking) 170 { 171 struct alloc_cache* a; 172 int tnum = 0; 173 if(locking) { 174 lock_basic_lock(&ctx->cfglock); 175 } 176 a = ctx->alloc_list; 177 if(a) 178 ctx->alloc_list = a->super; /* snip off list */ 179 else tnum = ctx->thr_next_num++; 180 if(locking) { 181 lock_basic_unlock(&ctx->cfglock); 182 } 183 if(a) { 184 a->super = &ctx->superalloc; 185 return a; 186 } 187 a = (struct alloc_cache*)calloc(1, sizeof(*a)); 188 if(!a) 189 return NULL; 190 alloc_init(a, &ctx->superalloc, tnum); 191 return a; 192 } 193 194 void 195 context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc, 196 int locking) 197 { 198 if(!ctx || !alloc) 199 return; 200 if(locking) { 201 lock_basic_lock(&ctx->cfglock); 202 } 203 alloc->super = ctx->alloc_list; 204 ctx->alloc_list = alloc; 205 if(locking) { 206 lock_basic_unlock(&ctx->cfglock); 207 } 208 } 209 210 uint8_t* 211 context_serialize_new_query(struct ctx_query* q, uint32_t* len) 212 { 213 /* format for new query is 214 * o uint32 cmd 215 * o uint32 id 216 * o uint32 type 217 * o uint32 class 218 * o rest queryname (string) 219 */ 220 uint8_t* p; 221 size_t slen = strlen(q->res->qname) + 1/*end of string*/; 222 *len = sizeof(uint32_t)*4 + slen; 223 p = (uint8_t*)malloc(*len); 224 if(!p) return NULL; 225 sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); 226 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 227 sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); 228 sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); 229 memmove(p+4*sizeof(uint32_t), q->res->qname, slen); 230 return p; 231 } 232 233 struct ctx_query* 234 context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 235 { 236 struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); 237 if(!q) return NULL; 238 if(len < 4*sizeof(uint32_t)+1) { 239 free(q); 240 return NULL; 241 } 242 log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 243 q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 244 q->node.key = &q->querynum; 245 q->async = 1; 246 q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); 247 if(!q->res) { 248 free(q); 249 return NULL; 250 } 251 q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 252 q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); 253 q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); 254 if(!q->res->qname) { 255 free(q->res); 256 free(q); 257 return NULL; 258 } 259 260 /** add to query list */ 261 ctx->num_async++; 262 (void)rbtree_insert(&ctx->queries, &q->node); 263 return q; 264 } 265 266 struct ctx_query* 267 context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) 268 { 269 struct ctx_query* q; 270 int querynum; 271 if(len < 4*sizeof(uint32_t)+1) { 272 return NULL; 273 } 274 log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); 275 querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); 276 q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); 277 if(!q) { 278 return NULL; 279 } 280 log_assert(q->async); 281 return q; 282 } 283 284 uint8_t* 285 context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, 286 uint32_t* len) 287 { 288 /* answer format 289 * o uint32 cmd 290 * o uint32 id 291 * o uint32 error_code 292 * o uint32 msg_security 293 * o uint32 length of why_bogus string (+1 for eos); 0 absent. 294 * o why_bogus_string 295 * o the remainder is the answer msg from resolver lookup. 296 * remainder can be length 0. 297 */ 298 size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0; 299 size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0; 300 uint8_t* p; 301 *len = sizeof(uint32_t)*5 + pkt_len + wlen; 302 p = (uint8_t*)malloc(*len); 303 if(!p) return NULL; 304 sldns_write_uint32(p, UB_LIBCMD_ANSWER); 305 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 306 sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); 307 sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); 308 sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen); 309 if(wlen > 0) 310 memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen); 311 if(pkt_len > 0) 312 memmove(p+5*sizeof(uint32_t)+wlen, 313 sldns_buffer_begin(pkt), pkt_len); 314 return p; 315 } 316 317 struct ctx_query* 318 context_deserialize_answer(struct ub_ctx* ctx, 319 uint8_t* p, uint32_t len, int* err) 320 { 321 struct ctx_query* q = NULL ; 322 int id; 323 size_t wlen; 324 if(len < 5*sizeof(uint32_t)) return NULL; 325 log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER); 326 id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 327 q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 328 if(!q) return NULL; 329 *err = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); 330 q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t)); 331 wlen = (size_t)sldns_read_uint32(p+4*sizeof(uint32_t)); 332 if(len > 5*sizeof(uint32_t) && wlen > 0) { 333 if(len >= 5*sizeof(uint32_t)+wlen) 334 q->res->why_bogus = (char*)memdup( 335 p+5*sizeof(uint32_t), wlen); 336 if(!q->res->why_bogus) { 337 /* pass malloc failure to the user callback */ 338 q->msg_len = 0; 339 *err = UB_NOMEM; 340 return q; 341 } 342 q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */ 343 } 344 if(len > 5*sizeof(uint32_t)+wlen) { 345 q->msg_len = len - 5*sizeof(uint32_t) - wlen; 346 q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen, 347 q->msg_len); 348 if(!q->msg) { 349 /* pass malloc failure to the user callback */ 350 q->msg_len = 0; 351 *err = UB_NOMEM; 352 return q; 353 } 354 } 355 return q; 356 } 357 358 uint8_t* 359 context_serialize_cancel(struct ctx_query* q, uint32_t* len) 360 { 361 /* format of cancel: 362 * o uint32 cmd 363 * o uint32 async-id */ 364 uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); 365 if(!p) return NULL; 366 *len = 2*sizeof(uint32_t); 367 sldns_write_uint32(p, UB_LIBCMD_CANCEL); 368 sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); 369 return p; 370 } 371 372 struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, 373 uint8_t* p, uint32_t len) 374 { 375 struct ctx_query* q; 376 int id; 377 if(len != 2*sizeof(uint32_t)) return NULL; 378 log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); 379 id = (int)sldns_read_uint32(p+sizeof(uint32_t)); 380 q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); 381 return q; 382 } 383 384 uint8_t* 385 context_serialize_quit(uint32_t* len) 386 { 387 uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t)); 388 if(!p) 389 return NULL; 390 *len = sizeof(uint32_t); 391 sldns_write_uint32(p, UB_LIBCMD_QUIT); 392 return p; 393 } 394 395 enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) 396 { 397 uint32_t v; 398 if((size_t)len < sizeof(v)) 399 return UB_LIBCMD_QUIT; 400 v = sldns_read_uint32(p); 401 return v; 402 } 403