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
ub_packed_rrset_parsedelete(struct ub_packed_rrset_key * pkey,struct alloc_cache * alloc)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
ub_rrset_sizefunc(void * key,void * data)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
packed_rrset_sizeof(struct packed_rrset_data * d)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
ub_rrset_compare(void * k1,void * k2)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
ub_rrset_key_delete(void * key,void * userdata)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
rrset_data_delete(void * data,void * ATTR_UNUSED (userdata))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
rrsetdata_equal(struct packed_rrset_data * d1,struct packed_rrset_data * d2)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
rrset_key_hash(struct packed_rrset_key * key)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
packed_rrset_ptr_fixup(struct packed_rrset_data * data)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
get_cname_target(struct ub_packed_rrset_key * rrset,uint8_t ** dname,size_t * dname_len)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
packed_rrset_ttl_add(struct packed_rrset_data * data,time_t add)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 = add;
224 data->ttl += add;
225 for(i=0; i<total; i++)
226 data->rr_ttl[i] += add;
227 }
228
229 const char*
rrset_trust_to_string(enum rrset_trust s)230 rrset_trust_to_string(enum rrset_trust s)
231 {
232 switch(s) {
233 case rrset_trust_none: return "rrset_trust_none";
234 case rrset_trust_add_noAA: return "rrset_trust_add_noAA";
235 case rrset_trust_auth_noAA: return "rrset_trust_auth_noAA";
236 case rrset_trust_add_AA: return "rrset_trust_add_AA";
237 case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
238 case rrset_trust_ans_noAA: return "rrset_trust_ans_noAA";
239 case rrset_trust_glue: return "rrset_trust_glue";
240 case rrset_trust_auth_AA: return "rrset_trust_auth_AA";
241 case rrset_trust_ans_AA: return "rrset_trust_ans_AA";
242 case rrset_trust_sec_noglue: return "rrset_trust_sec_noglue";
243 case rrset_trust_prim_noglue: return "rrset_trust_prim_noglue";
244 case rrset_trust_validated: return "rrset_trust_validated";
245 case rrset_trust_ultimate: return "rrset_trust_ultimate";
246 }
247 return "unknown_rrset_trust_value";
248 }
249
250 const char*
sec_status_to_string(enum sec_status s)251 sec_status_to_string(enum sec_status s)
252 {
253 switch(s) {
254 case sec_status_unchecked: return "sec_status_unchecked";
255 case sec_status_bogus: return "sec_status_bogus";
256 case sec_status_indeterminate: return "sec_status_indeterminate";
257 case sec_status_insecure: return "sec_status_insecure";
258 case sec_status_secure_sentinel_fail: return "sec_status_secure_sentinel_fail";
259 case sec_status_secure: return "sec_status_secure";
260 }
261 return "unknown_sec_status_value";
262 }
263
log_rrset_key(enum verbosity_value v,const char * str,struct ub_packed_rrset_key * rrset)264 void log_rrset_key(enum verbosity_value v, const char* str,
265 struct ub_packed_rrset_key* rrset)
266 {
267 if(verbosity >= v)
268 log_nametypeclass(v, str, rrset->rk.dname,
269 ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
270 }
271
packed_rr_to_string(struct ub_packed_rrset_key * rrset,size_t i,time_t now,char * dest,size_t dest_len)272 int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
273 time_t now, char* dest, size_t dest_len)
274 {
275 struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
276 entry.data;
277 uint8_t rr[65535];
278 size_t wlen;
279 size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
280 time_t adjust = 0;
281 log_assert(dest_len > 0 && dest);
282 if(rlen > dest_len) {
283 dest[0] = 0;
284 return 0;
285 }
286 memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
287 if(i < d->count)
288 memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
289 else sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
290 memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
291 adjust = SERVE_ORIGINAL_TTL ? d->ttl_add : now;
292 if (d->rr_ttl[i] < adjust) adjust = d->rr_ttl[i]; /* Prevent negative TTL overflow */
293 sldns_write_uint32(rr+rrset->rk.dname_len+4,
294 (uint32_t)(d->rr_ttl[i]-adjust));
295 memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
296 wlen = (size_t)sldns_wire2str_rr_buf(rr, rlen, dest, dest_len);
297 if(wlen >= dest_len) {
298 /* the output string was truncated */
299 log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
300 dest[0] = 0;
301 return 0;
302 }
303 return 1;
304 }
305
log_packed_rrset(enum verbosity_value v,const char * str,struct ub_packed_rrset_key * rrset)306 void log_packed_rrset(enum verbosity_value v, const char* str,
307 struct ub_packed_rrset_key* rrset)
308 {
309 struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
310 entry.data;
311 char buf[65535];
312 size_t i;
313 if(verbosity < v)
314 return;
315 for(i=0; i<d->count+d->rrsig_count; i++) {
316 if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
317 log_info("%s: rr %d wire2str-error", str, (int)i);
318 } else {
319 log_info("%s: %s", str, buf);
320 }
321 }
322 }
323
324 time_t
ub_packed_rrset_ttl(struct ub_packed_rrset_key * key)325 ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
326 {
327 struct packed_rrset_data* d = (struct packed_rrset_data*)key->
328 entry.data;
329 return d->ttl;
330 }
331
332 struct ub_packed_rrset_key*
packed_rrset_copy_region(struct ub_packed_rrset_key * key,struct regional * region,time_t now)333 packed_rrset_copy_region(struct ub_packed_rrset_key* key,
334 struct regional* region, time_t now)
335 {
336 struct ub_packed_rrset_key* ck = regional_alloc(region,
337 sizeof(struct ub_packed_rrset_key));
338 struct packed_rrset_data* d;
339 struct packed_rrset_data* data = (struct packed_rrset_data*)
340 key->entry.data;
341 size_t dsize, i;
342 time_t adjust = 0;
343 if(!ck)
344 return NULL;
345 ck->id = key->id;
346 memset(&ck->entry, 0, sizeof(ck->entry));
347 ck->entry.hash = key->entry.hash;
348 ck->entry.key = ck;
349 ck->rk = key->rk;
350 ck->rk.dname = regional_alloc_init(region, key->rk.dname,
351 key->rk.dname_len);
352 if(!ck->rk.dname)
353 return NULL;
354 dsize = packed_rrset_sizeof(data);
355 d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
356 if(!d)
357 return NULL;
358 ck->entry.data = d;
359 packed_rrset_ptr_fixup(d);
360 /* make TTLs relative - once per rrset */
361 adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now;
362 for(i=0; i<d->count + d->rrsig_count; i++) {
363 if(d->rr_ttl[i] < adjust)
364 d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
365 else d->rr_ttl[i] -= adjust;
366 }
367 if(d->ttl < adjust)
368 d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
369 else d->ttl -= adjust;
370 d->ttl_add = 0; /* TTLs have been made relative */
371 return ck;
372 }
373
374 struct ub_packed_rrset_key*
packed_rrset_copy_alloc(struct ub_packed_rrset_key * key,struct alloc_cache * alloc,time_t now)375 packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
376 struct alloc_cache* alloc, time_t now)
377 {
378 struct packed_rrset_data* fd, *dd;
379 struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
380 if(!dk) return NULL;
381 fd = (struct packed_rrset_data*)key->entry.data;
382 dk->entry.hash = key->entry.hash;
383 dk->rk = key->rk;
384 dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
385 if(!dk->rk.dname) {
386 alloc_special_release(alloc, dk);
387 return NULL;
388 }
389 dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
390 if(!dd) {
391 free(dk->rk.dname);
392 alloc_special_release(alloc, dk);
393 return NULL;
394 }
395 packed_rrset_ptr_fixup(dd);
396 dk->entry.data = (void*)dd;
397 packed_rrset_ttl_add(dd, now);
398 return dk;
399 }
400
401 int
packed_rrset_find_rr(struct packed_rrset_data * d,uint8_t * rdata,size_t len,size_t * index)402 packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
403 size_t* index)
404 {
405 size_t i;
406 for(i=0; i<d->count; i++) {
407 if(d->rr_len[i] != len)
408 continue;
409 if(memcmp(d->rr_data[i], rdata, len) == 0) {
410 *index = i;
411 return 1;
412 }
413 }
414 return 0;
415 }
416