File: | src/sbin/unwind/libunbound/validator/autotrust.c |
Warning: | line 721, column 3 Null pointer passed as 1st argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * validator/autotrust.c - RFC5011 trust anchor management for unbound. | ||||
3 | * | ||||
4 | * Copyright (c) 2009, 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 | * Contains autotrust implementation. The implementation was taken from | ||||
40 | * the autotrust daemon (BSD licensed), written by Matthijs Mekking. | ||||
41 | * It was modified to fit into unbound. The state table process is the same. | ||||
42 | */ | ||||
43 | #include "config.h" | ||||
44 | #include "validator/autotrust.h" | ||||
45 | #include "validator/val_anchor.h" | ||||
46 | #include "validator/val_utils.h" | ||||
47 | #include "validator/val_sigcrypt.h" | ||||
48 | #include "util/data/dname.h" | ||||
49 | #include "util/data/packed_rrset.h" | ||||
50 | #include "util/log.h" | ||||
51 | #include "util/module.h" | ||||
52 | #include "util/net_help.h" | ||||
53 | #include "util/config_file.h" | ||||
54 | #include "util/regional.h" | ||||
55 | #include "util/random.h" | ||||
56 | #include "util/data/msgparse.h" | ||||
57 | #include "services/mesh.h" | ||||
58 | #include "services/cache/rrset.h" | ||||
59 | #include "validator/val_kcache.h" | ||||
60 | #include "sldns/sbuffer.h" | ||||
61 | #include "sldns/wire2str.h" | ||||
62 | #include "sldns/str2wire.h" | ||||
63 | #include "sldns/keyraw.h" | ||||
64 | #include "sldns/rrdef.h" | ||||
65 | #include <stdarg.h> | ||||
66 | #include <ctype.h> | ||||
67 | |||||
68 | /** number of times a key must be seen before it can become valid */ | ||||
69 | #define MIN_PENDINGCOUNT2 2 | ||||
70 | |||||
71 | /** Event: Revoked */ | ||||
72 | static void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c); | ||||
73 | |||||
74 | struct autr_global_data* autr_global_create(void) | ||||
75 | { | ||||
76 | struct autr_global_data* global; | ||||
77 | global = (struct autr_global_data*)malloc(sizeof(*global)); | ||||
78 | if(!global) | ||||
79 | return NULL((void*)0); | ||||
80 | rbtree_init(&global->probe, &probetree_cmp); | ||||
81 | return global; | ||||
82 | } | ||||
83 | |||||
84 | void autr_global_delete(struct autr_global_data* global) | ||||
85 | { | ||||
86 | if(!global) | ||||
87 | return; | ||||
88 | /* elements deleted by parent */ | ||||
89 | free(global); | ||||
90 | } | ||||
91 | |||||
92 | int probetree_cmp(const void* x, const void* y) | ||||
93 | { | ||||
94 | struct trust_anchor* a = (struct trust_anchor*)x; | ||||
95 | struct trust_anchor* b = (struct trust_anchor*)y; | ||||
96 | log_assert(a->autr && b->autr); | ||||
97 | if(a->autr->next_probe_time < b->autr->next_probe_time) | ||||
98 | return -1; | ||||
99 | if(a->autr->next_probe_time > b->autr->next_probe_time) | ||||
100 | return 1; | ||||
101 | /* time is equal, sort on trust point identity */ | ||||
102 | return anchor_cmp(x, y); | ||||
103 | } | ||||
104 | |||||
105 | size_t | ||||
106 | autr_get_num_anchors(struct val_anchors* anchors) | ||||
107 | { | ||||
108 | size_t res = 0; | ||||
109 | if(!anchors) | ||||
110 | return 0; | ||||
111 | lock_basic_lock(&anchors->lock); | ||||
112 | if(anchors->autr) | ||||
113 | res = anchors->autr->probe.count; | ||||
114 | lock_basic_unlock(&anchors->lock); | ||||
115 | return res; | ||||
116 | } | ||||
117 | |||||
118 | /** Position in string */ | ||||
119 | static int | ||||
120 | position_in_string(char *str, const char* sub) | ||||
121 | { | ||||
122 | char* pos = strstr(str, sub); | ||||
123 | if(pos) | ||||
124 | return (int)(pos-str)+(int)strlen(sub); | ||||
125 | return -1; | ||||
126 | } | ||||
127 | |||||
128 | /** Debug routine to print pretty key information */ | ||||
129 | static void | ||||
130 | verbose_key(struct autr_ta* ta, enum verbosity_value level, | ||||
131 | const char* format, ...) ATTR_FORMAT(printf, 3, 4)__attribute__ ((format (printf, 3, 4))); | ||||
132 | |||||
133 | /** | ||||
134 | * Implementation of debug pretty key print | ||||
135 | * @param ta: trust anchor key with DNSKEY data. | ||||
136 | * @param level: verbosity level to print at. | ||||
137 | * @param format: printf style format string. | ||||
138 | */ | ||||
139 | static void | ||||
140 | verbose_key(struct autr_ta* ta, enum verbosity_value level, | ||||
141 | const char* format, ...) | ||||
142 | { | ||||
143 | va_list args; | ||||
144 | va_start(args, format)__builtin_va_start(args, format); | ||||
145 | if(verbosity >= level) { | ||||
146 | char* str = sldns_wire2str_dname(ta->rr, ta->dname_len); | ||||
147 | int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata( | ||||
148 | ta->rr, ta->rr_len, ta->dname_len), | ||||
149 | sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, | ||||
150 | ta->dname_len)); | ||||
151 | char msg[MAXSYSLOGMSGLEN10240]; | ||||
152 | vsnprintf(msg, sizeof(msg), format, args); | ||||
153 | verbose(level, "%s key %d %s", str?str:"??", keytag, msg); | ||||
154 | free(str); | ||||
155 | } | ||||
156 | va_end(args)__builtin_va_end(args); | ||||
157 | } | ||||
158 | |||||
159 | /** | ||||
160 | * Parse comments | ||||
161 | * @param str: to parse | ||||
162 | * @param ta: trust key autotrust metadata | ||||
163 | * @return false on failure. | ||||
164 | */ | ||||
165 | static int | ||||
166 | parse_comments(char* str, struct autr_ta* ta) | ||||
167 | { | ||||
168 | int len = (int)strlen(str), pos = 0, timestamp = 0; | ||||
169 | char* comment = (char*) malloc(sizeof(char)*len+1); | ||||
170 | char* comments = comment; | ||||
171 | if(!comment) { | ||||
172 | log_err("malloc failure in parse"); | ||||
173 | return 0; | ||||
174 | } | ||||
175 | /* skip over whitespace and data at start of line */ | ||||
176 | while (*str != '\0' && *str != ';') | ||||
177 | str++; | ||||
178 | if (*str == ';') | ||||
179 | str++; | ||||
180 | /* copy comments */ | ||||
181 | while (*str != '\0') | ||||
182 | { | ||||
183 | *comments = *str; | ||||
184 | comments++; | ||||
185 | str++; | ||||
186 | } | ||||
187 | *comments = '\0'; | ||||
188 | |||||
189 | comments = comment; | ||||
190 | |||||
191 | /* read state */ | ||||
192 | pos = position_in_string(comments, "state="); | ||||
193 | if (pos >= (int) strlen(comments)) | ||||
194 | { | ||||
195 | log_err("parse error"); | ||||
196 | free(comment); | ||||
197 | return 0; | ||||
198 | } | ||||
199 | if (pos <= 0) | ||||
200 | ta->s = AUTR_STATE_VALID; | ||||
201 | else | ||||
202 | { | ||||
203 | int s = (int) comments[pos] - '0'; | ||||
204 | switch(s) | ||||
205 | { | ||||
206 | case AUTR_STATE_START: | ||||
207 | case AUTR_STATE_ADDPEND: | ||||
208 | case AUTR_STATE_VALID: | ||||
209 | case AUTR_STATE_MISSING: | ||||
210 | case AUTR_STATE_REVOKED: | ||||
211 | case AUTR_STATE_REMOVED: | ||||
212 | ta->s = s; | ||||
213 | break; | ||||
214 | default: | ||||
215 | verbose_key(ta, VERB_OPS, "has undefined " | ||||
216 | "state, considered NewKey"); | ||||
217 | ta->s = AUTR_STATE_START; | ||||
218 | break; | ||||
219 | } | ||||
220 | } | ||||
221 | /* read pending count */ | ||||
222 | pos = position_in_string(comments, "count="); | ||||
223 | if (pos >= (int) strlen(comments)) | ||||
224 | { | ||||
225 | log_err("parse error"); | ||||
226 | free(comment); | ||||
227 | return 0; | ||||
228 | } | ||||
229 | if (pos <= 0) | ||||
230 | ta->pending_count = 0; | ||||
231 | else | ||||
232 | { | ||||
233 | comments += pos; | ||||
234 | ta->pending_count = (uint8_t)atoi(comments); | ||||
235 | } | ||||
236 | |||||
237 | /* read last change */ | ||||
238 | pos = position_in_string(comments, "lastchange="); | ||||
239 | if (pos >= (int) strlen(comments)) | ||||
240 | { | ||||
241 | log_err("parse error"); | ||||
242 | free(comment); | ||||
243 | return 0; | ||||
244 | } | ||||
245 | if (pos >= 0) | ||||
246 | { | ||||
247 | comments += pos; | ||||
248 | timestamp = atoi(comments); | ||||
249 | } | ||||
250 | if (pos < 0 || !timestamp) | ||||
251 | ta->last_change = 0; | ||||
252 | else | ||||
253 | ta->last_change = (time_t)timestamp; | ||||
254 | |||||
255 | free(comment); | ||||
256 | return 1; | ||||
257 | } | ||||
258 | |||||
259 | /** Check if a line contains data (besides comments) */ | ||||
260 | static int | ||||
261 | str_contains_data(char* str, char comment) | ||||
262 | { | ||||
263 | while (*str != '\0') { | ||||
264 | if (*str == comment || *str == '\n') | ||||
265 | return 0; | ||||
266 | if (*str != ' ' && *str != '\t') | ||||
267 | return 1; | ||||
268 | str++; | ||||
269 | } | ||||
270 | return 0; | ||||
271 | } | ||||
272 | |||||
273 | /** Get DNSKEY flags | ||||
274 | * rdata without rdatalen in front of it. */ | ||||
275 | static int | ||||
276 | dnskey_flags(uint16_t t, uint8_t* rdata, size_t len) | ||||
277 | { | ||||
278 | uint16_t f; | ||||
279 | if(t != LDNS_RR_TYPE_DNSKEY) | ||||
280 | return 0; | ||||
281 | if(len < 2) | ||||
282 | return 0; | ||||
283 | memmove(&f, rdata, 2); | ||||
284 | f = ntohs(f)(__uint16_t)(__builtin_constant_p(f) ? (__uint16_t)(((__uint16_t )(f) & 0xffU) << 8 | ((__uint16_t)(f) & 0xff00U ) >> 8) : __swap16md(f)); | ||||
285 | return (int)f; | ||||
286 | } | ||||
287 | |||||
288 | /** Check if KSK DNSKEY. | ||||
289 | * pass rdata without rdatalen in front of it */ | ||||
290 | static int | ||||
291 | rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len) | ||||
292 | { | ||||
293 | return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP0x0001); | ||||
294 | } | ||||
295 | |||||
296 | /** Check if TA is KSK DNSKEY */ | ||||
297 | static int | ||||
298 | ta_is_dnskey_sep(struct autr_ta* ta) | ||||
299 | { | ||||
300 | return (dnskey_flags( | ||||
301 | sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len), | ||||
302 | sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len), | ||||
303 | sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) | ||||
304 | ) & DNSKEY_BIT_SEP0x0001); | ||||
305 | } | ||||
306 | |||||
307 | /** Check if REVOKED DNSKEY | ||||
308 | * pass rdata without rdatalen in front of it */ | ||||
309 | static int | ||||
310 | rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len) | ||||
311 | { | ||||
312 | return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY0x0080); | ||||
313 | } | ||||
314 | |||||
315 | /** create ta */ | ||||
316 | static struct autr_ta* | ||||
317 | autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len) | ||||
318 | { | ||||
319 | struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta)); | ||||
320 | if(!ta) { | ||||
321 | free(rr); | ||||
322 | return NULL((void*)0); | ||||
323 | } | ||||
324 | ta->rr = rr; | ||||
325 | ta->rr_len = rr_len; | ||||
326 | ta->dname_len = dname_len; | ||||
327 | return ta; | ||||
328 | } | ||||
329 | |||||
330 | /** create tp */ | ||||
331 | static struct trust_anchor* | ||||
332 | autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len, | ||||
333 | uint16_t dc) | ||||
334 | { | ||||
335 | struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp)); | ||||
336 | if(!tp) return NULL((void*)0); | ||||
337 | tp->name = memdup(own, own_len); | ||||
338 | if(!tp->name) { | ||||
339 | free(tp); | ||||
340 | return NULL((void*)0); | ||||
341 | } | ||||
342 | tp->namelen = own_len; | ||||
343 | tp->namelabs = dname_count_labels(tp->name); | ||||
344 | tp->node.key = tp; | ||||
345 | tp->dclass = dc; | ||||
346 | tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr)); | ||||
347 | if(!tp->autr) { | ||||
348 | free(tp->name); | ||||
349 | free(tp); | ||||
350 | return NULL((void*)0); | ||||
351 | } | ||||
352 | tp->autr->pnode.key = tp; | ||||
353 | |||||
354 | lock_basic_lock(&anchors->lock); | ||||
355 | if(!rbtree_insert(anchors->tree, &tp->node)) { | ||||
356 | lock_basic_unlock(&anchors->lock); | ||||
357 | log_err("trust anchor presented twice"); | ||||
358 | free(tp->name); | ||||
359 | free(tp->autr); | ||||
360 | free(tp); | ||||
361 | return NULL((void*)0); | ||||
362 | } | ||||
363 | if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) { | ||||
364 | (void)rbtree_delete(anchors->tree, tp); | ||||
365 | lock_basic_unlock(&anchors->lock); | ||||
366 | log_err("trust anchor in probetree twice"); | ||||
367 | free(tp->name); | ||||
368 | free(tp->autr); | ||||
369 | free(tp); | ||||
370 | return NULL((void*)0); | ||||
371 | } | ||||
372 | lock_basic_init(&tp->lock); | ||||
373 | lock_protect(&tp->lock, tp, sizeof(*tp)); | ||||
374 | lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr)); | ||||
375 | lock_basic_unlock(&anchors->lock); | ||||
376 | return tp; | ||||
377 | } | ||||
378 | |||||
379 | /** delete assembled rrsets */ | ||||
380 | static void | ||||
381 | autr_rrset_delete(struct ub_packed_rrset_key* r) | ||||
382 | { | ||||
383 | if(r) { | ||||
384 | free(r->rk.dname); | ||||
385 | free(r->entry.data); | ||||
386 | free(r); | ||||
387 | } | ||||
388 | } | ||||
389 | |||||
390 | void autr_point_delete(struct trust_anchor* tp) | ||||
391 | { | ||||
392 | if(!tp) | ||||
393 | return; | ||||
394 | lock_unprotect(&tp->lock, tp); | ||||
395 | lock_unprotect(&tp->lock, tp->autr); | ||||
396 | lock_basic_destroy(&tp->lock); | ||||
397 | autr_rrset_delete(tp->ds_rrset); | ||||
398 | autr_rrset_delete(tp->dnskey_rrset); | ||||
399 | if(tp->autr) { | ||||
400 | struct autr_ta* p = tp->autr->keys, *np; | ||||
401 | while(p) { | ||||
402 | np = p->next; | ||||
403 | free(p->rr); | ||||
404 | free(p); | ||||
405 | p = np; | ||||
406 | } | ||||
407 | free(tp->autr->file); | ||||
408 | free(tp->autr); | ||||
409 | } | ||||
410 | free(tp->name); | ||||
411 | free(tp); | ||||
412 | } | ||||
413 | |||||
414 | /** find or add a new trust point for autotrust */ | ||||
415 | static struct trust_anchor* | ||||
416 | find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, | ||||
417 | size_t dname_len) | ||||
418 | { | ||||
419 | struct trust_anchor* tp; | ||||
420 | tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len, | ||||
421 | sldns_wirerr_get_class(rr, rr_len, dname_len)); | ||||
422 | if(tp) { | ||||
423 | if(!tp->autr) { | ||||
424 | log_err("anchor cannot be with and without autotrust"); | ||||
425 | lock_basic_unlock(&tp->lock); | ||||
426 | return NULL((void*)0); | ||||
427 | } | ||||
428 | return tp; | ||||
429 | } | ||||
430 | tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr, | ||||
431 | rr_len, dname_len)); | ||||
432 | if(!tp) | ||||
433 | return NULL((void*)0); | ||||
434 | lock_basic_lock(&tp->lock); | ||||
435 | return tp; | ||||
436 | } | ||||
437 | |||||
438 | /** Add trust anchor from RR */ | ||||
439 | static struct autr_ta* | ||||
440 | add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, | ||||
441 | size_t dname_len, struct trust_anchor** tp) | ||||
442 | { | ||||
443 | struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len); | ||||
444 | if(!ta) | ||||
445 | return NULL((void*)0); | ||||
446 | *tp = find_add_tp(anchors, rr, rr_len, dname_len); | ||||
447 | if(!*tp) { | ||||
448 | free(ta->rr); | ||||
449 | free(ta); | ||||
450 | return NULL((void*)0); | ||||
451 | } | ||||
452 | /* add ta to tp */ | ||||
453 | ta->next = (*tp)->autr->keys; | ||||
454 | (*tp)->autr->keys = ta; | ||||
455 | lock_basic_unlock(&(*tp)->lock); | ||||
456 | return ta; | ||||
457 | } | ||||
458 | |||||
459 | /** | ||||
460 | * Add new trust anchor from a string in file. | ||||
461 | * @param anchors: all anchors | ||||
462 | * @param str: string with anchor and comments, if any comments. | ||||
463 | * @param tp: trust point returned. | ||||
464 | * @param origin: what to use for @ | ||||
465 | * @param origin_len: length of origin | ||||
466 | * @param prev: previous rr name | ||||
467 | * @param prev_len: length of prev | ||||
468 | * @param skip: if true, the result is NULL, but not an error, skip it. | ||||
469 | * @return new key in trust point. | ||||
470 | */ | ||||
471 | static struct autr_ta* | ||||
472 | add_trustanchor_frm_str(struct val_anchors* anchors, char* str, | ||||
473 | struct trust_anchor** tp, uint8_t* origin, size_t origin_len, | ||||
474 | uint8_t** prev, size_t* prev_len, int* skip) | ||||
475 | { | ||||
476 | uint8_t rr[LDNS_RR_BUF_SIZE65535]; | ||||
477 | size_t rr_len = sizeof(rr), dname_len; | ||||
478 | uint8_t* drr; | ||||
479 | int lstatus; | ||||
480 | if (!str_contains_data(str, ';')) { | ||||
481 | *skip = 1; | ||||
482 | return NULL((void*)0); /* empty line */ | ||||
483 | } | ||||
484 | if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len, | ||||
485 | 0, origin, origin_len, *prev, *prev_len))) | ||||
486 | { | ||||
487 | log_err("ldns error while converting string to RR at%d: %s: %s", | ||||
488 | LDNS_WIREPARSE_OFFSET(lstatus)(((lstatus)&~0x0fff)>>12), | ||||
489 | sldns_get_errorstr_parse(lstatus), str); | ||||
490 | return NULL((void*)0); | ||||
491 | } | ||||
492 | free(*prev); | ||||
493 | *prev = memdup(rr, dname_len); | ||||
494 | *prev_len = dname_len; | ||||
495 | if(!*prev) { | ||||
496 | log_err("malloc failure in add_trustanchor"); | ||||
497 | return NULL((void*)0); | ||||
498 | } | ||||
499 | if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY && | ||||
500 | sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) { | ||||
501 | *skip = 1; | ||||
502 | return NULL((void*)0); /* only DS and DNSKEY allowed */ | ||||
503 | } | ||||
504 | drr = memdup(rr, rr_len); | ||||
505 | if(!drr) { | ||||
506 | log_err("malloc failure in add trustanchor"); | ||||
507 | return NULL((void*)0); | ||||
508 | } | ||||
509 | return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp); | ||||
510 | } | ||||
511 | |||||
512 | /** | ||||
513 | * Load single anchor | ||||
514 | * @param anchors: all points. | ||||
515 | * @param str: comments line | ||||
516 | * @param fname: filename | ||||
517 | * @param origin: the $ORIGIN. | ||||
518 | * @param origin_len: length of origin | ||||
519 | * @param prev: passed to ldns. | ||||
520 | * @param prev_len: length of prev | ||||
521 | * @param skip: if true, the result is NULL, but not an error, skip it. | ||||
522 | * @return false on failure, otherwise the tp read. | ||||
523 | */ | ||||
524 | static struct trust_anchor* | ||||
525 | load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, | ||||
526 | uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, | ||||
527 | int* skip) | ||||
528 | { | ||||
529 | struct autr_ta* ta = NULL((void*)0); | ||||
530 | struct trust_anchor* tp = NULL((void*)0); | ||||
531 | |||||
532 | ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len, | ||||
533 | prev, prev_len, skip); | ||||
534 | if(!ta) | ||||
535 | return NULL((void*)0); | ||||
536 | lock_basic_lock(&tp->lock); | ||||
537 | if(!parse_comments(str, ta)) { | ||||
538 | lock_basic_unlock(&tp->lock); | ||||
539 | return NULL((void*)0); | ||||
540 | } | ||||
541 | if(!tp->autr->file) { | ||||
542 | tp->autr->file = strdup(fname); | ||||
543 | if(!tp->autr->file) { | ||||
544 | lock_basic_unlock(&tp->lock); | ||||
545 | log_err("malloc failure"); | ||||
546 | return NULL((void*)0); | ||||
547 | } | ||||
548 | } | ||||
549 | lock_basic_unlock(&tp->lock); | ||||
550 | return tp; | ||||
551 | } | ||||
552 | |||||
553 | /** iterator for DSes from keylist. return true if a next element exists */ | ||||
554 | static int | ||||
555 | assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len, | ||||
556 | size_t* dname_len) | ||||
557 | { | ||||
558 | while(*list) { | ||||
559 | if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, | ||||
560 | (*list)->dname_len) == LDNS_RR_TYPE_DS) { | ||||
561 | *rr = (*list)->rr; | ||||
562 | *rr_len = (*list)->rr_len; | ||||
563 | *dname_len = (*list)->dname_len; | ||||
564 | *list = (*list)->next; | ||||
565 | return 1; | ||||
566 | } | ||||
567 | *list = (*list)->next; | ||||
568 | } | ||||
569 | return 0; | ||||
570 | } | ||||
571 | |||||
572 | /** iterator for DNSKEYs from keylist. return true if a next element exists */ | ||||
573 | static int | ||||
574 | assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len, | ||||
575 | size_t* dname_len) | ||||
576 | { | ||||
577 | while(*list) { | ||||
578 | if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, | ||||
579 | (*list)->dname_len) != LDNS_RR_TYPE_DS && | ||||
580 | ((*list)->s == AUTR_STATE_VALID || | ||||
581 | (*list)->s == AUTR_STATE_MISSING)) { | ||||
582 | *rr = (*list)->rr; | ||||
583 | *rr_len = (*list)->rr_len; | ||||
584 | *dname_len = (*list)->dname_len; | ||||
585 | *list = (*list)->next; | ||||
586 | return 1; | ||||
587 | } | ||||
588 | *list = (*list)->next; | ||||
589 | } | ||||
590 | return 0; | ||||
591 | } | ||||
592 | |||||
593 | /** see if iterator-list has any elements in it, or it is empty */ | ||||
594 | static int | ||||
595 | assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*, | ||||
596 | size_t*), struct autr_ta* list) | ||||
597 | { | ||||
598 | uint8_t* rr = NULL((void*)0); | ||||
599 | size_t rr_len = 0, dname_len = 0; | ||||
600 | return iter(&list, &rr, &rr_len, &dname_len); | ||||
601 | } | ||||
602 | |||||
603 | /** number of elements in iterator list */ | ||||
604 | static size_t | ||||
605 | assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*, | ||||
606 | size_t*), struct autr_ta* list) | ||||
607 | { | ||||
608 | uint8_t* rr = NULL((void*)0); | ||||
609 | size_t i = 0, rr_len = 0, dname_len = 0; | ||||
610 | while(iter(&list, &rr, &rr_len, &dname_len)) { | ||||
611 | i++; | ||||
612 | } | ||||
613 | return i; | ||||
614 | } | ||||
615 | |||||
616 | /** | ||||
617 | * Create a ub_packed_rrset_key allocated on the heap. | ||||
618 | * It therefore does not have the correct ID value, and cannot be used | ||||
619 | * inside the cache. It can be used in storage outside of the cache. | ||||
620 | * Keys for the cache have to be obtained from alloc.h . | ||||
621 | * @param iter: iterator over the elements in the list. It filters elements. | ||||
622 | * @param list: the list. | ||||
623 | * @return key allocated or NULL on failure. | ||||
624 | */ | ||||
625 | static struct ub_packed_rrset_key* | ||||
626 | ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*, | ||||
627 | size_t*), struct autr_ta* list) | ||||
628 | { | ||||
629 | uint8_t* rr = NULL((void*)0); | ||||
630 | size_t rr_len = 0, dname_len = 0; | ||||
631 | struct ub_packed_rrset_key* k; | ||||
632 | if(!iter(&list, &rr, &rr_len, &dname_len)) | ||||
633 | return NULL((void*)0); | ||||
634 | k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k)); | ||||
635 | if(!k) | ||||
636 | return NULL((void*)0); | ||||
637 | k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len))(__uint16_t)(__builtin_constant_p(sldns_wirerr_get_type(rr, rr_len , dname_len)) ? (__uint16_t)(((__uint16_t)(sldns_wirerr_get_type (rr, rr_len, dname_len)) & 0xffU) << 8 | ((__uint16_t )(sldns_wirerr_get_type(rr, rr_len, dname_len)) & 0xff00U ) >> 8) : __swap16md(sldns_wirerr_get_type(rr, rr_len, dname_len ))); | ||||
638 | k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len))(__uint16_t)(__builtin_constant_p(sldns_wirerr_get_class(rr, rr_len , dname_len)) ? (__uint16_t)(((__uint16_t)(sldns_wirerr_get_class (rr, rr_len, dname_len)) & 0xffU) << 8 | ((__uint16_t )(sldns_wirerr_get_class(rr, rr_len, dname_len)) & 0xff00U ) >> 8) : __swap16md(sldns_wirerr_get_class(rr, rr_len, dname_len))); | ||||
639 | k->rk.dname_len = dname_len; | ||||
640 | k->rk.dname = memdup(rr, dname_len); | ||||
641 | if(!k->rk.dname) { | ||||
642 | free(k); | ||||
643 | return NULL((void*)0); | ||||
644 | } | ||||
645 | return k; | ||||
646 | } | ||||
647 | |||||
648 | /** | ||||
649 | * Create packed_rrset data on the heap. | ||||
650 | * @param iter: iterator over the elements in the list. It filters elements. | ||||
651 | * @param list: the list. | ||||
652 | * @return data allocated or NULL on failure. | ||||
653 | */ | ||||
654 | static struct packed_rrset_data* | ||||
655 | packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*, | ||||
656 | size_t*), struct autr_ta* list) | ||||
657 | { | ||||
658 | uint8_t* rr = NULL((void*)0); | ||||
659 | size_t rr_len = 0, dname_len = 0; | ||||
660 | struct packed_rrset_data* data; | ||||
661 | size_t count=0, rrsig_count=0, len=0, i, total; | ||||
662 | uint8_t* nextrdata; | ||||
663 | struct autr_ta* list_i; | ||||
664 | time_t ttl = 0; | ||||
665 | |||||
666 | list_i = list; | ||||
667 | while(iter(&list_i, &rr, &rr_len, &dname_len)) { | ||||
668 | if(sldns_wirerr_get_type(rr, rr_len, dname_len) == | ||||
669 | LDNS_RR_TYPE_RRSIG) | ||||
670 | rrsig_count++; | ||||
671 | else count++; | ||||
672 | /* sizeof the rdlength + rdatalen */ | ||||
673 | len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); | ||||
674 | ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len); | ||||
675 | } | ||||
676 | if(count
| ||||
677 | return NULL((void*)0); | ||||
678 | |||||
679 | /* allocate */ | ||||
680 | total = count + rrsig_count; | ||||
681 | len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) + | ||||
682 | sizeof(uint8_t*)); | ||||
683 | data = (struct packed_rrset_data*)calloc(1, len); | ||||
684 | if(!data) | ||||
685 | return NULL((void*)0); | ||||
686 | |||||
687 | /* fill it */ | ||||
688 | data->ttl = ttl; | ||||
689 | data->count = count; | ||||
690 | data->rrsig_count = rrsig_count; | ||||
691 | data->rr_len = (size_t*)((uint8_t*)data + | ||||
692 | sizeof(struct packed_rrset_data)); | ||||
693 | data->rr_data = (uint8_t**)&(data->rr_len[total]); | ||||
694 | data->rr_ttl = (time_t*)&(data->rr_data[total]); | ||||
695 | nextrdata = (uint8_t*)&(data->rr_ttl[total]); | ||||
696 | |||||
697 | /* fill out len, ttl, fields */ | ||||
698 | list_i = list; | ||||
699 | i = 0; | ||||
700 | while(iter(&list_i, &rr, &rr_len, &dname_len)) { | ||||
701 | data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, | ||||
702 | dname_len); | ||||
703 | if(data->rr_ttl[i] < data->ttl) | ||||
704 | data->ttl = data->rr_ttl[i]; | ||||
705 | data->rr_len[i] = 2 /* the rdlength */ + | ||||
706 | sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); | ||||
707 | i++; | ||||
708 | } | ||||
709 | |||||
710 | /* fixup rest of ptrs */ | ||||
711 | for(i=0; i<total; i++) { | ||||
712 | data->rr_data[i] = nextrdata; | ||||
713 | nextrdata += data->rr_len[i]; | ||||
714 | } | ||||
715 | |||||
716 | /* copy data in there */ | ||||
717 | list_i = list; | ||||
718 | i = 0; | ||||
719 | while(iter(&list_i, &rr, &rr_len, &dname_len)) { | ||||
720 | log_assert(data->rr_data[i]); | ||||
721 | memmove(data->rr_data[i], | ||||
| |||||
722 | sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), | ||||
723 | data->rr_len[i]); | ||||
724 | i++; | ||||
725 | } | ||||
726 | |||||
727 | if(data->rrsig_count && data->count == 0) { | ||||
728 | data->count = data->rrsig_count; /* rrset type is RRSIG */ | ||||
729 | data->rrsig_count = 0; | ||||
730 | } | ||||
731 | return data; | ||||
732 | } | ||||
733 | |||||
734 | /** | ||||
735 | * Assemble the trust anchors into DS and DNSKEY packed rrsets. | ||||
736 | * Uses only VALID and MISSING DNSKEYs. | ||||
737 | * Read the sldns_rrs and builds packed rrsets | ||||
738 | * @param tp: the trust point. Must be locked. | ||||
739 | * @return false on malloc failure. | ||||
740 | */ | ||||
741 | static int | ||||
742 | autr_assemble(struct trust_anchor* tp) | ||||
743 | { | ||||
744 | struct ub_packed_rrset_key* ubds=NULL((void*)0), *ubdnskey=NULL((void*)0); | ||||
745 | |||||
746 | /* make packed rrset keys - malloced with no ID number, they | ||||
747 | * are not in the cache */ | ||||
748 | /* make packed rrset data (if there is a key) */ | ||||
749 | if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) { | ||||
750 | ubds = ub_packed_rrset_heap_key( | ||||
751 | assemble_iterate_ds, tp->autr->keys); | ||||
752 | if(!ubds
| ||||
753 | goto error_cleanup; | ||||
754 | ubds->entry.data = packed_rrset_heap_data( | ||||
755 | assemble_iterate_ds, tp->autr->keys); | ||||
756 | if(!ubds->entry.data) | ||||
757 | goto error_cleanup; | ||||
758 | } | ||||
759 | |||||
760 | /* make packed DNSKEY data */ | ||||
761 | if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) { | ||||
762 | ubdnskey = ub_packed_rrset_heap_key( | ||||
763 | assemble_iterate_dnskey, tp->autr->keys); | ||||
764 | if(!ubdnskey) | ||||
765 | goto error_cleanup; | ||||
766 | ubdnskey->entry.data = packed_rrset_heap_data( | ||||
767 | assemble_iterate_dnskey, tp->autr->keys); | ||||
768 | if(!ubdnskey->entry.data) { | ||||
769 | error_cleanup: | ||||
770 | autr_rrset_delete(ubds); | ||||
771 | autr_rrset_delete(ubdnskey); | ||||
772 | return 0; | ||||
773 | } | ||||
774 | } | ||||
775 | |||||
776 | /* we have prepared the new keys so nothing can go wrong any more. | ||||
777 | * And we are sure we cannot be left without trustanchor after | ||||
778 | * any errors. Put in the new keys and remove old ones. */ | ||||
779 | |||||
780 | /* free the old data */ | ||||
781 | autr_rrset_delete(tp->ds_rrset); | ||||
782 | autr_rrset_delete(tp->dnskey_rrset); | ||||
783 | |||||
784 | /* assign the data to replace the old */ | ||||
785 | tp->ds_rrset = ubds; | ||||
786 | tp->dnskey_rrset = ubdnskey; | ||||
787 | tp->numDS = assemble_iterate_count(assemble_iterate_ds, | ||||
788 | tp->autr->keys); | ||||
789 | tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey, | ||||
790 | tp->autr->keys); | ||||
791 | return 1; | ||||
792 | } | ||||
793 | |||||
794 | /** parse integer */ | ||||
795 | static unsigned int | ||||
796 | parse_int(char* line, int* ret) | ||||
797 | { | ||||
798 | char *e; | ||||
799 | unsigned int x = (unsigned int)strtol(line, &e, 10); | ||||
800 | if(line == e) { | ||||
801 | *ret = -1; /* parse error */ | ||||
802 | return 0; | ||||
803 | } | ||||
804 | *ret = 1; /* matched */ | ||||
805 | return x; | ||||
806 | } | ||||
807 | |||||
808 | /** parse id sequence for anchor */ | ||||
809 | static struct trust_anchor* | ||||
810 | parse_id(struct val_anchors* anchors, char* line) | ||||
811 | { | ||||
812 | struct trust_anchor *tp; | ||||
813 | int r; | ||||
814 | uint16_t dclass; | ||||
815 | uint8_t* dname; | ||||
816 | size_t dname_len; | ||||
817 | /* read the owner name */ | ||||
818 | char* next = strchr(line, ' '); | ||||
819 | if(!next) | ||||
820 | return NULL((void*)0); | ||||
821 | next[0] = 0; | ||||
822 | dname = sldns_str2wire_dname(line, &dname_len); | ||||
823 | if(!dname) | ||||
824 | return NULL((void*)0); | ||||
825 | |||||
826 | /* read the class */ | ||||
827 | dclass = parse_int(next+1, &r); | ||||
828 | if(r == -1) { | ||||
829 | free(dname); | ||||
830 | return NULL((void*)0); | ||||
831 | } | ||||
832 | |||||
833 | /* find the trust point */ | ||||
834 | tp = autr_tp_create(anchors, dname, dname_len, dclass); | ||||
835 | free(dname); | ||||
836 | return tp; | ||||
837 | } | ||||
838 | |||||
839 | /** | ||||
840 | * Parse variable from trustanchor header | ||||
841 | * @param line: to parse | ||||
842 | * @param anchors: the anchor is added to this, if "id:" is seen. | ||||
843 | * @param anchor: the anchor as result value or previously returned anchor | ||||
844 | * value to read the variable lines into. | ||||
845 | * @return: 0 no match, -1 failed syntax error, +1 success line read. | ||||
846 | * +2 revoked trust anchor file. | ||||
847 | */ | ||||
848 | static int | ||||
849 | parse_var_line(char* line, struct val_anchors* anchors, | ||||
850 | struct trust_anchor** anchor) | ||||
851 | { | ||||
852 | struct trust_anchor* tp = *anchor; | ||||
853 | int r = 0; | ||||
854 | if(strncmp(line, ";;id: ", 6) == 0) { | ||||
855 | *anchor = parse_id(anchors, line+6); | ||||
856 | if(!*anchor) return -1; | ||||
857 | else return 1; | ||||
858 | } else if(strncmp(line, ";;REVOKED", 9) == 0) { | ||||
859 | if(tp) { | ||||
860 | log_err("REVOKED statement must be at start of file"); | ||||
861 | return -1; | ||||
862 | } | ||||
863 | return 2; | ||||
864 | } else if(strncmp(line, ";;last_queried: ", 16) == 0) { | ||||
865 | if(!tp) return -1; | ||||
866 | lock_basic_lock(&tp->lock); | ||||
867 | tp->autr->last_queried = (time_t)parse_int(line+16, &r); | ||||
868 | lock_basic_unlock(&tp->lock); | ||||
869 | } else if(strncmp(line, ";;last_success: ", 16) == 0) { | ||||
870 | if(!tp) return -1; | ||||
871 | lock_basic_lock(&tp->lock); | ||||
872 | tp->autr->last_success = (time_t)parse_int(line+16, &r); | ||||
873 | lock_basic_unlock(&tp->lock); | ||||
874 | } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) { | ||||
875 | if(!tp) return -1; | ||||
876 | lock_basic_lock(&anchors->lock); | ||||
877 | lock_basic_lock(&tp->lock); | ||||
878 | (void)rbtree_delete(&anchors->autr->probe, tp); | ||||
879 | tp->autr->next_probe_time = (time_t)parse_int(line+19, &r); | ||||
880 | (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode); | ||||
881 | lock_basic_unlock(&tp->lock); | ||||
882 | lock_basic_unlock(&anchors->lock); | ||||
883 | } else if(strncmp(line, ";;query_failed: ", 16) == 0) { | ||||
884 | if(!tp) return -1; | ||||
885 | lock_basic_lock(&tp->lock); | ||||
886 | tp->autr->query_failed = (uint8_t)parse_int(line+16, &r); | ||||
887 | lock_basic_unlock(&tp->lock); | ||||
888 | } else if(strncmp(line, ";;query_interval: ", 18) == 0) { | ||||
889 | if(!tp) return -1; | ||||
890 | lock_basic_lock(&tp->lock); | ||||
891 | tp->autr->query_interval = (time_t)parse_int(line+18, &r); | ||||
892 | lock_basic_unlock(&tp->lock); | ||||
893 | } else if(strncmp(line, ";;retry_time: ", 14) == 0) { | ||||
894 | if(!tp) return -1; | ||||
895 | lock_basic_lock(&tp->lock); | ||||
896 | tp->autr->retry_time = (time_t)parse_int(line+14, &r); | ||||
897 | lock_basic_unlock(&tp->lock); | ||||
898 | } | ||||
899 | return r; | ||||
900 | } | ||||
901 | |||||
902 | /** handle origin lines */ | ||||
903 | static int | ||||
904 | handle_origin(char* line, uint8_t** origin, size_t* origin_len) | ||||
905 | { | ||||
906 | size_t len = 0; | ||||
907 | while(isspace((unsigned char)*line)) | ||||
908 | line++; | ||||
909 | if(strncmp(line, "$ORIGIN", 7) != 0) | ||||
910 | return 0; | ||||
911 | free(*origin); | ||||
912 | line += 7; | ||||
913 | while(isspace((unsigned char)*line)) | ||||
914 | line++; | ||||
915 | *origin = sldns_str2wire_dname(line, &len); | ||||
916 | *origin_len = len; | ||||
917 | if(!*origin) | ||||
918 | log_warn("malloc failure or parse error in $ORIGIN"); | ||||
919 | return 1; | ||||
920 | } | ||||
921 | |||||
922 | /** Read one line and put multiline RRs onto one line string */ | ||||
923 | static int | ||||
924 | read_multiline(char* buf, size_t len, FILE* in, int* linenr) | ||||
925 | { | ||||
926 | char* pos = buf; | ||||
927 | size_t left = len; | ||||
928 | int depth = 0; | ||||
929 | buf[len-1] = 0; | ||||
930 | while(left > 0 && fgets(pos, (int)left, in) != NULL((void*)0)) { | ||||
931 | size_t i, poslen = strlen(pos); | ||||
932 | (*linenr)++; | ||||
933 | |||||
934 | /* check what the new depth is after the line */ | ||||
935 | /* this routine cannot handle braces inside quotes, | ||||
936 | say for TXT records, but this routine only has to read keys */ | ||||
937 | for(i=0; i<poslen; i++) { | ||||
938 | if(pos[i] == '(') { | ||||
939 | depth++; | ||||
940 | } else if(pos[i] == ')') { | ||||
941 | if(depth == 0) { | ||||
942 | log_err("mismatch: too many ')'"); | ||||
943 | return -1; | ||||
944 | } | ||||
945 | depth--; | ||||
946 | } else if(pos[i] == ';') { | ||||
947 | break; | ||||
948 | } | ||||
949 | } | ||||
950 | |||||
951 | /* normal oneline or last line: keeps newline and comments */ | ||||
952 | if(depth == 0) { | ||||
953 | return 1; | ||||
954 | } | ||||
955 | |||||
956 | /* more lines expected, snip off comments and newline */ | ||||
957 | if(poslen>0) | ||||
958 | pos[poslen-1] = 0; /* strip newline */ | ||||
959 | if(strchr(pos, ';')) | ||||
960 | strchr(pos, ';')[0] = 0; /* strip comments */ | ||||
961 | |||||
962 | /* move to paste other lines behind this one */ | ||||
963 | poslen = strlen(pos); | ||||
964 | pos += poslen; | ||||
965 | left -= poslen; | ||||
966 | /* the newline is changed into a space */ | ||||
967 | if(left <= 2 /* space and eos */) { | ||||
968 | log_err("line too long"); | ||||
969 | return -1; | ||||
970 | } | ||||
971 | pos[0] = ' '; | ||||
972 | pos[1] = 0; | ||||
973 | pos += 1; | ||||
974 | left -= 1; | ||||
975 | } | ||||
976 | if(depth != 0) { | ||||
977 | log_err("mismatch: too many '('"); | ||||
978 | return -1; | ||||
979 | } | ||||
980 | if(pos != buf) | ||||
981 | return 1; | ||||
982 | return 0; | ||||
983 | } | ||||
984 | |||||
985 | int autr_read_file(struct val_anchors* anchors, const char* nm) | ||||
986 | { | ||||
987 | /* the file descriptor */ | ||||
988 | FILE* fd; | ||||
989 | /* keep track of line numbers */ | ||||
990 | int line_nr = 0; | ||||
991 | /* single line */ | ||||
992 | char line[10240]; | ||||
993 | /* trust point being read */ | ||||
994 | struct trust_anchor *tp = NULL((void*)0), *tp2; | ||||
995 | int r; | ||||
996 | /* for $ORIGIN parsing */ | ||||
997 | uint8_t *origin=NULL((void*)0), *prev=NULL((void*)0); | ||||
998 | size_t origin_len=0, prev_len=0; | ||||
999 | |||||
1000 | if (!(fd = fopen(nm, "r"))) { | ||||
1001 | log_err("unable to open %s for reading: %s", | ||||
1002 | nm, strerror(errno(*__errno()))); | ||||
1003 | return 0; | ||||
1004 | } | ||||
1005 | verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); | ||||
1006 | while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { | ||||
1007 | if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { | ||||
1008 | log_err("could not parse auto-trust-anchor-file " | ||||
1009 | "%s line %d", nm, line_nr); | ||||
1010 | fclose(fd); | ||||
1011 | free(origin); | ||||
1012 | free(prev); | ||||
1013 | return 0; | ||||
1014 | } else if(r == 1) { | ||||
1015 | continue; | ||||
1016 | } else if(r == 2) { | ||||
1017 | log_warn("trust anchor %s has been revoked", nm); | ||||
1018 | fclose(fd); | ||||
1019 | free(origin); | ||||
1020 | free(prev); | ||||
1021 | return 1; | ||||
1022 | } | ||||
1023 | if (!str_contains_data(line, ';')) | ||||
1024 | continue; /* empty lines allowed */ | ||||
1025 | if(handle_origin(line, &origin, &origin_len)) | ||||
1026 | continue; | ||||
1027 | r = 0; | ||||
1028 | if(!(tp2=load_trustanchor(anchors, line, nm, origin, | ||||
1029 | origin_len, &prev, &prev_len, &r))) { | ||||
1030 | if(!r) log_err("failed to load trust anchor from %s " | ||||
1031 | "at line %i, skipping", nm, line_nr); | ||||
1032 | /* try to do the rest */ | ||||
1033 | continue; | ||||
1034 | } | ||||
1035 | if(tp && tp != tp2) { | ||||
1036 | log_err("file %s has mismatching data inside: " | ||||
1037 | "the file may only contain keys for one name, " | ||||
1038 | "remove keys for other domain names", nm); | ||||
1039 | fclose(fd); | ||||
1040 | free(origin); | ||||
1041 | free(prev); | ||||
1042 | return 0; | ||||
1043 | } | ||||
1044 | tp = tp2; | ||||
1045 | } | ||||
1046 | fclose(fd); | ||||
1047 | free(origin); | ||||
1048 | free(prev); | ||||
1049 | if(!tp) { | ||||
1050 | log_err("failed to read %s", nm); | ||||
1051 | return 0; | ||||
1052 | } | ||||
1053 | |||||
1054 | /* now assemble the data into DNSKEY and DS packed rrsets */ | ||||
1055 | lock_basic_lock(&tp->lock); | ||||
1056 | if(!autr_assemble(tp)) { | ||||
1057 | lock_basic_unlock(&tp->lock); | ||||
1058 | log_err("malloc failure assembling %s", nm); | ||||
1059 | return 0; | ||||
1060 | } | ||||
1061 | lock_basic_unlock(&tp->lock); | ||||
1062 | return 1; | ||||
1063 | } | ||||
1064 | |||||
1065 | /** string for a trustanchor state */ | ||||
1066 | static const char* | ||||
1067 | trustanchor_state2str(autr_state_type s) | ||||
1068 | { | ||||
1069 | switch (s) { | ||||
1070 | case AUTR_STATE_START: return " START "; | ||||
1071 | case AUTR_STATE_ADDPEND: return " ADDPEND "; | ||||
1072 | case AUTR_STATE_VALID: return " VALID "; | ||||
1073 | case AUTR_STATE_MISSING: return " MISSING "; | ||||
1074 | case AUTR_STATE_REVOKED: return " REVOKED "; | ||||
1075 | case AUTR_STATE_REMOVED: return " REMOVED "; | ||||
1076 | } | ||||
1077 | return " UNKNOWN "; | ||||
1078 | } | ||||
1079 | |||||
1080 | /** ctime r for autotrust */ | ||||
1081 | static char* autr_ctime_r(time_t* t, char* s) | ||||
1082 | { | ||||
1083 | ctime_r(t, s); | ||||
1084 | #ifdef USE_WINSOCK | ||||
1085 | if(strlen(s) > 10 && s[7]==' ' && s[8]=='0') | ||||
1086 | s[8]=' '; /* fix error in windows ctime */ | ||||
1087 | #endif | ||||
1088 | return s; | ||||
1089 | } | ||||
1090 | |||||
1091 | /** print ID to file */ | ||||
1092 | static int | ||||
1093 | print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass) | ||||
1094 | { | ||||
1095 | char* s = sldns_wire2str_dname(nm, nmlen); | ||||
1096 | if(!s) { | ||||
1097 | log_err("malloc failure in write to %s", fname); | ||||
1098 | return 0; | ||||
1099 | } | ||||
1100 | if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) { | ||||
1101 | log_err("could not write to %s: %s", fname, strerror(errno(*__errno()))); | ||||
1102 | free(s); | ||||
1103 | return 0; | ||||
1104 | } | ||||
1105 | free(s); | ||||
1106 | return 1; | ||||
1107 | } | ||||
1108 | |||||
1109 | static int | ||||
1110 | autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) | ||||
1111 | { | ||||
1112 | char tmi[32]; | ||||
1113 | struct autr_ta* ta; | ||||
1114 | char* str; | ||||
1115 | |||||
1116 | /* write pretty header */ | ||||
1117 | if(fprintf(out, "; autotrust trust anchor file\n") < 0) { | ||||
1118 | log_err("could not write to %s: %s", fn, strerror(errno(*__errno()))); | ||||
1119 | return 0; | ||||
1120 | } | ||||
1121 | if(tp->autr->revoked) { | ||||
1122 | if(fprintf(out, ";;REVOKED\n") < 0 || | ||||
1123 | fprintf(out, "; The zone has all keys revoked, and is\n" | ||||
1124 | "; considered as if it has no trust anchors.\n" | ||||
1125 | "; the remainder of the file is the last probe.\n" | ||||
1126 | "; to restart the trust anchor, overwrite this file.\n" | ||||
1127 | "; with one containing valid DNSKEYs or DSes.\n") < 0) { | ||||
1128 | log_err("could not write to %s: %s", fn, strerror(errno(*__errno()))); | ||||
1129 | return 0; | ||||
1130 | } | ||||
1131 | } | ||||
1132 | if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) { | ||||
1133 | return 0; | ||||
1134 | } | ||||
1135 | if(fprintf(out, ";;last_queried: %u ;;%s", | ||||
1136 | (unsigned int)tp->autr->last_queried, | ||||
1137 | autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 || | ||||
1138 | fprintf(out, ";;last_success: %u ;;%s", | ||||
1139 | (unsigned int)tp->autr->last_success, | ||||
1140 | autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 || | ||||
1141 | fprintf(out, ";;next_probe_time: %u ;;%s", | ||||
1142 | (unsigned int)tp->autr->next_probe_time, | ||||
1143 | autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || | ||||
1144 | fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0 | ||||
1145 | || fprintf(out, ";;query_interval: %d\n", | ||||
1146 | (int)tp->autr->query_interval) < 0 || | ||||
1147 | fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) { | ||||
1148 | log_err("could not write to %s: %s", fn, strerror(errno(*__errno()))); | ||||
1149 | return 0; | ||||
1150 | } | ||||
1151 | |||||
1152 | /* write anchors */ | ||||
1153 | for(ta=tp->autr->keys; ta; ta=ta->next) { | ||||
1154 | /* by default do not store START and REMOVED keys */ | ||||
1155 | if(ta->s == AUTR_STATE_START) | ||||
1156 | continue; | ||||
1157 | if(ta->s == AUTR_STATE_REMOVED) | ||||
1158 | continue; | ||||
1159 | /* only store keys */ | ||||
1160 | if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) | ||||
1161 | != LDNS_RR_TYPE_DNSKEY) | ||||
1162 | continue; | ||||
1163 | str = sldns_wire2str_rr(ta->rr, ta->rr_len); | ||||
1164 | if(!str || !str[0]) { | ||||
1165 | free(str); | ||||
1166 | log_err("malloc failure writing %s", fn); | ||||
1167 | return 0; | ||||
1168 | } | ||||
1169 | str[strlen(str)-1] = 0; /* remove newline */ | ||||
1170 | if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d " | ||||
1171 | ";;lastchange=%u ;;%s", str, (int)ta->s, | ||||
1172 | trustanchor_state2str(ta->s), (int)ta->pending_count, | ||||
1173 | (unsigned int)ta->last_change, | ||||
1174 | autr_ctime_r(&(ta->last_change), tmi)) < 0) { | ||||
1175 | log_err("could not write to %s: %s", fn, strerror(errno(*__errno()))); | ||||
1176 | free(str); | ||||
1177 | return 0; | ||||
1178 | } | ||||
1179 | free(str); | ||||
1180 | } | ||||
1181 | return 1; | ||||
1182 | } | ||||
1183 | |||||
1184 | void autr_write_file(struct module_env* env, struct trust_anchor* tp) | ||||
1185 | { | ||||
1186 | FILE* out; | ||||
1187 | char* fname = tp->autr->file; | ||||
1188 | #ifndef S_SPLINT_S | ||||
1189 | long long llvalue; | ||||
1190 | #endif | ||||
1191 | char tempf[2048]; | ||||
1192 | log_assert(tp->autr); | ||||
1193 | if(!env) { | ||||
1194 | log_err("autr_write_file: Module environment is NULL."); | ||||
1195 | return; | ||||
1196 | } | ||||
1197 | /* unique name with pid number, thread number, and struct pointer | ||||
1198 | * (the pointer uniquifies for multiple libunbound contexts) */ | ||||
1199 | #ifndef S_SPLINT_S | ||||
1200 | #if defined(SIZE_MAX0xffffffffffffffffUL) && defined(UINT32_MAX0xffffffffU) && (UINT32_MAX0xffffffffU == SIZE_MAX0xffffffffffffffffUL || INT32_MAX0x7fffffff == SIZE_MAX0xffffffffffffffffUL) | ||||
1201 | /* avoid warning about upcast on 32bit systems */ | ||||
1202 | llvalue = (unsigned long)tp; | ||||
1203 | #else | ||||
1204 | llvalue = (unsigned long long)tp; | ||||
1205 | #endif | ||||
1206 | #ifndef USE_WINSOCK | ||||
1207 | snprintf(tempf, sizeof(tempf), "%s.%d-%d-%llx", fname, (int)getpid(), | ||||
1208 | env->worker?*(int*)env->worker:0, llvalue); | ||||
1209 | #else | ||||
1210 | snprintf(tempf, sizeof(tempf), "%s.%d-%d-%I64x", fname, (int)getpid(), | ||||
1211 | env->worker?*(int*)env->worker:0, llvalue); | ||||
1212 | #endif | ||||
1213 | #endif /* S_SPLINT_S */ | ||||
1214 | verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf); | ||||
1215 | out = fopen(tempf, "w"); | ||||
1216 | if(!out) { | ||||
1217 | fatal_exit("could not open autotrust file for writing, %s: %s", | ||||
1218 | tempf, strerror(errno(*__errno()))); | ||||
1219 | return; | ||||
1220 | } | ||||
1221 | if(!autr_write_contents(out, tempf, tp)) { | ||||
1222 | /* failed to write contents (completely) */ | ||||
1223 | fclose(out); | ||||
1224 | unlink(tempf); | ||||
1225 | fatal_exit("could not completely write: %s", fname); | ||||
1226 | return; | ||||
1227 | } | ||||
1228 | if(fflush(out) != 0) | ||||
1229 | log_err("could not fflush(%s): %s", fname, strerror(errno(*__errno()))); | ||||
1230 | #ifdef HAVE_FSYNC1 | ||||
1231 | if(fsync(fileno(out)(!__isthreaded ? ((out)->_file) : (fileno)(out))) != 0) | ||||
1232 | log_err("could not fsync(%s): %s", fname, strerror(errno(*__errno()))); | ||||
1233 | #else | ||||
1234 | FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); | ||||
1235 | #endif | ||||
1236 | if(fclose(out) != 0) { | ||||
1237 | fatal_exit("could not complete write: %s: %s", | ||||
1238 | fname, strerror(errno(*__errno()))); | ||||
1239 | unlink(tempf); | ||||
1240 | return; | ||||
1241 | } | ||||
1242 | /* success; overwrite actual file */ | ||||
1243 | verbose(VERB_ALGO, "autotrust: replaced %s", fname); | ||||
1244 | #ifdef UB_ON_WINDOWS | ||||
1245 | (void)unlink(fname); /* windows does not replace file with rename() */ | ||||
1246 | #endif | ||||
1247 | if(rename(tempf, fname) < 0) { | ||||
1248 | fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno(*__errno()))); | ||||
1249 | } | ||||
1250 | } | ||||
1251 | |||||
1252 | /** | ||||
1253 | * Verify if dnskey works for trust point | ||||
1254 | * @param env: environment (with time) for verification | ||||
1255 | * @param ve: validator environment (with options) for verification. | ||||
1256 | * @param tp: trust point to verify with | ||||
1257 | * @param rrset: DNSKEY rrset to verify. | ||||
1258 | * @param qstate: qstate with region. | ||||
1259 | * @return false on failure, true if verification successful. | ||||
1260 | */ | ||||
1261 | static int | ||||
1262 | verify_dnskey(struct module_env* env, struct val_env* ve, | ||||
1263 | struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, | ||||
1264 | struct module_qstate* qstate) | ||||
1265 | { | ||||
1266 | char* reason = NULL((void*)0); | ||||
1267 | uint8_t sigalg[ALGO_NEEDS_MAX256+1]; | ||||
1268 | int downprot = env->cfg->harden_algo_downgrade; | ||||
1269 | enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, | ||||
1270 | tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL((void*)0), &reason, | ||||
1271 | qstate); | ||||
1272 | /* sigalg is ignored, it returns algorithms signalled to exist, but | ||||
1273 | * in 5011 there are no other rrsets to check. if downprot is | ||||
1274 | * enabled, then it checks that the DNSKEY is signed with all | ||||
1275 | * algorithms available in the trust store. */ | ||||
1276 | verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s", | ||||
1277 | sec_status_to_string(sec)); | ||||
1278 | return sec == sec_status_secure; | ||||
1279 | } | ||||
1280 | |||||
1281 | static int32_t | ||||
1282 | rrsig_get_expiry(uint8_t* d, size_t len) | ||||
1283 | { | ||||
1284 | /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */ | ||||
1285 | if(len < 2+8+4) | ||||
1286 | return 0; | ||||
1287 | return sldns_read_uint32(d+2+8); | ||||
1288 | } | ||||
1289 | |||||
1290 | /** Find minimum expiration interval from signatures */ | ||||
1291 | static time_t | ||||
1292 | min_expiry(struct module_env* env, struct packed_rrset_data* dd) | ||||
1293 | { | ||||
1294 | size_t i; | ||||
1295 | int32_t t, r = 15 * 24 * 3600; /* 15 days max */ | ||||
1296 | for(i=dd->count; i<dd->count+dd->rrsig_count; i++) { | ||||
1297 | t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]); | ||||
1298 | if((int32_t)t - (int32_t)*env->now > 0) { | ||||
1299 | t -= (int32_t)*env->now; | ||||
1300 | if(t < r) | ||||
1301 | r = t; | ||||
1302 | } | ||||
1303 | } | ||||
1304 | return (time_t)r; | ||||
1305 | } | ||||
1306 | |||||
1307 | /** Is rr self-signed revoked key */ | ||||
1308 | static int | ||||
1309 | rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, | ||||
1310 | struct ub_packed_rrset_key* dnskey_rrset, size_t i, | ||||
1311 | struct module_qstate* qstate) | ||||
1312 | { | ||||
1313 | enum sec_status sec; | ||||
1314 | char* reason = NULL((void*)0); | ||||
1315 | verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", | ||||
1316 | (int)i); | ||||
1317 | /* no algorithm downgrade protection necessary, if it is selfsigned | ||||
1318 | * revoked it can be removed. */ | ||||
1319 | sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, | ||||
1320 | &reason, LDNS_SECTION_ANSWER, qstate); | ||||
1321 | return (sec == sec_status_secure); | ||||
1322 | } | ||||
1323 | |||||
1324 | /** Set fetched value */ | ||||
1325 | static void | ||||
1326 | seen_trustanchor(struct autr_ta* ta, uint8_t seen) | ||||
1327 | { | ||||
1328 | ta->fetched = seen; | ||||
1329 | if(ta->pending_count < 250) /* no numerical overflow, please */ | ||||
1330 | ta->pending_count++; | ||||
1331 | } | ||||
1332 | |||||
1333 | /** set revoked value */ | ||||
1334 | static void | ||||
1335 | seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked) | ||||
1336 | { | ||||
1337 | ta->revoked = revoked; | ||||
1338 | } | ||||
1339 | |||||
1340 | /** revoke a trust anchor */ | ||||
1341 | static void | ||||
1342 | revoke_dnskey(struct autr_ta* ta, int off) | ||||
1343 | { | ||||
1344 | uint16_t flags; | ||||
1345 | uint8_t* data; | ||||
1346 | if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) != | ||||
1347 | LDNS_RR_TYPE_DNSKEY) | ||||
1348 | return; | ||||
1349 | if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2) | ||||
1350 | return; | ||||
1351 | data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len); | ||||
1352 | flags = sldns_read_uint16(data); | ||||
1353 | if (off && (flags&LDNS_KEY_REVOKE_KEY0x0080)) | ||||
1354 | flags ^= LDNS_KEY_REVOKE_KEY0x0080; /* flip */ | ||||
1355 | else | ||||
1356 | flags |= LDNS_KEY_REVOKE_KEY0x0080; | ||||
1357 | sldns_write_uint16(data, flags); | ||||
1358 | } | ||||
1359 | |||||
1360 | /** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */ | ||||
1361 | static int | ||||
1362 | dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len) | ||||
1363 | { | ||||
1364 | size_t i; | ||||
1365 | if(a_len != b_len) | ||||
1366 | return -1; | ||||
1367 | /* compare RRs RDATA byte for byte. */ | ||||
1368 | for(i = 0; i < a_len; i++) | ||||
1369 | { | ||||
1370 | uint8_t rdf1, rdf2; | ||||
1371 | rdf1 = a[i]; | ||||
1372 | rdf2 = b[i]; | ||||
1373 | if(i==1) { | ||||
1374 | /* this is the second part of the flags field */ | ||||
1375 | rdf1 |= LDNS_KEY_REVOKE_KEY0x0080; | ||||
1376 | rdf2 |= LDNS_KEY_REVOKE_KEY0x0080; | ||||
1377 | } | ||||
1378 | if (rdf1 < rdf2) return -1; | ||||
1379 | else if (rdf1 > rdf2) return 1; | ||||
1380 | } | ||||
1381 | return 0; | ||||
1382 | } | ||||
1383 | |||||
1384 | |||||
1385 | /** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */ | ||||
1386 | static int | ||||
1387 | ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len) | ||||
1388 | { | ||||
1389 | if(!a) return -1; | ||||
1390 | else if(!b) return -1; | ||||
1391 | else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t) | ||||
1392 | return (int)sldns_wirerr_get_type(a->rr, a->rr_len, | ||||
1393 | a->dname_len) - (int)t; | ||||
1394 | else if(t == LDNS_RR_TYPE_DNSKEY) { | ||||
1395 | return dnskey_compare_skip_revbit( | ||||
1396 | sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len), | ||||
1397 | sldns_wirerr_get_rdatalen(a->rr, a->rr_len, | ||||
1398 | a->dname_len), b, b_len); | ||||
1399 | } | ||||
1400 | else if(t == LDNS_RR_TYPE_DS) { | ||||
1401 | if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) != | ||||
1402 | b_len) | ||||
1403 | return -1; | ||||
1404 | return memcmp(sldns_wirerr_get_rdata(a->rr, | ||||
1405 | a->rr_len, a->dname_len), b, b_len); | ||||
1406 | } | ||||
1407 | return -1; | ||||
1408 | } | ||||
1409 | |||||
1410 | /** | ||||
1411 | * Find key | ||||
1412 | * @param tp: to search in | ||||
1413 | * @param t: rr type of the rdata. | ||||
1414 | * @param rdata: to look for (no rdatalen in it) | ||||
1415 | * @param rdata_len: length of rdata | ||||
1416 | * @param result: returns NULL or the ta key looked for. | ||||
1417 | * @return false on malloc failure during search. if true examine result. | ||||
1418 | */ | ||||
1419 | static int | ||||
1420 | find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len, | ||||
1421 | struct autr_ta** result) | ||||
1422 | { | ||||
1423 | struct autr_ta* ta; | ||||
1424 | if(!tp || !rdata) { | ||||
1425 | *result = NULL((void*)0); | ||||
1426 | return 0; | ||||
1427 | } | ||||
1428 | for(ta=tp->autr->keys; ta; ta=ta->next) { | ||||
1429 | if(ta_compare(ta, t, rdata, rdata_len) == 0) { | ||||
1430 | *result = ta; | ||||
1431 | return 1; | ||||
1432 | } | ||||
1433 | } | ||||
1434 | *result = NULL((void*)0); | ||||
1435 | return 1; | ||||
1436 | } | ||||
1437 | |||||
1438 | /** add key and clone RR and tp already locked. rdata without rdlen. */ | ||||
1439 | static struct autr_ta* | ||||
1440 | add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len) | ||||
1441 | { | ||||
1442 | struct autr_ta* ta; | ||||
1443 | uint8_t* rr; | ||||
1444 | size_t rr_len, dname_len; | ||||
1445 | uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY)(__uint16_t)(__builtin_constant_p(LDNS_RR_TYPE_DNSKEY) ? (__uint16_t )(((__uint16_t)(LDNS_RR_TYPE_DNSKEY) & 0xffU) << 8 | ((__uint16_t)(LDNS_RR_TYPE_DNSKEY) & 0xff00U) >> 8 ) : __swap16md(LDNS_RR_TYPE_DNSKEY)); | ||||
1446 | uint16_t rrclass = htons(LDNS_RR_CLASS_IN)(__uint16_t)(__builtin_constant_p(LDNS_RR_CLASS_IN) ? (__uint16_t )(((__uint16_t)(LDNS_RR_CLASS_IN) & 0xffU) << 8 | ( (__uint16_t)(LDNS_RR_CLASS_IN) & 0xff00U) >> 8) : __swap16md (LDNS_RR_CLASS_IN)); | ||||
1447 | uint16_t rdlen = htons(rdata_len)(__uint16_t)(__builtin_constant_p(rdata_len) ? (__uint16_t)(( (__uint16_t)(rdata_len) & 0xffU) << 8 | ((__uint16_t )(rdata_len) & 0xff00U) >> 8) : __swap16md(rdata_len )); | ||||
1448 | dname_len = tp->namelen; | ||||
1449 | ttl = htonl(ttl)(__uint32_t)(__builtin_constant_p(ttl) ? (__uint32_t)(((__uint32_t )(ttl) & 0xff) << 24 | ((__uint32_t)(ttl) & 0xff00 ) << 8 | ((__uint32_t)(ttl) & 0xff0000) >> 8 | ((__uint32_t)(ttl) & 0xff000000) >> 24) : __swap32md (ttl)); | ||||
1450 | rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len; | ||||
1451 | rr = (uint8_t*)malloc(rr_len); | ||||
1452 | if(!rr) return NULL((void*)0); | ||||
1453 | memmove(rr, tp->name, tp->namelen); | ||||
1454 | memmove(rr+dname_len, &rrtype, 2); | ||||
1455 | memmove(rr+dname_len+2, &rrclass, 2); | ||||
1456 | memmove(rr+dname_len+4, &ttl, 4); | ||||
1457 | memmove(rr+dname_len+8, &rdlen, 2); | ||||
1458 | memmove(rr+dname_len+10, rdata, rdata_len); | ||||
1459 | ta = autr_ta_create(rr, rr_len, dname_len); | ||||
1460 | if(!ta) { | ||||
1461 | /* rr freed in autr_ta_create */ | ||||
1462 | return NULL((void*)0); | ||||
1463 | } | ||||
1464 | /* link in, tp already locked */ | ||||
1465 | ta->next = tp->autr->keys; | ||||
1466 | tp->autr->keys = ta; | ||||
1467 | return ta; | ||||
1468 | } | ||||
1469 | |||||
1470 | /** get TTL from DNSKEY rrset */ | ||||
1471 | static time_t | ||||
1472 | key_ttl(struct ub_packed_rrset_key* k) | ||||
1473 | { | ||||
1474 | struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; | ||||
1475 | return d->ttl; | ||||
1476 | } | ||||
1477 | |||||
1478 | /** update the time values for the trustpoint */ | ||||
1479 | static void | ||||
1480 | set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, | ||||
1481 | time_t origttl, int* changed) | ||||
1482 | { | ||||
1483 | time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; | ||||
1484 | |||||
1485 | /* x = MIN(15days, ttl/2, expire/2) */ | ||||
1486 | x = 15 * 24 * 3600; | ||||
1487 | if(origttl/2 < x) | ||||
1488 | x = origttl/2; | ||||
1489 | if(rrsig_exp_interval/2 < x) | ||||
1490 | x = rrsig_exp_interval/2; | ||||
1491 | /* MAX(1hr, x) */ | ||||
1492 | if(!autr_permit_small_holddown) { | ||||
1493 | if(x < 3600) | ||||
1494 | tp->autr->query_interval = 3600; | ||||
1495 | else tp->autr->query_interval = x; | ||||
1496 | } else tp->autr->query_interval = x; | ||||
1497 | |||||
1498 | /* x= MIN(1day, ttl/10, expire/10) */ | ||||
1499 | x = 24 * 3600; | ||||
1500 | if(origttl/10 < x) | ||||
1501 | x = origttl/10; | ||||
1502 | if(rrsig_exp_interval/10 < x) | ||||
1503 | x = rrsig_exp_interval/10; | ||||
1504 | /* MAX(1hr, x) */ | ||||
1505 | if(!autr_permit_small_holddown) { | ||||
1506 | if(x < 3600) | ||||
1507 | tp->autr->retry_time = 3600; | ||||
1508 | else tp->autr->retry_time = x; | ||||
1509 | } else tp->autr->retry_time = x; | ||||
1510 | |||||
1511 | if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { | ||||
1512 | *changed = 1; | ||||
1513 | verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl); | ||||
1514 | verbose(VERB_ALGO, "rrsig_exp_interval is %d", | ||||
1515 | (int)rrsig_exp_interval); | ||||
1516 | verbose(VERB_ALGO, "query_interval: %d, retry_time: %d", | ||||
1517 | (int)tp->autr->query_interval, | ||||
1518 | (int)tp->autr->retry_time); | ||||
1519 | } | ||||
1520 | } | ||||
1521 | |||||
1522 | /** init events to zero */ | ||||
1523 | static void | ||||
1524 | init_events(struct trust_anchor* tp) | ||||
1525 | { | ||||
1526 | struct autr_ta* ta; | ||||
1527 | for(ta=tp->autr->keys; ta; ta=ta->next) { | ||||
1528 | ta->fetched = 0; | ||||
1529 | } | ||||
1530 | } | ||||
1531 | |||||
1532 | /** check for revoked keys without trusting any other information */ | ||||
1533 | static void | ||||
1534 | check_contains_revoked(struct module_env* env, struct val_env* ve, | ||||
1535 | struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, | ||||
1536 | int* changed, struct module_qstate* qstate) | ||||
1537 | { | ||||
1538 | struct packed_rrset_data* dd = (struct packed_rrset_data*) | ||||
1539 | dnskey_rrset->entry.data; | ||||
1540 | size_t i; | ||||
1541 | log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); | ||||
1542 | for(i=0; i<dd->count; i++) { | ||||
1543 | struct autr_ta* ta = NULL((void*)0); | ||||
1544 | if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1545 | dd->rr_data[i]+2, dd->rr_len[i]-2) || | ||||
1546 | !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1547 | dd->rr_data[i]+2, dd->rr_len[i]-2)) | ||||
1548 | continue; /* not a revoked KSK */ | ||||
1549 | if(!find_key(tp, ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1550 | dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { | ||||
1551 | log_err("malloc failure"); | ||||
1552 | continue; /* malloc fail in compare*/ | ||||
1553 | } | ||||
1554 | if(!ta) | ||||
1555 | continue; /* key not found */ | ||||
1556 | if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) { | ||||
1557 | /* checked if there is an rrsig signed by this key. */ | ||||
1558 | /* same keytag, but stored can be revoked already, so | ||||
1559 | * compare keytags, with +0 or +128(REVOKE flag) */ | ||||
1560 | log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 == | ||||
1561 | sldns_calc_keytag_raw(sldns_wirerr_get_rdata( | ||||
1562 | ta->rr, ta->rr_len, ta->dname_len), | ||||
1563 | sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, | ||||
1564 | ta->dname_len)) || | ||||
1565 | dnskey_calc_keytag(dnskey_rrset, i) == | ||||
1566 | sldns_calc_keytag_raw(sldns_wirerr_get_rdata( | ||||
1567 | ta->rr, ta->rr_len, ta->dname_len), | ||||
1568 | sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, | ||||
1569 | ta->dname_len))); /* checks conversion*/ | ||||
1570 | verbose_key(ta, VERB_ALGO, "is self-signed revoked"); | ||||
1571 | if(!ta->revoked) | ||||
1572 | *changed = 1; | ||||
1573 | seen_revoked_trustanchor(ta, 1); | ||||
1574 | do_revoked(env, ta, changed); | ||||
1575 | } | ||||
1576 | } | ||||
1577 | } | ||||
1578 | |||||
1579 | /** See if a DNSKEY is verified by one of the DSes */ | ||||
1580 | static int | ||||
1581 | key_matches_a_ds(struct module_env* env, struct val_env* ve, | ||||
1582 | struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx, | ||||
1583 | struct ub_packed_rrset_key* ds_rrset) | ||||
1584 | { | ||||
1585 | struct packed_rrset_data* dd = (struct packed_rrset_data*) | ||||
1586 | ds_rrset->entry.data; | ||||
1587 | size_t ds_idx, num = dd->count; | ||||
1588 | int d = val_favorite_ds_algo(ds_rrset); | ||||
1589 | char* reason = ""; | ||||
1590 | for(ds_idx=0; ds_idx<num; ds_idx++) { | ||||
1591 | if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) || | ||||
1592 | !ds_key_algo_is_supported(ds_rrset, ds_idx) || | ||||
1593 | !dnskey_size_is_supported(dnskey_rrset, key_idx) || | ||||
1594 | ds_get_digest_algo(ds_rrset, ds_idx) != d) | ||||
1595 | continue; | ||||
1596 | if(ds_get_key_algo(ds_rrset, ds_idx) | ||||
1597 | != dnskey_get_algo(dnskey_rrset, key_idx) | ||||
1598 | || dnskey_calc_keytag(dnskey_rrset, key_idx) | ||||
1599 | != ds_get_keytag(ds_rrset, ds_idx)) { | ||||
1600 | continue; | ||||
1601 | } | ||||
1602 | if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx, | ||||
1603 | ds_rrset, ds_idx)) { | ||||
1604 | verbose(VERB_ALGO, "DS match attempt failed"); | ||||
1605 | continue; | ||||
1606 | } | ||||
1607 | /* match of hash is sufficient for bootstrap of trust point */ | ||||
1608 | (void)reason; | ||||
1609 | (void)ve; | ||||
1610 | return 1; | ||||
1611 | /* no need to check RRSIG, DS hash already matched with source | ||||
1612 | if(dnskey_verify_rrset(env, ve, dnskey_rrset, | ||||
1613 | dnskey_rrset, key_idx, &reason) == sec_status_secure) { | ||||
1614 | return 1; | ||||
1615 | } else { | ||||
1616 | verbose(VERB_ALGO, "DS match failed because the key " | ||||
1617 | "does not verify the keyset: %s", reason); | ||||
1618 | } | ||||
1619 | */ | ||||
1620 | } | ||||
1621 | return 0; | ||||
1622 | } | ||||
1623 | |||||
1624 | /** Set update events */ | ||||
1625 | static int | ||||
1626 | update_events(struct module_env* env, struct val_env* ve, | ||||
1627 | struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, | ||||
1628 | int* changed) | ||||
1629 | { | ||||
1630 | struct packed_rrset_data* dd = (struct packed_rrset_data*) | ||||
1631 | dnskey_rrset->entry.data; | ||||
1632 | size_t i; | ||||
1633 | log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); | ||||
1634 | init_events(tp); | ||||
1635 | for(i=0; i<dd->count; i++) { | ||||
1636 | struct autr_ta* ta = NULL((void*)0); | ||||
1637 | if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1638 | dd->rr_data[i]+2, dd->rr_len[i]-2)) | ||||
1639 | continue; | ||||
1640 | if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1641 | dd->rr_data[i]+2, dd->rr_len[i]-2)) { | ||||
1642 | /* self-signed revoked keys already detected before, | ||||
1643 | * other revoked keys are not 'added' again */ | ||||
1644 | continue; | ||||
1645 | } | ||||
1646 | /* is a key of this type supported?. Note rr_list and | ||||
1647 | * packed_rrset are in the same order. */ | ||||
1648 | if(!dnskey_algo_is_supported(dnskey_rrset, i) || | ||||
1649 | !dnskey_size_is_supported(dnskey_rrset, i)) { | ||||
1650 | /* skip unknown algorithm key, it is useless to us */ | ||||
1651 | log_nametypeclass(VERB_DETAIL, "trust point has " | ||||
1652 | "unsupported algorithm at", | ||||
1653 | tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); | ||||
1654 | continue; | ||||
1655 | } | ||||
1656 | |||||
1657 | /* is it new? if revocation bit set, find the unrevoked key */ | ||||
1658 | if(!find_key(tp, ntohs(dnskey_rrset->rk.type)(__uint16_t)(__builtin_constant_p(dnskey_rrset->rk.type) ? (__uint16_t)(((__uint16_t)(dnskey_rrset->rk.type) & 0xffU ) << 8 | ((__uint16_t)(dnskey_rrset->rk.type) & 0xff00U ) >> 8) : __swap16md(dnskey_rrset->rk.type)), | ||||
1659 | dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { | ||||
1660 | return 0; | ||||
1661 | } | ||||
1662 | if(!ta) { | ||||
1663 | ta = add_key(tp, (uint32_t)dd->rr_ttl[i], | ||||
1664 | dd->rr_data[i]+2, dd->rr_len[i]-2); | ||||
1665 | *changed = 1; | ||||
1666 | /* first time seen, do we have DSes? if match: VALID */ | ||||
1667 | if(ta && tp->ds_rrset && key_matches_a_ds(env, ve, | ||||
1668 | dnskey_rrset, i, tp->ds_rrset)) { | ||||
1669 | verbose_key(ta, VERB_ALGO, "verified by DS"); | ||||
1670 | ta->s = AUTR_STATE_VALID; | ||||
1671 | } | ||||
1672 | } | ||||
1673 | if(!ta) { | ||||
1674 | return 0; | ||||
1675 | } | ||||
1676 | seen_trustanchor(ta, 1); | ||||
1677 | verbose_key(ta, VERB_ALGO, "in DNS response"); | ||||
1678 | } | ||||
1679 | set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed); | ||||
1680 | return 1; | ||||
1681 | } | ||||
1682 | |||||
1683 | /** | ||||
1684 | * Check if the holddown time has already exceeded | ||||
1685 | * setting: add-holddown: add holddown timer | ||||
1686 | * setting: del-holddown: del holddown timer | ||||
1687 | * @param env: environment with current time | ||||
1688 | * @param ta: trust anchor to check for. | ||||
1689 | * @param holddown: the timer value | ||||
1690 | * @return number of seconds the holddown has passed. | ||||
1691 | */ | ||||
1692 | static time_t | ||||
1693 | check_holddown(struct module_env* env, struct autr_ta* ta, | ||||
1694 | unsigned int holddown) | ||||
1695 | { | ||||
1696 | time_t elapsed; | ||||
1697 | if(*env->now < ta->last_change) { | ||||
1698 | log_warn("time goes backwards. delaying key holddown"); | ||||
1699 | return 0; | ||||
1700 | } | ||||
1701 | elapsed = *env->now - ta->last_change; | ||||
1702 | if (elapsed > (time_t)holddown) { | ||||
1703 | return elapsed-(time_t)holddown; | ||||
1704 | } | ||||
1705 | verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL"%ll" "d seconds to go", | ||||
1706 | (long long) ((time_t)holddown-elapsed)); | ||||
1707 | return 0; | ||||
1708 | } | ||||
1709 | |||||
1710 | |||||
1711 | /** Set last_change to now */ | ||||
1712 | static void | ||||
1713 | reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed) | ||||
1714 | { | ||||
1715 | ta->last_change = *env->now; | ||||
1716 | *changed = 1; | ||||
1717 | } | ||||
1718 | |||||
1719 | /** Set the state for this trust anchor */ | ||||
1720 | static void | ||||
1721 | set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed, | ||||
1722 | autr_state_type s) | ||||
1723 | { | ||||
1724 | verbose_key(ta, VERB_ALGO, "update: %s to %s", | ||||
1725 | trustanchor_state2str(ta->s), trustanchor_state2str(s)); | ||||
1726 | ta->s = s; | ||||
1727 | reset_holddown(env, ta, changed); | ||||
1728 | } | ||||
1729 | |||||
1730 | |||||
1731 | /** Event: NewKey */ | ||||
1732 | static void | ||||
1733 | do_newkey(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1734 | { | ||||
1735 | if (anchor->s == AUTR_STATE_START) | ||||
1736 | set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND); | ||||
1737 | } | ||||
1738 | |||||
1739 | /** Event: AddTime */ | ||||
1740 | static void | ||||
1741 | do_addtime(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1742 | { | ||||
1743 | /* This not according to RFC, this is 30 days, but the RFC demands | ||||
1744 | * MAX(30days, TTL expire time of first DNSKEY set with this key), | ||||
1745 | * The value may be too small if a very large TTL was used. */ | ||||
1746 | time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown); | ||||
1747 | if (exceeded && anchor->s == AUTR_STATE_ADDPEND) { | ||||
1748 | verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded " | ||||
1749 | ARG_LL"%ll" "d seconds ago, and pending-count %d", | ||||
1750 | (long long)exceeded, anchor->pending_count); | ||||
1751 | if(anchor->pending_count >= MIN_PENDINGCOUNT2) { | ||||
1752 | set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); | ||||
1753 | anchor->pending_count = 0; | ||||
1754 | return; | ||||
1755 | } | ||||
1756 | verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check " | ||||
1757 | "failed (pending count: %d)", anchor->pending_count); | ||||
1758 | } | ||||
1759 | } | ||||
1760 | |||||
1761 | /** Event: RemTime */ | ||||
1762 | static void | ||||
1763 | do_remtime(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1764 | { | ||||
1765 | time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown); | ||||
1766 | if(exceeded && anchor->s == AUTR_STATE_REVOKED) { | ||||
1767 | verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded " | ||||
1768 | ARG_LL"%ll" "d seconds ago", (long long)exceeded); | ||||
1769 | set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED); | ||||
1770 | } | ||||
1771 | } | ||||
1772 | |||||
1773 | /** Event: KeyRem */ | ||||
1774 | static void | ||||
1775 | do_keyrem(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1776 | { | ||||
1777 | if(anchor->s == AUTR_STATE_ADDPEND) { | ||||
1778 | set_trustanchor_state(env, anchor, c, AUTR_STATE_START); | ||||
1779 | anchor->pending_count = 0; | ||||
1780 | } else if(anchor->s == AUTR_STATE_VALID) | ||||
1781 | set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING); | ||||
1782 | } | ||||
1783 | |||||
1784 | /** Event: KeyPres */ | ||||
1785 | static void | ||||
1786 | do_keypres(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1787 | { | ||||
1788 | if(anchor->s == AUTR_STATE_MISSING) | ||||
1789 | set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); | ||||
1790 | } | ||||
1791 | |||||
1792 | /* Event: Revoked */ | ||||
1793 | static void | ||||
1794 | do_revoked(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1795 | { | ||||
1796 | if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) { | ||||
1797 | set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED); | ||||
1798 | verbose_key(anchor, VERB_ALGO, "old id, prior to revocation"); | ||||
1799 | revoke_dnskey(anchor, 0); | ||||
1800 | verbose_key(anchor, VERB_ALGO, "new id, after revocation"); | ||||
1801 | } | ||||
1802 | } | ||||
1803 | |||||
1804 | /** Do statestable transition matrix for anchor */ | ||||
1805 | static void | ||||
1806 | anchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c) | ||||
1807 | { | ||||
1808 | log_assert(anchor); | ||||
1809 | switch(anchor->s) { | ||||
1810 | /* START */ | ||||
1811 | case AUTR_STATE_START: | ||||
1812 | /* NewKey: ADDPEND */ | ||||
1813 | if (anchor->fetched) | ||||
1814 | do_newkey(env, anchor, c); | ||||
1815 | break; | ||||
1816 | /* ADDPEND */ | ||||
1817 | case AUTR_STATE_ADDPEND: | ||||
1818 | /* KeyRem: START */ | ||||
1819 | if (!anchor->fetched) | ||||
1820 | do_keyrem(env, anchor, c); | ||||
1821 | /* AddTime: VALID */ | ||||
1822 | else do_addtime(env, anchor, c); | ||||
1823 | break; | ||||
1824 | /* VALID */ | ||||
1825 | case AUTR_STATE_VALID: | ||||
1826 | /* RevBit: REVOKED */ | ||||
1827 | if (anchor->revoked) | ||||
1828 | do_revoked(env, anchor, c); | ||||
1829 | /* KeyRem: MISSING */ | ||||
1830 | else if (!anchor->fetched) | ||||
1831 | do_keyrem(env, anchor, c); | ||||
1832 | else if(!anchor->last_change) { | ||||
1833 | verbose_key(anchor, VERB_ALGO, "first seen"); | ||||
1834 | reset_holddown(env, anchor, c); | ||||
1835 | } | ||||
1836 | break; | ||||
1837 | /* MISSING */ | ||||
1838 | case AUTR_STATE_MISSING: | ||||
1839 | /* RevBit: REVOKED */ | ||||
1840 | if (anchor->revoked) | ||||
1841 | do_revoked(env, anchor, c); | ||||
1842 | /* KeyPres */ | ||||
1843 | else if (anchor->fetched) | ||||
1844 | do_keypres(env, anchor, c); | ||||
1845 | break; | ||||
1846 | /* REVOKED */ | ||||
1847 | case AUTR_STATE_REVOKED: | ||||
1848 | if (anchor->fetched) | ||||
1849 | reset_holddown(env, anchor, c); | ||||
1850 | /* RemTime: REMOVED */ | ||||
1851 | else do_remtime(env, anchor, c); | ||||
1852 | break; | ||||
1853 | /* REMOVED */ | ||||
1854 | case AUTR_STATE_REMOVED: | ||||
1855 | default: | ||||
1856 | break; | ||||
1857 | } | ||||
1858 | } | ||||
1859 | |||||
1860 | /** if ZSK init then trust KSKs */ | ||||
1861 | static int | ||||
1862 | init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed) | ||||
1863 | { | ||||
1864 | /* search for VALID ZSKs */ | ||||
1865 | struct autr_ta* anchor; | ||||
1866 | int validzsk = 0; | ||||
1867 | int validksk = 0; | ||||
1868 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1869 | /* last_change test makes sure it was manually configured */ | ||||
1870 | if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len, | ||||
1871 | anchor->dname_len) == LDNS_RR_TYPE_DNSKEY && | ||||
1872 | anchor->last_change == 0 && | ||||
1873 | !ta_is_dnskey_sep(anchor) && | ||||
1874 | anchor->s == AUTR_STATE_VALID) | ||||
1875 | validzsk++; | ||||
1876 | } | ||||
1877 | if(validzsk == 0) | ||||
1878 | return 0; | ||||
1879 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1880 | if (ta_is_dnskey_sep(anchor) && | ||||
1881 | anchor->s == AUTR_STATE_ADDPEND) { | ||||
1882 | verbose_key(anchor, VERB_ALGO, "trust KSK from " | ||||
1883 | "ZSK(config)"); | ||||
1884 | set_trustanchor_state(env, anchor, changed, | ||||
1885 | AUTR_STATE_VALID); | ||||
1886 | validksk++; | ||||
1887 | } | ||||
1888 | } | ||||
1889 | return validksk; | ||||
1890 | } | ||||
1891 | |||||
1892 | /** Remove missing trustanchors so the list does not grow forever */ | ||||
1893 | static void | ||||
1894 | remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, | ||||
1895 | int* changed) | ||||
1896 | { | ||||
1897 | struct autr_ta* anchor; | ||||
1898 | time_t exceeded; | ||||
1899 | int valid = 0; | ||||
1900 | /* see if we have anchors that are valid */ | ||||
1901 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1902 | /* Only do KSKs */ | ||||
1903 | if (!ta_is_dnskey_sep(anchor)) | ||||
1904 | continue; | ||||
1905 | if (anchor->s == AUTR_STATE_VALID) | ||||
1906 | valid++; | ||||
1907 | } | ||||
1908 | /* if there are no SEP Valid anchors, see if we started out with | ||||
1909 | * a ZSK (last-change=0) anchor, which is VALID and there are KSKs | ||||
1910 | * now that can be made valid. Do this immediately because there | ||||
1911 | * is no guarantee that the ZSKs get announced long enough. Usually | ||||
1912 | * this is immediately after init with a ZSK trusted, unless the domain | ||||
1913 | * was not advertising any KSKs at all. In which case we perfectly | ||||
1914 | * track the zero number of KSKs. */ | ||||
1915 | if(valid == 0) { | ||||
1916 | valid = init_zsk_to_ksk(env, tp, changed); | ||||
1917 | if(valid == 0) | ||||
1918 | return; | ||||
1919 | } | ||||
1920 | |||||
1921 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1922 | /* ignore ZSKs if newly added */ | ||||
1923 | if(anchor->s == AUTR_STATE_START) | ||||
1924 | continue; | ||||
1925 | /* remove ZSKs if a KSK is present */ | ||||
1926 | if (!ta_is_dnskey_sep(anchor)) { | ||||
1927 | if(valid > 0) { | ||||
1928 | verbose_key(anchor, VERB_ALGO, "remove ZSK " | ||||
1929 | "[%d key(s) VALID]", valid); | ||||
1930 | set_trustanchor_state(env, anchor, changed, | ||||
1931 | AUTR_STATE_REMOVED); | ||||
1932 | } | ||||
1933 | continue; | ||||
1934 | } | ||||
1935 | /* Only do MISSING keys */ | ||||
1936 | if (anchor->s != AUTR_STATE_MISSING) | ||||
1937 | continue; | ||||
1938 | if(env->cfg->keep_missing == 0) | ||||
1939 | continue; /* keep forever */ | ||||
1940 | |||||
1941 | exceeded = check_holddown(env, anchor, env->cfg->keep_missing); | ||||
1942 | /* If keep_missing has exceeded and we still have more than | ||||
1943 | * one valid KSK: remove missing trust anchor */ | ||||
1944 | if (exceeded && valid > 0) { | ||||
1945 | verbose_key(anchor, VERB_ALGO, "keep-missing time " | ||||
1946 | "exceeded " ARG_LL"%ll" "d seconds ago, [%d key(s) VALID]", | ||||
1947 | (long long)exceeded, valid); | ||||
1948 | set_trustanchor_state(env, anchor, changed, | ||||
1949 | AUTR_STATE_REMOVED); | ||||
1950 | } | ||||
1951 | } | ||||
1952 | } | ||||
1953 | |||||
1954 | /** Do the statetable from RFC5011 transition matrix */ | ||||
1955 | static int | ||||
1956 | do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed) | ||||
1957 | { | ||||
1958 | struct autr_ta* anchor; | ||||
1959 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1960 | /* Only do KSKs */ | ||||
1961 | if(!ta_is_dnskey_sep(anchor)) | ||||
1962 | continue; | ||||
1963 | anchor_state_update(env, anchor, changed); | ||||
1964 | } | ||||
1965 | remove_missing_trustanchors(env, tp, changed); | ||||
1966 | return 1; | ||||
1967 | } | ||||
1968 | |||||
1969 | /** See if time alone makes ADDPEND to VALID transition */ | ||||
1970 | static void | ||||
1971 | autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c) | ||||
1972 | { | ||||
1973 | struct autr_ta* anchor; | ||||
1974 | for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { | ||||
1975 | if(ta_is_dnskey_sep(anchor) && | ||||
1976 | anchor->s == AUTR_STATE_ADDPEND) | ||||
1977 | do_addtime(env, anchor, c); | ||||
1978 | } | ||||
1979 | } | ||||
1980 | |||||
1981 | /** cleanup key list */ | ||||
1982 | static void | ||||
1983 | autr_cleanup_keys(struct trust_anchor* tp) | ||||
1984 | { | ||||
1985 | struct autr_ta* p, **prevp; | ||||
1986 | prevp = &tp->autr->keys; | ||||
1987 | p = tp->autr->keys; | ||||
1988 | while(p) { | ||||
1989 | /* do we want to remove this key? */ | ||||
1990 | if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED || | ||||
1991 | sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len) | ||||
1992 | != LDNS_RR_TYPE_DNSKEY) { | ||||
1993 | struct autr_ta* np = p->next; | ||||
1994 | /* remove */ | ||||
1995 | free(p->rr); | ||||
1996 | free(p); | ||||
1997 | /* snip and go to next item */ | ||||
1998 | *prevp = np; | ||||
1999 | p = np; | ||||
2000 | continue; | ||||
2001 | } | ||||
2002 | /* remove pending counts if no longer pending */ | ||||
2003 | if(p->s != AUTR_STATE_ADDPEND) | ||||
2004 | p->pending_count = 0; | ||||
2005 | prevp = &p->next; | ||||
2006 | p = p->next; | ||||
2007 | } | ||||
2008 | } | ||||
2009 | |||||
2010 | /** calculate next probe time */ | ||||
2011 | static time_t | ||||
2012 | calc_next_probe(struct module_env* env, time_t wait) | ||||
2013 | { | ||||
2014 | /* make it random, 90-100% */ | ||||
2015 | time_t rnd, rest; | ||||
2016 | if(!autr_permit_small_holddown) { | ||||
2017 | if(wait < 3600) | ||||
2018 | wait = 3600; | ||||
2019 | } else { | ||||
2020 | if(wait == 0) wait = 1; | ||||
2021 | } | ||||
2022 | rnd = wait/10; | ||||
2023 | rest = wait-rnd; | ||||
2024 | rnd = (time_t)ub_random_max(env->rnd, (long int)rnd); | ||||
2025 | return (time_t)(*env->now + rest + rnd); | ||||
2026 | } | ||||
2027 | |||||
2028 | /** what is first probe time (anchors must be locked) */ | ||||
2029 | static time_t | ||||
2030 | wait_probe_time(struct val_anchors* anchors) | ||||
2031 | { | ||||
2032 | rbnode_type* t = rbtree_first(&anchors->autr->probe); | ||||
2033 | if(t != RBTREE_NULL&rbtree_null_node) | ||||
2034 | return ((struct trust_anchor*)t->key)->autr->next_probe_time; | ||||
2035 | return 0; | ||||
2036 | } | ||||
2037 | |||||
2038 | /** reset worker timer */ | ||||
2039 | static void | ||||
2040 | reset_worker_timer(struct module_env* env) | ||||
2041 | { | ||||
2042 | struct timeval tv; | ||||
2043 | #ifndef S_SPLINT_S | ||||
2044 | time_t next = (time_t)wait_probe_time(env->anchors); | ||||
2045 | /* in case this is libunbound, no timer */ | ||||
2046 | if(!env->probe_timer) | ||||
2047 | return; | ||||
2048 | if(next > *env->now) | ||||
2049 | tv.tv_sec = (time_t)(next - *env->now); | ||||
2050 | else tv.tv_sec = 0; | ||||
2051 | #endif | ||||
2052 | tv.tv_usec = 0; | ||||
2053 | comm_timer_set(env->probe_timer, &tv); | ||||
2054 | verbose(VERB_ALGO, "scheduled next probe in " ARG_LL"%ll" "d sec", (long long)tv.tv_sec); | ||||
2055 | } | ||||
2056 | |||||
2057 | /** set next probe for trust anchor */ | ||||
2058 | static int | ||||
2059 | set_next_probe(struct module_env* env, struct trust_anchor* tp, | ||||
2060 | struct ub_packed_rrset_key* dnskey_rrset) | ||||
2061 | { | ||||
2062 | struct trust_anchor key, *tp2; | ||||
2063 | time_t mold, mnew; | ||||
2064 | /* use memory allocated in rrset for temporary name storage */ | ||||
2065 | key.node.key = &key; | ||||
2066 | key.name = dnskey_rrset->rk.dname; | ||||
2067 | key.namelen = dnskey_rrset->rk.dname_len; | ||||
2068 | key.namelabs = dname_count_labels(key.name); | ||||
2069 | key.dclass = tp->dclass; | ||||
2070 | lock_basic_unlock(&tp->lock); | ||||
2071 | |||||
2072 | /* fetch tp again and lock anchors, so that we can modify the trees */ | ||||
2073 | lock_basic_lock(&env->anchors->lock); | ||||
2074 | tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key); | ||||
2075 | if(!tp2) { | ||||
2076 | verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe"); | ||||
2077 | lock_basic_unlock(&env->anchors->lock); | ||||
2078 | return 0; | ||||
2079 | } | ||||
2080 | log_assert(tp == tp2); | ||||
2081 | lock_basic_lock(&tp->lock); | ||||
2082 | |||||
2083 | /* schedule */ | ||||
2084 | mold = wait_probe_time(env->anchors); | ||||
2085 | (void)rbtree_delete(&env->anchors->autr->probe, tp); | ||||
2086 | tp->autr->next_probe_time = calc_next_probe(env, | ||||
2087 | tp->autr->query_interval); | ||||
2088 | (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); | ||||
2089 | mnew = wait_probe_time(env->anchors); | ||||
2090 | |||||
2091 | lock_basic_unlock(&env->anchors->lock); | ||||
2092 | verbose(VERB_ALGO, "next probe set in %d seconds", | ||||
2093 | (int)tp->autr->next_probe_time - (int)*env->now); | ||||
2094 | if(mold != mnew) { | ||||
2095 | reset_worker_timer(env); | ||||
2096 | } | ||||
2097 | return 1; | ||||
2098 | } | ||||
2099 | |||||
2100 | /** Revoke and Delete a trust point */ | ||||
2101 | static void | ||||
2102 | autr_tp_remove(struct module_env* env, struct trust_anchor* tp, | ||||
2103 | struct ub_packed_rrset_key* dnskey_rrset) | ||||
2104 | { | ||||
2105 | struct trust_anchor* del_tp; | ||||
2106 | struct trust_anchor key; | ||||
2107 | struct autr_point_data pd; | ||||
2108 | time_t mold, mnew; | ||||
2109 | |||||
2110 | log_nametypeclass(VERB_OPS, "trust point was revoked", | ||||
2111 | tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); | ||||
2112 | tp->autr->revoked = 1; | ||||
2113 | |||||
2114 | /* use space allocated for dnskey_rrset to save name of anchor */ | ||||
2115 | memset(&key, 0, sizeof(key)); | ||||
2116 | memset(&pd, 0, sizeof(pd)); | ||||
2117 | key.autr = &pd; | ||||
2118 | key.node.key = &key; | ||||
2119 | pd.pnode.key = &key; | ||||
2120 | pd.next_probe_time = tp->autr->next_probe_time; | ||||
2121 | key.name = dnskey_rrset->rk.dname; | ||||
2122 | key.namelen = tp->namelen; | ||||
2123 | key.namelabs = tp->namelabs; | ||||
2124 | key.dclass = tp->dclass; | ||||
2125 | |||||
2126 | /* unlock */ | ||||
2127 | lock_basic_unlock(&tp->lock); | ||||
2128 | |||||
2129 | /* take from tree. It could be deleted by someone else,hence (void). */ | ||||
2130 | lock_basic_lock(&env->anchors->lock); | ||||
2131 | del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key); | ||||
2132 | mold = wait_probe_time(env->anchors); | ||||
2133 | (void)rbtree_delete(&env->anchors->autr->probe, &key); | ||||
2134 | mnew = wait_probe_time(env->anchors); | ||||
2135 | anchors_init_parents_locked(env->anchors); | ||||
2136 | lock_basic_unlock(&env->anchors->lock); | ||||
2137 | |||||
2138 | /* if !del_tp then the trust point is no longer present in the tree, | ||||
2139 | * it was deleted by someone else, who will write the zonefile and | ||||
2140 | * clean up the structure */ | ||||
2141 | if(del_tp) { | ||||
2142 | /* save on disk */ | ||||
2143 | del_tp->autr->next_probe_time = 0; /* no more probing for it */ | ||||
2144 | autr_write_file(env, del_tp); | ||||
2145 | |||||
2146 | /* delete */ | ||||
2147 | autr_point_delete(del_tp); | ||||
2148 | } | ||||
2149 | if(mold != mnew) { | ||||
2150 | reset_worker_timer(env); | ||||
2151 | } | ||||
2152 | } | ||||
2153 | |||||
2154 | int autr_process_prime(struct module_env* env, struct val_env* ve, | ||||
2155 | struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, | ||||
2156 | struct module_qstate* qstate) | ||||
2157 | { | ||||
2158 | int changed = 0; | ||||
2159 | log_assert(tp && tp->autr); | ||||
2160 | /* autotrust update trust anchors */ | ||||
2161 | /* the tp is locked, and stays locked unless it is deleted */ | ||||
2162 | |||||
2163 | /* we could just catch the anchor here while another thread | ||||
2164 | * is busy deleting it. Just unlock and let the other do its job */ | ||||
2165 | if(tp->autr->revoked) { | ||||
| |||||
2166 | log_nametypeclass(VERB_ALGO, "autotrust not processed, " | ||||
2167 | "trust point revoked", tp->name, | ||||
2168 | LDNS_RR_TYPE_DNSKEY, tp->dclass); | ||||
2169 | lock_basic_unlock(&tp->lock); | ||||
2170 | return 0; /* it is revoked */ | ||||
2171 | } | ||||
2172 | |||||
2173 | /* query_dnskeys(): */ | ||||
2174 | tp->autr->last_queried = *env->now; | ||||
2175 | |||||
2176 | log_nametypeclass(VERB_ALGO, "autotrust process for", | ||||
2177 | tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); | ||||
2178 | /* see if time alone makes some keys valid */ | ||||
2179 | autr_holddown_exceed(env, tp, &changed); | ||||
2180 | if(changed
| ||||
2181 | verbose(VERB_ALGO, "autotrust: morekeys, reassemble"); | ||||
2182 | if(!autr_assemble(tp)) { | ||||
2183 | log_err("malloc failure assembling autotrust keys"); | ||||
2184 | return 1; /* unchanged */ | ||||
2185 | } | ||||
2186 | } | ||||
2187 | /* did we get any data? */ | ||||
2188 | if(!dnskey_rrset) { | ||||
2189 | verbose(VERB_ALGO, "autotrust: no dnskey rrset"); | ||||
2190 | /* no update of query_failed, because then we would have | ||||
2191 | * to write to disk. But we cannot because we maybe are | ||||
2192 | * still 'initializing' with DS records, that we cannot write | ||||
2193 | * in the full format (which only contains KSKs). */ | ||||
2194 | return 1; /* trust point exists */ | ||||
2195 | } | ||||
2196 | /* check for revoked keys to remove immediately */ | ||||
2197 | check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate); | ||||
2198 | if(changed
| ||||
2199 | verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); | ||||
2200 | if(!autr_assemble(tp)) { | ||||
2201 | log_err("malloc failure assembling autotrust keys"); | ||||
2202 | return 1; /* unchanged */ | ||||
2203 | } | ||||
2204 | if(!tp->ds_rrset && !tp->dnskey_rrset) { | ||||
2205 | /* no more keys, all are revoked */ | ||||
2206 | /* this is a success for this probe attempt */ | ||||
2207 | tp->autr->last_success = *env->now; | ||||
2208 | autr_tp_remove(env, tp, dnskey_rrset); | ||||
2209 | return 0; /* trust point removed */ | ||||
2210 | } | ||||
2211 | } | ||||
2212 | /* verify the dnskey rrset and see if it is valid. */ | ||||
2213 | if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) { | ||||
2214 | verbose(VERB_ALGO, "autotrust: dnskey did not verify."); | ||||
2215 | /* only increase failure count if this is not the first prime, | ||||
2216 | * this means there was a previous successful probe */ | ||||
2217 | if(tp->autr->last_success) { | ||||
2218 | tp->autr->query_failed += 1; | ||||
2219 | autr_write_file(env, tp); | ||||
2220 | } | ||||
2221 | return 1; /* trust point exists */ | ||||
2222 | } | ||||
2223 | |||||
2224 | tp->autr->last_success = *env->now; | ||||
2225 | tp->autr->query_failed = 0; | ||||
2226 | |||||
2227 | /* Add new trust anchors to the data structure | ||||
2228 | * - note which trust anchors are seen this probe. | ||||
2229 | * Set trustpoint query_interval and retry_time. | ||||
2230 | * - find minimum rrsig expiration interval | ||||
2231 | */ | ||||
2232 | if(!update_events(env, ve, tp, dnskey_rrset, &changed)) { | ||||
2233 | log_err("malloc failure in autotrust update_events. " | ||||
2234 | "trust point unchanged."); | ||||
2235 | return 1; /* trust point unchanged, so exists */ | ||||
2236 | } | ||||
2237 | |||||
2238 | /* - for every SEP key do the 5011 statetable. | ||||
2239 | * - remove missing trustanchors (if veryold and we have new anchors). | ||||
2240 | */ | ||||
2241 | if(!do_statetable(env, tp, &changed)) { | ||||
2242 | log_err("malloc failure in autotrust do_statetable. " | ||||
2243 | "trust point unchanged."); | ||||
2244 | return 1; /* trust point unchanged, so exists */ | ||||
2245 | } | ||||
2246 | |||||
2247 | autr_cleanup_keys(tp); | ||||
2248 | if(!set_next_probe(env, tp, dnskey_rrset)) | ||||
2249 | return 0; /* trust point does not exist */ | ||||
2250 | autr_write_file(env, tp); | ||||
2251 | if(changed) { | ||||
2252 | verbose(VERB_ALGO, "autotrust: changed, reassemble"); | ||||
2253 | if(!autr_assemble(tp)) { | ||||
2254 | log_err("malloc failure assembling autotrust keys"); | ||||
2255 | return 1; /* unchanged */ | ||||
2256 | } | ||||
2257 | if(!tp->ds_rrset && !tp->dnskey_rrset) { | ||||
2258 | /* no more keys, all are revoked */ | ||||
2259 | autr_tp_remove(env, tp, dnskey_rrset); | ||||
2260 | return 0; /* trust point removed */ | ||||
2261 | } | ||||
2262 | } else verbose(VERB_ALGO, "autotrust: no changes"); | ||||
2263 | |||||
2264 | return 1; /* trust point exists */ | ||||
2265 | } | ||||
2266 | |||||
2267 | /** debug print a trust anchor key */ | ||||
2268 | static void | ||||
2269 | autr_debug_print_ta(struct autr_ta* ta) | ||||
2270 | { | ||||
2271 | char buf[32]; | ||||
2272 | char* str = sldns_wire2str_rr(ta->rr, ta->rr_len); | ||||
2273 | if(!str) { | ||||
2274 | log_info("out of memory in debug_print_ta"); | ||||
2275 | return; | ||||
2276 | } | ||||
2277 | if(str[0]) str[strlen(str)-1]=0; /* remove newline */ | ||||
2278 | (void)autr_ctime_r(&ta->last_change, buf); | ||||
2279 | if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ | ||||
2280 | log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s", | ||||
2281 | trustanchor_state2str(ta->s), str, ta->s, ta->pending_count, | ||||
2282 | ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf); | ||||
2283 | free(str); | ||||
2284 | } | ||||
2285 | |||||
2286 | /** debug print a trust point */ | ||||
2287 | static void | ||||
2288 | autr_debug_print_tp(struct trust_anchor* tp) | ||||
2289 | { | ||||
2290 | struct autr_ta* ta; | ||||
2291 | char buf[257]; | ||||
2292 | if(!tp->autr) | ||||
2293 | return; | ||||
2294 | dname_str(tp->name, buf); | ||||
2295 | log_info("trust point %s : %d", buf, (int)tp->dclass); | ||||
2296 | log_info("assembled %d DS and %d DNSKEYs", | ||||
2297 | (int)tp->numDS, (int)tp->numDNSKEY); | ||||
2298 | if(tp->ds_rrset) { | ||||
2299 | log_packed_rrset(NO_VERBOSE, "DS:", tp->ds_rrset); | ||||
2300 | } | ||||
2301 | if(tp->dnskey_rrset) { | ||||
2302 | log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset); | ||||
2303 | } | ||||
2304 | log_info("file %s", tp->autr->file); | ||||
2305 | (void)autr_ctime_r(&tp->autr->last_queried, buf); | ||||
2306 | if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ | ||||
2307 | log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); | ||||
2308 | (void)autr_ctime_r(&tp->autr->last_success, buf); | ||||
2309 | if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ | ||||
2310 | log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf); | ||||
2311 | (void)autr_ctime_r(&tp->autr->next_probe_time, buf); | ||||
2312 | if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ | ||||
2313 | log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time, | ||||
2314 | buf); | ||||
2315 | log_info("query_interval: %u", (unsigned)tp->autr->query_interval); | ||||
2316 | log_info("retry_time: %u", (unsigned)tp->autr->retry_time); | ||||
2317 | log_info("query_failed: %u", (unsigned)tp->autr->query_failed); | ||||
2318 | |||||
2319 | for(ta=tp->autr->keys; ta; ta=ta->next) { | ||||
2320 | autr_debug_print_ta(ta); | ||||
2321 | } | ||||
2322 | } | ||||
2323 | |||||
2324 | void | ||||
2325 | autr_debug_print(struct val_anchors* anchors) | ||||
2326 | { | ||||
2327 | struct trust_anchor* tp; | ||||
2328 | lock_basic_lock(&anchors->lock); | ||||
2329 | RBTREE_FOR(tp, struct trust_anchor*, anchors->tree)for(tp=(struct trust_anchor*)rbtree_first(anchors->tree); ( rbnode_type*)tp != &rbtree_null_node; tp = (struct trust_anchor *)rbtree_next((rbnode_type*)tp)) { | ||||
2330 | lock_basic_lock(&tp->lock); | ||||
2331 | autr_debug_print_tp(tp); | ||||
2332 | lock_basic_unlock(&tp->lock); | ||||
2333 | } | ||||
2334 | lock_basic_unlock(&anchors->lock); | ||||
2335 | } | ||||
2336 | |||||
2337 | void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode)rcode __attribute__((unused)), | ||||
2338 | sldns_buffer* ATTR_UNUSED(buf)buf __attribute__((unused)), enum sec_status ATTR_UNUSED(sec)sec __attribute__((unused)), | ||||
2339 | char* ATTR_UNUSED(why_bogus)why_bogus __attribute__((unused)), int ATTR_UNUSED(was_ratelimited)was_ratelimited __attribute__((unused))) | ||||
2340 | { | ||||
2341 | /* retry was set before the query was done, | ||||
2342 | * re-querytime is set when query succeeded, but that may not | ||||
2343 | * have reset this timer because the query could have been | ||||
2344 | * handled by another thread. In that case, this callback would | ||||
2345 | * get called after the original timeout is done. | ||||
2346 | * By not resetting the timer, it may probe more often, but not | ||||
2347 | * less often. | ||||
2348 | * Unless the new lookup resulted in smaller TTLs and thus smaller | ||||
2349 | * timeout values. In that case one old TTL could be mistakenly done. | ||||
2350 | */ | ||||
2351 | struct module_env* env = (struct module_env*)arg; | ||||
2352 | verbose(VERB_ALGO, "autotrust probe answer cb"); | ||||
2353 | reset_worker_timer(env); | ||||
2354 | } | ||||
2355 | |||||
2356 | /** probe a trust anchor DNSKEY and unlocks tp */ | ||||
2357 | static void | ||||
2358 | probe_anchor(struct module_env* env, struct trust_anchor* tp) | ||||
2359 | { | ||||
2360 | struct query_info qinfo; | ||||
2361 | uint16_t qflags = BIT_RD0x0100; | ||||
2362 | struct edns_data edns; | ||||
2363 | sldns_buffer* buf = env->scratch_buffer; | ||||
2364 | qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen); | ||||
2365 | if(!qinfo.qname) { | ||||
2366 | log_err("out of memory making 5011 probe"); | ||||
2367 | return; | ||||
2368 | } | ||||
2369 | qinfo.qname_len = tp->namelen; | ||||
2370 | qinfo.qtype = LDNS_RR_TYPE_DNSKEY; | ||||
2371 | qinfo.qclass = tp->dclass; | ||||
2372 | qinfo.local_alias = NULL((void*)0); | ||||
2373 | log_query_info(VERB_ALGO, "autotrust probe", &qinfo); | ||||
2374 | verbose(VERB_ALGO, "retry probe set in %d seconds", | ||||
2375 | (int)tp->autr->next_probe_time - (int)*env->now); | ||||
2376 | edns.edns_present = 1; | ||||
2377 | edns.ext_rcode = 0; | ||||
2378 | edns.edns_version = 0; | ||||
2379 | edns.bits = EDNS_DO0x8000; | ||||
2380 | edns.opt_list = NULL((void*)0); | ||||
2381 | edns.padding_block_size = 0; | ||||
2382 | if(sldns_buffer_capacity(buf) < 65535) | ||||
2383 | edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); | ||||
2384 | else edns.udp_size = 65535; | ||||
2385 | |||||
2386 | /* can't hold the lock while mesh_run is processing */ | ||||
2387 | lock_basic_unlock(&tp->lock); | ||||
2388 | |||||
2389 | /* delete the DNSKEY from rrset and key cache so an active probe | ||||
2390 | * is done. First the rrset so another thread does not use it | ||||
2391 | * to recreate the key entry in a race condition. */ | ||||
2392 | rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len, | ||||
2393 | qinfo.qtype, qinfo.qclass, 0); | ||||
2394 | key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len, | ||||
2395 | qinfo.qclass); | ||||
2396 | |||||
2397 | if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, | ||||
2398 | &probe_answer_cb, env)) { | ||||
2399 | log_err("out of memory making 5011 probe"); | ||||
2400 | } | ||||
2401 | } | ||||
2402 | |||||
2403 | /** fetch first to-probe trust-anchor and lock it and set retrytime */ | ||||
2404 | static struct trust_anchor* | ||||
2405 | todo_probe(struct module_env* env, time_t* next) | ||||
2406 | { | ||||
2407 | struct trust_anchor* tp; | ||||
2408 | rbnode_type* el; | ||||
2409 | /* get first one */ | ||||
2410 | lock_basic_lock(&env->anchors->lock); | ||||
2411 | if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL&rbtree_null_node) { | ||||
2412 | /* in case of revoked anchors */ | ||||
2413 | lock_basic_unlock(&env->anchors->lock); | ||||
2414 | /* signal that there are no anchors to probe */ | ||||
2415 | *next = 0; | ||||
2416 | return NULL((void*)0); | ||||
2417 | } | ||||
2418 | tp = (struct trust_anchor*)el->key; | ||||
2419 | lock_basic_lock(&tp->lock); | ||||
2420 | |||||
2421 | /* is it eligible? */ | ||||
2422 | if((time_t)tp->autr->next_probe_time > *env->now) { | ||||
2423 | /* no more to probe */ | ||||
2424 | *next = (time_t)tp->autr->next_probe_time - *env->now; | ||||
2425 | lock_basic_unlock(&tp->lock); | ||||
2426 | lock_basic_unlock(&env->anchors->lock); | ||||
2427 | return NULL((void*)0); | ||||
2428 | } | ||||
2429 | |||||
2430 | /* reset its next probe time */ | ||||
2431 | (void)rbtree_delete(&env->anchors->autr->probe, tp); | ||||
2432 | tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time); | ||||
2433 | (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); | ||||
2434 | lock_basic_unlock(&env->anchors->lock); | ||||
2435 | |||||
2436 | return tp; | ||||
2437 | } | ||||
2438 | |||||
2439 | time_t | ||||
2440 | autr_probe_timer(struct module_env* env) | ||||
2441 | { | ||||
2442 | struct trust_anchor* tp; | ||||
2443 | time_t next_probe = 3600; | ||||
2444 | int num = 0; | ||||
2445 | if(autr_permit_small_holddown) next_probe = 1; | ||||
2446 | verbose(VERB_ALGO, "autotrust probe timer callback"); | ||||
2447 | /* while there are still anchors to probe */ | ||||
2448 | while( (tp = todo_probe(env, &next_probe)) ) { | ||||
2449 | /* make a probe for this anchor */ | ||||
2450 | probe_anchor(env, tp); | ||||
2451 | num++; | ||||
2452 | } | ||||
2453 | regional_free_all(env->scratch); | ||||
2454 | if(next_probe == 0) | ||||
2455 | return 0; /* no trust points to probe */ | ||||
2456 | verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); | ||||
2457 | return next_probe; | ||||
2458 | } |