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