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