]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/data/packed_rrset.c
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / util / data / packed_rrset.c
1 /*
2  * util/data/packed_rrset.c - data storage for a set of resource records.
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 the data storage for RRsets.
40  */
41
42 #include "config.h"
43 #include "util/data/msgparse.h"
44 #include "util/data/packed_rrset.h"
45 #include "util/data/dname.h"
46 #include "util/storage/lookup3.h"
47 #include "util/log.h"
48 #include "util/alloc.h"
49 #include "util/regional.h"
50 #include "util/net_help.h"
51 #include "sldns/rrdef.h"
52 #include "sldns/sbuffer.h"
53 #include "sldns/wire2str.h"
54
55 void
56 ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
57         struct alloc_cache* alloc)
58 {
59         if(!pkey)
60                 return;
61         free(pkey->entry.data);
62         pkey->entry.data = NULL;
63         free(pkey->rk.dname);
64         pkey->rk.dname = NULL;
65         pkey->id = 0;
66         alloc_special_release(alloc, pkey);
67 }
68
69 size_t 
70 ub_rrset_sizefunc(void* key, void* data)
71 {
72         struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
73         struct packed_rrset_data* d = (struct packed_rrset_data*)data;
74         size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
75         s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
76         return s;
77 }
78
79 size_t 
80 packed_rrset_sizeof(struct packed_rrset_data* d)
81 {
82         size_t s;
83         if(d->rrsig_count > 0) {
84                 s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] - 
85                         (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
86         } else {
87                 log_assert(d->count > 0);
88                 s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) + 
89                         d->rr_len[d->count-1];
90         }
91         return s;
92 }
93
94 int 
95 ub_rrset_compare(void* k1, void* k2)
96 {
97         struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
98         struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
99         int c;
100         if(key1 == key2)
101                 return 0;
102         if(key1->rk.type != key2->rk.type) {
103                 if(key1->rk.type < key2->rk.type)
104                         return -1;
105                 return 1;
106         }
107         if(key1->rk.dname_len != key2->rk.dname_len) {
108                 if(key1->rk.dname_len < key2->rk.dname_len)
109                         return -1;
110                 return 1;
111         }
112         if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
113                 return c;
114         if(key1->rk.rrset_class != key2->rk.rrset_class) {
115                 if(key1->rk.rrset_class < key2->rk.rrset_class)
116                         return -1;
117                 return 1;
118         }
119         if(key1->rk.flags != key2->rk.flags) {
120                 if(key1->rk.flags < key2->rk.flags)
121                         return -1;
122                 return 1;
123         }
124         return 0;
125 }
126
127 void 
128 ub_rrset_key_delete(void* key, void* userdata)
129 {
130         struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
131         struct alloc_cache* a = (struct alloc_cache*)userdata;
132         k->id = 0;
133         free(k->rk.dname);
134         k->rk.dname = NULL;
135         alloc_special_release(a, k);
136 }
137
138 void 
139 rrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
140 {
141         struct packed_rrset_data* d = (struct packed_rrset_data*)data;
142         free(d);
143 }
144
145 int 
146 rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
147 {
148         size_t i;
149         size_t total;
150         if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count) 
151                 return 0;
152         total = d1->count + d1->rrsig_count;
153         for(i=0; i<total; i++) {
154                 if(d1->rr_len[i] != d2->rr_len[i])
155                         return 0;
156                 if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
157                         return 0;
158         }
159         return 1;
160 }
161
162 hashvalue_type
163 rrset_key_hash(struct packed_rrset_key* key)
164 {
165         /* type is hashed in host order */
166         uint16_t t = ntohs(key->type);
167         /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */
168         /* this routine does not have a compressed name */
169         hashvalue_type h = 0xab;
170         h = dname_query_hash(key->dname, h);
171         h = hashlittle(&t, sizeof(t), h);
172         h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
173         h = hashlittle(&key->flags, sizeof(uint32_t), h);
174         return h;
175 }
176
177 void 
178 packed_rrset_ptr_fixup(struct packed_rrset_data* data)
179 {
180         size_t i;
181         size_t total = data->count + data->rrsig_count;
182         uint8_t* nextrdata;
183         /* fixup pointers in packed rrset data */
184         data->rr_len = (size_t*)((uint8_t*)data +
185                 sizeof(struct packed_rrset_data));
186         data->rr_data = (uint8_t**)&(data->rr_len[total]);
187         data->rr_ttl = (time_t*)&(data->rr_data[total]);
188         nextrdata = (uint8_t*)&(data->rr_ttl[total]);
189         for(i=0; i<total; i++) {
190                 data->rr_data[i] = nextrdata;
191                 nextrdata += data->rr_len[i];
192         }
193 }
194
195 void 
196 get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, 
197         size_t* dname_len)
198 {
199         struct packed_rrset_data* d;
200         size_t len;
201         if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && 
202                 ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
203                 return;
204         d = (struct packed_rrset_data*)rrset->entry.data;
205         if(d->count < 1)
206                 return;
207         if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
208                 return;
209         len = sldns_read_uint16(d->rr_data[0]);
210         if(len != d->rr_len[0] - sizeof(uint16_t))
211                 return;
212         if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
213                 return;
214         *dname = d->rr_data[0]+sizeof(uint16_t);
215         *dname_len = len;
216 }
217
218 void 
219 packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
220 {
221         size_t i;
222         size_t total = data->count + data->rrsig_count;
223         data->ttl += add;
224         for(i=0; i<total; i++)
225                 data->rr_ttl[i] += add;
226 }
227
228 const char* 
229 rrset_trust_to_string(enum rrset_trust s)
230 {
231         switch(s) {
232         case rrset_trust_none:          return "rrset_trust_none";
233         case rrset_trust_add_noAA:      return "rrset_trust_add_noAA";
234         case rrset_trust_auth_noAA:     return "rrset_trust_auth_noAA";
235         case rrset_trust_add_AA:        return "rrset_trust_add_AA";
236         case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
237         case rrset_trust_ans_noAA:      return "rrset_trust_ans_noAA";
238         case rrset_trust_glue:          return "rrset_trust_glue";
239         case rrset_trust_auth_AA:       return "rrset_trust_auth_AA";
240         case rrset_trust_ans_AA:        return "rrset_trust_ans_AA";
241         case rrset_trust_sec_noglue:    return "rrset_trust_sec_noglue";
242         case rrset_trust_prim_noglue:   return "rrset_trust_prim_noglue";
243         case rrset_trust_validated:     return "rrset_trust_validated";
244         case rrset_trust_ultimate:      return "rrset_trust_ultimate";
245         }
246         return "unknown_rrset_trust_value";
247 }
248
249 const char* 
250 sec_status_to_string(enum sec_status s)
251 {
252         switch(s) {
253         case sec_status_unchecked:      return "sec_status_unchecked";
254         case sec_status_bogus:          return "sec_status_bogus";
255         case sec_status_indeterminate:  return "sec_status_indeterminate";
256         case sec_status_insecure:       return "sec_status_insecure";
257         case sec_status_secure_sentinel_fail:   return "sec_status_secure_sentinel_fail";
258         case sec_status_secure:         return "sec_status_secure";
259         }
260         return "unknown_sec_status_value";
261 }
262
263 void log_rrset_key(enum verbosity_value v, const char* str, 
264         struct ub_packed_rrset_key* rrset)
265 {
266         if(verbosity >= v)
267                 log_nametypeclass(v, str, rrset->rk.dname,
268                         ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
269 }
270
271 int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
272         time_t now, char* dest, size_t dest_len)
273 {
274         struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
275                 entry.data;
276         uint8_t rr[65535];
277         size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
278         log_assert(dest_len > 0 && dest);
279         if(rlen > dest_len) {
280                 dest[0] = 0;
281                 return 0;
282         }
283         memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
284         if(i < d->count)
285                 memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
286         else    sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
287         memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
288         sldns_write_uint32(rr+rrset->rk.dname_len+4,
289                 (uint32_t)(d->rr_ttl[i]-now));
290         memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
291         if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) {
292                 log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
293                 dest[0] = 0;
294                 return 0;
295         } 
296         return 1;
297 }
298
299 void log_packed_rrset(enum verbosity_value v, const char* str,
300         struct ub_packed_rrset_key* rrset)
301 {
302         struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
303                 entry.data;
304         char buf[65535];
305         size_t i;
306         if(verbosity < v)
307                 return;
308         for(i=0; i<d->count+d->rrsig_count; i++) {
309                 if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
310                         log_info("%s: rr %d wire2str-error", str, (int)i);
311                 } else {
312                         log_info("%s: %s", str, buf);
313                 }
314         }
315 }
316
317 time_t 
318 ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
319 {
320         struct packed_rrset_data* d = (struct packed_rrset_data*)key->
321                 entry.data;
322         return d->ttl;
323 }
324
325 struct ub_packed_rrset_key*
326 packed_rrset_copy_region(struct ub_packed_rrset_key* key, 
327         struct regional* region, time_t now)
328 {
329         struct ub_packed_rrset_key* ck = regional_alloc(region, 
330                 sizeof(struct ub_packed_rrset_key));
331         struct packed_rrset_data* d;
332         struct packed_rrset_data* data = (struct packed_rrset_data*)
333                 key->entry.data;
334         size_t dsize, i;
335         if(!ck)
336                 return NULL;
337         ck->id = key->id;
338         memset(&ck->entry, 0, sizeof(ck->entry));
339         ck->entry.hash = key->entry.hash;
340         ck->entry.key = ck;
341         ck->rk = key->rk;
342         ck->rk.dname = regional_alloc_init(region, key->rk.dname, 
343                 key->rk.dname_len);
344         if(!ck->rk.dname)
345                 return NULL;
346         dsize = packed_rrset_sizeof(data);
347         d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
348         if(!d)
349                 return NULL;
350         ck->entry.data = d;
351         packed_rrset_ptr_fixup(d);
352         /* make TTLs relative - once per rrset */
353         for(i=0; i<d->count + d->rrsig_count; i++) {
354                 if(d->rr_ttl[i] < now)
355                         d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
356                 else    d->rr_ttl[i] -= now;
357         }
358         if(d->ttl < now)
359                 d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
360         else    d->ttl -= now;
361         return ck;
362 }
363
364 struct ub_packed_rrset_key* 
365 packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, 
366         struct alloc_cache* alloc, time_t now)
367 {
368         struct packed_rrset_data* fd, *dd;
369         struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
370         if(!dk) return NULL;
371         fd = (struct packed_rrset_data*)key->entry.data;
372         dk->entry.hash = key->entry.hash;
373         dk->rk = key->rk;
374         dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
375         if(!dk->rk.dname) {
376                 alloc_special_release(alloc, dk);
377                 return NULL;
378         }
379         dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
380         if(!dd) {
381                 free(dk->rk.dname);
382                 alloc_special_release(alloc, dk);
383                 return NULL;
384         }
385         packed_rrset_ptr_fixup(dd);
386         dk->entry.data = (void*)dd;
387         packed_rrset_ttl_add(dd, now);
388         return dk;
389 }
390
391 int
392 packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
393         size_t* index)
394 {
395         size_t i;
396         for(i=0; i<d->count; i++) {
397                 if(d->rr_len[i] != len)
398                         continue;
399                 if(memcmp(d->rr_data[i], rdata, len) == 0) {
400                         *index = i;
401                         return 1;
402                 }
403         }
404         return 0;
405 }