/src/unbound/validator/val_kentry.c
Line | Count | Source |
1 | | /* |
2 | | * validator/val_kentry.c - validator key entry definition. |
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 functions for dealing with validator key entries. |
40 | | */ |
41 | | #include "config.h" |
42 | | #include "validator/val_kentry.h" |
43 | | #include "util/data/packed_rrset.h" |
44 | | #include "util/data/dname.h" |
45 | | #include "util/storage/lookup3.h" |
46 | | #include "util/regional.h" |
47 | | #include "util/net_help.h" |
48 | | #include "sldns/rrdef.h" |
49 | | #include "sldns/keyraw.h" |
50 | | |
51 | | size_t |
52 | | key_entry_sizefunc(void* key, void* data) |
53 | 0 | { |
54 | 0 | struct key_entry_key* kk = (struct key_entry_key*)key; |
55 | 0 | struct key_entry_data* kd = (struct key_entry_data*)data; |
56 | 0 | size_t s = sizeof(*kk) + kk->namelen; |
57 | 0 | s += sizeof(*kd) + lock_get_mem(&kk->entry.lock); |
58 | 0 | if(kd->rrset_data) |
59 | 0 | s += packed_rrset_sizeof(kd->rrset_data); |
60 | 0 | if(kd->reason) |
61 | 0 | s += strlen(kd->reason)+1; |
62 | 0 | if(kd->algo) |
63 | 0 | s += strlen((char*)kd->algo)+1; |
64 | 0 | return s; |
65 | 0 | } |
66 | | |
67 | | int |
68 | | key_entry_compfunc(void* k1, void* k2) |
69 | 0 | { |
70 | 0 | struct key_entry_key* n1 = (struct key_entry_key*)k1; |
71 | 0 | struct key_entry_key* n2 = (struct key_entry_key*)k2; |
72 | 0 | if(n1->key_class != n2->key_class) { |
73 | 0 | if(n1->key_class < n2->key_class) |
74 | 0 | return -1; |
75 | 0 | return 1; |
76 | 0 | } |
77 | 0 | return query_dname_compare(n1->name, n2->name); |
78 | 0 | } |
79 | | |
80 | | void |
81 | | key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg)) |
82 | 0 | { |
83 | 0 | struct key_entry_key* kk = (struct key_entry_key*)key; |
84 | 0 | if(!key) |
85 | 0 | return; |
86 | 0 | lock_rw_destroy(&kk->entry.lock); |
87 | 0 | free(kk->name); |
88 | 0 | free(kk); |
89 | 0 | } |
90 | | |
91 | | void |
92 | | key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg)) |
93 | 0 | { |
94 | 0 | struct key_entry_data* kd = (struct key_entry_data*)data; |
95 | 0 | free(kd->reason); |
96 | 0 | free(kd->rrset_data); |
97 | 0 | free(kd->algo); |
98 | 0 | free(kd); |
99 | 0 | } |
100 | | |
101 | | void |
102 | | key_entry_hash(struct key_entry_key* kk) |
103 | 0 | { |
104 | 0 | kk->entry.hash = 0x654; |
105 | 0 | kk->entry.hash = hashlittle(&kk->key_class, sizeof(kk->key_class), |
106 | 0 | kk->entry.hash); |
107 | 0 | kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash); |
108 | 0 | } |
109 | | |
110 | | struct key_entry_key* |
111 | | key_entry_copy_toregion(struct key_entry_key* kkey, struct regional* region) |
112 | 0 | { |
113 | 0 | struct key_entry_key* newk; |
114 | 0 | newk = regional_alloc_init(region, kkey, sizeof(*kkey)); |
115 | 0 | if(!newk) |
116 | 0 | return NULL; |
117 | 0 | newk->name = regional_alloc_init(region, kkey->name, kkey->namelen); |
118 | 0 | if(!newk->name) |
119 | 0 | return NULL; |
120 | 0 | newk->entry.key = newk; |
121 | 0 | if(newk->entry.data) { |
122 | | /* copy data element */ |
123 | 0 | struct key_entry_data *d = (struct key_entry_data*) |
124 | 0 | kkey->entry.data; |
125 | 0 | struct key_entry_data *newd; |
126 | 0 | newd = regional_alloc_init(region, d, sizeof(*d)); |
127 | 0 | if(!newd) |
128 | 0 | return NULL; |
129 | | /* copy rrset */ |
130 | 0 | if(d->rrset_data) { |
131 | 0 | newd->rrset_data = regional_alloc_init(region, |
132 | 0 | d->rrset_data, |
133 | 0 | packed_rrset_sizeof(d->rrset_data)); |
134 | 0 | if(!newd->rrset_data) |
135 | 0 | return NULL; |
136 | 0 | packed_rrset_ptr_fixup(newd->rrset_data); |
137 | 0 | } |
138 | 0 | if(d->reason) { |
139 | 0 | newd->reason = regional_strdup(region, d->reason); |
140 | 0 | if(!newd->reason) |
141 | 0 | return NULL; |
142 | 0 | } |
143 | 0 | if(d->algo) { |
144 | 0 | newd->algo = (uint8_t*)regional_strdup(region, |
145 | 0 | (char*)d->algo); |
146 | 0 | if(!newd->algo) |
147 | 0 | return NULL; |
148 | 0 | } |
149 | 0 | newk->entry.data = newd; |
150 | 0 | } |
151 | 0 | return newk; |
152 | 0 | } |
153 | | |
154 | | struct key_entry_key* |
155 | | key_entry_copy(struct key_entry_key* kkey, int copy_reason) |
156 | 0 | { |
157 | 0 | struct key_entry_key* newk; |
158 | 0 | if(!kkey) |
159 | 0 | return NULL; |
160 | 0 | newk = memdup(kkey, sizeof(*kkey)); |
161 | 0 | if(!newk) |
162 | 0 | return NULL; |
163 | 0 | newk->name = memdup(kkey->name, kkey->namelen); |
164 | 0 | if(!newk->name) { |
165 | 0 | free(newk); |
166 | 0 | return NULL; |
167 | 0 | } |
168 | 0 | lock_rw_init(&newk->entry.lock); |
169 | 0 | newk->entry.key = newk; |
170 | 0 | if(newk->entry.data) { |
171 | | /* copy data element */ |
172 | 0 | struct key_entry_data *d = (struct key_entry_data*) |
173 | 0 | kkey->entry.data; |
174 | 0 | struct key_entry_data *newd; |
175 | 0 | newd = memdup(d, sizeof(*d)); |
176 | 0 | if(!newd) { |
177 | 0 | free(newk->name); |
178 | 0 | free(newk); |
179 | 0 | return NULL; |
180 | 0 | } |
181 | | /* copy rrset */ |
182 | 0 | if(d->rrset_data) { |
183 | 0 | newd->rrset_data = memdup(d->rrset_data, |
184 | 0 | packed_rrset_sizeof(d->rrset_data)); |
185 | 0 | if(!newd->rrset_data) { |
186 | 0 | free(newd); |
187 | 0 | free(newk->name); |
188 | 0 | free(newk); |
189 | 0 | return NULL; |
190 | 0 | } |
191 | 0 | packed_rrset_ptr_fixup(newd->rrset_data); |
192 | 0 | } |
193 | 0 | if(copy_reason && d->reason && *d->reason != 0) { |
194 | 0 | newd->reason = strdup(d->reason); |
195 | 0 | if(!newd->reason) { |
196 | 0 | free(newd->rrset_data); |
197 | 0 | free(newd); |
198 | 0 | free(newk->name); |
199 | 0 | free(newk); |
200 | 0 | return NULL; |
201 | 0 | } |
202 | 0 | } else { |
203 | 0 | newd->reason = NULL; |
204 | 0 | } |
205 | 0 | if(d->algo) { |
206 | 0 | newd->algo = (uint8_t*)strdup((char*)d->algo); |
207 | 0 | if(!newd->algo) { |
208 | 0 | free(newd->rrset_data); |
209 | 0 | free(newd->reason); |
210 | 0 | free(newd); |
211 | 0 | free(newk->name); |
212 | 0 | free(newk); |
213 | 0 | return NULL; |
214 | 0 | } |
215 | 0 | } |
216 | 0 | newk->entry.data = newd; |
217 | 0 | } |
218 | 0 | return newk; |
219 | 0 | } |
220 | | |
221 | | int |
222 | | key_entry_isnull(struct key_entry_key* kkey) |
223 | 0 | { |
224 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
225 | 0 | return (!d->isbad && d->rrset_data == NULL); |
226 | 0 | } |
227 | | |
228 | | int |
229 | | key_entry_isgood(struct key_entry_key* kkey) |
230 | 0 | { |
231 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
232 | 0 | return (!d->isbad && d->rrset_data != NULL); |
233 | 0 | } |
234 | | |
235 | | int |
236 | | key_entry_isbad(struct key_entry_key* kkey) |
237 | 0 | { |
238 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
239 | 0 | return (int)(d->isbad); |
240 | 0 | } |
241 | | |
242 | | char* |
243 | | key_entry_get_reason(struct key_entry_key* kkey) |
244 | 0 | { |
245 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
246 | 0 | return d->reason; |
247 | 0 | } |
248 | | |
249 | | sldns_ede_code |
250 | | key_entry_get_reason_bogus(struct key_entry_key* kkey) |
251 | 0 | { |
252 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
253 | 0 | return d->reason_bogus; |
254 | |
|
255 | 0 | } |
256 | | |
257 | | /** setup key entry in region */ |
258 | | static int |
259 | | key_entry_setup(struct regional* region, |
260 | | uint8_t* name, size_t namelen, uint16_t dclass, |
261 | | struct key_entry_key** k, struct key_entry_data** d) |
262 | 0 | { |
263 | 0 | *k = regional_alloc(region, sizeof(**k)); |
264 | 0 | if(!*k) |
265 | 0 | return 0; |
266 | 0 | memset(*k, 0, sizeof(**k)); |
267 | 0 | (*k)->entry.key = *k; |
268 | 0 | (*k)->name = regional_alloc_init(region, name, namelen); |
269 | 0 | if(!(*k)->name) |
270 | 0 | return 0; |
271 | 0 | (*k)->namelen = namelen; |
272 | 0 | (*k)->key_class = dclass; |
273 | 0 | *d = regional_alloc(region, sizeof(**d)); |
274 | 0 | if(!*d) |
275 | 0 | return 0; |
276 | 0 | (*k)->entry.data = *d; |
277 | 0 | return 1; |
278 | 0 | } |
279 | | |
280 | | struct key_entry_key* |
281 | | key_entry_create_null(struct regional* region, |
282 | | uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl, |
283 | | sldns_ede_code reason_bogus, const char* reason, |
284 | | time_t now) |
285 | 0 | { |
286 | 0 | struct key_entry_key* k; |
287 | 0 | struct key_entry_data* d; |
288 | 0 | if(!key_entry_setup(region, name, namelen, dclass, &k, &d)) |
289 | 0 | return NULL; |
290 | 0 | d->ttl = now + ttl; |
291 | 0 | d->isbad = 0; |
292 | 0 | d->reason = (!reason || *reason == 0) |
293 | 0 | ?NULL :(char*)regional_strdup(region, reason); |
294 | | /* On allocation error we don't store the reason string */ |
295 | 0 | d->reason_bogus = reason_bogus; |
296 | 0 | d->rrset_type = LDNS_RR_TYPE_DNSKEY; |
297 | 0 | d->rrset_data = NULL; |
298 | 0 | d->algo = NULL; |
299 | 0 | return k; |
300 | 0 | } |
301 | | |
302 | | struct key_entry_key* |
303 | | key_entry_create_rrset(struct regional* region, |
304 | | uint8_t* name, size_t namelen, uint16_t dclass, |
305 | | struct ub_packed_rrset_key* rrset, uint8_t* sigalg, |
306 | | sldns_ede_code reason_bogus, const char* reason, |
307 | | time_t now) |
308 | 0 | { |
309 | 0 | struct key_entry_key* k; |
310 | 0 | struct key_entry_data* d; |
311 | 0 | struct packed_rrset_data* rd = (struct packed_rrset_data*) |
312 | 0 | rrset->entry.data; |
313 | 0 | if(!key_entry_setup(region, name, namelen, dclass, &k, &d)) |
314 | 0 | return NULL; |
315 | 0 | d->ttl = rd->ttl + now; |
316 | 0 | d->isbad = 0; |
317 | 0 | d->reason = (!reason || *reason == 0) |
318 | 0 | ?NULL :(char*)regional_strdup(region, reason); |
319 | | /* On allocation error we don't store the reason string */ |
320 | 0 | d->reason_bogus = reason_bogus; |
321 | 0 | d->rrset_type = ntohs(rrset->rk.type); |
322 | 0 | d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region, |
323 | 0 | rd, packed_rrset_sizeof(rd)); |
324 | 0 | if(!d->rrset_data) |
325 | 0 | return NULL; |
326 | 0 | if(sigalg) { |
327 | 0 | d->algo = (uint8_t*)regional_strdup(region, (char*)sigalg); |
328 | 0 | if(!d->algo) |
329 | 0 | return NULL; |
330 | 0 | } else d->algo = NULL; |
331 | 0 | packed_rrset_ptr_fixup(d->rrset_data); |
332 | 0 | return k; |
333 | 0 | } |
334 | | |
335 | | struct key_entry_key* |
336 | | key_entry_create_bad(struct regional* region, |
337 | | uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl, |
338 | | sldns_ede_code reason_bogus, const char* reason, |
339 | | time_t now) |
340 | 0 | { |
341 | 0 | struct key_entry_key* k; |
342 | 0 | struct key_entry_data* d; |
343 | 0 | if(!key_entry_setup(region, name, namelen, dclass, &k, &d)) |
344 | 0 | return NULL; |
345 | 0 | d->ttl = now + ttl; |
346 | 0 | d->isbad = 1; |
347 | 0 | d->reason = (!reason || *reason == 0) |
348 | 0 | ?NULL :(char*)regional_strdup(region, reason); |
349 | | /* On allocation error we don't store the reason string */ |
350 | 0 | d->reason_bogus = reason_bogus; |
351 | 0 | d->rrset_type = LDNS_RR_TYPE_DNSKEY; |
352 | 0 | d->rrset_data = NULL; |
353 | 0 | d->algo = NULL; |
354 | 0 | return k; |
355 | 0 | } |
356 | | |
357 | | struct ub_packed_rrset_key* |
358 | | key_entry_get_rrset(struct key_entry_key* kkey, struct regional* region) |
359 | 0 | { |
360 | 0 | struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data; |
361 | 0 | struct ub_packed_rrset_key* rrk; |
362 | 0 | struct packed_rrset_data* rrd; |
363 | 0 | if(!d || !d->rrset_data) |
364 | 0 | return NULL; |
365 | 0 | rrk = regional_alloc(region, sizeof(*rrk)); |
366 | 0 | if(!rrk) |
367 | 0 | return NULL; |
368 | 0 | memset(rrk, 0, sizeof(*rrk)); |
369 | 0 | rrk->rk.dname = regional_alloc_init(region, kkey->name, kkey->namelen); |
370 | 0 | if(!rrk->rk.dname) |
371 | 0 | return NULL; |
372 | 0 | rrk->rk.dname_len = kkey->namelen; |
373 | 0 | rrk->rk.type = htons(d->rrset_type); |
374 | 0 | rrk->rk.rrset_class = htons(kkey->key_class); |
375 | 0 | rrk->entry.key = rrk; |
376 | 0 | rrd = regional_alloc_init(region, d->rrset_data, |
377 | 0 | packed_rrset_sizeof(d->rrset_data)); |
378 | 0 | if(!rrd) |
379 | 0 | return NULL; |
380 | 0 | rrk->entry.data = rrd; |
381 | 0 | packed_rrset_ptr_fixup(rrd); |
382 | 0 | return rrk; |
383 | 0 | } |
384 | | |
385 | | /** Get size of key in keyset */ |
386 | | static size_t |
387 | | dnskey_get_keysize(struct packed_rrset_data* data, size_t idx) |
388 | 0 | { |
389 | 0 | unsigned char* pk; |
390 | 0 | unsigned int pklen = 0; |
391 | 0 | int algo; |
392 | 0 | if(data->rr_len[idx] < 2+5) |
393 | 0 | return 0; |
394 | 0 | algo = (int)data->rr_data[idx][2+3]; |
395 | 0 | pk = (unsigned char*)data->rr_data[idx]+2+4; |
396 | 0 | pklen = (unsigned)data->rr_len[idx]-2-4; |
397 | 0 | return sldns_rr_dnskey_key_size_raw(pk, pklen, algo); |
398 | 0 | } |
399 | | |
400 | | /** get dnskey flags from data */ |
401 | | static uint16_t |
402 | | kd_get_flags(struct packed_rrset_data* data, size_t idx) |
403 | 0 | { |
404 | 0 | uint16_t f; |
405 | 0 | if(data->rr_len[idx] < 2+2) |
406 | 0 | return 0; |
407 | 0 | memmove(&f, data->rr_data[idx]+2, 2); |
408 | 0 | f = ntohs(f); |
409 | 0 | return f; |
410 | 0 | } |
411 | | |
412 | | size_t |
413 | | key_entry_keysize(struct key_entry_key* kkey) |
414 | 0 | { |
415 | 0 | struct packed_rrset_data* d; |
416 | | /* compute size of smallest ZSK key in the rrset */ |
417 | 0 | size_t i; |
418 | 0 | size_t bits = 0; |
419 | 0 | if(!key_entry_isgood(kkey)) |
420 | 0 | return 0; |
421 | 0 | d = ((struct key_entry_data*)kkey->entry.data)->rrset_data; |
422 | 0 | for(i=0; i<d->count; i++) { |
423 | 0 | if(!(kd_get_flags(d, i) & DNSKEY_BIT_ZSK)) |
424 | 0 | continue; |
425 | 0 | if(i==0 || dnskey_get_keysize(d, i) < bits) |
426 | 0 | bits = dnskey_get_keysize(d, i); |
427 | 0 | } |
428 | 0 | return bits; |
429 | 0 | } |