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