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
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * 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"
50238106Sdes#include "util/data/msgreply.h"
51238106Sdes#include "util/storage/slabhash.h"
52291767Sdes#include "sldns/sbuffer.h"
53238106Sdes
54238106Sdesint
55238106Sdescontext_finalize(struct ub_ctx* ctx)
56238106Sdes{
57238106Sdes	struct config_file* cfg = ctx->env->cfg;
58238106Sdes	verbosity = cfg->verbosity;
59238106Sdes	if(ctx->logfile_override)
60238106Sdes		log_file(ctx->log_out);
61238106Sdes	else	log_init(cfg->logfile, cfg->use_syslog, NULL);
62238106Sdes	config_apply(cfg);
63238106Sdes	if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
64238106Sdes		return UB_INITFAIL;
65238106Sdes	ctx->local_zones = local_zones_create();
66238106Sdes	if(!ctx->local_zones)
67238106Sdes		return UB_NOMEM;
68238106Sdes	if(!local_zones_apply_cfg(ctx->local_zones, cfg))
69238106Sdes		return UB_INITFAIL;
70238106Sdes	if(!ctx->env->msg_cache ||
71238106Sdes	   cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) ||
72238106Sdes	   cfg->msg_cache_slabs != ctx->env->msg_cache->size) {
73238106Sdes		slabhash_delete(ctx->env->msg_cache);
74238106Sdes		ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
75238106Sdes			HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
76238106Sdes			msgreply_sizefunc, query_info_compare,
77238106Sdes			query_entry_delete, reply_info_delete, NULL);
78238106Sdes		if(!ctx->env->msg_cache)
79238106Sdes			return UB_NOMEM;
80238106Sdes	}
81238106Sdes	ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
82238106Sdes		ctx->env->cfg, ctx->env->alloc);
83238106Sdes	if(!ctx->env->rrset_cache)
84238106Sdes		return UB_NOMEM;
85238106Sdes	ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
86238106Sdes	if(!ctx->env->infra_cache)
87238106Sdes		return UB_NOMEM;
88238106Sdes	ctx->finalized = 1;
89238106Sdes	return UB_NOERROR;
90238106Sdes}
91238106Sdes
92238106Sdesint context_query_cmp(const void* a, const void* b)
93238106Sdes{
94238106Sdes	if( *(int*)a < *(int*)b )
95238106Sdes		return -1;
96238106Sdes	if( *(int*)a > *(int*)b )
97238106Sdes		return 1;
98238106Sdes	return 0;
99238106Sdes}
100238106Sdes
101238106Sdesvoid
102238106Sdescontext_query_delete(struct ctx_query* q)
103238106Sdes{
104238106Sdes	if(!q) return;
105238106Sdes	ub_resolve_free(q->res);
106238106Sdes	free(q->msg);
107238106Sdes	free(q);
108238106Sdes}
109238106Sdes
110238106Sdes/** How many times to try to find an unused query-id-number for async */
111238106Sdes#define NUM_ID_TRIES 100000
112238106Sdes/** find next useful id number of 0 on error */
113238106Sdesstatic int
114238106Sdesfind_id(struct ub_ctx* ctx, int* id)
115238106Sdes{
116238106Sdes	size_t tries = 0;
117238106Sdes	ctx->next_querynum++;
118238106Sdes	while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
119238106Sdes		ctx->next_querynum++; /* numerical wraparound is fine */
120238106Sdes		if(tries++ > NUM_ID_TRIES)
121238106Sdes			return 0;
122238106Sdes	}
123238106Sdes	*id = ctx->next_querynum;
124238106Sdes	return 1;
125238106Sdes}
126238106Sdes
127238106Sdesstruct ctx_query*
128269257Sdescontext_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass,
129238106Sdes	ub_callback_t cb, void* cbarg)
130238106Sdes{
131238106Sdes	struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
132238106Sdes	if(!q) return NULL;
133238106Sdes	lock_basic_lock(&ctx->cfglock);
134238106Sdes	if(!find_id(ctx, &q->querynum)) {
135238106Sdes		lock_basic_unlock(&ctx->cfglock);
136238106Sdes		free(q);
137238106Sdes		return NULL;
138238106Sdes	}
139238106Sdes	lock_basic_unlock(&ctx->cfglock);
140238106Sdes	q->node.key = &q->querynum;
141238106Sdes	q->async = (cb != NULL);
142238106Sdes	q->cb = cb;
143238106Sdes	q->cb_arg = cbarg;
144238106Sdes	q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
145238106Sdes	if(!q->res) {
146238106Sdes		free(q);
147238106Sdes		return NULL;
148238106Sdes	}
149238106Sdes	q->res->qname = strdup(name);
150238106Sdes	if(!q->res->qname) {
151238106Sdes		free(q->res);
152238106Sdes		free(q);
153238106Sdes		return NULL;
154238106Sdes	}
155238106Sdes	q->res->qtype = rrtype;
156238106Sdes	q->res->qclass = rrclass;
157238106Sdes
158238106Sdes	/* add to query list */
159238106Sdes	lock_basic_lock(&ctx->cfglock);
160238106Sdes	if(q->async)
161238106Sdes		ctx->num_async ++;
162238106Sdes	(void)rbtree_insert(&ctx->queries, &q->node);
163238106Sdes	lock_basic_unlock(&ctx->cfglock);
164238106Sdes	return q;
165238106Sdes}
166238106Sdes
167238106Sdesstruct alloc_cache*
168238106Sdescontext_obtain_alloc(struct ub_ctx* ctx, int locking)
169238106Sdes{
170238106Sdes	struct alloc_cache* a;
171238106Sdes	int tnum = 0;
172238106Sdes	if(locking) {
173238106Sdes		lock_basic_lock(&ctx->cfglock);
174238106Sdes	}
175238106Sdes	a = ctx->alloc_list;
176238106Sdes	if(a)
177238106Sdes		ctx->alloc_list = a->super; /* snip off list */
178238106Sdes	else	tnum = ctx->thr_next_num++;
179238106Sdes	if(locking) {
180238106Sdes		lock_basic_unlock(&ctx->cfglock);
181238106Sdes	}
182238106Sdes	if(a) {
183238106Sdes		a->super = &ctx->superalloc;
184238106Sdes		return a;
185238106Sdes	}
186238106Sdes	a = (struct alloc_cache*)calloc(1, sizeof(*a));
187238106Sdes	if(!a)
188238106Sdes		return NULL;
189238106Sdes	alloc_init(a, &ctx->superalloc, tnum);
190238106Sdes	return a;
191238106Sdes}
192238106Sdes
193238106Sdesvoid
194238106Sdescontext_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
195238106Sdes	int locking)
196238106Sdes{
197238106Sdes	if(!ctx || !alloc)
198238106Sdes		return;
199238106Sdes	if(locking) {
200238106Sdes		lock_basic_lock(&ctx->cfglock);
201238106Sdes	}
202238106Sdes	alloc->super = ctx->alloc_list;
203238106Sdes	ctx->alloc_list = alloc;
204238106Sdes	if(locking) {
205238106Sdes		lock_basic_unlock(&ctx->cfglock);
206238106Sdes	}
207238106Sdes}
208238106Sdes
209238106Sdesuint8_t*
210238106Sdescontext_serialize_new_query(struct ctx_query* q, uint32_t* len)
211238106Sdes{
212238106Sdes	/* format for new query is
213238106Sdes	 * 	o uint32 cmd
214238106Sdes	 * 	o uint32 id
215238106Sdes	 * 	o uint32 type
216238106Sdes	 * 	o uint32 class
217238106Sdes	 * 	o rest queryname (string)
218238106Sdes	 */
219238106Sdes	uint8_t* p;
220238106Sdes	size_t slen = strlen(q->res->qname) + 1/*end of string*/;
221238106Sdes	*len = sizeof(uint32_t)*4 + slen;
222238106Sdes	p = (uint8_t*)malloc(*len);
223238106Sdes	if(!p) return NULL;
224269257Sdes	sldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
225269257Sdes	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
226269257Sdes	sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
227269257Sdes	sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
228238106Sdes	memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
229238106Sdes	return p;
230238106Sdes}
231238106Sdes
232238106Sdesstruct ctx_query*
233238106Sdescontext_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
234238106Sdes{
235238106Sdes	struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
236238106Sdes	if(!q) return NULL;
237238106Sdes	if(len < 4*sizeof(uint32_t)+1) {
238238106Sdes		free(q);
239238106Sdes		return NULL;
240238106Sdes	}
241269257Sdes	log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
242269257Sdes	q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
243238106Sdes	q->node.key = &q->querynum;
244238106Sdes	q->async = 1;
245238106Sdes	q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
246238106Sdes	if(!q->res) {
247238106Sdes		free(q);
248238106Sdes		return NULL;
249238106Sdes	}
250269257Sdes	q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
251269257Sdes	q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t));
252238106Sdes	q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
253238106Sdes	if(!q->res->qname) {
254238106Sdes		free(q->res);
255238106Sdes		free(q);
256238106Sdes		return NULL;
257238106Sdes	}
258238106Sdes
259238106Sdes	/** add to query list */
260238106Sdes	ctx->num_async++;
261238106Sdes	(void)rbtree_insert(&ctx->queries, &q->node);
262238106Sdes	return q;
263238106Sdes}
264238106Sdes
265238106Sdesstruct ctx_query*
266238106Sdescontext_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
267238106Sdes{
268238106Sdes	struct ctx_query* q;
269238106Sdes	int querynum;
270238106Sdes	if(len < 4*sizeof(uint32_t)+1) {
271238106Sdes		return NULL;
272238106Sdes	}
273269257Sdes	log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
274269257Sdes	querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
275238106Sdes	q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
276238106Sdes	if(!q) {
277238106Sdes		return NULL;
278238106Sdes	}
279238106Sdes	log_assert(q->async);
280238106Sdes	return q;
281238106Sdes}
282238106Sdes
283238106Sdesuint8_t*
284269257Sdescontext_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt,
285238106Sdes	uint32_t* len)
286238106Sdes{
287238106Sdes	/* answer format
288238106Sdes	 * 	o uint32 cmd
289238106Sdes	 * 	o uint32 id
290238106Sdes	 * 	o uint32 error_code
291238106Sdes	 * 	o uint32 msg_security
292238106Sdes	 * 	o uint32 length of why_bogus string (+1 for eos); 0 absent.
293238106Sdes	 * 	o why_bogus_string
294238106Sdes	 * 	o the remainder is the answer msg from resolver lookup.
295238106Sdes	 * 	  remainder can be length 0.
296238106Sdes	 */
297269257Sdes	size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0;
298238106Sdes	size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
299238106Sdes	uint8_t* p;
300238106Sdes	*len = sizeof(uint32_t)*5 + pkt_len + wlen;
301238106Sdes	p = (uint8_t*)malloc(*len);
302238106Sdes	if(!p) return NULL;
303269257Sdes	sldns_write_uint32(p, UB_LIBCMD_ANSWER);
304269257Sdes	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
305269257Sdes	sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
306269257Sdes	sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
307269257Sdes	sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen);
308238106Sdes	if(wlen > 0)
309238106Sdes		memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen);
310238106Sdes	if(pkt_len > 0)
311238106Sdes		memmove(p+5*sizeof(uint32_t)+wlen,
312269257Sdes			sldns_buffer_begin(pkt), pkt_len);
313238106Sdes	return p;
314238106Sdes}
315238106Sdes
316238106Sdesstruct ctx_query*
317238106Sdescontext_deserialize_answer(struct ub_ctx* ctx,
318238106Sdes        uint8_t* p, uint32_t len, int* err)
319238106Sdes{
320238106Sdes	struct ctx_query* q = NULL ;
321238106Sdes	int id;
322238106Sdes	size_t wlen;
323238106Sdes	if(len < 5*sizeof(uint32_t)) return NULL;
324269257Sdes	log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER);
325269257Sdes	id = (int)sldns_read_uint32(p+sizeof(uint32_t));
326238106Sdes	q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
327238106Sdes	if(!q) return NULL;
328269257Sdes	*err = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
329269257Sdes	q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t));
330269257Sdes	wlen = (size_t)sldns_read_uint32(p+4*sizeof(uint32_t));
331238106Sdes	if(len > 5*sizeof(uint32_t) && wlen > 0) {
332238106Sdes		if(len >= 5*sizeof(uint32_t)+wlen)
333238106Sdes			q->res->why_bogus = (char*)memdup(
334238106Sdes				p+5*sizeof(uint32_t), wlen);
335238106Sdes		if(!q->res->why_bogus) {
336238106Sdes			/* pass malloc failure to the user callback */
337238106Sdes			q->msg_len = 0;
338238106Sdes			*err = UB_NOMEM;
339238106Sdes			return q;
340238106Sdes		}
341238106Sdes		q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
342238106Sdes	}
343238106Sdes	if(len > 5*sizeof(uint32_t)+wlen) {
344238106Sdes		q->msg_len = len - 5*sizeof(uint32_t) - wlen;
345238106Sdes		q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen,
346238106Sdes			q->msg_len);
347238106Sdes		if(!q->msg) {
348238106Sdes			/* pass malloc failure to the user callback */
349238106Sdes			q->msg_len = 0;
350238106Sdes			*err = UB_NOMEM;
351238106Sdes			return q;
352238106Sdes		}
353238106Sdes	}
354238106Sdes	return q;
355238106Sdes}
356238106Sdes
357238106Sdesuint8_t*
358238106Sdescontext_serialize_cancel(struct ctx_query* q, uint32_t* len)
359238106Sdes{
360238106Sdes	/* format of cancel:
361238106Sdes	 * 	o uint32 cmd
362238106Sdes	 * 	o uint32 async-id */
363291767Sdes	uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2);
364238106Sdes	if(!p) return NULL;
365238106Sdes	*len = 2*sizeof(uint32_t);
366269257Sdes	sldns_write_uint32(p, UB_LIBCMD_CANCEL);
367269257Sdes	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
368238106Sdes	return p;
369238106Sdes}
370238106Sdes
371238106Sdesstruct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
372238106Sdes        uint8_t* p, uint32_t len)
373238106Sdes{
374238106Sdes	struct ctx_query* q;
375238106Sdes	int id;
376238106Sdes	if(len != 2*sizeof(uint32_t)) return NULL;
377269257Sdes	log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL);
378269257Sdes	id = (int)sldns_read_uint32(p+sizeof(uint32_t));
379238106Sdes	q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
380238106Sdes	return q;
381238106Sdes}
382238106Sdes
383238106Sdesuint8_t*
384238106Sdescontext_serialize_quit(uint32_t* len)
385238106Sdes{
386238106Sdes	uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t));
387238106Sdes	if(!p)
388238106Sdes		return NULL;
389238106Sdes	*len = sizeof(uint32_t);
390269257Sdes	sldns_write_uint32(p, UB_LIBCMD_QUIT);
391238106Sdes	return p;
392238106Sdes}
393238106Sdes
394238106Sdesenum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
395238106Sdes{
396238106Sdes	uint32_t v;
397238106Sdes	if((size_t)len < sizeof(v))
398238106Sdes		return UB_LIBCMD_QUIT;
399269257Sdes	v = sldns_read_uint32(p);
400238106Sdes	return v;
401238106Sdes}
402