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