xref: /freebsd/contrib/unbound/util/data/msgreply.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
1 /*
2  * util/data/msgreply.c - store message and reply data.
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 a data structure to store a message and its reply.
40  */
41 
42 #include "config.h"
43 #include <ldns/ldns.h>
44 #include "util/data/msgreply.h"
45 #include "util/storage/lookup3.h"
46 #include "util/log.h"
47 #include "util/alloc.h"
48 #include "util/netevent.h"
49 #include "util/net_help.h"
50 #include "util/data/dname.h"
51 #include "util/regional.h"
52 #include "util/data/msgparse.h"
53 #include "util/data/msgencode.h"
54 
55 /** MAX TTL default for messages and rrsets */
56 uint32_t MAX_TTL = 3600 * 24 * 10; /* ten days */
57 /** MIN TTL default for messages and rrsets */
58 uint32_t MIN_TTL = 0;
59 
60 /** allocate qinfo, return 0 on error */
61 static int
62 parse_create_qinfo(ldns_buffer* pkt, struct msg_parse* msg,
63 	struct query_info* qinf, struct regional* region)
64 {
65 	if(msg->qname) {
66 		if(region)
67 			qinf->qname = (uint8_t*)regional_alloc(region,
68 				msg->qname_len);
69 		else	qinf->qname = (uint8_t*)malloc(msg->qname_len);
70 		if(!qinf->qname) return 0;
71 		dname_pkt_copy(pkt, qinf->qname, msg->qname);
72 	} else	qinf->qname = 0;
73 	qinf->qname_len = msg->qname_len;
74 	qinf->qtype = msg->qtype;
75 	qinf->qclass = msg->qclass;
76 	return 1;
77 }
78 
79 /** constructor for replyinfo */
80 static struct reply_info*
81 construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
82 	uint32_t ttl, uint32_t prettl, size_t an, size_t ns, size_t ar,
83 	size_t total, enum sec_status sec)
84 {
85 	struct reply_info* rep;
86 	/* rrset_count-1 because the first ref is part of the struct. */
87 	size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
88 		sizeof(struct ub_packed_rrset_key*) * total;
89 	if(region)
90 		rep = (struct reply_info*)regional_alloc(region, s);
91 	else	rep = (struct reply_info*)malloc(s +
92 			sizeof(struct rrset_ref) * (total));
93 	if(!rep)
94 		return NULL;
95 	rep->flags = flags;
96 	rep->qdcount = qd;
97 	rep->ttl = ttl;
98 	rep->prefetch_ttl = prettl;
99 	rep->an_numrrsets = an;
100 	rep->ns_numrrsets = ns;
101 	rep->ar_numrrsets = ar;
102 	rep->rrset_count = total;
103 	rep->security = sec;
104 	rep->authoritative = 0;
105 	/* array starts after the refs */
106 	if(region)
107 		rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]);
108 	else	rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]);
109 	/* zero the arrays to assist cleanup in case of malloc failure */
110 	memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total);
111 	if(!region)
112 		memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total);
113 	return rep;
114 }
115 
116 /** allocate replyinfo, return 0 on error */
117 static int
118 parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
119 	struct regional* region)
120 {
121 	*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
122 		0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
123 		msg->rrset_count, sec_status_unchecked);
124 	if(!*rep)
125 		return 0;
126 	return 1;
127 }
128 
129 /** allocate (special) rrset keys, return 0 on error */
130 static int
131 repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
132 	struct regional* region)
133 {
134 	size_t i;
135 	for(i=0; i<rep->rrset_count; i++) {
136 		if(region) {
137 			rep->rrsets[i] = (struct ub_packed_rrset_key*)
138 				regional_alloc(region,
139 				sizeof(struct ub_packed_rrset_key));
140 			if(rep->rrsets[i]) {
141 				memset(rep->rrsets[i], 0,
142 					sizeof(struct ub_packed_rrset_key));
143 				rep->rrsets[i]->entry.key = rep->rrsets[i];
144 			}
145 		}
146 		else	rep->rrsets[i] = alloc_special_obtain(alloc);
147 		if(!rep->rrsets[i])
148 			return 0;
149 		rep->rrsets[i]->entry.data = NULL;
150 	}
151 	return 1;
152 }
153 
154 /** do the rdata copy */
155 static int
156 rdata_copy(ldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
157 	struct rr_parse* rr, uint32_t* rr_ttl, uint16_t type)
158 {
159 	uint16_t pkt_len;
160 	const ldns_rr_descriptor* desc;
161 
162 	*rr_ttl = ldns_read_uint32(rr->ttl_data);
163 	/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
164 	if(*rr_ttl & 0x80000000U)
165 		*rr_ttl = 0;
166 	if(*rr_ttl < MIN_TTL)
167 		*rr_ttl = MIN_TTL;
168 	if(*rr_ttl < data->ttl)
169 		data->ttl = *rr_ttl;
170 
171 	if(rr->outside_packet) {
172 		/* uncompressed already, only needs copy */
173 		memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
174 		return 1;
175 	}
176 
177 	ldns_buffer_set_position(pkt, (size_t)
178 		(rr->ttl_data - ldns_buffer_begin(pkt) + sizeof(uint32_t)));
179 	/* insert decompressed size into rdata len stored in memory */
180 	/* -2 because rdatalen bytes are not included. */
181 	pkt_len = htons(rr->size - 2);
182 	memmove(to, &pkt_len, sizeof(uint16_t));
183 	to += 2;
184 	/* read packet rdata len */
185 	pkt_len = ldns_buffer_read_u16(pkt);
186 	if(ldns_buffer_remaining(pkt) < pkt_len)
187 		return 0;
188 	desc = ldns_rr_descript(type);
189 	if(pkt_len > 0 && desc && desc->_dname_count > 0) {
190 		int count = (int)desc->_dname_count;
191 		int rdf = 0;
192 		size_t len;
193 		size_t oldpos;
194 		/* decompress dnames. */
195 		while(pkt_len > 0 && count) {
196 			switch(desc->_wireformat[rdf]) {
197 			case LDNS_RDF_TYPE_DNAME:
198 				oldpos = ldns_buffer_position(pkt);
199 				dname_pkt_copy(pkt, to,
200 					ldns_buffer_current(pkt));
201 				to += pkt_dname_len(pkt);
202 				pkt_len -= ldns_buffer_position(pkt)-oldpos;
203 				count--;
204 				len = 0;
205 				break;
206 			case LDNS_RDF_TYPE_STR:
207 				len = ldns_buffer_current(pkt)[0] + 1;
208 				break;
209 			default:
210 				len = get_rdf_size(desc->_wireformat[rdf]);
211 				break;
212 			}
213 			if(len) {
214 				memmove(to, ldns_buffer_current(pkt), len);
215 				to += len;
216 				ldns_buffer_skip(pkt, (ssize_t)len);
217 				log_assert(len <= pkt_len);
218 				pkt_len -= len;
219 			}
220 			rdf++;
221 		}
222 	}
223 	/* copy remaining rdata */
224 	if(pkt_len >  0)
225 		memmove(to, ldns_buffer_current(pkt), pkt_len);
226 
227 	return 1;
228 }
229 
230 /** copy over the data into packed rrset */
231 static int
232 parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset,
233 	struct packed_rrset_data* data)
234 {
235 	size_t i;
236 	struct rr_parse* rr = pset->rr_first;
237 	uint8_t* nextrdata;
238 	size_t total = pset->rr_count + pset->rrsig_count;
239 	data->ttl = MAX_TTL;
240 	data->count = pset->rr_count;
241 	data->rrsig_count = pset->rrsig_count;
242 	data->trust = rrset_trust_none;
243 	data->security = sec_status_unchecked;
244 	/* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */
245 	data->rr_len = (size_t*)((uint8_t*)data +
246 		sizeof(struct packed_rrset_data));
247 	data->rr_data = (uint8_t**)&(data->rr_len[total]);
248 	data->rr_ttl = (uint32_t*)&(data->rr_data[total]);
249 	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
250 	for(i=0; i<data->count; i++) {
251 		data->rr_len[i] = rr->size;
252 		data->rr_data[i] = nextrdata;
253 		nextrdata += rr->size;
254 		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
255 			&data->rr_ttl[i], pset->type))
256 			return 0;
257 		rr = rr->next;
258 	}
259 	/* if rrsig, its rdata is at nextrdata */
260 	rr = pset->rrsig_first;
261 	for(i=data->count; i<total; i++) {
262 		data->rr_len[i] = rr->size;
263 		data->rr_data[i] = nextrdata;
264 		nextrdata += rr->size;
265 		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
266 			&data->rr_ttl[i], LDNS_RR_TYPE_RRSIG))
267 			return 0;
268 		rr = rr->next;
269 	}
270 	return 1;
271 }
272 
273 /** create rrset return 0 on failure */
274 static int
275 parse_create_rrset(ldns_buffer* pkt, struct rrset_parse* pset,
276 	struct packed_rrset_data** data, struct regional* region)
277 {
278 	/* allocate */
279 	size_t s = sizeof(struct packed_rrset_data) +
280 		(pset->rr_count + pset->rrsig_count) *
281 		(sizeof(size_t)+sizeof(uint8_t*)+sizeof(uint32_t)) +
282 		pset->size;
283 	if(region)
284 		*data = regional_alloc(region, s);
285 	else	*data = malloc(s);
286 	if(!*data)
287 		return 0;
288 	/* copy & decompress */
289 	if(!parse_rr_copy(pkt, pset, *data)) {
290 		if(!region) free(*data);
291 		return 0;
292 	}
293 	return 1;
294 }
295 
296 /** get trust value for rrset */
297 static enum rrset_trust
298 get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset)
299 {
300 	uint16_t AA = msg->flags & BIT_AA;
301 	if(rrset->section == LDNS_SECTION_ANSWER) {
302 		if(AA) {
303 			/* RFC2181 says remainder of CNAME chain is nonauth*/
304 			if(msg->rrset_first &&
305 				msg->rrset_first->section==LDNS_SECTION_ANSWER
306 				&& msg->rrset_first->type==LDNS_RR_TYPE_CNAME){
307 				if(rrset == msg->rrset_first)
308 					return rrset_trust_ans_AA;
309 				else 	return rrset_trust_ans_noAA;
310 			}
311 			if(msg->rrset_first &&
312 				msg->rrset_first->section==LDNS_SECTION_ANSWER
313 				&& msg->rrset_first->type==LDNS_RR_TYPE_DNAME){
314 				if(rrset == msg->rrset_first ||
315 				   rrset == msg->rrset_first->rrset_all_next)
316 					return rrset_trust_ans_AA;
317 				else 	return rrset_trust_ans_noAA;
318 			}
319 			return rrset_trust_ans_AA;
320 		}
321 		else	return rrset_trust_ans_noAA;
322 	} else if(rrset->section == LDNS_SECTION_AUTHORITY) {
323 		if(AA)	return rrset_trust_auth_AA;
324 		else	return rrset_trust_auth_noAA;
325 	} else {
326 		/* addit section */
327 		if(AA)	return rrset_trust_add_AA;
328 		else	return rrset_trust_add_noAA;
329 	}
330 	/* NOTREACHED */
331 	return rrset_trust_none;
332 }
333 
334 int
335 parse_copy_decompress_rrset(ldns_buffer* pkt, struct msg_parse* msg,
336 	struct rrset_parse *pset, struct regional* region,
337 	struct ub_packed_rrset_key* pk)
338 {
339 	struct packed_rrset_data* data;
340 	pk->rk.flags = pset->flags;
341 	pk->rk.dname_len = pset->dname_len;
342 	if(region)
343 		pk->rk.dname = (uint8_t*)regional_alloc(
344 			region, pset->dname_len);
345 	else	pk->rk.dname =
346 			(uint8_t*)malloc(pset->dname_len);
347 	if(!pk->rk.dname)
348 		return 0;
349 	/** copy & decompress dname */
350 	dname_pkt_copy(pkt, pk->rk.dname, pset->dname);
351 	/** copy over type and class */
352 	pk->rk.type = htons(pset->type);
353 	pk->rk.rrset_class = pset->rrset_class;
354 	/** read data part. */
355 	if(!parse_create_rrset(pkt, pset, &data, region))
356 		return 0;
357 	pk->entry.data = (void*)data;
358 	pk->entry.key = (void*)pk;
359 	pk->entry.hash = pset->hash;
360 	data->trust = get_rrset_trust(msg, pset);
361 	return 1;
362 }
363 
364 /**
365  * Copy and decompress rrs
366  * @param pkt: the packet for compression pointer resolution.
367  * @param msg: the parsed message
368  * @param rep: reply info to put rrs into.
369  * @param region: if not NULL, used for allocation.
370  * @return 0 on failure.
371  */
372 static int
373 parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg,
374 	struct reply_info* rep, struct regional* region)
375 {
376 	size_t i;
377 	struct rrset_parse *pset = msg->rrset_first;
378 	struct packed_rrset_data* data;
379 	log_assert(rep);
380 	rep->ttl = MAX_TTL;
381 	rep->security = sec_status_unchecked;
382 	if(rep->rrset_count == 0)
383 		rep->ttl = NORR_TTL;
384 
385 	for(i=0; i<rep->rrset_count; i++) {
386 		if(!parse_copy_decompress_rrset(pkt, msg, pset, region,
387 			rep->rrsets[i]))
388 			return 0;
389 		data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
390 		if(data->ttl < rep->ttl)
391 			rep->ttl = data->ttl;
392 
393 		pset = pset->rrset_all_next;
394 	}
395 	rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
396 	return 1;
397 }
398 
399 int
400 parse_create_msg(ldns_buffer* pkt, struct msg_parse* msg,
401 	struct alloc_cache* alloc, struct query_info* qinf,
402 	struct reply_info** rep, struct regional* region)
403 {
404 	log_assert(pkt && msg);
405 	if(!parse_create_qinfo(pkt, msg, qinf, region))
406 		return 0;
407 	if(!parse_create_repinfo(msg, rep, region))
408 		return 0;
409 	if(!repinfo_alloc_rrset_keys(*rep, alloc, region))
410 		return 0;
411 	if(!parse_copy_decompress(pkt, msg, *rep, region))
412 		return 0;
413 	return 1;
414 }
415 
416 int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc,
417         struct query_info* qinf, struct reply_info** rep,
418 	struct regional* region, struct edns_data* edns)
419 {
420 	/* use scratch pad region-allocator during parsing. */
421 	struct msg_parse* msg;
422 	int ret;
423 
424 	qinf->qname = NULL;
425 	*rep = NULL;
426 	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
427 		return LDNS_RCODE_SERVFAIL;
428 	}
429 	memset(msg, 0, sizeof(*msg));
430 
431 	ldns_buffer_set_position(pkt, 0);
432 	if((ret = parse_packet(pkt, msg, region)) != 0) {
433 		return ret;
434 	}
435 	if((ret = parse_extract_edns(msg, edns)) != 0)
436 		return ret;
437 
438 	/* parse OK, allocate return structures */
439 	/* this also performs dname decompression */
440 	if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
441 		query_info_clear(qinf);
442 		reply_info_parsedelete(*rep, alloc);
443 		*rep = NULL;
444 		return LDNS_RCODE_SERVFAIL;
445 	}
446 	return 0;
447 }
448 
449 /** helper compare function to sort in lock order */
450 static int
451 reply_info_sortref_cmp(const void* a, const void* b)
452 {
453 	struct rrset_ref* x = (struct rrset_ref*)a;
454 	struct rrset_ref* y = (struct rrset_ref*)b;
455 	if(x->key < y->key) return -1;
456 	if(x->key > y->key) return 1;
457 	return 0;
458 }
459 
460 void
461 reply_info_sortref(struct reply_info* rep)
462 {
463 	qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
464 		reply_info_sortref_cmp);
465 }
466 
467 void
468 reply_info_set_ttls(struct reply_info* rep, uint32_t timenow)
469 {
470 	size_t i, j;
471 	rep->ttl += timenow;
472 	rep->prefetch_ttl += timenow;
473 	for(i=0; i<rep->rrset_count; i++) {
474 		struct packed_rrset_data* data = (struct packed_rrset_data*)
475 			rep->ref[i].key->entry.data;
476 		if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
477 			continue;
478 		data->ttl += timenow;
479 		for(j=0; j<data->count + data->rrsig_count; j++) {
480 			data->rr_ttl[j] += timenow;
481 		}
482 	}
483 }
484 
485 void
486 reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
487 {
488 	size_t i;
489 	if(!rep)
490 		return;
491 	/* no need to lock, since not shared in hashtables. */
492 	for(i=0; i<rep->rrset_count; i++) {
493 		ub_packed_rrset_parsedelete(rep->rrsets[i], alloc);
494 	}
495 	free(rep);
496 }
497 
498 int
499 query_info_parse(struct query_info* m, ldns_buffer* query)
500 {
501 	uint8_t* q = ldns_buffer_begin(query);
502 	/* minimum size: header + \0 + qtype + qclass */
503 	if(ldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
504 		return 0;
505 	if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY ||
506 		LDNS_QDCOUNT(q) != 1 || ldns_buffer_position(query) != 0)
507 		return 0;
508 	ldns_buffer_skip(query, LDNS_HEADER_SIZE);
509 	m->qname = ldns_buffer_current(query);
510 	if((m->qname_len = query_dname_len(query)) == 0)
511 		return 0; /* parse error */
512 	if(ldns_buffer_remaining(query) < 4)
513 		return 0; /* need qtype, qclass */
514 	m->qtype = ldns_buffer_read_u16(query);
515 	m->qclass = ldns_buffer_read_u16(query);
516 	return 1;
517 }
518 
519 /** tiny subroutine for msgreply_compare */
520 #define COMPARE_IT(x, y) \
521 	if( (x) < (y) ) return -1; \
522 	else if( (x) > (y) ) return +1; \
523 	log_assert( (x) == (y) );
524 
525 int
526 query_info_compare(void* m1, void* m2)
527 {
528 	struct query_info* msg1 = (struct query_info*)m1;
529 	struct query_info* msg2 = (struct query_info*)m2;
530 	int mc;
531 	/* from most different to least different for speed */
532 	COMPARE_IT(msg1->qtype, msg2->qtype);
533 	if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0)
534 		return mc;
535 	log_assert(msg1->qname_len == msg2->qname_len);
536 	COMPARE_IT(msg1->qclass, msg2->qclass);
537 	return 0;
538 #undef COMPARE_IT
539 }
540 
541 void
542 query_info_clear(struct query_info* m)
543 {
544 	free(m->qname);
545 	m->qname = NULL;
546 }
547 
548 size_t
549 msgreply_sizefunc(void* k, void* d)
550 {
551 	struct msgreply_entry* q = (struct msgreply_entry*)k;
552 	struct reply_info* r = (struct reply_info*)d;
553 	size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info)
554 		+ q->key.qname_len + lock_get_mem(&q->entry.lock)
555 		- sizeof(struct rrset_ref);
556 	s += r->rrset_count * sizeof(struct rrset_ref);
557 	s += r->rrset_count * sizeof(struct ub_packed_rrset_key*);
558 	return s;
559 }
560 
561 void
562 query_entry_delete(void *k, void* ATTR_UNUSED(arg))
563 {
564 	struct msgreply_entry* q = (struct msgreply_entry*)k;
565 	lock_rw_destroy(&q->entry.lock);
566 	query_info_clear(&q->key);
567 	free(q);
568 }
569 
570 void
571 reply_info_delete(void* d, void* ATTR_UNUSED(arg))
572 {
573 	struct reply_info* r = (struct reply_info*)d;
574 	free(r);
575 }
576 
577 hashvalue_t
578 query_info_hash(struct query_info *q)
579 {
580 	hashvalue_t h = 0xab;
581 	h = hashlittle(&q->qtype, sizeof(q->qtype), h);
582 	h = hashlittle(&q->qclass, sizeof(q->qclass), h);
583 	h = dname_query_hash(q->qname, h);
584 	return h;
585 }
586 
587 struct msgreply_entry*
588 query_info_entrysetup(struct query_info* q, struct reply_info* r,
589 	hashvalue_t h)
590 {
591 	struct msgreply_entry* e = (struct msgreply_entry*)malloc(
592 		sizeof(struct msgreply_entry));
593 	if(!e) return NULL;
594 	memcpy(&e->key, q, sizeof(*q));
595 	e->entry.hash = h;
596 	e->entry.key = e;
597 	e->entry.data = r;
598 	lock_rw_init(&e->entry.lock);
599 	lock_protect(&e->entry.lock, &e->key, sizeof(e->key));
600 	lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) +
601 		sizeof(e->entry.key) + sizeof(e->entry.data));
602 	lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
603 	q->qname = NULL;
604 	return e;
605 }
606 
607 /** copy rrsets from replyinfo to dest replyinfo */
608 static int
609 repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from,
610 	struct regional* region)
611 {
612 	size_t i, s;
613 	struct packed_rrset_data* fd, *dd;
614 	struct ub_packed_rrset_key* fk, *dk;
615 	for(i=0; i<dest->rrset_count; i++) {
616 		fk = from->rrsets[i];
617 		dk = dest->rrsets[i];
618 		fd = (struct packed_rrset_data*)fk->entry.data;
619 		dk->entry.hash = fk->entry.hash;
620 		dk->rk = fk->rk;
621 		if(region) {
622 			dk->id = fk->id;
623 			dk->rk.dname = (uint8_t*)regional_alloc_init(region,
624 				fk->rk.dname, fk->rk.dname_len);
625 		} else
626 			dk->rk.dname = (uint8_t*)memdup(fk->rk.dname,
627 				fk->rk.dname_len);
628 		if(!dk->rk.dname)
629 			return 0;
630 		s = packed_rrset_sizeof(fd);
631 		if(region)
632 			dd = (struct packed_rrset_data*)regional_alloc_init(
633 				region, fd, s);
634 		else	dd = (struct packed_rrset_data*)memdup(fd, s);
635 		if(!dd)
636 			return 0;
637 		packed_rrset_ptr_fixup(dd);
638 		dk->entry.data = (void*)dd;
639 	}
640 	return 1;
641 }
642 
643 struct reply_info*
644 reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
645 	struct regional* region)
646 {
647 	struct reply_info* cp;
648 	cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
649 		rep->ttl, rep->prefetch_ttl, rep->an_numrrsets,
650 		rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count,
651 		rep->security);
652 	if(!cp)
653 		return NULL;
654 	/* allocate ub_key structures special or not */
655 	if(!repinfo_alloc_rrset_keys(cp, alloc, region)) {
656 		if(!region)
657 			reply_info_parsedelete(cp, alloc);
658 		return NULL;
659 	}
660 	if(!repinfo_copy_rrsets(cp, rep, region)) {
661 		if(!region)
662 			reply_info_parsedelete(cp, alloc);
663 		return NULL;
664 	}
665 	return cp;
666 }
667 
668 uint8_t*
669 reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
670 {
671 	uint8_t* sname = qinfo->qname;
672 	size_t snamelen = qinfo->qname_len;
673 	size_t i;
674 	for(i=0; i<rep->an_numrrsets; i++) {
675 		struct ub_packed_rrset_key* s = rep->rrsets[i];
676 		/* follow CNAME chain (if any) */
677 		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
678 			ntohs(s->rk.rrset_class) == qinfo->qclass &&
679 			snamelen == s->rk.dname_len &&
680 			query_dname_compare(sname, s->rk.dname) == 0) {
681 			get_cname_target(s, &sname, &snamelen);
682 		}
683 	}
684 	if(sname != qinfo->qname)
685 		return sname;
686 	return NULL;
687 }
688 
689 struct ub_packed_rrset_key*
690 reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
691 {
692 	uint8_t* sname = qinfo->qname;
693 	size_t snamelen = qinfo->qname_len;
694 	size_t i;
695 	for(i=0; i<rep->an_numrrsets; i++) {
696 		struct ub_packed_rrset_key* s = rep->rrsets[i];
697 		/* first match type, for query of qtype cname */
698 		if(ntohs(s->rk.type) == qinfo->qtype &&
699 			ntohs(s->rk.rrset_class) == qinfo->qclass &&
700 			snamelen == s->rk.dname_len &&
701 			query_dname_compare(sname, s->rk.dname) == 0) {
702 			return s;
703 		}
704 		/* follow CNAME chain (if any) */
705 		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
706 			ntohs(s->rk.rrset_class) == qinfo->qclass &&
707 			snamelen == s->rk.dname_len &&
708 			query_dname_compare(sname, s->rk.dname) == 0) {
709 			get_cname_target(s, &sname, &snamelen);
710 		}
711 	}
712 	return NULL;
713 }
714 
715 struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
716 	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
717 {
718 	size_t i;
719 	for(i=0; i<rep->an_numrrsets; i++) {
720 		struct ub_packed_rrset_key* s = rep->rrsets[i];
721 		if(ntohs(s->rk.type) == type &&
722 			ntohs(s->rk.rrset_class) == dclass &&
723 			namelen == s->rk.dname_len &&
724 			query_dname_compare(name, s->rk.dname) == 0) {
725 			return s;
726 		}
727 	}
728 	return NULL;
729 }
730 
731 struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
732 	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
733 {
734 	size_t i;
735 	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
736 		struct ub_packed_rrset_key* s = rep->rrsets[i];
737 		if(ntohs(s->rk.type) == type &&
738 			ntohs(s->rk.rrset_class) == dclass &&
739 			namelen == s->rk.dname_len &&
740 			query_dname_compare(name, s->rk.dname) == 0) {
741 			return s;
742 		}
743 	}
744 	return NULL;
745 }
746 
747 struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
748 	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
749 {
750 	size_t i;
751 	for(i=0; i<rep->rrset_count; i++) {
752 		struct ub_packed_rrset_key* s = rep->rrsets[i];
753 		if(ntohs(s->rk.type) == type &&
754 			ntohs(s->rk.rrset_class) == dclass &&
755 			namelen == s->rk.dname_len &&
756 			query_dname_compare(name, s->rk.dname) == 0) {
757 			return s;
758 		}
759 	}
760 	return NULL;
761 }
762 
763 void
764 log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
765 {
766 	/* not particularly fast but flexible, make wireformat and print */
767 	ldns_buffer* buf = ldns_buffer_new(65535);
768 	struct regional* region = regional_create();
769 	if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
770 		region, 65535, 1)) {
771 		log_info("%s: log_dns_msg: out of memory", str);
772 	} else {
773 		ldns_status s;
774 		ldns_pkt* pkt = NULL;
775 		s = ldns_buffer2pkt_wire(&pkt, buf);
776 		if(s != LDNS_STATUS_OK) {
777 			log_info("%s: log_dns_msg: ldns parse gave: %s",
778 				str, ldns_get_errorstr_by_id(s));
779 		} else {
780 			ldns_buffer_clear(buf);
781 			s = ldns_pkt2buffer_str(buf, pkt);
782 			if(s != LDNS_STATUS_OK) {
783 				log_info("%s: log_dns_msg: ldns tostr gave: %s",
784 					str, ldns_get_errorstr_by_id(s));
785 			} else {
786 				log_info("%s %s",
787 					str, (char*)ldns_buffer_begin(buf));
788 			}
789 		}
790 		ldns_pkt_free(pkt);
791 	}
792 	ldns_buffer_free(buf);
793 	regional_destroy(region);
794 }
795 
796 void
797 log_query_info(enum verbosity_value v, const char* str,
798 	struct query_info* qinf)
799 {
800 	log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
801 }
802 
803 int
804 reply_check_cname_chain(struct reply_info* rep)
805 {
806 	/* check only answer section rrs for matching cname chain.
807 	 * the cache may return changed rdata, but owner names are untouched.*/
808 	size_t i;
809 	uint8_t* sname = rep->rrsets[0]->rk.dname;
810 	size_t snamelen = rep->rrsets[0]->rk.dname_len;
811 	for(i=0; i<rep->an_numrrsets; i++) {
812 		uint16_t t = ntohs(rep->rrsets[i]->rk.type);
813 		if(t == LDNS_RR_TYPE_DNAME)
814 			continue; /* skip dnames; note TTL 0 not cached */
815 		/* verify that owner matches current sname */
816 		if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
817 			/* cname chain broken */
818 			return 0;
819 		}
820 		/* if this is a cname; move on */
821 		if(t == LDNS_RR_TYPE_CNAME) {
822 			get_cname_target(rep->rrsets[i], &sname, &snamelen);
823 		}
824 	}
825 	return 1;
826 }
827 
828 int
829 reply_all_rrsets_secure(struct reply_info* rep)
830 {
831 	size_t i;
832 	for(i=0; i<rep->rrset_count; i++) {
833 		if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
834 			->security != sec_status_secure )
835 		return 0;
836 	}
837 	return 1;
838 }
839