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