xref: /openbsd-src/usr.sbin/unbound/libunbound/context.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1933707f3Ssthen /*
2933707f3Ssthen  * libunbound/context.c - validating context for unbound internal use
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39933707f3Ssthen  * This file contains the validator context structure.
40933707f3Ssthen  */
41933707f3Ssthen #include "config.h"
42933707f3Ssthen #include "libunbound/context.h"
43933707f3Ssthen #include "util/module.h"
44933707f3Ssthen #include "util/config_file.h"
45933707f3Ssthen #include "util/net_help.h"
46933707f3Ssthen #include "services/modstack.h"
47933707f3Ssthen #include "services/localzone.h"
48933707f3Ssthen #include "services/cache/rrset.h"
49933707f3Ssthen #include "services/cache/infra.h"
50938a3a5eSflorian #include "services/authzone.h"
51e21c60efSsthen #include "services/listen_dnsport.h"
52933707f3Ssthen #include "util/data/msgreply.h"
53933707f3Ssthen #include "util/storage/slabhash.h"
542c144df0Ssthen #include "util/edns.h"
55fdfb4ba6Ssthen #include "sldns/sbuffer.h"
562bdc0ed1Ssthen #include "iterator/iter_fwd.h"
572bdc0ed1Ssthen #include "iterator/iter_hints.h"
58933707f3Ssthen 
59933707f3Ssthen int
60933707f3Ssthen context_finalize(struct ub_ctx* ctx)
61933707f3Ssthen {
62eaf2578eSsthen 	int is_rpz = 0;
63933707f3Ssthen 	struct config_file* cfg = ctx->env->cfg;
64933707f3Ssthen 	verbosity = cfg->verbosity;
658240c1b9Ssthen 	if(ctx_logfile_overridden && !ctx->logfile_override) {
668240c1b9Ssthen 		log_file(NULL); /* clear that override */
678240c1b9Ssthen 		ctx_logfile_overridden = 0;
688240c1b9Ssthen 	}
698240c1b9Ssthen 	if(ctx->logfile_override) {
708240c1b9Ssthen 		ctx_logfile_overridden = 1;
71933707f3Ssthen 		log_file(ctx->log_out);
728240c1b9Ssthen 	} else {
738240c1b9Ssthen 		log_init(cfg->logfile, cfg->use_syslog, NULL);
748240c1b9Ssthen 	}
758b7325afSsthen 	ctx->pipe_pid = getpid();
76191f22c6Ssthen 	cfg_apply_local_port_policy(cfg, 65536);
77933707f3Ssthen 	config_apply(cfg);
78*98bc733bSsthen 	if(!modstack_call_startup(&ctx->mods, cfg->module_conf, ctx->env))
79*98bc733bSsthen 		return UB_INITFAIL;
80*98bc733bSsthen 	if(!modstack_call_init(&ctx->mods, cfg->module_conf, ctx->env))
81933707f3Ssthen 		return UB_INITFAIL;
82e21c60efSsthen 	listen_setup_locks();
8377079be7Ssthen 	log_edns_known_options(VERB_ALGO, ctx->env);
84933707f3Ssthen 	ctx->local_zones = local_zones_create();
85933707f3Ssthen 	if(!ctx->local_zones)
86933707f3Ssthen 		return UB_NOMEM;
87933707f3Ssthen 	if(!local_zones_apply_cfg(ctx->local_zones, cfg))
88933707f3Ssthen 		return UB_INITFAIL;
89191f22c6Ssthen 	if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
90191f22c6Ssthen 		ctx->env, &ctx->mods))
91938a3a5eSflorian 		return UB_INITFAIL;
922bdc0ed1Ssthen 	if(!(ctx->env->fwds = forwards_create()) ||
932bdc0ed1Ssthen 		!forwards_apply_cfg(ctx->env->fwds, cfg))
942bdc0ed1Ssthen 		return UB_INITFAIL;
952bdc0ed1Ssthen 	if(!(ctx->env->hints = hints_create()) ||
962bdc0ed1Ssthen 		!hints_apply_cfg(ctx->env->hints, cfg))
972bdc0ed1Ssthen 		return UB_INITFAIL;
98eba819a2Ssthen 	if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg))
992c144df0Ssthen 		return UB_INITFAIL;
1002308e98cSsthen 	if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
1012308e98cSsthen 		cfg->msg_cache_slabs)) {
102933707f3Ssthen 		slabhash_delete(ctx->env->msg_cache);
103933707f3Ssthen 		ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
104933707f3Ssthen 			HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
105933707f3Ssthen 			msgreply_sizefunc, query_info_compare,
106933707f3Ssthen 			query_entry_delete, reply_info_delete, NULL);
107933707f3Ssthen 		if(!ctx->env->msg_cache)
108933707f3Ssthen 			return UB_NOMEM;
109933707f3Ssthen 	}
110933707f3Ssthen 	ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
111933707f3Ssthen 		ctx->env->cfg, ctx->env->alloc);
112933707f3Ssthen 	if(!ctx->env->rrset_cache)
113933707f3Ssthen 		return UB_NOMEM;
114933707f3Ssthen 	ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
115933707f3Ssthen 	if(!ctx->env->infra_cache)
116933707f3Ssthen 		return UB_NOMEM;
117933707f3Ssthen 	ctx->finalized = 1;
118933707f3Ssthen 	return UB_NOERROR;
119933707f3Ssthen }
120933707f3Ssthen 
121933707f3Ssthen int context_query_cmp(const void* a, const void* b)
122933707f3Ssthen {
123933707f3Ssthen 	if( *(int*)a < *(int*)b )
124933707f3Ssthen 		return -1;
125933707f3Ssthen 	if( *(int*)a > *(int*)b )
126933707f3Ssthen 		return 1;
127933707f3Ssthen 	return 0;
128933707f3Ssthen }
129933707f3Ssthen 
130933707f3Ssthen void
131933707f3Ssthen context_query_delete(struct ctx_query* q)
132933707f3Ssthen {
133933707f3Ssthen 	if(!q) return;
134933707f3Ssthen 	ub_resolve_free(q->res);
135933707f3Ssthen 	free(q->msg);
136933707f3Ssthen 	free(q);
137933707f3Ssthen }
138933707f3Ssthen 
139933707f3Ssthen /** How many times to try to find an unused query-id-number for async */
140933707f3Ssthen #define NUM_ID_TRIES 100000
141933707f3Ssthen /** find next useful id number of 0 on error */
142933707f3Ssthen static int
143933707f3Ssthen find_id(struct ub_ctx* ctx, int* id)
144933707f3Ssthen {
145933707f3Ssthen 	size_t tries = 0;
146933707f3Ssthen 	ctx->next_querynum++;
147933707f3Ssthen 	while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
148933707f3Ssthen 		ctx->next_querynum++; /* numerical wraparound is fine */
149933707f3Ssthen 		if(tries++ > NUM_ID_TRIES)
150933707f3Ssthen 			return 0;
151933707f3Ssthen 	}
152933707f3Ssthen 	*id = ctx->next_querynum;
153933707f3Ssthen 	return 1;
154933707f3Ssthen }
155933707f3Ssthen 
156933707f3Ssthen struct ctx_query*
157229e174cSsthen context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass,
15820237c55Ssthen 	ub_callback_type cb, ub_event_callback_type cb_event, void* cbarg)
159933707f3Ssthen {
160933707f3Ssthen 	struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
161933707f3Ssthen 	if(!q) return NULL;
162933707f3Ssthen 	lock_basic_lock(&ctx->cfglock);
163933707f3Ssthen 	if(!find_id(ctx, &q->querynum)) {
164933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
165933707f3Ssthen 		free(q);
166933707f3Ssthen 		return NULL;
167933707f3Ssthen 	}
168933707f3Ssthen 	lock_basic_unlock(&ctx->cfglock);
169933707f3Ssthen 	q->node.key = &q->querynum;
17020237c55Ssthen 	q->async = (cb != NULL || cb_event != NULL);
171933707f3Ssthen 	q->cb = cb;
17220237c55Ssthen 	q->cb_event = cb_event;
173933707f3Ssthen 	q->cb_arg = cbarg;
174933707f3Ssthen 	q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
175933707f3Ssthen 	if(!q->res) {
176933707f3Ssthen 		free(q);
177933707f3Ssthen 		return NULL;
178933707f3Ssthen 	}
179933707f3Ssthen 	q->res->qname = strdup(name);
180933707f3Ssthen 	if(!q->res->qname) {
181933707f3Ssthen 		free(q->res);
182933707f3Ssthen 		free(q);
183933707f3Ssthen 		return NULL;
184933707f3Ssthen 	}
185933707f3Ssthen 	q->res->qtype = rrtype;
186933707f3Ssthen 	q->res->qclass = rrclass;
187933707f3Ssthen 
188933707f3Ssthen 	/* add to query list */
189933707f3Ssthen 	lock_basic_lock(&ctx->cfglock);
190933707f3Ssthen 	if(q->async)
191933707f3Ssthen 		ctx->num_async ++;
192933707f3Ssthen 	(void)rbtree_insert(&ctx->queries, &q->node);
193933707f3Ssthen 	lock_basic_unlock(&ctx->cfglock);
194933707f3Ssthen 	return q;
195933707f3Ssthen }
196933707f3Ssthen 
197933707f3Ssthen struct alloc_cache*
198933707f3Ssthen context_obtain_alloc(struct ub_ctx* ctx, int locking)
199933707f3Ssthen {
200933707f3Ssthen 	struct alloc_cache* a;
201933707f3Ssthen 	int tnum = 0;
202933707f3Ssthen 	if(locking) {
203933707f3Ssthen 		lock_basic_lock(&ctx->cfglock);
204933707f3Ssthen 	}
205933707f3Ssthen 	a = ctx->alloc_list;
206933707f3Ssthen 	if(a)
207933707f3Ssthen 		ctx->alloc_list = a->super; /* snip off list */
208933707f3Ssthen 	else	tnum = ctx->thr_next_num++;
209933707f3Ssthen 	if(locking) {
210933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
211933707f3Ssthen 	}
212933707f3Ssthen 	if(a) {
213933707f3Ssthen 		a->super = &ctx->superalloc;
214933707f3Ssthen 		return a;
215933707f3Ssthen 	}
216933707f3Ssthen 	a = (struct alloc_cache*)calloc(1, sizeof(*a));
217933707f3Ssthen 	if(!a)
218933707f3Ssthen 		return NULL;
219933707f3Ssthen 	alloc_init(a, &ctx->superalloc, tnum);
220933707f3Ssthen 	return a;
221933707f3Ssthen }
222933707f3Ssthen 
223933707f3Ssthen void
224933707f3Ssthen context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
225933707f3Ssthen 	int locking)
226933707f3Ssthen {
227933707f3Ssthen 	if(!ctx || !alloc)
228933707f3Ssthen 		return;
229933707f3Ssthen 	if(locking) {
230933707f3Ssthen 		lock_basic_lock(&ctx->cfglock);
231933707f3Ssthen 	}
232933707f3Ssthen 	alloc->super = ctx->alloc_list;
233933707f3Ssthen 	ctx->alloc_list = alloc;
234933707f3Ssthen 	if(locking) {
235933707f3Ssthen 		lock_basic_unlock(&ctx->cfglock);
236933707f3Ssthen 	}
237933707f3Ssthen }
238933707f3Ssthen 
239933707f3Ssthen uint8_t*
240933707f3Ssthen context_serialize_new_query(struct ctx_query* q, uint32_t* len)
241933707f3Ssthen {
242933707f3Ssthen 	/* format for new query is
243933707f3Ssthen 	 * 	o uint32 cmd
244933707f3Ssthen 	 * 	o uint32 id
245933707f3Ssthen 	 * 	o uint32 type
246933707f3Ssthen 	 * 	o uint32 class
247933707f3Ssthen 	 * 	o rest queryname (string)
248933707f3Ssthen 	 */
249933707f3Ssthen 	uint8_t* p;
250933707f3Ssthen 	size_t slen = strlen(q->res->qname) + 1/*end of string*/;
251933707f3Ssthen 	*len = sizeof(uint32_t)*4 + slen;
252933707f3Ssthen 	p = (uint8_t*)malloc(*len);
253933707f3Ssthen 	if(!p) return NULL;
2545d76a658Ssthen 	sldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
2555d76a658Ssthen 	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
2565d76a658Ssthen 	sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
2575d76a658Ssthen 	sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
258933707f3Ssthen 	memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
259933707f3Ssthen 	return p;
260933707f3Ssthen }
261933707f3Ssthen 
262933707f3Ssthen struct ctx_query*
263933707f3Ssthen context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
264933707f3Ssthen {
265933707f3Ssthen 	struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
266933707f3Ssthen 	if(!q) return NULL;
267933707f3Ssthen 	if(len < 4*sizeof(uint32_t)+1) {
268933707f3Ssthen 		free(q);
269933707f3Ssthen 		return NULL;
270933707f3Ssthen 	}
2715d76a658Ssthen 	log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
2725d76a658Ssthen 	q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
273933707f3Ssthen 	q->node.key = &q->querynum;
274933707f3Ssthen 	q->async = 1;
275933707f3Ssthen 	q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
276933707f3Ssthen 	if(!q->res) {
277933707f3Ssthen 		free(q);
278933707f3Ssthen 		return NULL;
279933707f3Ssthen 	}
2805d76a658Ssthen 	q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
2815d76a658Ssthen 	q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t));
282933707f3Ssthen 	q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
283933707f3Ssthen 	if(!q->res->qname) {
284933707f3Ssthen 		free(q->res);
285933707f3Ssthen 		free(q);
286933707f3Ssthen 		return NULL;
287933707f3Ssthen 	}
288933707f3Ssthen 
289933707f3Ssthen 	/** add to query list */
290933707f3Ssthen 	ctx->num_async++;
291933707f3Ssthen 	(void)rbtree_insert(&ctx->queries, &q->node);
292933707f3Ssthen 	return q;
293933707f3Ssthen }
294933707f3Ssthen 
295933707f3Ssthen struct ctx_query*
296933707f3Ssthen context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
297933707f3Ssthen {
298933707f3Ssthen 	struct ctx_query* q;
299933707f3Ssthen 	int querynum;
300933707f3Ssthen 	if(len < 4*sizeof(uint32_t)+1) {
301933707f3Ssthen 		return NULL;
302933707f3Ssthen 	}
3035d76a658Ssthen 	log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
3045d76a658Ssthen 	querynum = (int)sldns_read_uint32(p+sizeof(uint32_t));
305933707f3Ssthen 	q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
306933707f3Ssthen 	if(!q) {
307933707f3Ssthen 		return NULL;
308933707f3Ssthen 	}
309933707f3Ssthen 	log_assert(q->async);
310933707f3Ssthen 	return q;
311933707f3Ssthen }
312933707f3Ssthen 
313933707f3Ssthen uint8_t*
3145d76a658Ssthen context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt,
315933707f3Ssthen 	uint32_t* len)
316933707f3Ssthen {
317933707f3Ssthen 	/* answer format
318933707f3Ssthen 	 * 	o uint32 cmd
319933707f3Ssthen 	 * 	o uint32 id
320933707f3Ssthen 	 * 	o uint32 error_code
321933707f3Ssthen 	 * 	o uint32 msg_security
3222308e98cSsthen 	 * 	o uint32 was_ratelimited
323933707f3Ssthen 	 * 	o uint32 length of why_bogus string (+1 for eos); 0 absent.
324933707f3Ssthen 	 * 	o why_bogus_string
325933707f3Ssthen 	 * 	o the remainder is the answer msg from resolver lookup.
326933707f3Ssthen 	 * 	  remainder can be length 0.
327933707f3Ssthen 	 */
3282308e98cSsthen 	size_t size_of_uint32s = 6 * sizeof(uint32_t);
3295d76a658Ssthen 	size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0;
330933707f3Ssthen 	size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
331933707f3Ssthen 	uint8_t* p;
3322308e98cSsthen 	*len = size_of_uint32s + pkt_len + wlen;
333933707f3Ssthen 	p = (uint8_t*)malloc(*len);
334933707f3Ssthen 	if(!p) return NULL;
3355d76a658Ssthen 	sldns_write_uint32(p, UB_LIBCMD_ANSWER);
3365d76a658Ssthen 	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
3375d76a658Ssthen 	sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
3385d76a658Ssthen 	sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
3392308e98cSsthen 	sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited);
3402308e98cSsthen 	sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen);
341933707f3Ssthen 	if(wlen > 0)
3422308e98cSsthen 		memmove(p+size_of_uint32s, q->res->why_bogus, wlen);
343933707f3Ssthen 	if(pkt_len > 0)
3442308e98cSsthen 		memmove(p+size_of_uint32s+wlen,
3455d76a658Ssthen 			sldns_buffer_begin(pkt), pkt_len);
346933707f3Ssthen 	return p;
347933707f3Ssthen }
348933707f3Ssthen 
349933707f3Ssthen struct ctx_query*
350933707f3Ssthen context_deserialize_answer(struct ub_ctx* ctx,
351933707f3Ssthen         uint8_t* p, uint32_t len, int* err)
352933707f3Ssthen {
3532308e98cSsthen 	size_t size_of_uint32s = 6 * sizeof(uint32_t);
354933707f3Ssthen 	struct ctx_query* q = NULL ;
355933707f3Ssthen 	int id;
356933707f3Ssthen 	size_t wlen;
3572308e98cSsthen 	if(len < size_of_uint32s) return NULL;
3585d76a658Ssthen 	log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER);
3595d76a658Ssthen 	id = (int)sldns_read_uint32(p+sizeof(uint32_t));
360933707f3Ssthen 	q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
361933707f3Ssthen 	if(!q) return NULL;
3625d76a658Ssthen 	*err = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
3635d76a658Ssthen 	q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t));
3642308e98cSsthen 	q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t));
3652308e98cSsthen 	wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t));
3662308e98cSsthen 	if(len > size_of_uint32s && wlen > 0) {
3672308e98cSsthen 		if(len >= size_of_uint32s+wlen)
368933707f3Ssthen 			q->res->why_bogus = (char*)memdup(
3692308e98cSsthen 				p+size_of_uint32s, wlen);
370933707f3Ssthen 		if(!q->res->why_bogus) {
371933707f3Ssthen 			/* pass malloc failure to the user callback */
372933707f3Ssthen 			q->msg_len = 0;
373933707f3Ssthen 			*err = UB_NOMEM;
374933707f3Ssthen 			return q;
375933707f3Ssthen 		}
376933707f3Ssthen 		q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
377933707f3Ssthen 	}
3782308e98cSsthen 	if(len > size_of_uint32s+wlen) {
3792308e98cSsthen 		q->msg_len = len - size_of_uint32s - wlen;
3802308e98cSsthen 		q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen,
381933707f3Ssthen 			q->msg_len);
382933707f3Ssthen 		if(!q->msg) {
383933707f3Ssthen 			/* pass malloc failure to the user callback */
384933707f3Ssthen 			q->msg_len = 0;
385933707f3Ssthen 			*err = UB_NOMEM;
386933707f3Ssthen 			return q;
387933707f3Ssthen 		}
388933707f3Ssthen 	}
389933707f3Ssthen 	return q;
390933707f3Ssthen }
391933707f3Ssthen 
392933707f3Ssthen uint8_t*
393933707f3Ssthen context_serialize_cancel(struct ctx_query* q, uint32_t* len)
394933707f3Ssthen {
395933707f3Ssthen 	/* format of cancel:
396933707f3Ssthen 	 * 	o uint32 cmd
397933707f3Ssthen 	 * 	o uint32 async-id */
398fdfb4ba6Ssthen 	uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2);
399933707f3Ssthen 	if(!p) return NULL;
400933707f3Ssthen 	*len = 2*sizeof(uint32_t);
4015d76a658Ssthen 	sldns_write_uint32(p, UB_LIBCMD_CANCEL);
4025d76a658Ssthen 	sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
403933707f3Ssthen 	return p;
404933707f3Ssthen }
405933707f3Ssthen 
406933707f3Ssthen struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
407933707f3Ssthen         uint8_t* p, uint32_t len)
408933707f3Ssthen {
409933707f3Ssthen 	struct ctx_query* q;
410933707f3Ssthen 	int id;
411933707f3Ssthen 	if(len != 2*sizeof(uint32_t)) return NULL;
4125d76a658Ssthen 	log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL);
4135d76a658Ssthen 	id = (int)sldns_read_uint32(p+sizeof(uint32_t));
414933707f3Ssthen 	q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
415933707f3Ssthen 	return q;
416933707f3Ssthen }
417933707f3Ssthen 
418933707f3Ssthen uint8_t*
419933707f3Ssthen context_serialize_quit(uint32_t* len)
420933707f3Ssthen {
421452a1548Ssthen 	uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t));
422933707f3Ssthen 	if(!p)
423933707f3Ssthen 		return NULL;
424933707f3Ssthen 	*len = sizeof(uint32_t);
4255d76a658Ssthen 	sldns_write_uint32(p, UB_LIBCMD_QUIT);
426452a1548Ssthen 	return (uint8_t*)p;
427933707f3Ssthen }
428933707f3Ssthen 
429933707f3Ssthen enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
430933707f3Ssthen {
431933707f3Ssthen 	uint32_t v;
432933707f3Ssthen 	if((size_t)len < sizeof(v))
433933707f3Ssthen 		return UB_LIBCMD_QUIT;
4345d76a658Ssthen 	v = sldns_read_uint32(p);
435933707f3Ssthen 	return v;
436933707f3Ssthen }
437