1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup nsec3 NSEC3 functions
36 * @ingroup dnsdbdnssec
37 * @brief
38 *
39 *
40 *
41 * @{
42 */
43 /*------------------------------------------------------------------------------
44 *
45 * USE INCLUDES */
46 #include "dnsdb/dnsdb-config.h"
47 #include <stdio.h>
48 #include <stdlib.h>
49
50 #define DEBUG_LEVEL 0
51
52 #include <dnscore/dnscore.h>
53 #include <dnscore/ptr_set.h>
54 #include <dnscore/base32hex.h>
55
56 #include "dnsdb/dnssec.h"
57
58 #include "dnsdb/nsec3_load.h"
59 #include "dnsdb/nsec3_zone.h"
60 #include "dnsdb/zdb_zone_label_iterator.h"
61
62 #define MODULE_MSG_HANDLE g_dnssec_logger
63 extern logger_handle *g_dnssec_logger;
64
65 #define N3CHNCTX_TAG 0x5854434e4843334e
66 #define N3PRDATA_TAG 0x415441445250334e
67
68 #define N3LCTXRR_TAG 0x52525854434c334e
69 #define N3LCTXCN_TAG 0x434e5854434c334e
70 #define N3LKEYDG_TAG 0x474459454b4c334e
71 /*
72 ;; Owner: mejnertsen
73 4Q9DAPPUSCM8987DU4UL56CF2O5S0CNO.eu. 600 NSEC3 1 1 1 5ca1ab1e 4Q9DE8JTV8EA3H4IP8KC33F1RJK45SD1
74 RRSIG NSEC3 8 2 600 20181020080859 20180919080849 37080 eu. urzQ7qjZ5L+F0pEykY/IN5XHuwb5+iwqxz
75 */
76 /******************************************************************************
77 *
78 * NSEC3 - load (ie: from zone file / axfr / ...)
79 *
80 *****************************************************************************/
81
82 struct nsec3_context_record
83 {
84 zdb_packed_ttlrdata *rrsig;
85 s32 ttl;
86 u16 rdata_size;
87 u8 digest_then_rdata[];
88 };
89
90 typedef struct nsec3_context_record nsec3_context_record;
91
92 struct nsec3_load_context_chain
93 {
94 ptr_vector nsec3_added; // array of full of records
95 u16 nsec3param_rdata_size;
96 bool has_nsec3param;
97 u8 nsec3param_rdata[];
98 };
99
100 typedef struct nsec3_load_context_chain nsec3_load_context_chain;
101
102 static void
nsec3_load_context_record_delete_rrsig(nsec3_context_record * r)103 nsec3_load_context_record_delete_rrsig(nsec3_context_record *r)
104 {
105 zdb_packed_ttlrdata *rrsig = r->rrsig;
106 while(rrsig != NULL)
107 {
108 zdb_packed_ttlrdata *next = rrsig->next;
109 ZDB_RECORD_ZFREE(rrsig);
110 rrsig = next;
111 }
112
113 r->rrsig = NULL;
114 }
115
116 static void
nsec3_load_context_record_delete(nsec3_context_record * r)117 nsec3_load_context_record_delete(nsec3_context_record *r)
118 {
119 zdb_packed_ttlrdata *rrsig = r->rrsig;
120 while(rrsig != NULL)
121 {
122 zdb_packed_ttlrdata *next = rrsig->next;
123 ZDB_RECORD_ZFREE(rrsig);
124 rrsig = next;
125 }
126
127 size_t nsec3_context_record_size = sizeof(nsec3_context_record) + 1 + r->digest_then_rdata[0] + r->rdata_size;
128
129 #if DEBUG
130 memset(r, 0xfe, nsec3_context_record_size);
131 #endif
132
133 ZFREE_ARRAY(r, nsec3_context_record_size);
134 }
135
136 static nsec3_context_record*
nsec3_load_context_record_new(const u8 * base32hex_digest,s32 ttl,const u8 * rdata,u16 rdata_size)137 nsec3_load_context_record_new(const u8 *base32hex_digest, s32 ttl, const u8 *rdata, u16 rdata_size)
138 {
139 u8 digest_len = BASE32HEX_DECODED_LEN(base32hex_digest[0]);
140
141 nsec3_context_record *record;
142
143 ZALLOC_ARRAY_OR_DIE(nsec3_context_record*, record, sizeof(nsec3_context_record) + 1 + digest_len + rdata_size, N3LCTXRR_TAG);
144 record->rrsig = NULL;
145 record->ttl = ttl;
146 record->rdata_size = rdata_size;
147
148 // memcpy(&record->digest_then_rdata[0], digest, digest_len);
149 record->digest_then_rdata[0] = digest_len;
150
151 if(ISOK(base32hex_decode((const char*)&base32hex_digest[1], base32hex_digest[0], &record->digest_then_rdata[1])))
152 {
153 memcpy(&record->digest_then_rdata[digest_len + 1], rdata, rdata_size);
154 return record;
155 }
156 else
157 {
158 nsec3_load_context_record_delete(record);
159 return NULL;
160 }
161 }
162
163 static nsec3_context_record*
nsec3_load_context_record_new_binary(const u8 * binary_digest,s32 ttl,u16 rdata_size)164 nsec3_load_context_record_new_binary(const u8 *binary_digest, s32 ttl, u16 rdata_size)
165 {
166 u8 digest_len = binary_digest[0];
167
168 nsec3_context_record *record;
169
170 ZALLOC_ARRAY_OR_DIE(nsec3_context_record*, record, sizeof(nsec3_context_record) + 1 + digest_len + rdata_size, N3LCTXRR_TAG);
171 record->rrsig = NULL;
172 record->ttl = ttl;
173 record->rdata_size = rdata_size;
174
175 record->digest_then_rdata[0] = digest_len;
176 memcpy(record->digest_then_rdata, binary_digest, digest_len + 1);
177
178 #if DEBUG
179 memset(&record->digest_then_rdata[digest_len + 1], 0xff, rdata_size);
180 #endif
181
182 return record;
183 }
184
185 static void
nsec3_load_context_record_delete_void(void * r)186 nsec3_load_context_record_delete_void(void *r)
187 {
188 nsec3_load_context_record_delete((nsec3_context_record*)r);
189 }
190
191 static const u8*
nsec3_load_context_record_rdata(const nsec3_context_record * r)192 nsec3_load_context_record_rdata(const nsec3_context_record *r)
193 {
194 size_t digest_len = 1 + r->digest_then_rdata[0];
195 return &r->digest_then_rdata[digest_len];
196 }
197
198 static const u8*
nsec3_load_context_record_next_digest(const nsec3_context_record * r)199 nsec3_load_context_record_next_digest(const nsec3_context_record *r)
200 {
201 const u8 *rdata = nsec3_load_context_record_rdata(r);
202 size_t nsec3param_size = NSEC3PARAM_RDATA_SIZE_FROM_RDATA(rdata);
203 return &rdata[nsec3param_size];
204 }
205
206 static int
nsec3_load_context_record_qsort_callback(const void * a,const void * b)207 nsec3_load_context_record_qsort_callback(const void *a, const void *b)
208 {
209 const nsec3_context_record *ra = (nsec3_context_record*)a;
210 const nsec3_context_record *rb = (nsec3_context_record*)b;
211 int ra_size = ra->digest_then_rdata[0];
212 int rb_size = rb->digest_then_rdata[0];
213 int d = ra_size - rb_size;
214 if(d == 0)
215 {
216 d = memcmp(ra->digest_then_rdata, rb->digest_then_rdata, ra_size + 1);
217 }
218 return d;
219 }
220
221 static bool
nsec3_load_context_record_linked(const nsec3_context_record * ra,const nsec3_context_record * rb)222 nsec3_load_context_record_linked(const nsec3_context_record *ra, const nsec3_context_record *rb)
223 {
224 const u8 *next_digest = nsec3_load_context_record_next_digest(ra);
225 int next_size = next_digest[0];
226 int size = rb->digest_then_rdata[0];
227 if(next_size == size)
228 {
229 return memcmp(&next_digest[1], &rb->digest_then_rdata[1], size) == 0;
230 }
231 return FALSE;
232 }
233
234 static nsec3_load_context_chain*
nsec3_load_context_chain_new(nsec3_context_record * r)235 nsec3_load_context_chain_new(nsec3_context_record *r)
236 {
237 nsec3_load_context_chain *chain;
238 const u8 *nsec3param_rdata = nsec3_load_context_record_rdata(r);
239 size_t nsec3param_size = NSEC3PARAM_RDATA_SIZE_FROM_RDATA(nsec3param_rdata);
240
241 ZALLOC_ARRAY_OR_DIE(nsec3_load_context_chain*, chain, sizeof(nsec3_load_context_chain) + nsec3param_size, N3LCTXCN_TAG);
242 ZEROMEMORY(chain, sizeof(nsec3_load_context_chain));
243 ptr_vector_init_ex(&chain->nsec3_added, 65536);
244 chain->nsec3param_rdata_size = nsec3param_size;
245 memcpy(chain->nsec3param_rdata, nsec3param_rdata, nsec3param_size);
246
247 #if DEBUG
248 log_debug("nsec3_load_context_chain_new(%p) -> (%p, %p)", r, chain, chain->nsec3_added.data);
249 #endif
250
251 return chain;
252 }
253
254 static void
nsec3_load_context_chain_delete(nsec3_load_context_chain * chain)255 nsec3_load_context_chain_delete(nsec3_load_context_chain *chain)
256 {
257 #if DEBUG
258 log_debug("nsec3_load_context_chain_delete(%p) -> (%p)", chain, chain->nsec3_added.data);
259 #endif
260
261 ptr_vector_callback_and_destroy(&chain->nsec3_added, nsec3_load_context_record_delete_void);
262 ZFREE_ARRAY(chain, sizeof(nsec3_load_context_chain) + chain->nsec3param_rdata_size);
263 }
264
265 static void
nsec3_load_context_chain_add_nsec3(nsec3_load_context_chain * chain,nsec3_context_record * r)266 nsec3_load_context_chain_add_nsec3(nsec3_load_context_chain *chain, nsec3_context_record *r)
267 {
268 ptr_vector_append(&chain->nsec3_added, r);
269 }
270
271 static int
nsec3_load_context_chain_qsort_callback(const void * a,const void * b)272 nsec3_load_context_chain_qsort_callback(const void *a, const void *b)
273 {
274 const nsec3_load_context_chain *ca = (nsec3_load_context_chain*)a;
275 const nsec3_load_context_chain *cb = (nsec3_load_context_chain*)b;
276 int d = (ca->has_nsec3param?1:0) - (cb->has_nsec3param?1:0);
277 if(d == 0)
278 {
279 d = ca->nsec3param_rdata_size - cb->nsec3param_rdata_size;
280
281 if(d == 0)
282 {
283 d = memcmp(ca->nsec3param_rdata, cb->nsec3param_rdata, ca->nsec3param_rdata_size);
284 }
285 }
286 return d;
287 }
288
289 static bool
nsec3_load_context_chain_matches(nsec3_load_context_chain * chain,const u8 * rdata,u16 rdata_size)290 nsec3_load_context_chain_matches(nsec3_load_context_chain *chain, const u8 *rdata, u16 rdata_size)
291 {
292 if((chain->nsec3param_rdata_size <= rdata_size) && (chain->nsec3param_rdata[0] == rdata[0]))
293 {
294 if(memcmp(&chain->nsec3param_rdata[2], &rdata[2], chain->nsec3param_rdata_size - 2) == 0)
295 {
296 return TRUE;
297 }
298 }
299
300 return FALSE;
301 }
302
303 static nsec3_load_context_chain*
nsec3_load_context_get_chain(nsec3_load_context * context,nsec3_context_record * r)304 nsec3_load_context_get_chain(nsec3_load_context *context, nsec3_context_record *r)
305 {
306 // ptr_node *r_node = ptr_set_insert(&context->nsec3chain, r);
307 for(int i = 0; i <= ptr_vector_last_index(&context->nsec3chain); ++i)
308 {
309 nsec3_load_context_chain *chain = (nsec3_load_context_chain*)ptr_vector_get(&context->nsec3chain, i);
310 if(nsec3_load_context_chain_matches(chain, nsec3_load_context_record_rdata(r), r->rdata_size))
311 {
312 return chain;
313 }
314 }
315
316 nsec3_load_context_chain *chain = nsec3_load_context_chain_new(r);
317
318 ptr_vector_append(&context->nsec3chain, chain);
319
320 return chain;
321 }
322
323
324
nsec3_load_postponed_rrsig_node_compare(const void * node_a,const void * node_b)325 static int nsec3_load_postponed_rrsig_node_compare(const void *node_a, const void *node_b)
326 {
327 const u8 *key_a = (const u8*)node_a;
328 const u8 *key_b = (const u8*)node_b;
329 int d = key_a[0];
330 d -= key_b[0];
331 if(d == 0)
332 {
333 d = memcmp(&key_a[1], &key_b[1], key_a[0]);
334 }
335 return d;
336 }
337
338 ya_result
nsec3_load_init(nsec3_load_context * context,zdb_zone * zone)339 nsec3_load_init(nsec3_load_context *context, zdb_zone* zone)
340 {
341 ZEROMEMORY(context, sizeof(nsec3_load_context));
342 ptr_vector_init_ex(&context->nsec3chain, 2);
343 ptr_set_init(&context->postponed_rrsig);
344 context->postponed_rrsig.compare = nsec3_load_postponed_rrsig_node_compare;
345 context->zone = zone;
346 context->opt_out = TRUE;
347
348 return SUCCESS;
349 }
350
351 void
nsec3_load_destroy_nsec3chain_cb(void * ptr)352 nsec3_load_destroy_nsec3chain_cb(void *ptr)
353 {
354 nsec3_load_context_chain *chain = (nsec3_load_context_chain*)ptr;
355 nsec3_load_context_chain_delete(chain);
356 }
357
358 void
nsec3_load_destroy(nsec3_load_context * context)359 nsec3_load_destroy(nsec3_load_context *context)
360 {
361 ptr_vector_callback_and_destroy(&context->nsec3chain, nsec3_load_destroy_nsec3chain_cb);
362
363 if(!ptr_set_isempty(&context->postponed_rrsig))
364 {
365 ptr_set_iterator iter;
366 ptr_set_iterator_init(&context->postponed_rrsig, &iter);
367 while(ptr_set_iterator_hasnext(&iter))
368 {
369 ptr_node *rrsig_node = ptr_set_iterator_next_node(&iter);
370 if(rrsig_node->key != NULL)
371 {
372 u8 *key = (u8*)rrsig_node->key;
373 ZFREE_ARRAY(rrsig_node->key, key[0] + 1);
374 (void)key; // silence warning in some build settings
375 }
376 rrsig_node->key = NULL;
377 rrsig_node->value = NULL;
378 }
379
380 ptr_set_destroy(&context->postponed_rrsig);
381 }
382
383 context->zone = NULL;
384 }
385
386 ya_result
nsec3_load_add_nsec3param(nsec3_load_context * context,const u8 * rdata,u16 rdata_size)387 nsec3_load_add_nsec3param(nsec3_load_context *context, const u8 *rdata, u16 rdata_size)
388 {
389 if((rdata_size < 5) || (NSEC3_RDATA_ALGORITHM(rdata) != NSEC3_DIGEST_ALGORITHM_SHA1))
390 {
391 return DNSSEC_ERROR_UNSUPPORTEDDIGESTALGORITHM;
392 }
393
394 nsec3_context_record* nsec3param_r = nsec3_load_context_record_new((const u8*)"", 0, rdata, rdata_size);
395 nsec3_load_context_chain* chain = nsec3_load_context_get_chain(context, nsec3param_r);
396 nsec3_load_context_record_delete(nsec3param_r);
397 chain->has_nsec3param = TRUE;
398
399 return SUCCESS;
400 }
401
402 // TYPE_NSEC3CHAINSTATE
403
404 ya_result
nsec3_load_add_nsec3chainstate(nsec3_load_context * context,const u8 * rdata,u16 rdata_size)405 nsec3_load_add_nsec3chainstate(nsec3_load_context *context, const u8 *rdata, u16 rdata_size)
406 {
407 if((rdata_size < 5) || (NSEC3_RDATA_ALGORITHM(rdata) != NSEC3_DIGEST_ALGORITHM_SHA1))
408 {
409 return DNSSEC_ERROR_UNSUPPORTEDDIGESTALGORITHM;
410 }
411
412 nsec3_context_record* nsec3param_r = nsec3_load_context_record_new((const u8*)"", 0, rdata, rdata_size);
413 nsec3_load_context_chain* chain = nsec3_load_context_get_chain(context, nsec3param_r);
414 nsec3_load_context_record_delete(nsec3param_r);
415 chain->has_nsec3param = FALSE;
416
417 return SUCCESS;
418 }
419
420 ya_result
nsec3_load_add_nsec3(nsec3_load_context * context,const u8 * base32hex_digest,s32 ttl,const u8 * rdata,u16 rdata_size)421 nsec3_load_add_nsec3(nsec3_load_context *context, const u8 *base32hex_digest, s32 ttl, const u8 *rdata, u16 rdata_size)
422 {
423 /*
424 * Get the right chain from the rdata
425 * Add the record to the chain
426 */
427
428 if((rdata_size < 5) || (NSEC3_RDATA_ALGORITHM(rdata) != NSEC3_DIGEST_ALGORITHM_SHA1))
429 {
430 return DNSSEC_ERROR_UNSUPPORTEDDIGESTALGORITHM;
431 }
432
433 nsec3_context_record* nsec3_r = nsec3_load_context_record_new(base32hex_digest, ttl, rdata, rdata_size);
434 if(nsec3_r != NULL)
435 {
436 nsec3_load_context_chain* chain = nsec3_load_context_get_chain(context, nsec3_r);
437 nsec3_load_context_chain_add_nsec3(chain, nsec3_r);
438
439 context->last_inserted_nsec3 = nsec3_r;
440
441 if(!ptr_set_isempty(&context->postponed_rrsig))
442 {
443 ptr_node *node = ptr_set_find(&context->postponed_rrsig, nsec3_r->digest_then_rdata);
444
445 if(node != NULL)
446 {
447 u8 *key = node->key;
448 nsec3_r->rrsig = (zdb_packed_ttlrdata*)node->value;
449 ptr_set_delete(&context->postponed_rrsig, nsec3_r->digest_then_rdata);
450 ZFREE_ARRAY(key, key[0] + 1);
451 }
452 }
453
454 return SUCCESS;
455 }
456 else
457 {
458 context->last_inserted_nsec3 = NULL;
459
460 return DNSSEC_ERROR_NSEC3_LABELTODIGESTFAILED;
461 }
462 }
463
464 ya_result
nsec3_load_add_rrsig(nsec3_load_context * context,const u8 * digest_label,s32 ttl,const u8 * rdata,u16 rdata_size)465 nsec3_load_add_rrsig(nsec3_load_context *context, const u8 *digest_label, s32 ttl, const u8 *rdata, u16 rdata_size)
466 {
467 u8 digest_len = BASE32HEX_DECODED_LEN(digest_label[0]);
468 #if C11_VLA_AVAILABLE
469 u8 digest[digest_len + 1];
470 #else
471 u8 * const digest = (u8*const)stack_alloc(digest_len + 1);
472 #endif
473 digest[0] = digest_len;
474 if(ISOK(base32hex_decode((const char*)&digest_label[1], digest_label[0], &digest[1])))
475 {
476 zdb_packed_ttlrdata *rrsig;
477 ZDB_RECORD_ZALLOC(rrsig,ttl,rdata_size,rdata);
478
479 if(context->last_inserted_nsec3 != NULL)
480 {
481 nsec3_context_record* nsec3_r = (nsec3_context_record*)context->last_inserted_nsec3;
482 if(memcmp(nsec3_r->digest_then_rdata, digest, 1 + digest[0]) == 0)
483 {
484 rrsig->next = nsec3_r->rrsig;
485 nsec3_r->rrsig = rrsig;
486
487 return SUCCESS;
488 }
489 }
490
491 // the records are not nicely ordered : need to postpone the insertion of this record.
492
493 ptr_node *node = ptr_set_insert(&context->postponed_rrsig, digest);
494
495 if(node->value == NULL)
496 {
497 u8 *key;
498 ZALLOC_ARRAY_OR_DIE(u8*, key, digest_len + 1, N3LKEYDG_TAG);
499 memcpy(key, digest, digest_len + 1);
500 node->key = key;
501 }
502
503 rrsig->next = (zdb_packed_ttlrdata*)node->value;
504 node->value = rrsig;
505
506 return SUCCESS;
507 }
508 else
509 {
510 return DNSSEC_ERROR_NSEC3_LABELTODIGESTFAILED;
511 }
512 }
513
514 static int
nsec3_load_fix_chain_search_cb(const void * key,const void * item)515 nsec3_load_fix_chain_search_cb(const void *key, const void *item)
516 {
517 const u8 *digest = (const u8*)key;
518 nsec3_context_record *nsec3_record = (nsec3_context_record*)item;
519 int ret = memcmp(digest, nsec3_record->digest_then_rdata, digest[0] + 1);
520 return ret;
521 }
522
523 bool
nsec3_load_is_label_covered(zdb_rr_label * label)524 nsec3_load_is_label_covered(zdb_rr_label *label)
525 {
526 return !ZDB_LABEL_UNDERDELEGATION(label);
527 }
528
529 bool
nsec3_load_is_label_covered_optout(zdb_rr_label * label)530 nsec3_load_is_label_covered_optout(zdb_rr_label *label)
531 {
532 if(!ZDB_LABEL_ATORUNDERDELEGATION(label)) // includes APEX
533 {
534 return TRUE;
535 }
536 if(ZDB_LABEL_ATDELEGATION(label))
537 {
538 return zdb_rr_label_get_rrset(label, TYPE_DS) != NULL;
539 }
540 return FALSE;
541 }
542
543 /**
544 * Fixes extraneous NSEC3 records in chain.
545 *
546 * @returns TRUE iff the chain had no extraneous records;
547 */
548
549 static bool
nsec3_load_find_extranous_records_in_chain(nsec3_load_context * context,nsec3_load_context_chain * chain)550 nsec3_load_find_extranous_records_in_chain(nsec3_load_context *context, nsec3_load_context_chain *chain)
551 {
552 // for all labels
553 // check if the label should be covered by an NSEC3
554 // compute the digest
555 // seek for the digest
556 // if not missing
557 // mark the entry to tell it's covering something
558 //
559 // for all digests
560 // if the entry is not used, remove it
561
562 nsec3_hash_function *hash_function;
563 u8 *salt;
564 nsec3_load_is_label_covered_function *is_covered;
565 s32 min_ttl = context->zone->min_ttl;
566 u32 nsec3_correction_count = 0;
567 u16 hash_iterations;
568 u16 nsec3param_rdata_size;
569 u8 salt_len;
570 u8 digest_len;
571 bool fix_required;
572 zdb_zone_label_iterator iter;
573 u8 digest[64];
574 u8 fqdn[MAX_DOMAIN_LENGTH + 1];
575 u8 optout_byte;
576
577 digest_len = digest[0] = nsec3_hash_len(NSEC3PARAM_RDATA_ALGORITHM(chain->nsec3param_rdata));
578 hash_function = nsec3_hash_get_function(NSEC3PARAM_RDATA_ALGORITHM(chain->nsec3param_rdata));
579 salt = NSEC3PARAM_RDATA_SALT(chain->nsec3param_rdata);
580 salt_len = NSEC3PARAM_RDATA_SALT_LEN(chain->nsec3param_rdata);
581 hash_iterations = NSEC3PARAM_RDATA_ITERATIONS(chain->nsec3param_rdata);
582 nsec3param_rdata_size = NSEC3PARAM_MINIMUM_LENGTH + salt_len;
583 fix_required = FALSE;
584
585 if(context->opt_out)
586 {
587 is_covered = nsec3_load_is_label_covered_optout;
588 optout_byte = 1;
589 }
590 else
591 {
592 is_covered = nsec3_load_is_label_covered;
593 optout_byte = 0;
594 }
595
596 // find and mark all covered labels, the non-marked ones will be removed
597
598 zdb_zone_label_iterator_init(&iter, context->zone);
599 while(zdb_zone_label_iterator_hasnext(&iter))
600 {
601 u32 fqdn_len = zdb_zone_label_iterator_nextname(&iter, fqdn);
602 zdb_rr_label* label = zdb_zone_label_iterator_next(&iter);
603
604 if(is_covered(label)) // note: is_covered is a local variable pointing to the relevant function
605 {
606 // should be covered
607
608 hash_function(
609 fqdn,
610 fqdn_len,
611 salt,
612 salt_len,
613 hash_iterations,
614 &digest[1],
615 FALSE);
616
617 // digest exists ?
618
619 // nsec3 missing: generate the type bitmap and make an rdata with an nsec3 digest
620 type_bit_maps_context bitmap;
621
622 u16 bitmap_size = zdb_rr_label_bitmap_type_init(label, &bitmap);
623 u16 rdata_size_pre_bitmap = nsec3param_rdata_size + 1 + digest_len;
624 u16 rdata_size = rdata_size_pre_bitmap + bitmap_size;
625 nsec3_context_record* expected_nsec3_record = nsec3_load_context_record_new_binary(digest, min_ttl, rdata_size);
626 u8 *rdata = &expected_nsec3_record->digest_then_rdata[digest_len + 1];
627 memcpy(rdata, chain->nsec3param_rdata, nsec3param_rdata_size);
628 rdata[1] = optout_byte;
629 type_bit_maps_write(&bitmap, &rdata[nsec3param_rdata_size + 1 + digest_len]);
630 type_bit_maps_finalize(&bitmap);
631
632 s32 match_index = ptr_vector_search_index(&chain->nsec3_added, digest, nsec3_load_fix_chain_search_cb);
633 void *match;
634
635 if((match_index >= 0) && ((match = ptr_vector_get(&chain->nsec3_added, match_index)) != NULL))
636 {
637 // found
638
639 /*nsec3_context_record *nsec3_record = (nsec3_context_record*)match;
640 assert(nsec3_record->ttl >= 0);
641 nsec3_record->ttl = -nsec3_record->ttl;
642 */
643 bool nsec3_matches = FALSE;
644
645 nsec3_context_record *nsec3_record = (nsec3_context_record*)match;
646
647 if(nsec3_record->rdata_size == expected_nsec3_record->rdata_size)
648 {
649 if(memcmp(&nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], &expected_nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], bitmap_size) == 0)
650 {
651 nsec3_matches = TRUE;
652 }
653 }
654
655 if(nsec3_matches)
656 {
657 nsec3_load_context_record_delete(expected_nsec3_record);
658 nsec3_record->ttl = - nsec3_record->ttl;
659 }
660 else
661 {
662 ++nsec3_correction_count;
663 #if !DEBUG
664 log_debug("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} has mismatched bitmap: fixed (%{dnsname})", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin, fqdn);
665 #else
666 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} has mismatched bitmap: fixed (%{dnsname})", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin, fqdn);
667 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} expected: (DEBUG)", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
668 log_memdump(MODULE_MSG_HANDLE, MSG_WARNING, &expected_nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], bitmap_size, 32);
669 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} got: (DEBUG)", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
670 log_memdump(MODULE_MSG_HANDLE, MSG_WARNING, &nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], bitmap_size, 32);
671 #endif
672 memcpy(&expected_nsec3_record->digest_then_rdata[digest_len + 1 + nsec3param_rdata_size], &nsec3_record->digest_then_rdata[digest_len + 1 + nsec3param_rdata_size], digest_len + 1);
673 nsec3_load_context_record_delete_rrsig(expected_nsec3_record);
674 ptr_vector_set(&chain->nsec3_added, match_index, expected_nsec3_record);
675 nsec3_load_context_record_delete(nsec3_record);
676 expected_nsec3_record->ttl = - expected_nsec3_record->ttl;
677
678 fix_required = TRUE;
679 }
680 }
681 else
682 {
683 // will be trashed
684
685 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} covering %{dnsname} not found in chain",
686 context->zone->origin, digest, context->zone->origin, fqdn);
687 #if DEBUG
688 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} covering %{dnsname}: label flags=%04x, is_covered=%i at_or_under_delegation=%i, at_delegation=%i (DEBUG)",
689 context->zone->origin, digest, context->zone->origin, fqdn, zdb_rr_label_flag_get(label),
690 (int)is_covered(label), (int)ZDB_LABEL_ATORUNDERDELEGATION(label), (int)ZDB_LABEL_ATDELEGATION(label));
691 #endif
692 nsec3_load_context_record_delete(expected_nsec3_record);
693 }
694 }
695 }
696
697 int warning_quota = 1000;
698
699 // remove unused and replace them by missing (if any)
700
701 int last_good = -1;
702 for(int i = 0; i <= ptr_vector_last_index(&chain->nsec3_added); ++i)
703 {
704 nsec3_context_record *nsec3_record = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, i);
705 if(nsec3_record->ttl < 0)
706 {
707 nsec3_record->ttl = -nsec3_record->ttl;
708
709 ++last_good;
710 ptr_vector_set(&chain->nsec3_added, last_good, ptr_vector_get(&chain->nsec3_added, i));
711 }
712 else
713 {
714 // unused
715
716 if(warning_quota > 0)
717 {
718 log_warn("zone load: %{dnsname}: nsec3: unused %{digest32h}.%{dnsname} removed", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
719 if(--warning_quota == 0)
720 {
721 log_warn("zone load: %{dnsname}: nsec3: too many warnings, silently removing unused links remaining in the chain", context->zone->origin);
722 }
723 }
724
725 fix_required = TRUE;
726 }
727 }
728
729 if(nsec3_correction_count > 0)
730 {
731 log_warn("zone load: %{dnsname}: nsec3: %u bitmap corrections made", context->zone->origin, nsec3_correction_count);
732 }
733
734 ptr_vector_remove_after(&chain->nsec3_added, last_good);
735 ptr_vector_resize(&chain->nsec3_added, last_good + 1);
736
737 if(fix_required && context->can_fix)
738 {
739 // fix next digest
740
741 nsec3_context_record *prev_nsec3_record = (nsec3_context_record*)ptr_vector_last(&chain->nsec3_added);
742 size_t next_digest_offset = digest_len + 1 + nsec3param_rdata_size;
743
744 if(ptr_vector_last_index(&chain->nsec3_added) > 0)
745 {
746 for(int i = 0; i <= ptr_vector_last_index(&chain->nsec3_added); )
747 {
748 nsec3_context_record *nsec3_record = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, i);
749
750 if(memcmp(prev_nsec3_record->digest_then_rdata, nsec3_record->digest_then_rdata, digest_len + 1) == 0)
751 {
752 // unlikely case of hash collision : delete record, shrink ptr_vector (should also merge bitmap)
753 /// @todo edf 20180905 -- merge type bitmaps (this is a very unlikely case)
754
755 log_notice("zone load: %{dnsname}: nsec3: multiple %{digest32h}.%{dnsname} coverage. "
756 "This is highly unexpected as it requires an hash collision. You should probably change the salt value.",
757 context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
758
759 nsec3_load_context_record_delete(nsec3_record);
760 ptr_vector_remove_at(&chain->nsec3_added, i);
761 continue;
762 }
763
764 // if next-hash != next hash ...
765
766 if(memcmp(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1) != 0)
767 {
768 // overwrite next-hash value
769 memcpy(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1);
770
771 // clear all signatures
772 nsec3_load_context_record_delete_rrsig(prev_nsec3_record);
773 }
774
775 // proceed with the next record
776
777 prev_nsec3_record = nsec3_record;
778
779 ++i;
780 }
781 }
782 else
783 {
784 for(int i = 0; i <= ptr_vector_last_index(&chain->nsec3_added); ++i)
785 {
786 nsec3_context_record *nsec3_record = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, i);
787
788 // if next-hash != next hash ...
789
790 if(memcmp(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1) != 0)
791 {
792 // overwrite next-hash value
793 memcpy(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1);
794
795 // clear all signatures
796 nsec3_load_context_record_delete_rrsig(prev_nsec3_record);
797 }
798
799 // proceed with the next record
800
801 prev_nsec3_record = nsec3_record;
802 }
803 }
804
805 // chain is fixed
806
807 zdb_zone_set_status(context->zone, ZDB_ZONE_STATUS_MODIFIED);
808 }
809
810 return !fix_required;
811 }
812
813 /**
814 * There are two choices for fixing the chain.
815 * Either all digests are computed, associated with their fqdn and then matched with what exists in the context : this way costs (a lot of) memory (say 100 bytes per covered label.)
816 * Either for all fqdn the digest is computed, then sought in the context : this way costs about log2(#labels) seek/compare per covered label.
817 *
818 * This fix for extreme cases has more chances to succeed if it does not go out of memory so the second, slower, way has been chosen.
819 *
820 */
821
822 static void
nsec3_load_fix_chain(nsec3_load_context * context,nsec3_load_context_chain * chain)823 nsec3_load_fix_chain(nsec3_load_context *context, nsec3_load_context_chain *chain)
824 {
825 // for all labels
826 // check if the label should be covered by an NSEC3
827 // compute the digest
828 // seek for the digest
829 // if missing
830 // it will need to be added: keep it on the side for the next pass (with an uninitialised next)
831 // else
832 // mark the entry to tell it's covering something
833 //
834 // for all digests
835 // if the entry is not used, remove it
836 //
837 // add all new entries
838 //
839 // for all digests
840 // verify and fix the next fields
841 //
842
843 nsec3_hash_function *hash_function;
844 u8 *salt;
845 nsec3_load_is_label_covered_function *is_covered;
846 ptr_vector added_nsec3 = PTR_VECTOR_EMPTY;
847 s32 min_ttl = context->zone->min_ttl;
848 u16 hash_iterations;
849 u16 nsec3param_rdata_size;
850 u8 salt_len;
851 u8 optout_byte;
852 u8 digest_len;
853 bool dirty = FALSE;
854 zdb_zone_label_iterator iter;
855 u8 digest[64];
856 u8 fqdn[MAX_DOMAIN_LENGTH + 1];
857
858 digest_len = digest[0] = nsec3_hash_len(NSEC3PARAM_RDATA_ALGORITHM(chain->nsec3param_rdata));
859 hash_function = nsec3_hash_get_function(NSEC3PARAM_RDATA_ALGORITHM(chain->nsec3param_rdata));
860 salt = NSEC3PARAM_RDATA_SALT(chain->nsec3param_rdata);
861 salt_len = NSEC3PARAM_RDATA_SALT_LEN(chain->nsec3param_rdata);
862 hash_iterations = NSEC3PARAM_RDATA_ITERATIONS(chain->nsec3param_rdata);
863 nsec3param_rdata_size = NSEC3PARAM_MINIMUM_LENGTH + salt_len;
864
865 if(context->opt_out)
866 {
867 is_covered = nsec3_load_is_label_covered_optout;
868 optout_byte = 1;
869 }
870 else
871 {
872 is_covered = nsec3_load_is_label_covered;
873 optout_byte = 0;
874 }
875
876 zdb_zone_label_iterator_init(&iter, context->zone);
877 while(zdb_zone_label_iterator_hasnext(&iter))
878 {
879 u32 fqdn_len = zdb_zone_label_iterator_nextname(&iter, fqdn);
880 zdb_rr_label* label = zdb_zone_label_iterator_next(&iter);
881
882 if(is_covered(label))
883 {
884 // should be covered
885
886 hash_function(
887 fqdn,
888 fqdn_len,
889 salt,
890 salt_len,
891 hash_iterations,
892 &digest[1],
893 FALSE);
894
895 // digest exists ?
896
897 // nsec3 missing: generate the type bitmap and make an rdata with an nsec3 digest
898 type_bit_maps_context bitmap;
899
900 u16 bitmap_size = zdb_rr_label_bitmap_type_init(label, &bitmap);
901
902 u16 rdata_size_pre_bitmap = nsec3param_rdata_size + 1 + digest_len;
903 u16 rdata_size = rdata_size_pre_bitmap + bitmap_size;
904
905 nsec3_context_record *expected_nsec3_record = nsec3_load_context_record_new_binary(digest, min_ttl, rdata_size);
906 u8 *rdata = &expected_nsec3_record->digest_then_rdata[digest_len + 1];
907 memcpy(rdata, chain->nsec3param_rdata, nsec3param_rdata_size);
908 rdata[1] = optout_byte;
909 type_bit_maps_write(&bitmap, &rdata[nsec3param_rdata_size + 1 + digest_len]);
910 type_bit_maps_finalize(&bitmap);
911
912 s32 match_index = ptr_vector_search_index(&chain->nsec3_added, digest, nsec3_load_fix_chain_search_cb);
913 void *match = (match_index >= 0)?ptr_vector_get(&chain->nsec3_added, match_index):NULL;
914
915 if(match == NULL)
916 {
917 #if DEBUG
918 rdata[nsec3param_rdata_size] = digest_len;
919 rdata_desc nsec3_rdata = {TYPE_NSEC3, rdata_size, rdata};
920 log_debug("zone load: %{dnsname}: missing %{digest32h}.%{dnsname} %{typerdatadesc}",
921 context->zone->origin, expected_nsec3_record->digest_then_rdata, context->zone->origin, &nsec3_rdata);
922 #endif
923 ptr_vector_append(&added_nsec3, expected_nsec3_record);
924
925 log_warn("zone load: %{dnsname}: nsec3: missing %{digest32h}.%{dnsname} covering %{dnsname} added", context->zone->origin, digest, context->zone->origin, fqdn);
926 }
927 else
928 {
929 // found
930
931 bool nsec3_matches = FALSE;
932
933 nsec3_context_record *nsec3_record = (nsec3_context_record*)match;
934
935 if(nsec3_record->rdata_size == expected_nsec3_record->rdata_size)
936 {
937 if(memcmp(&nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], &expected_nsec3_record->digest_then_rdata[digest_len + 1 + rdata_size_pre_bitmap], bitmap_size) == 0)
938 {
939 nsec3_matches = TRUE;
940 }
941 }
942
943 if(nsec3_matches)
944 {
945 nsec3_load_context_record_delete(expected_nsec3_record);
946 nsec3_record->ttl = - nsec3_record->ttl;
947 }
948 else
949 {
950 log_warn("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} has mismatched bitmap: fixed (%{dnsname})", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin, fqdn);
951
952 ptr_vector_set(&chain->nsec3_added, match_index, expected_nsec3_record);
953 nsec3_load_context_record_delete(nsec3_record);
954 expected_nsec3_record->ttl = - expected_nsec3_record->ttl;
955 dirty = TRUE;
956 }
957 }
958 }
959 }
960
961 int j = 0;
962
963 // remove unused and replace them by missing (if any)
964
965 for(int i = 0; i <= ptr_vector_last_index(&chain->nsec3_added); ++i)
966 {
967 nsec3_context_record *nsec3_record = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, i);
968 if(nsec3_record->ttl < 0)
969 {
970 nsec3_record->ttl = - nsec3_record->ttl;
971 }
972 else
973 {
974 // unused
975
976 log_warn("zone load: %{dnsname}: nsec3: unused %{digest32h}.%{dnsname} removed", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
977
978 nsec3_load_context_record_delete(nsec3_record);
979 if(j <= ptr_vector_last_index(&added_nsec3))
980 {
981 ptr_vector_set(&chain->nsec3_added, i, ptr_vector_get(&added_nsec3, j));
982 ++j;
983 }
984 else
985 {
986 ptr_vector_set(&chain->nsec3_added, i, NULL);
987 }
988
989 dirty = TRUE;
990 }
991 }
992
993 // add missing not added in previous pass
994
995 if(j <= ptr_vector_last_index(&added_nsec3))
996 {
997 int reserve = ptr_vector_last_index(&added_nsec3) - j + 1;
998 ptr_vector_ensures(&chain->nsec3_added, ptr_vector_size(&chain->nsec3_added) + reserve);
999 for(; j <= ptr_vector_last_index(&added_nsec3); ++j)
1000 {
1001 ptr_vector_append(&chain->nsec3_added, ptr_vector_get(&added_nsec3, j));
1002 }
1003 }
1004
1005 ptr_vector_destroy(&added_nsec3);
1006
1007 ptr_vector_qsort(&chain->nsec3_added, nsec3_load_context_record_qsort_callback); // sort the records in the chain
1008
1009 // fix next digest
1010
1011 nsec3_context_record *prev_nsec3_record = (nsec3_context_record*)ptr_vector_last(&chain->nsec3_added);
1012 size_t next_digest_offset = digest_len + 1 + nsec3param_rdata_size;
1013
1014 for(int i = 0; i <= ptr_vector_last_index(&chain->nsec3_added); ++i)
1015 {
1016 nsec3_context_record *nsec3_record = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, i);
1017
1018 // check for duplicates (don't change the comparison order)
1019 // the first test is mandatory to find an error
1020 // the second test is cheap but pointless on all but duplicate cases
1021
1022 if(memcmp(prev_nsec3_record->digest_then_rdata, nsec3_record->digest_then_rdata, digest_len + 1) == 0)
1023 {
1024 if(ptr_vector_last_index(&chain->nsec3_added) > 0)
1025 {
1026 // unlikely case of hash collision : delete record, shrink ptr_vector (should also merge bitmap)
1027 /// @todo edf 20180905 -- merge type bitmaps (this is a very unlikely case)
1028
1029 log_notice("zone load: %{dnsname}: nsec3: multiple %{digest32h}.%{dnsname} coverage. This is highly unexpected as it requires an hash collision. You should probably change the salt value.", context->zone->origin, nsec3_record->digest_then_rdata, context->zone->origin);
1030
1031 dirty = TRUE;
1032
1033 nsec3_load_context_record_delete(nsec3_record);
1034 ptr_vector_remove_at(&chain->nsec3_added, i);
1035 --i;
1036
1037 continue;
1038 }
1039 }
1040
1041 if(memcmp(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1) != 0)
1042 {
1043 if(ptr_vector_last_index(&chain->nsec3_added) > 0)
1044 {
1045 memcpy(&prev_nsec3_record->digest_then_rdata[next_digest_offset], nsec3_record->digest_then_rdata, digest_len + 1);
1046 nsec3_load_context_record_delete_rrsig(prev_nsec3_record);
1047
1048 dirty = TRUE;
1049 }
1050 }
1051
1052 prev_nsec3_record = nsec3_record;
1053 }
1054
1055 // chain is fixed
1056
1057 if(dirty)
1058 {
1059 zdb_zone_set_status(context->zone, ZDB_ZONE_STATUS_MODIFIED);
1060 }
1061 }
1062
1063 /*
1064 * Use this to add the NSEC3 information from the context to the zone.
1065 * yadifad used to be more strict about the NSEC3 chain
1066 * Now it only requires the chain to loop.
1067 *
1068 * If an error is found, and the context allows fixing the zone then:
1069 * The function will correct it and mark the context to tell the zone has been modified.
1070 * The caller should then increment the serial, destroy the journal, and save the fixed zone.
1071 */
1072
1073 ya_result
nsec3_load_generate(nsec3_load_context * context)1074 nsec3_load_generate(nsec3_load_context *context)
1075 {
1076 // for all chains
1077 // sort the records
1078 // ensure the records are following (modulo)
1079 // create the nsec3 chain collection
1080 // add the collection to the zone (enabled or not)
1081
1082 for(int i = 0; i <= ptr_vector_last_index(&context->nsec3chain); ++i)
1083 {
1084 nsec3_load_context_chain *chain = (nsec3_load_context_chain*)ptr_vector_get(&context->nsec3chain, i);
1085
1086 if(ptr_vector_last_index(&chain->nsec3_added) >= 0)
1087 {
1088 ptr_vector_qsort(&chain->nsec3_added, nsec3_load_context_record_qsort_callback); // sort the records in the chain
1089
1090
1091 // slaves cannot fix their content
1092
1093 if(context->can_fix)
1094 {
1095 if(!nsec3_load_find_extranous_records_in_chain(context, chain))
1096 {
1097 context->fix_applied = TRUE;
1098 --i;
1099 continue;
1100 }
1101 }
1102
1103 const nsec3_context_record *p = (const nsec3_context_record*)ptr_vector_last(&chain->nsec3_added);
1104
1105 for(int j = 0; j <= ptr_vector_last_index(&chain->nsec3_added); ++j)
1106 {
1107 const nsec3_context_record *r = (const nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, j);
1108
1109 // the digest in the rdata of p has to be the digest of r
1110
1111 if(!nsec3_load_context_record_linked(p, r))
1112 {
1113 // the chain is broken
1114
1115 log_err("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} should be followed by %{digest32h}.%{dnsname} but was by %{digest32h}.%{dnsname} instead",
1116 context->zone->origin,
1117 p->digest_then_rdata, context->zone->origin,
1118 nsec3_load_context_record_next_digest(p), context->zone->origin,
1119 r->digest_then_rdata, context->zone->origin);
1120
1121 if(!context->can_fix)
1122 {
1123 // even with a more lenient yadifad, a broken chain is just not usable by a slave
1124 // the minimum requirement now is coherence
1125
1126 return DNSSEC_ERROR_NSEC3_INVALIDZONESTATE;
1127 }
1128
1129 nsec3_load_fix_chain(context, chain);
1130
1131 context->fix_applied = TRUE;
1132 // --i;
1133 break;
1134 }
1135
1136 p = r;
1137 }
1138
1139 if(!context->fix_applied)
1140 {
1141 const nsec3_context_record *s = (const nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, 0);
1142
1143 if(!nsec3_load_context_record_linked(p, s))
1144 {
1145 // the chain is broken
1146
1147 log_err("zone load: %{dnsname}: nsec3: %{digest32h}.%{dnsname} should be followed by %{digest32h}.%{dnsname} but was by %{digest32h}.%{dnsname} instead (back to front)",
1148 context->zone->origin,
1149 p->digest_then_rdata, context->zone->origin,
1150 nsec3_load_context_record_next_digest(p), context->zone->origin,
1151 s->digest_then_rdata, context->zone->origin);
1152
1153 if(!context->can_fix)
1154 {
1155 return DNSSEC_ERROR_NSEC3_INVALIDZONESTATE;
1156 }
1157
1158 nsec3_load_fix_chain(context, chain);
1159
1160 context->fix_applied = TRUE;
1161 //--i;
1162 break;
1163 }
1164 }
1165 }
1166 else
1167 {
1168 log_err("zone load: %{dnsname}: nsec3: empty chain %i", context->zone->origin, i);
1169
1170 // slaves cannot fix their content
1171
1172 if(context->can_fix)
1173 {
1174 nsec3_load_fix_chain(context, chain);
1175
1176 context->fix_applied = TRUE;
1177 }
1178 }
1179 }
1180
1181 nsec3_zone **n3p = &context->zone->nsec.nsec3;
1182
1183 // the chain are valid : create the collections
1184
1185 // but first sort the collections to put the ones with NSEC3PARAM with smallest digest/iterations
1186
1187 ptr_vector_qsort(&context->nsec3chain, nsec3_load_context_chain_qsort_callback); // sort the chains
1188
1189 for(int i = 0; i <= ptr_vector_last_index(&context->nsec3chain); ++i)
1190 {
1191 nsec3_load_context_chain *chain = (nsec3_load_context_chain*)ptr_vector_get(&context->nsec3chain, i);
1192
1193 nsec3_zone *n3 = nsec3_zone_new(chain->nsec3param_rdata, chain->nsec3param_rdata_size);
1194
1195 for(int j = 0; j <= ptr_vector_last_index(&chain->nsec3_added); ++j)
1196 {
1197 nsec3_context_record *r = (nsec3_context_record*)ptr_vector_get(&chain->nsec3_added, j);
1198 const u8 *rdata = nsec3_load_context_record_rdata(r);
1199 nsec3_node *node = nsec3_insert(&n3->items, r->digest_then_rdata);
1200 node->flags = rdata[1];
1201 nsec3_zone_item_update_bitmap(node, rdata, r->rdata_size);
1202 node->rrsig = r->rrsig;
1203 r->rrsig = NULL;
1204 }
1205 // the chain is complete
1206
1207 *n3p = n3;
1208 n3p = &n3->next;
1209
1210 // if the first chain has an nsec3param, it is visible
1211 if(i == 0 && chain->has_nsec3param)
1212 {
1213 // link the labels
1214 nsec3_zone_update_chain0_links(context->zone);
1215 }
1216 }
1217
1218 // finally: add the postponed rrsig records
1219
1220 ptr_set_iterator iter;
1221 ptr_set_iterator_init(&context->postponed_rrsig, &iter);
1222 while(ptr_set_iterator_hasnext(&iter))
1223 {
1224 ptr_node *rrsig_node = ptr_set_iterator_next_node(&iter);
1225
1226 bool useless = TRUE;
1227
1228 for(nsec3_zone *n3 = context->zone->nsec.nsec3; n3 != NULL; n3 = n3->next)
1229 {
1230 nsec3_node *nsec3_node = nsec3_find(&n3->items, rrsig_node->key);
1231 if(nsec3_node != NULL)
1232 {
1233 zdb_packed_ttlrdata *rrsig = (zdb_packed_ttlrdata*)rrsig_node->value;
1234
1235 nsec3_node->rrsig = rrsig;
1236 u8 *key = (u8*)rrsig_node->key;
1237 ZFREE_ARRAY(rrsig_node->key, key[0] + 1); // VS false positive: a key cannot be NULL
1238 rrsig_node->key = NULL;
1239 rrsig_node->value = NULL;
1240
1241 useless = FALSE;
1242
1243 break;
1244 }
1245 }
1246
1247 if(useless)
1248 {
1249 // complain
1250 log_warn("nsec3: %{dnsname}: %{digest32h}: RRSIG does not covers any known NSEC3 record",
1251 context->zone->origin,
1252 rrsig_node->key);
1253 }
1254 }
1255
1256 return SUCCESS;
1257 }
1258
1259 bool
nsec3_load_is_context_empty(nsec3_load_context * context)1260 nsec3_load_is_context_empty(nsec3_load_context* context)
1261 {
1262 return (context->zone == NULL) || (ptr_vector_last_index(&context->nsec3chain) < 0);
1263 }
1264
1265 /** @} */
1266
1267