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