1178479Sjb/*
2178479Sjb * util/data/msgreply.c - store message and reply data.
3178479Sjb *
4178479Sjb * Copyright (c) 2007, NLnet Labs. All rights reserved.
5178479Sjb *
6178479Sjb * This software is open source.
7178479Sjb *
8178479Sjb * Redistribution and use in source and binary forms, with or without
9178479Sjb * modification, are permitted provided that the following conditions
10178479Sjb * are met:
11178479Sjb *
12178479Sjb * Redistributions of source code must retain the above copyright notice,
13178479Sjb * this list of conditions and the following disclaimer.
14178479Sjb *
15178479Sjb * Redistributions in binary form must reproduce the above copyright notice,
16178479Sjb * this list of conditions and the following disclaimer in the documentation
17178479Sjb * and/or other materials provided with the distribution.
18178479Sjb *
19178479Sjb * Neither the name of the NLNET LABS nor the names of its contributors may
20178479Sjb * be used to endorse or promote products derived from this software without
21178479Sjb * specific prior written permission.
22178479Sjb *
23210767Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24237624Spfg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25253725Spfg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26178479Sjb * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27178479Sjb * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28178552Sjb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29178479Sjb * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30178552Sjb * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31178552Sjb * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32178552Sjb * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33178552Sjb * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34178479Sjb */
35178479Sjb
36178552Sjb/**
37178479Sjb * \file
38178552Sjb *
39178479Sjb * This file contains a data structure to store a message and its reply.
40178479Sjb */
41178479Sjb
42178479Sjb#include "config.h"
43210767Srpaulo#include "util/data/msgreply.h"
44210767Srpaulo#include "util/storage/lookup3.h"
45210767Srpaulo#include "util/log.h"
46210767Srpaulo#include "util/alloc.h"
47210767Srpaulo#include "util/netevent.h"
48178479Sjb#include "util/net_help.h"
49178479Sjb#include "util/data/dname.h"
50178479Sjb#include "util/regional.h"
51178479Sjb#include "util/data/msgparse.h"
52178479Sjb#include "util/data/msgencode.h"
53178479Sjb#include "sldns/sbuffer.h"
54178479Sjb#include "sldns/wire2str.h"
55178479Sjb#include "util/module.h"
56178479Sjb#include "util/fptr_wlist.h"
57178479Sjb
58178479Sjb/** MAX TTL default for messages and rrsets */
59178479Sjbtime_t MAX_TTL = 3600 * 24 * 10; /* ten days */
60178479Sjb/** MIN TTL default for messages and rrsets */
61178479Sjbtime_t MIN_TTL = 0;
62178479Sjb/** MAX Negative TTL, for SOA records in authority section */
63178479Sjbtime_t MAX_NEG_TTL = 3600; /* one hour */
64178479Sjb/** If we serve expired entries and prefetch them */
65178479Sjbint SERVE_EXPIRED = 0;
66178479Sjb/** Time to serve records after expiration */
67178479Sjbtime_t SERVE_EXPIRED_TTL = 0;
68178479Sjb/** TTL to use for expired records */
69178479Sjbtime_t SERVE_EXPIRED_REPLY_TTL = 30;
70178479Sjb/** If we serve the original TTL or decrementing TTLs */
71178479Sjbint SERVE_ORIGINAL_TTL = 0;
72178479Sjb
73178479Sjb/** allocate qinfo, return 0 on error */
74178479Sjbstatic int
75178479Sjbparse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
76178479Sjb	struct query_info* qinf, struct regional* region)
77178479Sjb{
78178479Sjb	if(msg->qname) {
79178479Sjb		if(region)
80178479Sjb			qinf->qname = (uint8_t*)regional_alloc(region,
81178479Sjb				msg->qname_len);
82178479Sjb		else	qinf->qname = (uint8_t*)malloc(msg->qname_len);
83178479Sjb		if(!qinf->qname) return 0;
84178479Sjb		dname_pkt_copy(pkt, qinf->qname, msg->qname);
85178479Sjb	} else	qinf->qname = 0;
86178479Sjb	qinf->qname_len = msg->qname_len;
87178479Sjb	qinf->qtype = msg->qtype;
88178479Sjb	qinf->qclass = msg->qclass;
89178479Sjb	qinf->local_alias = NULL;
90178479Sjb	return 1;
91178479Sjb}
92178479Sjb
93178479Sjb/** constructor for replyinfo */
94178479Sjbstruct reply_info*
95178479Sjbconstruct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
96178479Sjb	time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
97178479Sjb	size_t ar, size_t total, enum sec_status sec, sldns_ede_code reason_bogus)
98178479Sjb{
99178479Sjb	struct reply_info* rep;
100178479Sjb	/* rrset_count-1 because the first ref is part of the struct. */
101178479Sjb	size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
102178479Sjb		sizeof(struct ub_packed_rrset_key*) * total;
103178479Sjb	if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/
104178479Sjb	if(region)
105178479Sjb		rep = (struct reply_info*)regional_alloc(region, s);
106178479Sjb	else	rep = (struct reply_info*)malloc(s +
107178479Sjb			sizeof(struct rrset_ref) * (total));
108178479Sjb	if(!rep)
109178479Sjb		return NULL;
110178479Sjb	rep->flags = flags;
111178479Sjb	rep->qdcount = qd;
112178479Sjb	rep->ttl = ttl;
113178479Sjb	rep->prefetch_ttl = prettl;
114178479Sjb	rep->serve_expired_ttl = expttl;
115178479Sjb	rep->an_numrrsets = an;
116178479Sjb	rep->ns_numrrsets = ns;
117178479Sjb	rep->ar_numrrsets = ar;
118178479Sjb	rep->rrset_count = total;
119178479Sjb	rep->security = sec;
120178479Sjb	rep->reason_bogus = reason_bogus;
121178479Sjb	/* this is only allocated and used for caching on copy */
122178479Sjb	rep->reason_bogus_str = NULL;
123178479Sjb	rep->authoritative = 0;
124178479Sjb	/* array starts after the refs */
125178479Sjb	if(region)
126178479Sjb		rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]);
127178479Sjb	else	rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]);
128178479Sjb	/* zero the arrays to assist cleanup in case of malloc failure */
129178479Sjb	memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total);
130178479Sjb	if(!region)
131178479Sjb		memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total);
132178479Sjb	return rep;
133178479Sjb}
134178479Sjb
135178479Sjb/** allocate replyinfo, return 0 on error */
136178479Sjbstatic int
137178479Sjbparse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
138178479Sjb	struct regional* region)
139178479Sjb{
140178479Sjb	*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
141178479Sjb		0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
142178479Sjb		msg->rrset_count, sec_status_unchecked, LDNS_EDE_NONE);
143178479Sjb	if(!*rep)
144178479Sjb		return 0;
145178479Sjb	return 1;
146178479Sjb}
147178479Sjb
148178479Sjbint
149178479Sjbreply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
150178479Sjb	struct regional* region)
151178479Sjb{
152178479Sjb	size_t i;
153178479Sjb	for(i=0; i<rep->rrset_count; i++) {
154178479Sjb		if(region) {
155178479Sjb			rep->rrsets[i] = (struct ub_packed_rrset_key*)
156178479Sjb				regional_alloc(region,
157178479Sjb				sizeof(struct ub_packed_rrset_key));
158178479Sjb			if(rep->rrsets[i]) {
159178479Sjb				memset(rep->rrsets[i], 0,
160178479Sjb					sizeof(struct ub_packed_rrset_key));
161178479Sjb				rep->rrsets[i]->entry.key = rep->rrsets[i];
162178479Sjb			}
163178479Sjb		}
164178479Sjb		else	rep->rrsets[i] = alloc_special_obtain(alloc);
165253725Spfg		if(!rep->rrsets[i])
166178479Sjb			return 0;
167178479Sjb		rep->rrsets[i]->entry.data = NULL;
168178479Sjb	}
169178479Sjb	return 1;
170178479Sjb}
171178479Sjb
172178479Sjbstruct reply_info *
173178479Sjbmake_new_reply_info(const struct reply_info* rep, struct regional* region,
174178479Sjb	size_t an_numrrsets, size_t copy_rrsets)
175178479Sjb{
176178479Sjb	struct reply_info* new_rep;
177178479Sjb	size_t i;
178178479Sjb
179178479Sjb	/* create a base struct.  we specify 'insecure' security status as
180178479Sjb	 * the modified response won't be DNSSEC-valid.  In our faked response
181178479Sjb	 * the authority and additional sections will be empty (except possible
182178479Sjb	 * EDNS0 OPT RR in the additional section appended on sending it out),
183178479Sjb	 * so the total number of RRsets is an_numrrsets. */
184178479Sjb	new_rep = construct_reply_info_base(region, rep->flags,
185178479Sjb		rep->qdcount, rep->ttl, rep->prefetch_ttl,
186178479Sjb		rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
187178479Sjb		sec_status_insecure, LDNS_EDE_NONE);
188178479Sjb	if(!new_rep)
189178479Sjb		return NULL;
190178479Sjb	if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
191178479Sjb		return NULL;
192178479Sjb	for(i=0; i<copy_rrsets; i++)
193178479Sjb		new_rep->rrsets[i] = rep->rrsets[i];
194178479Sjb
195178479Sjb	return new_rep;
196178479Sjb}
197178479Sjb
198178479Sjb/** find the minimumttl in the rdata of SOA record */
199178479Sjbstatic time_t
200178479Sjbsoa_find_minttl(struct rr_parse* rr)
201178479Sjb{
202178479Sjb	uint16_t rlen = sldns_read_uint16(rr->ttl_data+4);
203178479Sjb	if(rlen < 20)
204178479Sjb		return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
205178479Sjb	/* minimum TTL is the last 32bit value in the rdata of the record */
206178479Sjb	/* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
207178479Sjb	return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4);
208178479Sjb}
209178479Sjb
210178479Sjb/** do the rdata copy */
211178479Sjbstatic int
212178479Sjbrdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
213178479Sjb	struct rr_parse* rr, time_t* rr_ttl, uint16_t type,
214178479Sjb	sldns_pkt_section section)
215178479Sjb{
216178479Sjb	uint16_t pkt_len;
217178479Sjb	const sldns_rr_descriptor* desc;
218178479Sjb
219178479Sjb	*rr_ttl = sldns_read_uint32(rr->ttl_data);
220178479Sjb	/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
221178479Sjb	if(*rr_ttl & 0x80000000U)
222178479Sjb		*rr_ttl = 0;
223178479Sjb	if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
224178479Sjb		/* negative response. see if TTL of SOA record larger than the
225178479Sjb		 * minimum-ttl in the rdata of the SOA record */
226178479Sjb		if(*rr_ttl > soa_find_minttl(rr))
227178479Sjb			*rr_ttl = soa_find_minttl(rr);
228178479Sjb	}
229178479Sjb	if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
230178479Sjb		*rr_ttl = MIN_TTL;
231178479Sjb	if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
232178479Sjb		*rr_ttl = MAX_TTL;
233178479Sjb	if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
234178479Sjb		/* max neg ttl overrides the min and max ttl of everything
235178479Sjb		 * else, it is for a more specific record */
236178479Sjb		if(*rr_ttl > MAX_NEG_TTL)
237178479Sjb			*rr_ttl = MAX_NEG_TTL;
238178479Sjb	}
239178479Sjb	if(*rr_ttl < data->ttl)
240178479Sjb		data->ttl = *rr_ttl;
241178479Sjb
242178479Sjb	if(rr->outside_packet) {
243178479Sjb		/* uncompressed already, only needs copy */
244178479Sjb		memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
245178479Sjb		return 1;
246178479Sjb	}
247178479Sjb
248178479Sjb	sldns_buffer_set_position(pkt, (size_t)
249178479Sjb		(rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
250178479Sjb	/* insert decompressed size into rdata len stored in memory */
251178479Sjb	/* -2 because rdatalen bytes are not included. */
252178479Sjb	pkt_len = htons(rr->size - 2);
253178479Sjb	memmove(to, &pkt_len, sizeof(uint16_t));
254178479Sjb	to += 2;
255178479Sjb	/* read packet rdata len */
256178479Sjb	pkt_len = sldns_buffer_read_u16(pkt);
257178479Sjb	if(sldns_buffer_remaining(pkt) < pkt_len)
258178479Sjb		return 0;
259178479Sjb	desc = sldns_rr_descript(type);
260178479Sjb	if(pkt_len > 0 && desc && desc->_dname_count > 0) {
261178479Sjb		int count = (int)desc->_dname_count;
262178479Sjb		int rdf = 0;
263178479Sjb		size_t len;
264178479Sjb		size_t oldpos;
265178479Sjb		/* decompress dnames. */
266178479Sjb		while(pkt_len > 0 && count) {
267178479Sjb			switch(desc->_wireformat[rdf]) {
268178479Sjb			case LDNS_RDF_TYPE_DNAME:
269178479Sjb				oldpos = sldns_buffer_position(pkt);
270178479Sjb				dname_pkt_copy(pkt, to,
271178479Sjb					sldns_buffer_current(pkt));
272178479Sjb				to += pkt_dname_len(pkt);
273178479Sjb				pkt_len -= sldns_buffer_position(pkt)-oldpos;
274178479Sjb				count--;
275178479Sjb				len = 0;
276178479Sjb				break;
277178479Sjb			case LDNS_RDF_TYPE_STR:
278178479Sjb				len = sldns_buffer_current(pkt)[0] + 1;
279178479Sjb				break;
280178479Sjb			default:
281178479Sjb				len = get_rdf_size(desc->_wireformat[rdf]);
282178479Sjb				break;
283178479Sjb			}
284178479Sjb			if(len) {
285178479Sjb				log_assert(len <= pkt_len);
286178479Sjb				memmove(to, sldns_buffer_current(pkt), len);
287178479Sjb				to += len;
288178479Sjb				sldns_buffer_skip(pkt, (ssize_t)len);
289178479Sjb				pkt_len -= len;
290178479Sjb			}
291178479Sjb			rdf++;
292178479Sjb		}
293178479Sjb	}
294178479Sjb	/* copy remaining rdata */
295178479Sjb	if(pkt_len >  0)
296178479Sjb		memmove(to, sldns_buffer_current(pkt), pkt_len);
297178479Sjb
298178479Sjb	return 1;
299178479Sjb}
300178479Sjb
301178479Sjb/** copy over the data into packed rrset */
302178479Sjbstatic int
303178479Sjbparse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset,
304178479Sjb	struct packed_rrset_data* data)
305178479Sjb{
306178479Sjb	size_t i;
307178479Sjb	struct rr_parse* rr = pset->rr_first;
308178479Sjb	uint8_t* nextrdata;
309178479Sjb	size_t total = pset->rr_count + pset->rrsig_count;
310178479Sjb	data->ttl = MAX_TTL;
311178479Sjb	data->count = pset->rr_count;
312178479Sjb	data->rrsig_count = pset->rrsig_count;
313183153Simp	data->trust = rrset_trust_none;
314178479Sjb	data->security = sec_status_unchecked;
315178479Sjb	/* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */
316178479Sjb	data->rr_len = (size_t*)((uint8_t*)data +
317178552Sjb		sizeof(struct packed_rrset_data));
318178479Sjb	data->rr_data = (uint8_t**)&(data->rr_len[total]);
319178479Sjb	data->rr_ttl = (time_t*)&(data->rr_data[total]);
320178479Sjb	nextrdata = (uint8_t*)&(data->rr_ttl[total]);
321178479Sjb	for(i=0; i<data->count; i++) {
322178479Sjb		data->rr_len[i] = rr->size;
323178479Sjb		data->rr_data[i] = nextrdata;
324178479Sjb		nextrdata += rr->size;
325178479Sjb		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
326178479Sjb			&data->rr_ttl[i], pset->type, pset->section))
327178479Sjb			return 0;
328178479Sjb		rr = rr->next;
329178479Sjb	}
330178479Sjb	/* if rrsig, its rdata is at nextrdata */
331178479Sjb	rr = pset->rrsig_first;
332178479Sjb	for(i=data->count; i<total; i++) {
333178479Sjb		data->rr_len[i] = rr->size;
334178479Sjb		data->rr_data[i] = nextrdata;
335178479Sjb		nextrdata += rr->size;
336178479Sjb		if(!rdata_copy(pkt, data, data->rr_data[i], rr,
337178479Sjb			&data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section))
338178479Sjb			return 0;
339178479Sjb		rr = rr->next;
340178479Sjb	}
341178479Sjb	return 1;
342178479Sjb}
343178479Sjb
344178479Sjb/** create rrset return 0 on failure */
345178479Sjbstatic int
346210767Srpauloparse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset,
347178479Sjb	struct packed_rrset_data** data, struct regional* region)
348178479Sjb{
349178479Sjb	/* allocate */
350178479Sjb	size_t s;
351178479Sjb	if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX ||
352178479Sjb		pset->size > RR_COUNT_MAX)
353178479Sjb		return 0; /* protect against integer overflow */
354178479Sjb	s = sizeof(struct packed_rrset_data) +
355178479Sjb		(pset->rr_count + pset->rrsig_count) *
356178479Sjb		(sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) +
357178479Sjb		pset->size;
358178479Sjb	if(region)
359178479Sjb		*data = regional_alloc_zero(region, s);
360178479Sjb	else	*data = calloc(1, s);
361178479Sjb	if(!*data)
362178479Sjb		return 0;
363178479Sjb	/* copy & decompress */
364178479Sjb	if(!parse_rr_copy(pkt, pset, *data)) {
365178479Sjb		if(!region) {
366178479Sjb			free(*data);
367178479Sjb			*data = NULL;
368178479Sjb		}
369178479Sjb		return 0;
370178479Sjb	}
371178479Sjb	return 1;
372178479Sjb}
373178479Sjb
374178479Sjb/** get trust value for rrset */
375178479Sjbstatic enum rrset_trust
376178479Sjbget_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset)
377178479Sjb{
378178479Sjb	uint16_t AA = msg->flags & BIT_AA;
379178479Sjb	if(rrset->section == LDNS_SECTION_ANSWER) {
380178479Sjb		if(AA) {
381178479Sjb			/* RFC2181 says remainder of CNAME chain is nonauth*/
382178479Sjb			if(msg->rrset_first &&
383178479Sjb				msg->rrset_first->section==LDNS_SECTION_ANSWER
384178479Sjb				&& msg->rrset_first->type==LDNS_RR_TYPE_CNAME){
385178479Sjb				if(rrset == msg->rrset_first)
386178479Sjb					return rrset_trust_ans_AA;
387178479Sjb				else 	return rrset_trust_ans_noAA;
388178479Sjb			}
389178479Sjb			if(msg->rrset_first &&
390178479Sjb				msg->rrset_first->section==LDNS_SECTION_ANSWER
391178479Sjb				&& msg->rrset_first->type==LDNS_RR_TYPE_DNAME){
392178479Sjb				if(rrset == msg->rrset_first ||
393178479Sjb				   rrset == msg->rrset_first->rrset_all_next)
394178479Sjb					return rrset_trust_ans_AA;
395178479Sjb				else 	return rrset_trust_ans_noAA;
396178479Sjb			}
397178479Sjb			return rrset_trust_ans_AA;
398178479Sjb		}
399210767Srpaulo		else	return rrset_trust_ans_noAA;
400178479Sjb	} else if(rrset->section == LDNS_SECTION_AUTHORITY) {
401178479Sjb		if(AA)	return rrset_trust_auth_AA;
402178479Sjb		else	return rrset_trust_auth_noAA;
403178479Sjb	} else {
404178479Sjb		/* addit section */
405178479Sjb		if(AA)	return rrset_trust_add_AA;
406178479Sjb		else	return rrset_trust_add_noAA;
407178479Sjb	}
408178479Sjb	/* NOTREACHED */
409178479Sjb	return rrset_trust_none;
410178479Sjb}
411178479Sjb
412178479Sjbint
413178479Sjbparse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg,
414178479Sjb	struct rrset_parse *pset, struct regional* region,
415178479Sjb	struct ub_packed_rrset_key* pk)
416178479Sjb{
417178479Sjb	struct packed_rrset_data* data;
418178479Sjb	pk->rk.flags = pset->flags;
419178479Sjb	pk->rk.dname_len = pset->dname_len;
420178479Sjb	if(region)
421178479Sjb		pk->rk.dname = (uint8_t*)regional_alloc(
422178479Sjb			region, pset->dname_len);
423178479Sjb	else	pk->rk.dname =
424178479Sjb			(uint8_t*)malloc(pset->dname_len);
425178479Sjb	if(!pk->rk.dname)
426178479Sjb		return 0;
427178479Sjb	/** copy & decompress dname */
428178479Sjb	dname_pkt_copy(pkt, pk->rk.dname, pset->dname);
429178479Sjb	/** copy over type and class */
430178479Sjb	pk->rk.type = htons(pset->type);
431178479Sjb	pk->rk.rrset_class = pset->rrset_class;
432178479Sjb	/** read data part. */
433178479Sjb	if(!parse_create_rrset(pkt, pset, &data, region)) {
434178479Sjb		if(!region) {
435178479Sjb			free(pk->rk.dname);
436178479Sjb			pk->rk.dname = NULL;
437178479Sjb		}
438178479Sjb		return 0;
439178479Sjb	}
440178479Sjb	pk->entry.data = (void*)data;
441178479Sjb	pk->entry.key = (void*)pk;
442178479Sjb	pk->entry.hash = pset->hash;
443178479Sjb	data->trust = get_rrset_trust(msg, pset);
444178479Sjb	return 1;
445178479Sjb}
446178479Sjb
447178479Sjb/**
448178479Sjb * Copy and decompress rrs
449178479Sjb * @param pkt: the packet for compression pointer resolution.
450178479Sjb * @param msg: the parsed message
451178479Sjb * @param rep: reply info to put rrs into.
452178479Sjb * @param region: if not NULL, used for allocation.
453178479Sjb * @return 0 on failure.
454178479Sjb */
455178479Sjbstatic int
456178479Sjbparse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg,
457178479Sjb	struct reply_info* rep, struct regional* region)
458178479Sjb{
459178479Sjb	size_t i;
460178479Sjb	struct rrset_parse *pset = msg->rrset_first;
461178479Sjb	struct packed_rrset_data* data;
462178479Sjb	log_assert(rep);
463178479Sjb	rep->ttl = MAX_TTL;
464178479Sjb	rep->security = sec_status_unchecked;
465178479Sjb	if(rep->rrset_count == 0)
466178479Sjb		rep->ttl = NORR_TTL;
467178479Sjb
468178479Sjb	for(i=0; i<rep->rrset_count; i++) {
469178479Sjb		if(!parse_copy_decompress_rrset(pkt, msg, pset, region,
470178552Sjb			rep->rrsets[i]))
471178479Sjb			return 0;
472178552Sjb		data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
473178552Sjb		if(data->ttl < rep->ttl)
474178552Sjb			rep->ttl = data->ttl;
475178479Sjb
476178479Sjb		pset = pset->rrset_all_next;
477178479Sjb	}
478178479Sjb	rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
479178479Sjb	rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
480178479Sjb	return 1;
481178479Sjb}
482178479Sjb
483178479Sjbint
484178479Sjbparse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
485178479Sjb	struct alloc_cache* alloc, struct query_info* qinf,
486178479Sjb	struct reply_info** rep, struct regional* region)
487178479Sjb{
488178479Sjb	log_assert(pkt && msg);
489178479Sjb	if(!parse_create_qinfo(pkt, msg, qinf, region))
490178479Sjb		return 0;
491178479Sjb	if(!parse_create_repinfo(msg, rep, region))
492178479Sjb		return 0;
493178479Sjb	if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) {
494178479Sjb		if(!region) reply_info_parsedelete(*rep, alloc);
495178479Sjb		return 0;
496178479Sjb	}
497178479Sjb	if(!parse_copy_decompress(pkt, msg, *rep, region)) {
498178479Sjb		if(!region) reply_info_parsedelete(*rep, alloc);
499178479Sjb		return 0;
500178479Sjb	}
501178479Sjb	return 1;
502178479Sjb}
503178479Sjb
504178479Sjbint reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
505178479Sjb        struct query_info* qinf, struct reply_info** rep,
506178479Sjb	struct regional* region, struct edns_data* edns)
507178479Sjb{
508178479Sjb	/* use scratch pad region-allocator during parsing. */
509178479Sjb	struct msg_parse* msg;
510178479Sjb	int ret;
511178479Sjb
512178479Sjb	qinf->qname = NULL;
513178479Sjb	qinf->local_alias = NULL;
514210767Srpaulo	*rep = NULL;
515210767Srpaulo	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
516210767Srpaulo		return LDNS_RCODE_SERVFAIL;
517210767Srpaulo	}
518210767Srpaulo	memset(msg, 0, sizeof(*msg));
519210767Srpaulo
520210767Srpaulo	sldns_buffer_set_position(pkt, 0);
521210767Srpaulo	if((ret = parse_packet(pkt, msg, region)) != 0) {
522210767Srpaulo		return ret;
523210767Srpaulo	}
524210767Srpaulo	if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0)
525210767Srpaulo		return ret;
526210767Srpaulo
527210767Srpaulo	/* parse OK, allocate return structures */
528210767Srpaulo	/* this also performs dname decompression */
529210767Srpaulo	if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
530210767Srpaulo		query_info_clear(qinf);
531210767Srpaulo		*rep = NULL;
532210767Srpaulo		return LDNS_RCODE_SERVFAIL;
533210767Srpaulo	}
534210767Srpaulo	return 0;
535210767Srpaulo}
536210767Srpaulo
537210767Srpaulo/** helper compare function to sort in lock order */
538210767Srpaulostatic int
539210767Srpauloreply_info_sortref_cmp(const void* a, const void* b)
540210767Srpaulo{
541210767Srpaulo	struct rrset_ref* x = (struct rrset_ref*)a;
542210767Srpaulo	struct rrset_ref* y = (struct rrset_ref*)b;
543210767Srpaulo	if(x->key < y->key) return -1;
544210767Srpaulo	if(x->key > y->key) return 1;
545210767Srpaulo	return 0;
546210767Srpaulo}
547210767Srpaulo
548210767Srpaulovoid
549210767Srpauloreply_info_sortref(struct reply_info* rep)
550210767Srpaulo{
551210767Srpaulo	qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
552210767Srpaulo		reply_info_sortref_cmp);
553210767Srpaulo}
554210767Srpaulo
555210767Srpaulovoid
556210767Srpauloreply_info_set_ttls(struct reply_info* rep, time_t timenow)
557210767Srpaulo{
558210767Srpaulo	size_t i, j;
559210767Srpaulo	rep->ttl += timenow;
560210767Srpaulo	rep->prefetch_ttl += timenow;
561210767Srpaulo	rep->serve_expired_ttl += timenow;
562210767Srpaulo	for(i=0; i<rep->rrset_count; i++) {
563210767Srpaulo		struct packed_rrset_data* data = (struct packed_rrset_data*)
564210767Srpaulo			rep->ref[i].key->entry.data;
565210767Srpaulo		if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
566178479Sjb			continue;
567178479Sjb		data->ttl += timenow;
568178479Sjb		for(j=0; j<data->count + data->rrsig_count; j++) {
569178479Sjb			data->rr_ttl[j] += timenow;
570178479Sjb		}
571178479Sjb		data->ttl_add = timenow;
572178479Sjb	}
573178479Sjb}
574178479Sjb
575178479Sjbvoid
576178479Sjbreply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
577178479Sjb{
578178479Sjb	size_t i;
579178479Sjb	if(!rep)
580178479Sjb		return;
581178479Sjb	/* no need to lock, since not shared in hashtables. */
582178479Sjb	for(i=0; i<rep->rrset_count; i++) {
583178479Sjb		ub_packed_rrset_parsedelete(rep->rrsets[i], alloc);
584178479Sjb	}
585178479Sjb	if(rep->reason_bogus_str) {
586178479Sjb		free(rep->reason_bogus_str);
587178479Sjb		rep->reason_bogus_str = NULL;
588178479Sjb	}
589178479Sjb	free(rep);
590178479Sjb}
591178479Sjb
592178479Sjbint
593178479Sjbquery_info_parse(struct query_info* m, sldns_buffer* query)
594178479Sjb{
595178479Sjb	uint8_t* q = sldns_buffer_begin(query);
596178479Sjb	/* minimum size: header + \0 + qtype + qclass */
597178479Sjb	if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
598178479Sjb		return 0;
599178479Sjb	if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) !=
600178479Sjb		LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 ||
601178479Sjb		sldns_buffer_position(query) != 0)
602178479Sjb		return 0;
603178479Sjb	sldns_buffer_skip(query, LDNS_HEADER_SIZE);
604178479Sjb	m->qname = sldns_buffer_current(query);
605178479Sjb	if((m->qname_len = query_dname_len(query)) == 0)
606178479Sjb		return 0; /* parse error */
607178479Sjb	if(sldns_buffer_remaining(query) < 4)
608178479Sjb		return 0; /* need qtype, qclass */
609178479Sjb	m->qtype = sldns_buffer_read_u16(query);
610178479Sjb	m->qclass = sldns_buffer_read_u16(query);
611178479Sjb	m->local_alias = NULL;
612178479Sjb	return 1;
613178479Sjb}
614178479Sjb
615178479Sjb/** tiny subroutine for msgreply_compare */
616178479Sjb#define COMPARE_IT(x, y) \
617178479Sjb	if( (x) < (y) ) return -1; \
618178479Sjb	else if( (x) > (y) ) return +1; \
619178479Sjb	log_assert( (x) == (y) );
620178479Sjb
621178479Sjbint
622178479Sjbquery_info_compare(void* m1, void* m2)
623178479Sjb{
624178479Sjb	struct query_info* msg1 = (struct query_info*)m1;
625178479Sjb	struct query_info* msg2 = (struct query_info*)m2;
626178479Sjb	int mc;
627178479Sjb	/* from most different to least different for speed */
628178479Sjb	COMPARE_IT(msg1->qtype, msg2->qtype);
629178479Sjb	if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0)
630178479Sjb		return mc;
631178479Sjb	log_assert(msg1->qname_len == msg2->qname_len);
632178479Sjb	COMPARE_IT(msg1->qclass, msg2->qclass);
633178479Sjb	return 0;
634178479Sjb#undef COMPARE_IT
635178479Sjb}
636178479Sjb
637178479Sjbvoid
638178479Sjbquery_info_clear(struct query_info* m)
639178479Sjb{
640178479Sjb	free(m->qname);
641178479Sjb	m->qname = NULL;
642178479Sjb}
643178479Sjb
644178479Sjbsize_t
645178479Sjbmsgreply_sizefunc(void* k, void* d)
646178479Sjb{
647178479Sjb	struct msgreply_entry* q = (struct msgreply_entry*)k;
648178479Sjb	struct reply_info* r = (struct reply_info*)d;
649178479Sjb	size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info)
650178479Sjb		+ q->key.qname_len + lock_get_mem(&q->entry.lock)
651178479Sjb		- sizeof(struct rrset_ref);
652178479Sjb	s += r->rrset_count * sizeof(struct rrset_ref);
653178479Sjb	s += r->rrset_count * sizeof(struct ub_packed_rrset_key*);
654178479Sjb	return s;
655178479Sjb}
656178479Sjb
657178479Sjbvoid
658178479Sjbquery_entry_delete(void *k, void* ATTR_UNUSED(arg))
659178479Sjb{
660178479Sjb	struct msgreply_entry* q = (struct msgreply_entry*)k;
661178479Sjb	lock_rw_destroy(&q->entry.lock);
662178479Sjb	query_info_clear(&q->key);
663178479Sjb	free(q);
664178479Sjb}
665178479Sjb
666178479Sjbvoid
667178479Sjbreply_info_delete(void* d, void* ATTR_UNUSED(arg))
668253725Spfg{
669210767Srpaulo	struct reply_info* r = (struct reply_info*)d;
670178479Sjb	if(r->reason_bogus_str) {
671178479Sjb		free(r->reason_bogus_str);
672178479Sjb		r->reason_bogus_str = NULL;
673178479Sjb	}
674178479Sjb	free(r);
675178479Sjb}
676178479Sjb
677178479Sjbhashvalue_type
678178479Sjbquery_info_hash(struct query_info *q, uint16_t flags)
679178479Sjb{
680178479Sjb	hashvalue_type h = 0xab;
681178479Sjb	h = hashlittle(&q->qtype, sizeof(q->qtype), h);
682178479Sjb	if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD))
683178479Sjb		h++;
684178479Sjb	h = hashlittle(&q->qclass, sizeof(q->qclass), h);
685178479Sjb	h = dname_query_hash(q->qname, h);
686178479Sjb	return h;
687178479Sjb}
688178479Sjb
689178479Sjbstruct msgreply_entry*
690178479Sjbquery_info_entrysetup(struct query_info* q, struct reply_info* r,
691178479Sjb	hashvalue_type h)
692210767Srpaulo{
693178479Sjb	struct msgreply_entry* e = (struct msgreply_entry*)malloc(
694178479Sjb		sizeof(struct msgreply_entry));
695178479Sjb	if(!e) return NULL;
696178479Sjb	memcpy(&e->key, q, sizeof(*q));
697178479Sjb	e->entry.hash = h;
698178479Sjb	e->entry.key = e;
699178479Sjb	e->entry.data = r;
700178479Sjb	lock_rw_init(&e->entry.lock);
701178479Sjb	lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname));
702178479Sjb	lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len));
703178479Sjb	lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype));
704178479Sjb	lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass));
705178479Sjb	lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias));
706178479Sjb	lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash));
707178479Sjb	lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key));
708178479Sjb	lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data));
709178479Sjb	lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
710178479Sjb	q->qname = NULL;
711178479Sjb	return e;
712178479Sjb}
713178479Sjb
714178479Sjb/** copy rrsets from replyinfo to dest replyinfo */
715178479Sjbstatic int
716178479Sjbrepinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from,
717178479Sjb	struct regional* region)
718178479Sjb{
719178479Sjb	size_t i, s;
720178479Sjb	struct packed_rrset_data* fd, *dd;
721178479Sjb	struct ub_packed_rrset_key* fk, *dk;
722178479Sjb	for(i=0; i<dest->rrset_count; i++) {
723178479Sjb		fk = from->rrsets[i];
724178479Sjb		dk = dest->rrsets[i];
725178479Sjb		fd = (struct packed_rrset_data*)fk->entry.data;
726178479Sjb		dk->entry.hash = fk->entry.hash;
727178479Sjb		dk->rk = fk->rk;
728178479Sjb		if(region) {
729178479Sjb			dk->id = fk->id;
730178479Sjb			dk->rk.dname = (uint8_t*)regional_alloc_init(region,
731178479Sjb				fk->rk.dname, fk->rk.dname_len);
732178479Sjb		} else
733178479Sjb			dk->rk.dname = (uint8_t*)memdup(fk->rk.dname,
734178479Sjb				fk->rk.dname_len);
735178479Sjb		if(!dk->rk.dname)
736178479Sjb			return 0;
737178479Sjb		s = packed_rrset_sizeof(fd);
738178479Sjb		if(region)
739178479Sjb			dd = (struct packed_rrset_data*)regional_alloc_init(
740178479Sjb				region, fd, s);
741178479Sjb		else	dd = (struct packed_rrset_data*)memdup(fd, s);
742178479Sjb		if(!dd)
743178479Sjb			return 0;
744178479Sjb		packed_rrset_ptr_fixup(dd);
745178479Sjb		dk->entry.data = (void*)dd;
746178479Sjb	}
747178479Sjb	return 1;
748178479Sjb}
749178479Sjb
750178479Sjbstruct reply_info*
751178479Sjbreply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
752178479Sjb	struct regional* region)
753178479Sjb{
754178479Sjb	struct reply_info* cp;
755178479Sjb	cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
756178479Sjb		rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl,
757178479Sjb		rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
758178479Sjb		rep->rrset_count, rep->security, rep->reason_bogus);
759178479Sjb	if(!cp)
760178479Sjb		return NULL;
761178479Sjb
762178479Sjb	if(rep->reason_bogus_str && *rep->reason_bogus_str != 0) {
763178479Sjb		if(region) {
764178479Sjb			cp->reason_bogus_str = (char*)regional_alloc(region,
765178479Sjb				sizeof(char)
766178479Sjb				* (strlen(rep->reason_bogus_str)+1));
767178479Sjb		} else {
768178479Sjb			cp->reason_bogus_str = malloc(sizeof(char)
769178479Sjb				* (strlen(rep->reason_bogus_str)+1));
770178479Sjb		}
771178479Sjb		if(!cp->reason_bogus_str) {
772178479Sjb			if(!region)
773178479Sjb				reply_info_parsedelete(cp, alloc);
774178479Sjb			return NULL;
775178479Sjb		}
776178479Sjb		memcpy(cp->reason_bogus_str, rep->reason_bogus_str,
777178479Sjb			strlen(rep->reason_bogus_str)+1);
778178479Sjb	}
779178479Sjb
780178479Sjb	/* allocate ub_key structures special or not */
781178479Sjb	if(!reply_info_alloc_rrset_keys(cp, alloc, region)) {
782178479Sjb		if(!region)
783178479Sjb			reply_info_parsedelete(cp, alloc);
784178479Sjb		return NULL;
785178479Sjb	}
786178479Sjb	if(!repinfo_copy_rrsets(cp, rep, region)) {
787178479Sjb		if(!region)
788178479Sjb			reply_info_parsedelete(cp, alloc);
789178479Sjb		return NULL;
790178479Sjb	}
791178479Sjb	return cp;
792178479Sjb}
793178479Sjb
794178479Sjbuint8_t*
795178479Sjbreply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
796178479Sjb{
797178479Sjb	uint8_t* sname = qinfo->qname;
798178479Sjb	size_t snamelen = qinfo->qname_len;
799178479Sjb	size_t i;
800178479Sjb	for(i=0; i<rep->an_numrrsets; i++) {
801178479Sjb		struct ub_packed_rrset_key* s = rep->rrsets[i];
802178479Sjb		/* follow CNAME chain (if any) */
803178479Sjb		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
804178479Sjb			ntohs(s->rk.rrset_class) == qinfo->qclass &&
805178479Sjb			snamelen == s->rk.dname_len &&
806178479Sjb			query_dname_compare(sname, s->rk.dname) == 0) {
807178479Sjb			get_cname_target(s, &sname, &snamelen);
808178479Sjb		}
809178479Sjb	}
810178479Sjb	if(sname != qinfo->qname)
811178479Sjb		return sname;
812178479Sjb	return NULL;
813178479Sjb}
814178479Sjb
815178479Sjbstruct ub_packed_rrset_key*
816178479Sjbreply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
817178479Sjb{
818178479Sjb	uint8_t* sname = qinfo->qname;
819178479Sjb	size_t snamelen = qinfo->qname_len;
820178479Sjb	size_t i;
821178479Sjb	for(i=0; i<rep->an_numrrsets; i++) {
822178479Sjb		struct ub_packed_rrset_key* s = rep->rrsets[i];
823178479Sjb		/* first match type, for query of qtype cname */
824178479Sjb		if(ntohs(s->rk.type) == qinfo->qtype &&
825178479Sjb			ntohs(s->rk.rrset_class) == qinfo->qclass &&
826178479Sjb			snamelen == s->rk.dname_len &&
827178479Sjb			query_dname_compare(sname, s->rk.dname) == 0) {
828178479Sjb			return s;
829178479Sjb		}
830178479Sjb		/* follow CNAME chain (if any) */
831178479Sjb		if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
832178479Sjb			ntohs(s->rk.rrset_class) == qinfo->qclass &&
833178479Sjb			snamelen == s->rk.dname_len &&
834178479Sjb			query_dname_compare(sname, s->rk.dname) == 0) {
835178479Sjb			get_cname_target(s, &sname, &snamelen);
836178479Sjb		}
837178479Sjb	}
838178479Sjb	return NULL;
839178479Sjb}
840178479Sjb
841178479Sjbstruct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
842178479Sjb	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
843178479Sjb{
844178479Sjb	size_t i;
845178479Sjb	for(i=0; i<rep->an_numrrsets; i++) {
846178479Sjb		struct ub_packed_rrset_key* s = rep->rrsets[i];
847178479Sjb		if(ntohs(s->rk.type) == type &&
848178479Sjb			ntohs(s->rk.rrset_class) == dclass &&
849178479Sjb			namelen == s->rk.dname_len &&
850178479Sjb			query_dname_compare(name, s->rk.dname) == 0) {
851178479Sjb			return s;
852178479Sjb		}
853178479Sjb	}
854178479Sjb	return NULL;
855178479Sjb}
856178479Sjb
857178479Sjbstruct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
858178479Sjb	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
859178479Sjb{
860178479Sjb	size_t i;
861178479Sjb	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
862178479Sjb		struct ub_packed_rrset_key* s = rep->rrsets[i];
863178479Sjb		if(ntohs(s->rk.type) == type &&
864178479Sjb			ntohs(s->rk.rrset_class) == dclass &&
865178479Sjb			namelen == s->rk.dname_len &&
866178479Sjb			query_dname_compare(name, s->rk.dname) == 0) {
867178479Sjb			return s;
868178479Sjb		}
869178479Sjb	}
870178479Sjb	return NULL;
871178479Sjb}
872178479Sjb
873178479Sjbstruct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
874178479Sjb	uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
875178479Sjb{
876178479Sjb	size_t i;
877178479Sjb	for(i=0; i<rep->rrset_count; i++) {
878178479Sjb		struct ub_packed_rrset_key* s = rep->rrsets[i];
879178479Sjb		if(ntohs(s->rk.type) == type &&
880178479Sjb			ntohs(s->rk.rrset_class) == dclass &&
881178479Sjb			namelen == s->rk.dname_len &&
882178479Sjb			query_dname_compare(name, s->rk.dname) == 0) {
883178479Sjb			return s;
884178479Sjb		}
885178479Sjb	}
886178479Sjb	return NULL;
887178479Sjb}
888178479Sjb
889178479Sjbvoid
890178479Sjblog_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
891178479Sjb{
892178479Sjb	/* not particularly fast but flexible, make wireformat and print */
893178479Sjb	sldns_buffer* buf = sldns_buffer_new(65535);
894178479Sjb	struct regional* region = regional_create();
895178479Sjb	if(!(buf && region)) {
896178479Sjb		log_err("%s: log_dns_msg: out of memory", str);
897178479Sjb		sldns_buffer_free(buf);
898178479Sjb		regional_destroy(region);
899178479Sjb		return;
900178479Sjb	}
901178479Sjb	if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
902178479Sjb		region, 65535, 1, 0)) {
903178479Sjb		log_err("%s: log_dns_msg: out of memory", str);
904178479Sjb	} else {
905178479Sjb		char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf),
906178479Sjb			sldns_buffer_limit(buf));
907178479Sjb		if(!s) {
908178479Sjb			log_info("%s: log_dns_msg: ldns tostr failed", str);
909178479Sjb		} else {
910178479Sjb			log_info("%s %s", str, s);
911178479Sjb		}
912178479Sjb		free(s);
913178479Sjb	}
914178479Sjb	sldns_buffer_free(buf);
915178479Sjb	regional_destroy(region);
916178479Sjb}
917178479Sjb
918178479Sjbvoid
919178479Sjblog_reply_info(enum verbosity_value v, struct query_info *qinf,
920178479Sjb	struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur,
921178479Sjb	int cached, struct sldns_buffer *rmsg, struct sockaddr_storage* daddr,
922178479Sjb	enum comm_point_type tp)
923178479Sjb{
924178479Sjb	char qname_buf[LDNS_MAX_DOMAINLEN+1];
925178479Sjb	char clientip_buf[128];
926178479Sjb	char rcode_buf[16];
927178479Sjb	char type_buf[16];
928178479Sjb	char class_buf[16];
929178479Sjb	char dest_buf[160];
930178479Sjb	size_t pktlen;
931178479Sjb	uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2));
932178479Sjb
933178479Sjb	if(verbosity < v)
934178479Sjb	  return;
935178479Sjb
936178479Sjb	sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf));
937178479Sjb	addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf));
938178479Sjb	if(daddr) {
939178479Sjb		char da[128];
940178479Sjb		int port = 0;
941178479Sjb		char* comm;
942178479Sjb		if(daddr->ss_family == AF_INET6) {
943178479Sjb			struct sockaddr_in6 *d = (struct sockaddr_in6 *)daddr;
944178479Sjb			if(inet_ntop(d->sin6_family, &d->sin6_addr, da,
945178479Sjb				sizeof(*d)) == 0)
946178479Sjb				snprintf(dest_buf, sizeof(dest_buf),
947178479Sjb					"(inet_ntop_error)");
948178479Sjb			port = ntohs(d->sin6_port);
949178479Sjb		} else if(daddr->ss_family == AF_INET) {
950178479Sjb			struct sockaddr_in *d = (struct sockaddr_in *)daddr;
951178479Sjb			if(inet_ntop(d->sin_family, &d->sin_addr, da,
952178479Sjb				sizeof(*d)) == 0)
953178479Sjb				snprintf(dest_buf, sizeof(dest_buf),
954178479Sjb					"(inet_ntop_error)");
955178479Sjb			port = ntohs(d->sin_port);
956178479Sjb		} else {
957178479Sjb			snprintf(da, sizeof(da), "socket%d",
958178479Sjb				(int)daddr->ss_family);
959178479Sjb		}
960178479Sjb		comm = "udp";
961178479Sjb		if(tp == comm_tcp) comm = "tcp";
962178479Sjb		else if(tp == comm_tcp_accept) comm = "tcp";
963178479Sjb		else if(tp == comm_http) comm = "dot";
964178479Sjb		else if(tp == comm_local) comm = "unix";
965178479Sjb		else if(tp == comm_raw) comm = "raw";
966178479Sjb		snprintf(dest_buf, sizeof(dest_buf), " on %s %s %d",
967178479Sjb			comm, da, port);
968178479Sjb	} else {
969178479Sjb		dest_buf[0]=0;
970178479Sjb	}
971178479Sjb	if(rcode == LDNS_RCODE_FORMERR)
972178479Sjb	{
973178479Sjb		if(LOG_TAG_QUERYREPLY)
974178479Sjb			log_reply("%s - - - %s - - -%s", clientip_buf,
975178479Sjb				rcode_buf, dest_buf);
976178479Sjb		else	log_info("%s - - - %s - - -%s", clientip_buf,
977178479Sjb				rcode_buf, dest_buf);
978178479Sjb	} else {
979178479Sjb		if(qinf->qname)
980178479Sjb			dname_str(qinf->qname, qname_buf);
981178479Sjb		else	snprintf(qname_buf, sizeof(qname_buf), "null");
982178479Sjb		pktlen = sldns_buffer_limit(rmsg);
983178479Sjb		sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf));
984178479Sjb		sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf));
985178479Sjb		if(LOG_TAG_QUERYREPLY)
986178479Sjb		     log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d%s",
987178479Sjb			clientip_buf, qname_buf, type_buf, class_buf,
988178479Sjb			rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec,
989178479Sjb			cached, (int)pktlen, dest_buf);
990178479Sjb		else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d%s",
991178479Sjb			clientip_buf, qname_buf, type_buf, class_buf,
992178479Sjb			rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec,
993178479Sjb			cached, (int)pktlen, dest_buf);
994178479Sjb	}
995178479Sjb}
996178479Sjb
997178479Sjbvoid
998178479Sjblog_query_info(enum verbosity_value v, const char* str,
999178479Sjb	struct query_info* qinf)
1000178479Sjb{
1001178479Sjb	log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
1002178479Sjb}
1003178479Sjb
1004178479Sjbint
1005178479Sjbreply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep)
1006178479Sjb{
1007178479Sjb	/* check only answer section rrs for matching cname chain.
1008178479Sjb	 * the cache may return changed rdata, but owner names are untouched.*/
1009178479Sjb	size_t i;
1010178479Sjb	uint8_t* sname = qinfo->qname;
1011178479Sjb	size_t snamelen = qinfo->qname_len;
1012178479Sjb	for(i=0; i<rep->an_numrrsets; i++) {
1013178479Sjb		uint16_t t = ntohs(rep->rrsets[i]->rk.type);
1014178479Sjb		if(t == LDNS_RR_TYPE_DNAME)
1015178479Sjb			continue; /* skip dnames; note TTL 0 not cached */
1016178479Sjb		/* verify that owner matches current sname */
1017178479Sjb		if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
1018178479Sjb			/* cname chain broken */
1019178479Sjb			return 0;
1020178479Sjb		}
1021178479Sjb		/* if this is a cname; move on */
1022178479Sjb		if(t == LDNS_RR_TYPE_CNAME) {
1023178479Sjb			get_cname_target(rep->rrsets[i], &sname, &snamelen);
1024178479Sjb		}
1025178479Sjb	}
1026178479Sjb	return 1;
1027178479Sjb}
1028178479Sjb
1029178479Sjbint
1030178479Sjbreply_all_rrsets_secure(struct reply_info* rep)
1031178479Sjb{
1032178479Sjb	size_t i;
1033178479Sjb	for(i=0; i<rep->rrset_count; i++) {
1034178479Sjb		if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
1035178479Sjb			->security != sec_status_secure )
1036178479Sjb		return 0;
1037178479Sjb	}
1038178479Sjb	return 1;
1039178479Sjb}
1040178479Sjb
1041178479Sjbstruct reply_info*
1042178479Sjbparse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
1043178479Sjb	struct query_info* qi)
1044178479Sjb{
1045178479Sjb	struct reply_info* rep;
1046178479Sjb	struct msg_parse* msg;
1047178479Sjb	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
1048178479Sjb		return NULL;
1049178479Sjb	}
1050178479Sjb	memset(msg, 0, sizeof(*msg));
1051178479Sjb	sldns_buffer_set_position(pkt, 0);
1052178479Sjb	if(parse_packet(pkt, msg, region) != 0){
1053178479Sjb		return 0;
1054178479Sjb	}
1055178479Sjb	if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
1056178479Sjb		return 0;
1057178479Sjb	}
1058178479Sjb	return rep;
1059178479Sjb}
1060178479Sjb
1061178479Sjbint edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
1062178479Sjb	sldns_ede_code code, const char *txt)
1063178479Sjb{
1064178479Sjb	struct edns_option** prevp;
1065178479Sjb	struct edns_option* opt;
1066178479Sjb	size_t txt_len = txt ? strlen(txt) : 0;
1067178479Sjb
1068178479Sjb	/* allocate new element */
1069178479Sjb	opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
1070178479Sjb	if(!opt)
1071178479Sjb		return 0;
1072178479Sjb	opt->next = NULL;
1073178479Sjb	opt->opt_code = LDNS_EDNS_EDE;
1074178479Sjb	opt->opt_len = txt_len + sizeof(uint16_t);
1075178479Sjb	opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t));
1076178479Sjb	if(!opt->opt_data)
1077178479Sjb		return 0;
1078178479Sjb	sldns_write_uint16(opt->opt_data, (uint16_t)code);
1079178479Sjb	if (txt_len)
1080178479Sjb		memmove(opt->opt_data + 2, txt, txt_len);
1081178479Sjb
1082178479Sjb	/* append at end of list */
1083178479Sjb	prevp = list;
1084178479Sjb	while(*prevp != NULL)
1085178479Sjb		prevp = &((*prevp)->next);
1086178479Sjb	verbose(VERB_ALGO, "attached EDE code: %d with message: %s", code, (txt?txt:"\"\""));
1087178479Sjb	*prevp = opt;
1088178479Sjb	return 1;
1089178479Sjb}
1090178479Sjb
1091178479Sjbint edns_opt_list_append_keepalive(struct edns_option** list, int msec,
1092178479Sjb	struct regional* region)
1093178479Sjb{
1094178479Sjb	uint8_t data[2]; /* For keepalive value */
1095178479Sjb	data[0] = (uint8_t)((msec >> 8) & 0xff);
1096178479Sjb	data[1] = (uint8_t)(msec & 0xff);
1097178479Sjb	return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data),
1098178479Sjb		data, region);
1099178479Sjb}
1100178479Sjb
1101178479Sjbint edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
1102178479Sjb	uint8_t* data, struct regional* region)
1103178479Sjb{
1104178479Sjb	struct edns_option** prevp;
1105178479Sjb	struct edns_option* opt;
1106178479Sjb
1107178479Sjb	/* allocate new element */
1108178479Sjb	opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
1109178479Sjb	if(!opt)
1110178479Sjb		return 0;
1111178479Sjb	opt->next = NULL;
1112178479Sjb	opt->opt_code = code;
1113178479Sjb	opt->opt_len = len;
1114178479Sjb	opt->opt_data = NULL;
1115178479Sjb	if(len > 0) {
1116178479Sjb		opt->opt_data = regional_alloc_init(region, data, len);
1117178479Sjb		if(!opt->opt_data)
1118178479Sjb			return 0;
1119178479Sjb	}
1120178479Sjb
1121178479Sjb	/* append at end of list */
1122178479Sjb	prevp = list;
1123178479Sjb	while(*prevp != NULL) {
1124178479Sjb		prevp = &((*prevp)->next);
1125178479Sjb	}
1126178479Sjb	*prevp = opt;
1127178479Sjb	return 1;
1128178479Sjb}
1129178479Sjb
1130178479Sjbint edns_opt_list_remove(struct edns_option** list, uint16_t code)
1131178479Sjb{
1132178479Sjb	/* The list should already be allocated in a region. Freeing the
1133178479Sjb	 * allocated space in a region is not possible. We just unlink the
1134178479Sjb	 * required elements and they will be freed together with the region. */
1135178479Sjb
1136178479Sjb	struct edns_option* prev;
1137178479Sjb	struct edns_option* curr;
1138178479Sjb	if(!list || !(*list)) return 0;
1139178479Sjb
1140178479Sjb	/* Unlink and repoint if the element(s) are first in list */
1141178479Sjb	while(list && *list && (*list)->opt_code == code) {
1142178479Sjb		*list = (*list)->next;
1143178479Sjb	}
1144178479Sjb
1145178479Sjb	if(!list || !(*list)) return 1;
1146178479Sjb	/* Unlink elements and reattach the list */
1147178479Sjb	prev = *list;
1148178479Sjb	curr = (*list)->next;
1149178479Sjb	while(curr != NULL) {
1150178479Sjb		if(curr->opt_code == code) {
1151178479Sjb			prev->next = curr->next;
1152178479Sjb			curr = curr->next;
1153178479Sjb		} else {
1154178479Sjb			prev = curr;
1155178479Sjb			curr = curr->next;
1156178479Sjb		}
1157178479Sjb	}
1158178479Sjb	return 1;
1159178479Sjb}
1160178479Sjb
1161178479Sjbstatic int inplace_cb_reply_call_generic(
1162178479Sjb    struct inplace_cb* callback_list, enum inplace_cb_list_type type,
1163178479Sjb	struct query_info* qinfo, struct module_qstate* qstate,
1164178479Sjb	struct reply_info* rep, int rcode, struct edns_data* edns,
1165178479Sjb	struct comm_reply* repinfo, struct regional* region,
1166178479Sjb	struct timeval* start_time)
1167178479Sjb{
1168178479Sjb	struct inplace_cb* cb;
1169178479Sjb	struct edns_option* opt_list_out = NULL;
1170178479Sjb#if defined(EXPORT_ALL_SYMBOLS)
1171178479Sjb	(void)type; /* param not used when fptr_ok disabled */
1172178479Sjb#endif
1173178479Sjb	if(qstate)
1174178479Sjb		opt_list_out = qstate->edns_opts_front_out;
1175178479Sjb	for(cb=callback_list; cb; cb=cb->next) {
1176178479Sjb		fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
1177178479Sjb			(inplace_cb_reply_func_type*)cb->cb, type));
1178178479Sjb		(void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
1179178479Sjb			rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg);
1180178479Sjb	}
1181178479Sjb	edns->opt_list_inplace_cb_out = opt_list_out;
1182178479Sjb	return 1;
1183178479Sjb}
1184178479Sjb
1185178479Sjbint inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
1186178479Sjb	struct module_qstate* qstate, struct reply_info* rep, int rcode,
1187178479Sjb	struct edns_data* edns, struct comm_reply* repinfo, struct regional* region,
1188178479Sjb	struct timeval* start_time)
1189178479Sjb{
1190178479Sjb	return inplace_cb_reply_call_generic(
1191178479Sjb		env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
1192178479Sjb		qstate, rep, rcode, edns, repinfo, region, start_time);
1193178479Sjb}
1194178479Sjb
1195178479Sjbint inplace_cb_reply_cache_call(struct module_env* env,
1196178479Sjb	struct query_info* qinfo, struct module_qstate* qstate,
1197178479Sjb	struct reply_info* rep, int rcode, struct edns_data* edns,
1198178479Sjb	struct comm_reply* repinfo, struct regional* region,
1199178479Sjb	struct timeval* start_time)
1200178479Sjb{
1201178479Sjb	return inplace_cb_reply_call_generic(
1202178479Sjb		env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
1203178479Sjb		qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
1204178479Sjb}
1205178479Sjb
1206178479Sjbint inplace_cb_reply_local_call(struct module_env* env,
1207178479Sjb	struct query_info* qinfo, struct module_qstate* qstate,
1208178479Sjb	struct reply_info* rep, int rcode, struct edns_data* edns,
1209178479Sjb	struct comm_reply* repinfo, struct regional* region,
1210178479Sjb	struct timeval* start_time)
1211178479Sjb{
1212178479Sjb	return inplace_cb_reply_call_generic(
1213178479Sjb		env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
1214178479Sjb		qinfo, qstate, rep, rcode, edns, repinfo, region, start_time);
1215178479Sjb}
1216178479Sjb
1217178479Sjbint inplace_cb_reply_servfail_call(struct module_env* env,
1218178479Sjb	struct query_info* qinfo, struct module_qstate* qstate,
1219178479Sjb	struct reply_info* rep, int rcode, struct edns_data* edns,
1220178479Sjb	struct comm_reply* repinfo, struct regional* region,
1221178479Sjb	struct timeval* start_time)
1222178479Sjb{
1223178479Sjb	/* We are going to servfail. Remove any potential edns options. */
1224178479Sjb	if(qstate)
1225178479Sjb		qstate->edns_opts_front_out = NULL;
1226178479Sjb	return inplace_cb_reply_call_generic(
1227178479Sjb		env->inplace_cb_lists[inplace_cb_reply_servfail],
1228178479Sjb		inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
1229178479Sjb		region, start_time);
1230178479Sjb}
1231178479Sjb
1232178479Sjbint inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
1233178479Sjb	uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
1234178479Sjb	uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
1235178479Sjb	struct regional* region)
1236178479Sjb{
1237178479Sjb	struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query];
1238178479Sjb	for(; cb; cb=cb->next) {
1239178479Sjb		fptr_ok(fptr_whitelist_inplace_cb_query(
1240178479Sjb			(inplace_cb_query_func_type*)cb->cb));
1241178479Sjb		(void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags,
1242178479Sjb			qstate, addr, addrlen, zone, zonelen, region,
1243178479Sjb			cb->id, cb->cb_arg);
1244178479Sjb	}
1245178479Sjb	return 1;
1246178479Sjb}
1247178479Sjb
1248178479Sjbint inplace_cb_edns_back_parsed_call(struct module_env* env,
1249178479Sjb	struct module_qstate* qstate)
1250178479Sjb{
1251178479Sjb	struct inplace_cb* cb =
1252178479Sjb		env->inplace_cb_lists[inplace_cb_edns_back_parsed];
1253178479Sjb	for(; cb; cb=cb->next) {
1254178479Sjb		fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed(
1255178479Sjb			(inplace_cb_edns_back_parsed_func_type*)cb->cb));
1256178479Sjb		(void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate,
1257178479Sjb			cb->id, cb->cb_arg);
1258178479Sjb	}
1259178479Sjb	return 1;
1260178479Sjb}
1261178479Sjb
1262178479Sjbint inplace_cb_query_response_call(struct module_env* env,
1263178479Sjb	struct module_qstate* qstate, struct dns_msg* response) {
1264178479Sjb	struct inplace_cb* cb =
1265178479Sjb		env->inplace_cb_lists[inplace_cb_query_response];
1266178479Sjb	for(; cb; cb=cb->next) {
1267178479Sjb		fptr_ok(fptr_whitelist_inplace_cb_query_response(
1268178479Sjb			(inplace_cb_query_response_func_type*)cb->cb));
1269178479Sjb		(void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate,
1270178479Sjb			response, cb->id, cb->cb_arg);
1271178479Sjb	}
1272178479Sjb	return 1;
1273178479Sjb}
1274178479Sjb
1275178479Sjbstruct edns_option* edns_opt_copy_region(struct edns_option* list,
1276178479Sjb	struct regional* region)
1277178479Sjb{
1278178479Sjb	struct edns_option* result = NULL, *cur = NULL, *s;
1279178479Sjb	while(list) {
1280178479Sjb		/* copy edns option structure */
1281178479Sjb		s = regional_alloc_init(region, list, sizeof(*list));
1282178479Sjb		if(!s) return NULL;
1283178479Sjb		s->next = NULL;
1284178479Sjb
1285178479Sjb		/* copy option data */
1286178479Sjb		if(s->opt_data) {
1287178479Sjb			s->opt_data = regional_alloc_init(region, s->opt_data,
1288178479Sjb				s->opt_len);
1289178479Sjb			if(!s->opt_data)
1290178479Sjb				return NULL;
1291178479Sjb		}
1292178479Sjb
1293178479Sjb		/* link into list */
1294178479Sjb		if(cur)
1295178479Sjb			cur->next = s;
1296178479Sjb		else	result = s;
1297178479Sjb		cur = s;
1298178479Sjb
1299210767Srpaulo		/* examine next element */
1300210767Srpaulo		list = list->next;
1301210767Srpaulo	}
1302210767Srpaulo	return result;
1303210767Srpaulo}
1304210767Srpaulo
1305210767Srpaulostruct edns_option* edns_opt_copy_filter_region(struct edns_option* list,
1306210767Srpaulo	uint16_t* filter_list, size_t filter_list_len, struct regional* region)
1307210767Srpaulo{
1308210767Srpaulo	struct edns_option* result = NULL, *cur = NULL, *s;
1309210767Srpaulo	size_t i;
1310210767Srpaulo	while(list) {
1311210767Srpaulo		for(i=0; i<filter_list_len; i++)
1312210767Srpaulo			if(filter_list[i] == list->opt_code) goto found;
1313178479Sjb		if(i == filter_list_len) goto next;
1314178479Sjbfound:
1315178479Sjb		/* copy edns option structure */
1316178479Sjb		s = regional_alloc_init(region, list, sizeof(*list));
1317178479Sjb		if(!s) return NULL;
1318178479Sjb		s->next = NULL;
1319178479Sjb
1320178479Sjb		/* copy option data */
1321178479Sjb		if(s->opt_data) {
1322178479Sjb			s->opt_data = regional_alloc_init(region, s->opt_data,
1323178479Sjb				s->opt_len);
1324178479Sjb			if(!s->opt_data)
1325178479Sjb				return NULL;
1326178479Sjb		}
1327237624Spfg
1328178479Sjb		/* link into list */
1329237624Spfg		if(cur)
1330237624Spfg			cur->next = s;
1331237624Spfg		else	result = s;
1332237624Spfg		cur = s;
1333237624Spfg
1334237624Spfgnext:
1335237624Spfg		/* examine next element */
1336178479Sjb		list = list->next;
1337178479Sjb	}
1338178479Sjb	return result;
1339178479Sjb}
1340178479Sjb
1341178479Sjbint edns_opt_compare(struct edns_option* p, struct edns_option* q)
1342178479Sjb{
1343178479Sjb	if(!p && !q) return 0;
1344178479Sjb	if(!p) return -1;
1345178479Sjb	if(!q) return 1;
1346178479Sjb	log_assert(p && q);
1347178479Sjb	if(p->opt_code != q->opt_code)
1348178479Sjb		return (int)q->opt_code - (int)p->opt_code;
1349178479Sjb	if(p->opt_len != q->opt_len)
1350178479Sjb		return (int)q->opt_len - (int)p->opt_len;
1351178479Sjb	if(p->opt_len != 0)
1352178479Sjb		return memcmp(p->opt_data, q->opt_data, p->opt_len);
1353178479Sjb	return 0;
1354178479Sjb}
1355178479Sjb
1356178479Sjbint edns_opt_list_compare(struct edns_option* p, struct edns_option* q)
1357178479Sjb{
1358178479Sjb	int r;
1359178479Sjb	while(p && q) {
1360178479Sjb		r = edns_opt_compare(p, q);
1361178479Sjb		if(r != 0)
1362178479Sjb			return r;
1363178479Sjb		p = p->next;
1364178479Sjb		q = q->next;
1365178479Sjb	}
1366178479Sjb	if(p || q) {
1367178479Sjb		/* uneven length lists */
1368178479Sjb		if(p) return 1;
1369178479Sjb		if(q) return -1;
1370178479Sjb	}
1371178479Sjb	return 0;
1372178479Sjb}
1373178479Sjb
1374178479Sjbvoid edns_opt_list_free(struct edns_option* list)
1375178479Sjb{
1376178479Sjb	struct edns_option* n;
1377178479Sjb	while(list) {
1378178479Sjb		free(list->opt_data);
1379178479Sjb		n = list->next;
1380178479Sjb		free(list);
1381178479Sjb		list = n;
1382178479Sjb	}
1383178479Sjb}
1384178479Sjb
1385178479Sjbstruct edns_option* edns_opt_copy_alloc(struct edns_option* list)
1386178479Sjb{
1387178479Sjb	struct edns_option* result = NULL, *cur = NULL, *s;
1388178479Sjb	while(list) {
1389178479Sjb		/* copy edns option structure */
1390178479Sjb		s = memdup(list, sizeof(*list));
1391178479Sjb		if(!s) {
1392178479Sjb			edns_opt_list_free(result);
1393178479Sjb			return NULL;
1394178479Sjb		}
1395178479Sjb		s->next = NULL;
1396178479Sjb
1397178479Sjb		/* copy option data */
1398178479Sjb		if(s->opt_data) {
1399178479Sjb			s->opt_data = memdup(s->opt_data, s->opt_len);
1400178479Sjb			if(!s->opt_data) {
1401178479Sjb				free(s);
1402178479Sjb				edns_opt_list_free(result);
1403178479Sjb				return NULL;
1404178479Sjb			}
1405178479Sjb		}
1406178479Sjb
1407178479Sjb		/* link into list */
1408178479Sjb		if(cur)
1409178479Sjb			cur->next = s;
1410178479Sjb		else	result = s;
1411178479Sjb		cur = s;
1412178479Sjb
1413178479Sjb		/* examine next element */
1414178479Sjb		list = list->next;
1415178479Sjb	}
1416178479Sjb	return result;
1417178479Sjb}
1418178479Sjb
1419178479Sjbstruct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
1420178479Sjb{
1421178479Sjb	struct edns_option* p;
1422178479Sjb	for(p=list; p; p=p->next) {
1423178479Sjb		if(p->opt_code == code)
1424178479Sjb			return p;
1425178479Sjb	}
1426178479Sjb	return NULL;
1427178479Sjb}
1428178479Sjb