]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/unbound/util/data/msgreply.c
MFH (r266114, r266138): upgrade to latest ldns and unbound
[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
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 static 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)
580 {
581         hashvalue_t h = 0xab;
582         h = hashlittle(&q->qtype, sizeof(q->qtype), h);
583         h = hashlittle(&q->qclass, sizeof(q->qclass), h);
584         h = dname_query_hash(q->qname, h);
585         return h;
586 }
587
588 struct msgreply_entry* 
589 query_info_entrysetup(struct query_info* q, struct reply_info* r, 
590         hashvalue_t h)
591 {
592         struct msgreply_entry* e = (struct msgreply_entry*)malloc( 
593                 sizeof(struct msgreply_entry));
594         if(!e) return NULL;
595         memcpy(&e->key, q, sizeof(*q));
596         e->entry.hash = h;
597         e->entry.key = e;
598         e->entry.data = r;
599         lock_rw_init(&e->entry.lock);
600         lock_protect(&e->entry.lock, &e->key, sizeof(e->key));
601         lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) +
602                 sizeof(e->entry.key) + sizeof(e->entry.data));
603         lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
604         q->qname = NULL;
605         return e;
606 }
607
608 /** copy rrsets from replyinfo to dest replyinfo */
609 static int
610 repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 
611         struct regional* region)
612 {
613         size_t i, s;
614         struct packed_rrset_data* fd, *dd;
615         struct ub_packed_rrset_key* fk, *dk;
616         for(i=0; i<dest->rrset_count; i++) {
617                 fk = from->rrsets[i];
618                 dk = dest->rrsets[i];
619                 fd = (struct packed_rrset_data*)fk->entry.data;
620                 dk->entry.hash = fk->entry.hash;
621                 dk->rk = fk->rk;
622                 if(region) {
623                         dk->id = fk->id;
624                         dk->rk.dname = (uint8_t*)regional_alloc_init(region,
625                                 fk->rk.dname, fk->rk.dname_len);
626                 } else  
627                         dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 
628                                 fk->rk.dname_len);
629                 if(!dk->rk.dname)
630                         return 0;
631                 s = packed_rrset_sizeof(fd);
632                 if(region)
633                         dd = (struct packed_rrset_data*)regional_alloc_init(
634                                 region, fd, s);
635                 else    dd = (struct packed_rrset_data*)memdup(fd, s);
636                 if(!dd) 
637                         return 0;
638                 packed_rrset_ptr_fixup(dd);
639                 dk->entry.data = (void*)dd;
640         }
641         return 1;
642 }
643
644 struct reply_info* 
645 reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 
646         struct regional* region)
647 {
648         struct reply_info* cp;
649         cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 
650                 rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, 
651                 rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, 
652                 rep->security);
653         if(!cp)
654                 return NULL;
655         /* allocate ub_key structures special or not */
656         if(!repinfo_alloc_rrset_keys(cp, alloc, region)) {
657                 if(!region)
658                         reply_info_parsedelete(cp, alloc);
659                 return NULL;
660         }
661         if(!repinfo_copy_rrsets(cp, rep, region)) {
662                 if(!region)
663                         reply_info_parsedelete(cp, alloc);
664                 return NULL;
665         }
666         return cp;
667 }
668
669 uint8_t* 
670 reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
671 {
672         uint8_t* sname = qinfo->qname;
673         size_t snamelen = qinfo->qname_len;
674         size_t i;
675         for(i=0; i<rep->an_numrrsets; i++) {
676                 struct ub_packed_rrset_key* s = rep->rrsets[i];
677                 /* follow CNAME chain (if any) */
678                 if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 
679                         ntohs(s->rk.rrset_class) == qinfo->qclass && 
680                         snamelen == s->rk.dname_len &&
681                         query_dname_compare(sname, s->rk.dname) == 0) {
682                         get_cname_target(s, &sname, &snamelen);
683                 }
684         }
685         if(sname != qinfo->qname)
686                 return sname;
687         return NULL;
688 }
689
690 struct ub_packed_rrset_key* 
691 reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
692 {
693         uint8_t* sname = qinfo->qname;
694         size_t snamelen = qinfo->qname_len;
695         size_t i;
696         for(i=0; i<rep->an_numrrsets; i++) {
697                 struct ub_packed_rrset_key* s = rep->rrsets[i];
698                 /* first match type, for query of qtype cname */
699                 if(ntohs(s->rk.type) == qinfo->qtype && 
700                         ntohs(s->rk.rrset_class) == qinfo->qclass && 
701                         snamelen == s->rk.dname_len &&
702                         query_dname_compare(sname, s->rk.dname) == 0) {
703                         return s;
704                 }
705                 /* follow CNAME chain (if any) */
706                 if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 
707                         ntohs(s->rk.rrset_class) == qinfo->qclass && 
708                         snamelen == s->rk.dname_len &&
709                         query_dname_compare(sname, s->rk.dname) == 0) {
710                         get_cname_target(s, &sname, &snamelen);
711                 }
712         }
713         return NULL;
714 }
715
716 struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
717         uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
718 {
719         size_t i;
720         for(i=0; i<rep->an_numrrsets; i++) {
721                 struct ub_packed_rrset_key* s = rep->rrsets[i];
722                 if(ntohs(s->rk.type) == type && 
723                         ntohs(s->rk.rrset_class) == dclass && 
724                         namelen == s->rk.dname_len &&
725                         query_dname_compare(name, s->rk.dname) == 0) {
726                         return s;
727                 }
728         }
729         return NULL;
730 }
731
732 struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
733         uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
734 {
735         size_t i;
736         for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
737                 struct ub_packed_rrset_key* s = rep->rrsets[i];
738                 if(ntohs(s->rk.type) == type && 
739                         ntohs(s->rk.rrset_class) == dclass && 
740                         namelen == s->rk.dname_len &&
741                         query_dname_compare(name, s->rk.dname) == 0) {
742                         return s;
743                 }
744         }
745         return NULL;
746 }
747
748 struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
749         uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
750 {
751         size_t i;
752         for(i=0; i<rep->rrset_count; i++) {
753                 struct ub_packed_rrset_key* s = rep->rrsets[i];
754                 if(ntohs(s->rk.type) == type && 
755                         ntohs(s->rk.rrset_class) == dclass && 
756                         namelen == s->rk.dname_len &&
757                         query_dname_compare(name, s->rk.dname) == 0) {
758                         return s;
759                 }
760         }
761         return NULL;
762 }
763
764 void 
765 log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
766 {
767         /* not particularly fast but flexible, make wireformat and print */
768         sldns_buffer* buf = sldns_buffer_new(65535);
769         struct regional* region = regional_create();
770         if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 
771                 region, 65535, 1)) {
772                 log_info("%s: log_dns_msg: out of memory", str);
773         } else {
774                 char* str = sldns_wire2str_pkt(sldns_buffer_begin(buf),
775                         sldns_buffer_limit(buf));
776                 if(!str) {
777                         log_info("%s: log_dns_msg: ldns tostr failed", str);
778                 } else {
779                         log_info("%s %s", 
780                                 str, (char*)sldns_buffer_begin(buf));
781                 }
782                 free(str);
783         }
784         sldns_buffer_free(buf);
785         regional_destroy(region);
786 }
787
788 void 
789 log_query_info(enum verbosity_value v, const char* str, 
790         struct query_info* qinf)
791 {
792         log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
793 }
794
795 int
796 reply_check_cname_chain(struct reply_info* rep) 
797 {
798         /* check only answer section rrs for matching cname chain.
799          * the cache may return changed rdata, but owner names are untouched.*/
800         size_t i;
801         uint8_t* sname = rep->rrsets[0]->rk.dname;
802         size_t snamelen = rep->rrsets[0]->rk.dname_len;
803         for(i=0; i<rep->an_numrrsets; i++) {
804                 uint16_t t = ntohs(rep->rrsets[i]->rk.type);
805                 if(t == LDNS_RR_TYPE_DNAME)
806                         continue; /* skip dnames; note TTL 0 not cached */
807                 /* verify that owner matches current sname */
808                 if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
809                         /* cname chain broken */
810                         return 0;
811                 }
812                 /* if this is a cname; move on */
813                 if(t == LDNS_RR_TYPE_CNAME) {
814                         get_cname_target(rep->rrsets[i], &sname, &snamelen);
815                 }
816         }
817         return 1;
818 }
819
820 int
821 reply_all_rrsets_secure(struct reply_info* rep) 
822 {
823         size_t i;
824         for(i=0; i<rep->rrset_count; i++) {
825                 if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
826                         ->security != sec_status_secure )
827                 return 0;
828         }
829         return 1;
830 }