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