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