msgreply.c revision 356345
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
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE 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 "util/data/msgreply.h"
44#include "util/storage/lookup3.h"
45#include "util/log.h"
46#include "util/alloc.h"
47#include "util/netevent.h"
48#include "util/net_help.h"
49#include "util/data/dname.h"
50#include "util/regional.h"
51#include "util/data/msgparse.h"
52#include "util/data/msgencode.h"
53#include "sldns/sbuffer.h"
54#include "sldns/wire2str.h"
55#include "util/module.h"
56#include "util/fptr_wlist.h"
57
58/** MAX TTL default for messages and rrsets */
59time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
60/** MIN TTL default for messages and rrsets */
61time_t MIN_TTL = 0;
62/** MAX Negative TTL, for SOA records in authority section */
63time_t MAX_NEG_TTL = 3600; /* one hour */
64/** Time to serve records after expiration */
65time_t SERVE_EXPIRED_TTL = 0;
66
67/** allocate qinfo, return 0 on error */
68static int
69parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
70	struct query_info* qinf, struct regional* region)
71{
72	if(msg->qname) {
73		if(region)
74			qinf->qname = (uint8_t*)regional_alloc(region,
75				msg->qname_len);
76		else	qinf->qname = (uint8_t*)malloc(msg->qname_len);
77		if(!qinf->qname) return 0;
78		dname_pkt_copy(pkt, qinf->qname, msg->qname);
79	} else	qinf->qname = 0;
80	qinf->qname_len = msg->qname_len;
81	qinf->qtype = msg->qtype;
82	qinf->qclass = msg->qclass;
83	qinf->local_alias = NULL;
84	return 1;
85}
86
87/** constructor for replyinfo */
88struct reply_info*
89construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
90	time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
91	size_t ar, size_t total, enum sec_status sec)
92{
93	struct reply_info* rep;
94	/* rrset_count-1 because the first ref is part of the struct. */
95	size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
96		sizeof(struct ub_packed_rrset_key*) * total;
97	if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/
98	if(region)
99		rep = (struct reply_info*)regional_alloc(region, s);
100	else	rep = (struct reply_info*)malloc(s +
101			sizeof(struct rrset_ref) * (total));
102	if(!rep)
103		return NULL;
104	rep->flags = flags;
105	rep->qdcount = qd;
106	rep->ttl = ttl;
107	rep->prefetch_ttl = prettl;
108	rep->serve_expired_ttl = expttl;
109	rep->an_numrrsets = an;
110	rep->ns_numrrsets = ns;
111	rep->ar_numrrsets = ar;
112	rep->rrset_count = total;
113	rep->security = sec;
114	rep->authoritative = 0;
115	/* array starts after the refs */
116	if(region)
117		rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]);
118	else	rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]);
119	/* zero the arrays to assist cleanup in case of malloc failure */
120	memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total);
121	if(!region)
122		memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total);
123	return rep;
124}
125
126/** allocate replyinfo, return 0 on error */
127static int
128parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
129	struct regional* region)
130{
131	*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
132		0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
133		msg->rrset_count, sec_status_unchecked);
134	if(!*rep)
135		return 0;
136	return 1;
137}
138
139int
140reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
141	struct regional* region)
142{
143	size_t i;
144	for(i=0; i<rep->rrset_count; i++) {
145		if(region) {
146			rep->rrsets[i] = (struct ub_packed_rrset_key*)
147				regional_alloc(region,
148				sizeof(struct ub_packed_rrset_key));
149			if(rep->rrsets[i]) {
150				memset(rep->rrsets[i], 0,
151					sizeof(struct ub_packed_rrset_key));
152				rep->rrsets[i]->entry.key = rep->rrsets[i];
153			}
154		}
155		else	rep->rrsets[i] = alloc_special_obtain(alloc);
156		if(!rep->rrsets[i])
157			return 0;
158		rep->rrsets[i]->entry.data = NULL;
159	}
160	return 1;
161}
162
163/** find the minimumttl in the rdata of SOA record */
164static time_t
165soa_find_minttl(struct rr_parse* rr)
166{
167	uint16_t rlen = sldns_read_uint16(rr->ttl_data+4);
168	if(rlen < 20)
169		return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
170	/* minimum TTL is the last 32bit value in the rdata of the record */
171	/* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
172	return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4);
173}
174
175/** do the rdata copy */
176static int
177rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
178	struct rr_parse* rr, time_t* rr_ttl, uint16_t type,
179	sldns_pkt_section section)
180{
181	uint16_t pkt_len;
182	const sldns_rr_descriptor* desc;
183
184	*rr_ttl = sldns_read_uint32(rr->ttl_data);
185	/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
186	if(*rr_ttl & 0x80000000U)
187		*rr_ttl = 0;
188	if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
189		/* negative response. see if TTL of SOA record larger than the
190		 * minimum-ttl in the rdata of the SOA record */
191		if(*rr_ttl > soa_find_minttl(rr))
192			*rr_ttl = soa_find_minttl(rr);
193		if(*rr_ttl > MAX_NEG_TTL)
194			*rr_ttl = MAX_NEG_TTL;
195	}
196	if(*rr_ttl < MIN_TTL)
197		*rr_ttl = MIN_TTL;
198	if(*rr_ttl > MAX_TTL)
199		*rr_ttl = MAX_TTL;
200	if(*rr_ttl < data->ttl)
201		data->ttl = *rr_ttl;
202
203	if(rr->outside_packet) {
204		/* uncompressed already, only needs copy */
205		memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
206		return 1;
207	}
208
209	sldns_buffer_set_position(pkt, (size_t)
210		(rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
211	/* insert decompressed size into rdata len stored in memory */
212	/* -2 because rdatalen bytes are not included. */
213	pkt_len = htons(rr->size - 2);
214	memmove(to, &pkt_len, sizeof(uint16_t));
215	to += 2;
216	/* read packet rdata len */
217	pkt_len = sldns_buffer_read_u16(pkt);
218	if(sldns_buffer_remaining(pkt) < pkt_len)
219		return 0;
220	desc = sldns_rr_descript(type);
221	if(pkt_len > 0 && desc && desc->_dname_count > 0) {
222		int count = (int)desc->_dname_count;
223		int rdf = 0;
224		size_t len;
225		size_t oldpos;
226		/* decompress dnames. */
227		while(pkt_len > 0 && count) {
228			switch(desc->_wireformat[rdf]) {
229			case LDNS_RDF_TYPE_DNAME:
230				oldpos = sldns_buffer_position(pkt);
231				dname_pkt_copy(pkt, to,
232					sldns_buffer_current(pkt));
233				to += pkt_dname_len(pkt);
234				pkt_len -= sldns_buffer_position(pkt)-oldpos;
235				count--;
236				len = 0;
237				break;
238			case LDNS_RDF_TYPE_STR:
239				len = sldns_buffer_current(pkt)[0] + 1;
240				break;
241			default:
242				len = get_rdf_size(desc->_wireformat[rdf]);
243				break;
244			}
245			if(len) {
246				log_assert(len <= pkt_len);
247				memmove(to, sldns_buffer_current(pkt), len);
248				to += len;
249				sldns_buffer_skip(pkt, (ssize_t)len);
250				pkt_len -= len;
251			}
252			rdf++;
253		}
254	}
255	/* copy remaining rdata */
256	if(pkt_len >  0)
257		memmove(to, sldns_buffer_current(pkt), pkt_len);
258
259	return 1;
260}
261
262/** copy over the data into packed rrset */
263static int
264parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset,
265	struct packed_rrset_data* data)
266{
267	size_t i;
268	struct rr_parse* rr = pset->rr_first;
269	uint8_t* nextrdata;
270	size_t total = pset->rr_count + pset->rrsig_count;
271	data->ttl = MAX_TTL;
272	data->count = pset->rr_count;
273	data->rrsig_count = pset->rrsig_count;
274	data->trust = rrset_trust_none;
275	data->security = sec_status_unchecked;
276	/* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */
277	data->rr_len = (size_t*)((uint8_t*)data +
278		sizeof(struct packed_rrset_data));
279	data->rr_data = (uint8_t**)&(data->rr_len[total]);
280	data->rr_ttl = (time_t*)&(data->rr_data[total]);
281	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
282	for(i=0; i<data->count; i++) {
283		data->rr_len[i] = rr->size;
284		data->rr_data[i] = nextrdata;
285		nextrdata += rr->size;
286		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
287			&data->rr_ttl[i], pset->type, pset->section))
288			return 0;
289		rr = rr->next;
290	}
291	/* if rrsig, its rdata is at nextrdata */
292	rr = pset->rrsig_first;
293	for(i=data->count; i<total; i++) {
294		data->rr_len[i] = rr->size;
295		data->rr_data[i] = nextrdata;
296		nextrdata += rr->size;
297		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
298			&data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section))
299			return 0;
300		rr = rr->next;
301	}
302	return 1;
303}
304
305/** create rrset return 0 on failure */
306static int
307parse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset,
308	struct packed_rrset_data** data, struct regional* region)
309{
310	/* allocate */
311	size_t s;
312	if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX ||
313		pset->size > RR_COUNT_MAX)
314		return 0; /* protect against integer overflow */
315	s = sizeof(struct packed_rrset_data) +
316		(pset->rr_count + pset->rrsig_count) *
317		(sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) +
318		pset->size;
319	if(region)
320		*data = regional_alloc(region, s);
321	else	*data = malloc(s);
322	if(!*data)
323		return 0;
324	/* copy & decompress */
325	if(!parse_rr_copy(pkt, pset, *data)) {
326		if(!region) free(*data);
327		return 0;
328	}
329	return 1;
330}
331
332/** get trust value for rrset */
333static enum rrset_trust
334get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset)
335{
336	uint16_t AA = msg->flags & BIT_AA;
337	if(rrset->section == LDNS_SECTION_ANSWER) {
338		if(AA) {
339			/* RFC2181 says remainder of CNAME chain is nonauth*/
340			if(msg->rrset_first &&
341				msg->rrset_first->section==LDNS_SECTION_ANSWER
342				&& msg->rrset_first->type==LDNS_RR_TYPE_CNAME){
343				if(rrset == msg->rrset_first)
344					return rrset_trust_ans_AA;
345				else 	return rrset_trust_ans_noAA;
346			}
347			if(msg->rrset_first &&
348				msg->rrset_first->section==LDNS_SECTION_ANSWER
349				&& msg->rrset_first->type==LDNS_RR_TYPE_DNAME){
350				if(rrset == msg->rrset_first ||
351				   rrset == msg->rrset_first->rrset_all_next)
352					return rrset_trust_ans_AA;
353				else 	return rrset_trust_ans_noAA;
354			}
355			return rrset_trust_ans_AA;
356		}
357		else	return rrset_trust_ans_noAA;
358	} else if(rrset->section == LDNS_SECTION_AUTHORITY) {
359		if(AA)	return rrset_trust_auth_AA;
360		else	return rrset_trust_auth_noAA;
361	} else {
362		/* addit section */
363		if(AA)	return rrset_trust_add_AA;
364		else	return rrset_trust_add_noAA;
365	}
366	/* NOTREACHED */
367	return rrset_trust_none;
368}
369
370int
371parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg,
372	struct rrset_parse *pset, struct regional* region,
373	struct ub_packed_rrset_key* pk)
374{
375	struct packed_rrset_data* data;
376	pk->rk.flags = pset->flags;
377	pk->rk.dname_len = pset->dname_len;
378	if(region)
379		pk->rk.dname = (uint8_t*)regional_alloc(
380			region, pset->dname_len);
381	else	pk->rk.dname =
382			(uint8_t*)malloc(pset->dname_len);
383	if(!pk->rk.dname)
384		return 0;
385	/** copy & decompress dname */
386	dname_pkt_copy(pkt, pk->rk.dname, pset->dname);
387	/** copy over type and class */
388	pk->rk.type = htons(pset->type);
389	pk->rk.rrset_class = pset->rrset_class;
390	/** read data part. */
391	if(!parse_create_rrset(pkt, pset, &data, region))
392		return 0;
393	pk->entry.data = (void*)data;
394	pk->entry.key = (void*)pk;
395	pk->entry.hash = pset->hash;
396	data->trust = get_rrset_trust(msg, pset);
397	return 1;
398}
399
400/**
401 * Copy and decompress rrs
402 * @param pkt: the packet for compression pointer resolution.
403 * @param msg: the parsed message
404 * @param rep: reply info to put rrs into.
405 * @param region: if not NULL, used for allocation.
406 * @return 0 on failure.
407 */
408static int
409parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg,
410	struct reply_info* rep, struct regional* region)
411{
412	size_t i;
413	struct rrset_parse *pset = msg->rrset_first;
414	struct packed_rrset_data* data;
415	log_assert(rep);
416	rep->ttl = MAX_TTL;
417	rep->security = sec_status_unchecked;
418	if(rep->rrset_count == 0)
419		rep->ttl = NORR_TTL;
420
421	for(i=0; i<rep->rrset_count; i++) {
422		if(!parse_copy_decompress_rrset(pkt, msg, pset, region,
423			rep->rrsets[i]))
424			return 0;
425		data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
426		if(data->ttl < rep->ttl)
427			rep->ttl = data->ttl;
428
429		pset = pset->rrset_all_next;
430	}
431	rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
432	rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
433	return 1;
434}
435
436int
437parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
438	struct alloc_cache* alloc, struct query_info* qinf,
439	struct reply_info** rep, struct regional* region)
440{
441	log_assert(pkt && msg);
442	if(!parse_create_qinfo(pkt, msg, qinf, region))
443		return 0;
444	if(!parse_create_repinfo(msg, rep, region))
445		return 0;
446	if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) {
447		if(!region) reply_info_parsedelete(*rep, alloc);
448		return 0;
449	}
450	if(!parse_copy_decompress(pkt, msg, *rep, region)) {
451		if(!region) reply_info_parsedelete(*rep, alloc);
452		return 0;
453	}
454	return 1;
455}
456
457int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
458        struct query_info* qinf, struct reply_info** rep,
459	struct regional* region, struct edns_data* edns)
460{
461	/* use scratch pad region-allocator during parsing. */
462	struct msg_parse* msg;
463	int ret;
464
465	qinf->qname = NULL;
466	qinf->local_alias = NULL;
467	*rep = NULL;
468	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
469		return LDNS_RCODE_SERVFAIL;
470	}
471	memset(msg, 0, sizeof(*msg));
472
473	sldns_buffer_set_position(pkt, 0);
474	if((ret = parse_packet(pkt, msg, region)) != 0) {
475		return ret;
476	}
477	if((ret = parse_extract_edns(msg, edns, region)) != 0)
478		return ret;
479
480	/* parse OK, allocate return structures */
481	/* this also performs dname decompression */
482	if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
483		query_info_clear(qinf);
484		reply_info_parsedelete(*rep, alloc);
485		*rep = NULL;
486		return LDNS_RCODE_SERVFAIL;
487	}
488	return 0;
489}
490
491/** helper compare function to sort in lock order */
492static int
493reply_info_sortref_cmp(const void* a, const void* b)
494{
495	struct rrset_ref* x = (struct rrset_ref*)a;
496	struct rrset_ref* y = (struct rrset_ref*)b;
497	if(x->key < y->key) return -1;
498	if(x->key > y->key) return 1;
499	return 0;
500}
501
502void
503reply_info_sortref(struct reply_info* rep)
504{
505	qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
506		reply_info_sortref_cmp);
507}
508
509void
510reply_info_set_ttls(struct reply_info* rep, time_t timenow)
511{
512	size_t i, j;
513	rep->ttl += timenow;
514	rep->prefetch_ttl += timenow;
515	rep->serve_expired_ttl += timenow;
516	for(i=0; i<rep->rrset_count; i++) {
517		struct packed_rrset_data* data = (struct packed_rrset_data*)
518			rep->ref[i].key->entry.data;
519		if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
520			continue;
521		data->ttl += timenow;
522		for(j=0; j<data->count + data->rrsig_count; j++) {
523			data->rr_ttl[j] += timenow;
524		}
525	}
526}
527
528void
529reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
530{
531	size_t i;
532	if(!rep)
533		return;
534	/* no need to lock, since not shared in hashtables. */
535	for(i=0; i<rep->rrset_count; i++) {
536		ub_packed_rrset_parsedelete(rep->rrsets[i], alloc);
537	}
538	free(rep);
539}
540
541int
542query_info_parse(struct query_info* m, sldns_buffer* query)
543{
544	uint8_t* q = sldns_buffer_begin(query);
545	/* minimum size: header + \0 + qtype + qclass */
546	if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
547		return 0;
548	if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) !=
549		LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 ||
550		sldns_buffer_position(query) != 0)
551		return 0;
552	sldns_buffer_skip(query, LDNS_HEADER_SIZE);
553	m->qname = sldns_buffer_current(query);
554	if((m->qname_len = query_dname_len(query)) == 0)
555		return 0; /* parse error */
556	if(sldns_buffer_remaining(query) < 4)
557		return 0; /* need qtype, qclass */
558	m->qtype = sldns_buffer_read_u16(query);
559	m->qclass = sldns_buffer_read_u16(query);
560	m->local_alias = NULL;
561	return 1;
562}
563
564/** tiny subroutine for msgreply_compare */
565#define COMPARE_IT(x, y) \
566	if( (x) < (y) ) return -1; \
567	else if( (x) > (y) ) return +1; \
568	log_assert( (x) == (y) );
569
570int
571query_info_compare(void* m1, void* m2)
572{
573	struct query_info* msg1 = (struct query_info*)m1;
574	struct query_info* msg2 = (struct query_info*)m2;
575	int mc;
576	/* from most different to least different for speed */
577	COMPARE_IT(msg1->qtype, msg2->qtype);
578	if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0)
579		return mc;
580	log_assert(msg1->qname_len == msg2->qname_len);
581	COMPARE_IT(msg1->qclass, msg2->qclass);
582	return 0;
583#undef COMPARE_IT
584}
585
586void
587query_info_clear(struct query_info* m)
588{
589	free(m->qname);
590	m->qname = NULL;
591}
592
593size_t
594msgreply_sizefunc(void* k, void* d)
595{
596	struct msgreply_entry* q = (struct msgreply_entry*)k;
597	struct reply_info* r = (struct reply_info*)d;
598	size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info)
599		+ q->key.qname_len + lock_get_mem(&q->entry.lock)
600		- sizeof(struct rrset_ref);
601	s += r->rrset_count * sizeof(struct rrset_ref);
602	s += r->rrset_count * sizeof(struct ub_packed_rrset_key*);
603	return s;
604}
605
606void
607query_entry_delete(void *k, void* ATTR_UNUSED(arg))
608{
609	struct msgreply_entry* q = (struct msgreply_entry*)k;
610	lock_rw_destroy(&q->entry.lock);
611	query_info_clear(&q->key);
612	free(q);
613}
614
615void
616reply_info_delete(void* d, void* ATTR_UNUSED(arg))
617{
618	struct reply_info* r = (struct reply_info*)d;
619	free(r);
620}
621
622hashvalue_type
623query_info_hash(struct query_info *q, uint16_t flags)
624{
625	hashvalue_type h = 0xab;
626	h = hashlittle(&q->qtype, sizeof(q->qtype), h);
627	if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
628		h++;
629	h = hashlittle(&q->qclass, sizeof(q->qclass), h);
630	h = dname_query_hash(q->qname, h);
631	return h;
632}
633
634struct msgreply_entry*
635query_info_entrysetup(struct query_info* q, struct reply_info* r,
636	hashvalue_type h)
637{
638	struct msgreply_entry* e = (struct msgreply_entry*)malloc(
639		sizeof(struct msgreply_entry));
640	if(!e) return NULL;
641	memcpy(&e->key, q, sizeof(*q));
642	e->entry.hash = h;
643	e->entry.key = e;
644	e->entry.data = r;
645	lock_rw_init(&e->entry.lock);
646	lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname));
647	lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len));
648	lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype));
649	lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass));
650	lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias));
651	lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash));
652	lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key));
653	lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data));
654	lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
655	q->qname = NULL;
656	return e;
657}
658
659/** copy rrsets from replyinfo to dest replyinfo */
660static int
661repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from,
662	struct regional* region)
663{
664	size_t i, s;
665	struct packed_rrset_data* fd, *dd;
666	struct ub_packed_rrset_key* fk, *dk;
667	for(i=0; i<dest->rrset_count; i++) {
668		fk = from->rrsets[i];
669		dk = dest->rrsets[i];
670		fd = (struct packed_rrset_data*)fk->entry.data;
671		dk->entry.hash = fk->entry.hash;
672		dk->rk = fk->rk;
673		if(region) {
674			dk->id = fk->id;
675			dk->rk.dname = (uint8_t*)regional_alloc_init(region,
676				fk->rk.dname, fk->rk.dname_len);
677		} else
678			dk->rk.dname = (uint8_t*)memdup(fk->rk.dname,
679				fk->rk.dname_len);
680		if(!dk->rk.dname)
681			return 0;
682		s = packed_rrset_sizeof(fd);
683		if(region)
684			dd = (struct packed_rrset_data*)regional_alloc_init(
685				region, fd, s);
686		else	dd = (struct packed_rrset_data*)memdup(fd, s);
687		if(!dd)
688			return 0;
689		packed_rrset_ptr_fixup(dd);
690		dk->entry.data = (void*)dd;
691	}
692	return 1;
693}
694
695struct reply_info*
696reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
697	struct regional* region)
698{
699	struct reply_info* cp;
700	cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
701		rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl,
702		rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
703		rep->rrset_count, rep->security);
704	if(!cp)
705		return NULL;
706	/* allocate ub_key structures special or not */
707	if(!reply_info_alloc_rrset_keys(cp, alloc, region)) {
708		if(!region)
709			reply_info_parsedelete(cp, alloc);
710		return NULL;
711	}
712	if(!repinfo_copy_rrsets(cp, rep, region)) {
713		if(!region)
714			reply_info_parsedelete(cp, alloc);
715		return NULL;
716	}
717	return cp;
718}
719
720uint8_t*
721reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
722{
723	uint8_t* sname = qinfo->qname;
724	size_t snamelen = qinfo->qname_len;
725	size_t i;
726	for(i=0; i<rep->an_numrrsets; i++) {
727		struct ub_packed_rrset_key* s = rep->rrsets[i];
728		/* follow CNAME chain (if any) */
729		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
730			ntohs(s->rk.rrset_class) == qinfo->qclass &&
731			snamelen == s->rk.dname_len &&
732			query_dname_compare(sname, s->rk.dname) == 0) {
733			get_cname_target(s, &sname, &snamelen);
734		}
735	}
736	if(sname != qinfo->qname)
737		return sname;
738	return NULL;
739}
740
741struct ub_packed_rrset_key*
742reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
743{
744	uint8_t* sname = qinfo->qname;
745	size_t snamelen = qinfo->qname_len;
746	size_t i;
747	for(i=0; i<rep->an_numrrsets; i++) {
748		struct ub_packed_rrset_key* s = rep->rrsets[i];
749		/* first match type, for query of qtype cname */
750		if(ntohs(s->rk.type) == qinfo->qtype &&
751			ntohs(s->rk.rrset_class) == qinfo->qclass &&
752			snamelen == s->rk.dname_len &&
753			query_dname_compare(sname, s->rk.dname) == 0) {
754			return s;
755		}
756		/* follow CNAME chain (if any) */
757		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
758			ntohs(s->rk.rrset_class) == qinfo->qclass &&
759			snamelen == s->rk.dname_len &&
760			query_dname_compare(sname, s->rk.dname) == 0) {
761			get_cname_target(s, &sname, &snamelen);
762		}
763	}
764	return NULL;
765}
766
767struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
768	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
769{
770	size_t i;
771	for(i=0; i<rep->an_numrrsets; i++) {
772		struct ub_packed_rrset_key* s = rep->rrsets[i];
773		if(ntohs(s->rk.type) == type &&
774			ntohs(s->rk.rrset_class) == dclass &&
775			namelen == s->rk.dname_len &&
776			query_dname_compare(name, s->rk.dname) == 0) {
777			return s;
778		}
779	}
780	return NULL;
781}
782
783struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
784	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
785{
786	size_t i;
787	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
788		struct ub_packed_rrset_key* s = rep->rrsets[i];
789		if(ntohs(s->rk.type) == type &&
790			ntohs(s->rk.rrset_class) == dclass &&
791			namelen == s->rk.dname_len &&
792			query_dname_compare(name, s->rk.dname) == 0) {
793			return s;
794		}
795	}
796	return NULL;
797}
798
799struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
800	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
801{
802	size_t i;
803	for(i=0; i<rep->rrset_count; i++) {
804		struct ub_packed_rrset_key* s = rep->rrsets[i];
805		if(ntohs(s->rk.type) == type &&
806			ntohs(s->rk.rrset_class) == dclass &&
807			namelen == s->rk.dname_len &&
808			query_dname_compare(name, s->rk.dname) == 0) {
809			return s;
810		}
811	}
812	return NULL;
813}
814
815void
816log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
817{
818	/* not particularly fast but flexible, make wireformat and print */
819	sldns_buffer* buf = sldns_buffer_new(65535);
820	struct regional* region = regional_create();
821	if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
822		region, 65535, 1, 0)) {
823		log_info("%s: log_dns_msg: out of memory", str);
824	} else {
825		char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf),
826			sldns_buffer_limit(buf));
827		if(!s) {
828			log_info("%s: log_dns_msg: ldns tostr failed", str);
829		} else {
830			log_info("%s %s", str, s);
831		}
832		free(s);
833	}
834	sldns_buffer_free(buf);
835	regional_destroy(region);
836}
837
838void
839log_reply_info(enum verbosity_value v, struct query_info *qinf,
840	struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur,
841	int cached, struct sldns_buffer *rmsg)
842{
843	char qname_buf[LDNS_MAX_DOMAINLEN+1];
844	char clientip_buf[128];
845	char rcode_buf[16];
846	char type_buf[16];
847	char class_buf[16];
848	size_t pktlen;
849	uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2));
850
851	if(verbosity < v)
852	  return;
853
854	sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf));
855	addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf));
856	if(rcode == LDNS_RCODE_FORMERR)
857	{
858		if(LOG_TAG_QUERYREPLY)
859			log_reply("%s - - - %s - - - ", clientip_buf, rcode_buf);
860		else	log_info("%s - - - %s - - - ", clientip_buf, rcode_buf);
861	} else {
862		if(qinf->qname)
863			dname_str(qinf->qname, qname_buf);
864		else	snprintf(qname_buf, sizeof(qname_buf), "null");
865		pktlen = sldns_buffer_limit(rmsg);
866		sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf));
867		sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf));
868		if(LOG_TAG_QUERYREPLY)
869		     log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d",
870			clientip_buf, qname_buf, type_buf, class_buf,
871			rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen);
872		else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d",
873			clientip_buf, qname_buf, type_buf, class_buf,
874			rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen);
875	}
876}
877
878void
879log_query_info(enum verbosity_value v, const char* str,
880	struct query_info* qinf)
881{
882	log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
883}
884
885int
886reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep)
887{
888	/* check only answer section rrs for matching cname chain.
889	 * the cache may return changed rdata, but owner names are untouched.*/
890	size_t i;
891	uint8_t* sname = qinfo->qname;
892	size_t snamelen = qinfo->qname_len;
893	for(i=0; i<rep->an_numrrsets; i++) {
894		uint16_t t = ntohs(rep->rrsets[i]->rk.type);
895		if(t == LDNS_RR_TYPE_DNAME)
896			continue; /* skip dnames; note TTL 0 not cached */
897		/* verify that owner matches current sname */
898		if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
899			/* cname chain broken */
900			return 0;
901		}
902		/* if this is a cname; move on */
903		if(t == LDNS_RR_TYPE_CNAME) {
904			get_cname_target(rep->rrsets[i], &sname, &snamelen);
905		}
906	}
907	return 1;
908}
909
910int
911reply_all_rrsets_secure(struct reply_info* rep)
912{
913	size_t i;
914	for(i=0; i<rep->rrset_count; i++) {
915		if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
916			->security != sec_status_secure )
917		return 0;
918	}
919	return 1;
920}
921
922struct reply_info*
923parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
924	struct query_info* qi)
925{
926	struct reply_info* rep;
927	struct msg_parse* msg;
928	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
929		return NULL;
930	}
931	memset(msg, 0, sizeof(*msg));
932	sldns_buffer_set_position(pkt, 0);
933	if(parse_packet(pkt, msg, region) != 0){
934		return 0;
935	}
936	if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
937		return 0;
938	}
939	return rep;
940}
941
942int edns_opt_append(struct edns_data* edns, struct regional* region,
943	uint16_t code, size_t len, uint8_t* data)
944{
945	struct edns_option** prevp;
946	struct edns_option* opt;
947
948	/* allocate new element */
949	opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
950	if(!opt)
951		return 0;
952	opt->next = NULL;
953	opt->opt_code = code;
954	opt->opt_len = len;
955	opt->opt_data = NULL;
956	if(len > 0) {
957		opt->opt_data = regional_alloc_init(region, data, len);
958		if(!opt->opt_data)
959			return 0;
960	}
961
962	/* append at end of list */
963	prevp = &edns->opt_list;
964	while(*prevp != NULL)
965		prevp = &((*prevp)->next);
966	*prevp = opt;
967	return 1;
968}
969
970int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
971	uint8_t* data, struct regional* region)
972{
973	struct edns_option** prevp;
974	struct edns_option* opt;
975
976	/* allocate new element */
977	opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
978	if(!opt)
979		return 0;
980	opt->next = NULL;
981	opt->opt_code = code;
982	opt->opt_len = len;
983	opt->opt_data = NULL;
984	if(len > 0) {
985		opt->opt_data = regional_alloc_init(region, data, len);
986		if(!opt->opt_data)
987			return 0;
988	}
989
990	/* append at end of list */
991	prevp = list;
992	while(*prevp != NULL) {
993		prevp = &((*prevp)->next);
994	}
995	*prevp = opt;
996	return 1;
997}
998
999int edns_opt_list_remove(struct edns_option** list, uint16_t code)
1000{
1001	/* The list should already be allocated in a region. Freeing the
1002	 * allocated space in a region is not possible. We just unlink the
1003	 * required elements and they will be freed together with the region. */
1004
1005	struct edns_option* prev;
1006	struct edns_option* curr;
1007	if(!list || !(*list)) return 0;
1008
1009	/* Unlink and repoint if the element(s) are first in list */
1010	while(list && *list && (*list)->opt_code == code) {
1011		*list = (*list)->next;
1012	}
1013
1014	if(!list || !(*list)) return 1;
1015	/* Unlink elements and reattach the list */
1016	prev = *list;
1017	curr = (*list)->next;
1018	while(curr != NULL) {
1019		if(curr->opt_code == code) {
1020			prev->next = curr->next;
1021			curr = curr->next;
1022		} else {
1023			prev = curr;
1024			curr = curr->next;
1025		}
1026	}
1027	return 1;
1028}
1029
1030static int inplace_cb_reply_call_generic(
1031    struct inplace_cb* callback_list, enum inplace_cb_list_type type,
1032	struct query_info* qinfo, struct module_qstate* qstate,
1033	struct reply_info* rep, int rcode, struct edns_data* edns,
1034	struct comm_reply* repinfo, struct regional* region)
1035{
1036	struct inplace_cb* cb;
1037	struct edns_option* opt_list_out = NULL;
1038#if defined(EXPORT_ALL_SYMBOLS)
1039	(void)type; /* param not used when fptr_ok disabled */
1040#endif
1041	if(qstate)
1042		opt_list_out = qstate->edns_opts_front_out;
1043	for(cb=callback_list; cb; cb=cb->next) {
1044		fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
1045			(inplace_cb_reply_func_type*)cb->cb, type));
1046		(void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
1047			rcode, edns, &opt_list_out, repinfo, region, cb->id, cb->cb_arg);
1048	}
1049	edns->opt_list = opt_list_out;
1050	return 1;
1051}
1052
1053int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
1054	struct module_qstate* qstate, struct reply_info* rep, int rcode,
1055	struct edns_data* edns, struct comm_reply* repinfo, struct regional* region)
1056{
1057	return inplace_cb_reply_call_generic(
1058		env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
1059		qstate, rep, rcode, edns, repinfo, region);
1060}
1061
1062int inplace_cb_reply_cache_call(struct module_env* env,
1063	struct query_info* qinfo, struct module_qstate* qstate,
1064	struct reply_info* rep, int rcode, struct edns_data* edns,
1065	struct comm_reply* repinfo, struct regional* region)
1066{
1067	return inplace_cb_reply_call_generic(
1068		env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
1069		qinfo, qstate, rep, rcode, edns, repinfo, region);
1070}
1071
1072int inplace_cb_reply_local_call(struct module_env* env,
1073	struct query_info* qinfo, struct module_qstate* qstate,
1074	struct reply_info* rep, int rcode, struct edns_data* edns,
1075	struct comm_reply* repinfo, struct regional* region)
1076{
1077	return inplace_cb_reply_call_generic(
1078		env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
1079		qinfo, qstate, rep, rcode, edns, repinfo, region);
1080}
1081
1082int inplace_cb_reply_servfail_call(struct module_env* env,
1083	struct query_info* qinfo, struct module_qstate* qstate,
1084	struct reply_info* rep, int rcode, struct edns_data* edns,
1085	struct comm_reply* repinfo, struct regional* region)
1086{
1087	/* We are going to servfail. Remove any potential edns options. */
1088	if(qstate)
1089		qstate->edns_opts_front_out = NULL;
1090	return inplace_cb_reply_call_generic(
1091		env->inplace_cb_lists[inplace_cb_reply_servfail],
1092		inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
1093		region);
1094}
1095
1096int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
1097	uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
1098	uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
1099	struct regional* region)
1100{
1101	struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query];
1102	for(; cb; cb=cb->next) {
1103		fptr_ok(fptr_whitelist_inplace_cb_query(
1104			(inplace_cb_query_func_type*)cb->cb));
1105		(void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags,
1106			qstate, addr, addrlen, zone, zonelen, region,
1107			cb->id, cb->cb_arg);
1108	}
1109	return 1;
1110}
1111
1112int inplace_cb_edns_back_parsed_call(struct module_env* env,
1113	struct module_qstate* qstate)
1114{
1115	struct inplace_cb* cb =
1116		env->inplace_cb_lists[inplace_cb_edns_back_parsed];
1117	for(; cb; cb=cb->next) {
1118		fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed(
1119			(inplace_cb_edns_back_parsed_func_type*)cb->cb));
1120		(void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate,
1121			cb->id, cb->cb_arg);
1122	}
1123	return 1;
1124}
1125
1126int inplace_cb_query_response_call(struct module_env* env,
1127	struct module_qstate* qstate, struct dns_msg* response) {
1128	struct inplace_cb* cb =
1129		env->inplace_cb_lists[inplace_cb_query_response];
1130	for(; cb; cb=cb->next) {
1131		fptr_ok(fptr_whitelist_inplace_cb_query_response(
1132			(inplace_cb_query_response_func_type*)cb->cb));
1133		(void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate,
1134			response, cb->id, cb->cb_arg);
1135	}
1136	return 1;
1137}
1138
1139struct edns_option* edns_opt_copy_region(struct edns_option* list,
1140        struct regional* region)
1141{
1142	struct edns_option* result = NULL, *cur = NULL, *s;
1143	while(list) {
1144		/* copy edns option structure */
1145		s = regional_alloc_init(region, list, sizeof(*list));
1146		if(!s) return NULL;
1147		s->next = NULL;
1148
1149		/* copy option data */
1150		if(s->opt_data) {
1151			s->opt_data = regional_alloc_init(region, s->opt_data,
1152				s->opt_len);
1153			if(!s->opt_data)
1154				return NULL;
1155		}
1156
1157		/* link into list */
1158		if(cur)
1159			cur->next = s;
1160		else	result = s;
1161		cur = s;
1162
1163		/* examine next element */
1164		list = list->next;
1165	}
1166	return result;
1167}
1168
1169int edns_opt_compare(struct edns_option* p, struct edns_option* q)
1170{
1171	if(!p && !q) return 0;
1172	if(!p) return -1;
1173	if(!q) return 1;
1174	log_assert(p && q);
1175	if(p->opt_code != q->opt_code)
1176		return (int)q->opt_code - (int)p->opt_code;
1177	if(p->opt_len != q->opt_len)
1178		return (int)q->opt_len - (int)p->opt_len;
1179	if(p->opt_len != 0)
1180		return memcmp(p->opt_data, q->opt_data, p->opt_len);
1181	return 0;
1182}
1183
1184int edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
1185{
1186	int r;
1187	while(p && q) {
1188		r = edns_opt_compare(p, q);
1189		if(r != 0)
1190			return r;
1191		p = p->next;
1192		q = q->next;
1193	}
1194	if(p || q) {
1195		/* uneven length lists */
1196		if(p) return 1;
1197		if(q) return -1;
1198	}
1199	return 0;
1200}
1201
1202void edns_opt_list_free(struct edns_option* list)
1203{
1204	struct edns_option* n;
1205	while(list) {
1206		free(list->opt_data);
1207		n = list->next;
1208		free(list);
1209		list = n;
1210	}
1211}
1212
1213struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
1214{
1215	struct edns_option* result = NULL, *cur = NULL, *s;
1216	while(list) {
1217		/* copy edns option structure */
1218		s = memdup(list, sizeof(*list));
1219		if(!s) {
1220			edns_opt_list_free(result);
1221			return NULL;
1222		}
1223		s->next = NULL;
1224
1225		/* copy option data */
1226		if(s->opt_data) {
1227			s->opt_data = memdup(s->opt_data, s->opt_len);
1228			if(!s->opt_data) {
1229				free(s);
1230				edns_opt_list_free(result);
1231				return NULL;
1232			}
1233		}
1234
1235		/* link into list */
1236		if(cur)
1237			cur->next = s;
1238		else	result = s;
1239		cur = s;
1240
1241		/* examine next element */
1242		list = list->next;
1243	}
1244	return result;
1245}
1246
1247struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
1248{
1249	struct edns_option* p;
1250	for(p=list; p; p=p->next) {
1251		if(p->opt_code == code)
1252			return p;
1253	}
1254	return NULL;
1255}
1256