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 /*
51  *  RFC 5155
52  *
53  *  Server Response to a Run-Time Collision
54  *
55  *  If the hash of a non-existing QNAME collides with the owner name of
56  *  an existing NSEC3 RR, then the server will be unable to return a
57  *  response that proves that QNAME does not exist.  In this case, the
58  *  server MUST return a response with an RCODE of 2 (server failure).
59  *
60  *  Note that with the hash algorithm specified in this document, SHA-1,
61  *  such collisions are highly unlikely.
62  *
63  */
64 
65 #include "dnsdb/zdb_types.h"
66 
67 #if !ZDB_HAS_NSEC3_SUPPORT
68 #error nsec3.c should not be compiled when ZDB_HAS_NSEC3_SUPPORT == 0
69 #endif
70 
71 #include <dnscore/dnsname.h>
72 #include <dnscore/base32hex.h>
73 #include <dnscore/rfc.h>
74 #include <dnscore/ptr_vector.h>
75 #include <dnscore/logger.h>
76 #include <dnscore/dnskey-signature.h>
77 
78 #include "dnsdb/zdb_zone.h"
79 #include "dnsdb/zdb_zone_label_iterator.h"
80 #include "dnsdb/zdb_record.h"
81 #include "dnsdb/nsec3.h"
82 #include "dnsdb/nsec_common.h"
83 #include "dnsdb/nsec3_owner.h"
84 #include "dnsdb/rrsig.h"
85 #include "dnsdb/dynupdate-diff.h"
86 #include "dnsdb/dynupdate-message.h"
87 #include "dnsdb/zdb-zone-path-provider.h"
88 
89 #define NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG 0
90 
91 #if NSEC3_UPDATE_ZONE_DEBUG
92 #pragma message("NSEC3_UPDATE_ZONE_DEBUG enabled, disable this for release builds")
93 #endif
94 
95 #define MODULE_MSG_HANDLE g_dnssec_logger
96 extern logger_handle *g_dnssec_logger;
97 
98 #define N3IRRVDT_TAG 0x544456525249334e
99 #define RRVDATA_TAG 0x41544144565252
100 
101 /**
102  * used by nsec3_label_link
103  *
104  * It will find if the label has got a matching NSEC3 record (by digest)
105  * If so, it will link to it.
106  */
107 
108 static nsec3_zone_item *
nsec3_label_link_seeknode(nsec3_zone * n3,const u8 * fqdn,s32 fqdn_len,u8 * digest)109 nsec3_label_link_seeknode(nsec3_zone* n3, const u8 *fqdn, s32 fqdn_len, u8 *digest)
110 {
111     nsec3_compute_digest_from_fqdn_with_len(n3, fqdn, fqdn_len, digest, FALSE);
112 
113 #if NSEC3_UPDATE_ZONE_DEBUG
114     log_debug("nsec3: seeking node for %{dnsname} with %{digest32h}", fqdn, digest);
115 #endif
116 
117     nsec3_zone_item *self = nsec3_find(&n3->items, digest);
118 
119     return self;
120 }
121 
122 /**
123  * used by nsec3_label_link
124  *
125  * It will find if the *.label has got a matching NSEC3 record (by digest)
126  * If so, it will link to it.
127  */
128 
129 static nsec3_zone_item *
nsec3_label_link_seekstar(nsec3_zone * n3,const u8 * fqdn,s32 fqdn_len,u8 * digest)130 nsec3_label_link_seekstar(nsec3_zone* n3, const u8 *fqdn, s32 fqdn_len, u8 *digest)
131 {
132     nsec3_compute_digest_from_fqdn_with_len(n3, fqdn, fqdn_len, digest, TRUE);
133 
134 #if NSEC3_UPDATE_ZONE_DEBUG
135     log_debug("nsec3: seeking star for %{dnsname} with %{digest32h}", fqdn, digest);
136 #endif
137 
138     nsec3_zone_item* star = nsec3_find_interval_start(&n3->items, digest);
139 
140     return star;
141 }
142 
143 /*
144  * This destroy all the NSEC3 structures from the zone, starting from the NSEC3PARAM.
145  * The zdb_rr_label are also affected by the call.
146  */
147 
148 void
nsec3_destroy_zone(zdb_zone * zone)149 nsec3_destroy_zone(zdb_zone *zone)
150 {
151      // Note that from the 'transaction' update, the dnssec zone collections have to be read without checking for the NSEC3 flag
152 
153     while(zone->nsec.nsec3 != NULL)
154     {
155 #if DEBUG
156         nsec3_zone *n3 = zone->nsec.nsec3;
157 #endif
158         nsec3_zone_destroy(zone, zone->nsec.nsec3);
159 #if DEBUG
160         yassert(n3 != zone->nsec.nsec3);
161 #endif
162     }
163 }
164 
165 /******************************************************************************
166  *
167  * NSEC3 - queries
168  *
169  *****************************************************************************/
170 
171 /**
172  * @brief Finds the provable resource record label matching a path of labels starting from another rr label
173  *
174  * Finds the resource record label matching a path of labels starting from another rr label
175  * Typically the starting label is a zone cut.
176  * The starting point MUST be provable (ie: the apex in NSEC and in NSEC3 zones)
177  *
178  * @param[in] apex the starting label
179  * @param[in] path a stack of labels
180  * @param[in] path_index the index of the top of the stack
181  *
182  * @return the matching label or NULL if it has not been found
183  */
184 
185 /* NSEC3: Zone possible */
186 static int
nsec3_get_closest_provable_encloser_match(const void * label,const dictionary_node * node)187 nsec3_get_closest_provable_encloser_match(const void *label, const dictionary_node *node)
188 {
189     zdb_rr_label* rr_label = (zdb_rr_label*) node;
190     return dnslabel_equals(rr_label->name, label);
191 }
192 
193 /**
194  *
195  * Finds what is the closest provable encloser for a label in a zone
196  *
197  * @param apex
198  * @param sections
199  * @param sections_topp
200  * @return
201  */
202 
203 const zdb_rr_label*
nsec3_get_closest_provable_encloser_optin(const zdb_rr_label * apex,const_dnslabel_vector_reference sections,s32 * sections_topp)204 nsec3_get_closest_provable_encloser_optin(const zdb_rr_label *apex, const_dnslabel_vector_reference sections, s32 *sections_topp)
205 {
206     yassert((apex != NULL) && (sections != NULL) && (sections_topp != NULL));
207 
208     s32 index = *sections_topp;
209     const zdb_rr_label* rr_label = apex; /* the zone cut */
210 
211     const zdb_rr_label* provable = apex;
212 
213     /*
214      * the apex is already known, so we don't loop for it
215      */
216 
217     index--;
218 
219     /* look into the sub level*/
220 
221     while(index >= 0)
222     {
223         const u8* label = sections[index];
224         hashcode hash = hash_dnslabel(label);
225 
226         rr_label = (zdb_rr_label*) dictionary_find(&rr_label->sub, hash, label, nsec3_get_closest_provable_encloser_match);
227 
228         if(rr_label == NULL)
229         {
230             index++;
231             break;
232         }
233 
234         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_N3COVERED))
235         {
236             provable = rr_label;
237             *sections_topp = index;
238         }
239 
240         index--;
241     }
242 
243     return provable;
244 }
245 
246 const zdb_rr_label*
nsec3_get_closest_provable_encloser_optout(const zdb_rr_label * apex,const_dnslabel_vector_reference sections,s32 * sections_topp)247 nsec3_get_closest_provable_encloser_optout(const zdb_rr_label *apex, const_dnslabel_vector_reference sections, s32 *sections_topp)
248 {
249     yassert(apex != NULL && sections != NULL && sections_topp != NULL);
250 
251     s32 index = *sections_topp;
252     const zdb_rr_label* rr_label = apex; /* the zone cut */
253 
254     const zdb_rr_label* provable = apex;
255 
256     /*
257      * the apex is already known, so we don't loop for it
258      */
259 
260     index--;
261 
262     /* look into the sub level*/
263 
264     while(index >= 0)
265     {
266         const u8* label = sections[index];
267         hashcode hash = hash_dnslabel(label);
268 
269         rr_label = (zdb_rr_label*) dictionary_find(&rr_label->sub, hash, label, nsec3_get_closest_provable_encloser_match);
270 
271         if(rr_label == NULL)
272         {
273             index++;
274             break;
275         }
276 
277         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_N3OCOVERED))
278         {
279             provable = rr_label;
280             *sections_topp = index;
281         }
282         /*
283         else if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_GOT_WILD))
284         {
285             dictionary_iterator iter;
286             dictionary_iterator_init(&rr_label->sub, &iter);
287             if(dictionary_iterator_hasnext(&iter))
288             {
289                 provable =  *(zdb_rr_label**)dictionary_iterator_next(&iter);
290                 *sections_topp = index - 1;
291                 break;
292             }
293         }
294         */
295 
296         index--;
297     }
298 
299     return provable;
300 }
301 
302 void
nsec3_get_wild_match_and_closest_provable_encloser_optin(const zdb_rr_label * apex,const_dnslabel_vector_reference sections,s32 sections_top,const zdb_rr_label ** wild_matchp,s32 * wild_topp,const zdb_rr_label ** provable_matchp,s32 * provable_topp)303 nsec3_get_wild_match_and_closest_provable_encloser_optin(const zdb_rr_label *apex, const_dnslabel_vector_reference sections, s32 sections_top,
304                                           const zdb_rr_label** wild_matchp, s32 *wild_topp,
305                                           const zdb_rr_label** provable_matchp, s32 *provable_topp)
306 {
307     yassert(apex != NULL && sections != NULL && wild_matchp != NULL && wild_topp != NULL && provable_matchp != NULL && provable_topp != NULL);
308 
309     s32 index = sections_top;
310     const zdb_rr_label* rr_label = apex; /* the zone cut */
311     *wild_matchp = NULL;
312     *provable_matchp = apex;
313     *provable_topp = sections_top;
314 
315     /*
316      * the apex is already known, so we don't loop for it
317      */
318 
319     index--;
320 
321     /* look into the sub level*/
322 
323     while(index >= 0)
324     {
325         const u8* label = sections[index];
326         hashcode hash = hash_dnslabel(label);
327 
328         rr_label = (zdb_rr_label*) dictionary_find(&rr_label->sub, hash, label, nsec3_get_closest_provable_encloser_match);
329 
330         if(rr_label == NULL)
331         {
332             break;
333         }
334 
335         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_GOT_WILD))
336         {
337             dictionary_iterator iter;
338             dictionary_iterator_init(&rr_label->sub, &iter);
339             if(dictionary_iterator_hasnext(&iter))
340             {
341                 *wild_matchp =  *(zdb_rr_label**)dictionary_iterator_next(&iter);
342                 *wild_topp = index - 1;
343             }
344         }
345         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_N3COVERED))
346         {
347             *provable_matchp = rr_label;
348             *provable_topp = index;
349         }
350     }
351 }
352 
353 void
nsec3_get_wild_match_and_closest_provable_encloser_optout(const zdb_rr_label * apex,const_dnslabel_vector_reference sections,s32 sections_top,const zdb_rr_label ** wild_matchp,s32 * wild_topp,const zdb_rr_label ** provable_matchp,s32 * provable_topp)354 nsec3_get_wild_match_and_closest_provable_encloser_optout(const zdb_rr_label *apex, const_dnslabel_vector_reference sections, s32 sections_top,
355                     const zdb_rr_label** wild_matchp, s32 *wild_topp,
356                     const zdb_rr_label** provable_matchp, s32 *provable_topp
357                     )
358 {
359     yassert(apex != NULL && sections != NULL && wild_matchp != NULL && wild_topp != NULL && provable_matchp != NULL && provable_topp != NULL);
360 
361     s32 index = sections_top;
362     const zdb_rr_label* rr_label = apex; /* the zone cut */
363     *wild_matchp = NULL;
364     *provable_matchp = apex;
365     *provable_topp = sections_top;
366 
367     --index;
368 
369     /* look into the sub level*/
370 
371     while(index >= 0)
372     {
373         const u8* label = sections[index];
374         hashcode hash = hash_dnslabel(label);
375 
376         rr_label = (zdb_rr_label*) dictionary_find(&rr_label->sub, hash, label, nsec3_get_closest_provable_encloser_match);
377 
378         if(rr_label == NULL)
379         {
380             break;
381         }
382 
383         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_GOT_WILD))
384         {
385             dictionary_iterator iter;
386             dictionary_iterator_init(&rr_label->sub, &iter);
387             if(dictionary_iterator_hasnext(&iter))
388             {
389                 *wild_matchp =  *(zdb_rr_label**)dictionary_iterator_next(&iter);
390                 *wild_topp = index - 1;
391             }
392         }
393         if(zdb_rr_label_flag_matches(rr_label, ZDB_RR_LABEL_N3OCOVERED))
394         {
395             *provable_matchp = rr_label;
396             *provable_topp = index;
397         }
398 
399         index--;
400     }
401 }
402 
403 /**
404  * Computes the closest closer proof for a name in a zone
405  * Results are returned in 3 pointers
406  * The last one of them can be set NULL if the information is not needed.
407  *
408  * @param zone
409  * @param qname the fqdn of the query
410  * @param apex_index the index of the apex in qname
411  * @param encloser_nsec3p will point to the encloser
412  * @param closest_provable_encloser_nsec3p will point to the closest provable encloser
413  * @param wild_closest_provable_encloser_nsec3p will point to the *.closest provable encloser
414  *
415  */
416 
417 void
nsec3_wild_closest_encloser_proof(const zdb_zone * zone,const dnsname_vector * qname,s32 apex_index,const nsec3_zone_item ** wild_encloser_nsec3p,const nsec3_zone_item ** closest_provable_encloser_nsec3p,const nsec3_zone_item ** qname_encloser_nsec3p)418 nsec3_wild_closest_encloser_proof(
419     const zdb_zone *zone,
420     const dnsname_vector *qname, s32 apex_index,
421     const nsec3_zone_item **wild_encloser_nsec3p,
422     const nsec3_zone_item **closest_provable_encloser_nsec3p,
423     const nsec3_zone_item **qname_encloser_nsec3p
424 )
425 {
426     u8 tmp_fqdn[MAX_DOMAIN_LENGTH + 1];
427     u8 digest[64 + 1];
428     digest[0] = SHA_DIGEST_LENGTH;
429 
430     // wild_closest_provable_encloser_nsec3p can be NULL
431 
432     const_dnslabel_vector_reference qname_sections = qname->labels;
433     s32 closest_encloser_index_limit = qname->size - apex_index + 1; /* not "+1'" because it starts at the apex */
434 
435     const nsec3_zone* n3 = zone->nsec.nsec3;
436 
437 #if DEBUG
438     if((n3 == NULL) || (n3->items == NULL))
439     {
440         log_err("zone %{dnsname} has invalid NSEC3 data");
441         return;
442     }
443 #endif
444 
445     if(closest_encloser_index_limit > 0)
446     {
447         const zdb_rr_label* wild_match;
448         const zdb_rr_label* provable_match;
449         s32 wild_top;
450         s32 provable_top;
451 
452         if((zdb_zone_get_flags(zone) & ZDB_ZONE_HAS_OPTOUT_COVERAGE) != 0)
453         {
454             nsec3_get_wild_match_and_closest_provable_encloser_optout(zone->apex, qname_sections, closest_encloser_index_limit,
455                                                                       &wild_match, &wild_top,
456                                                                       &provable_match, &provable_top);
457         }
458         else
459         {
460             nsec3_get_wild_match_and_closest_provable_encloser_optin(zone->apex, qname_sections, closest_encloser_index_limit,
461                                                                       &wild_match, &wild_top,
462                                                                       &provable_match, &provable_top);
463         }
464 
465         /* Get ZONE NSEC3PARAM */
466         u16 iterations = nsec3_zone_get_iterations(n3);
467         u8 salt_len = NSEC3_ZONE_SALT_LEN(n3);
468         const u8* salt = NSEC3_ZONE_SALT(n3);
469 
470         nsec3_hash_function* const digestname = nsec3_hash_get_function(NSEC3_ZONE_ALGORITHM(n3)); /// @note 20150917 edf -- do not use nsec3_compute_digest_from_fqdn_with_len
471 
472         /** @note log_* cannot be used here (except yassert because if that one logs it will abort anyway ...) */
473 
474         //dnsname_vector_sub_to_dnsname(qname, closest_encloser_index_limit  , );
475 
476         const nsec3_zone_item *wild_closest_provable_encloser_nsec3 = NULL;
477         const nsec3_zone_item *qname_encloser_nsec3 = NULL;
478 
479         if((wild_match != NULL) && zdb_rr_label_nsec3_linked(wild_match))
480         {
481             wild_closest_provable_encloser_nsec3 = nsec3_label_extension_self(wild_match->nsec.nsec3);
482 
483             // add the interval for the fqdn at the * level
484 
485             dnsname_vector_sub_to_dnsname(qname, wild_top, tmp_fqdn);
486             digestname(tmp_fqdn, dnsname_len(tmp_fqdn), salt, salt_len, iterations, &digest[1], FALSE);
487             qname_encloser_nsec3 = nsec3_find_interval_start(&n3->items, digest);
488 
489             if(qname_encloser_nsec3 != wild_closest_provable_encloser_nsec3)
490             {
491                 *qname_encloser_nsec3p = qname_encloser_nsec3;
492             }
493         }
494 
495         *wild_encloser_nsec3p = wild_closest_provable_encloser_nsec3;
496 
497         const nsec3_zone_item *closest_provable_encloser_nsec3;
498 
499         if(zdb_rr_label_nsec3_linked(provable_match))
500         {
501             closest_provable_encloser_nsec3 = nsec3_label_extension_self(provable_match->nsec.nsec3);
502         }
503         else
504         {
505             digestname(tmp_fqdn, dnsname_len(tmp_fqdn), salt, salt_len, iterations, &digest[1], FALSE);
506             closest_provable_encloser_nsec3 = nsec3_find_interval_start(&n3->items, digest);
507         }
508 
509         if((closest_provable_encloser_nsec3 != wild_closest_provable_encloser_nsec3) && (closest_provable_encloser_nsec3 != qname_encloser_nsec3))
510         {
511             *closest_provable_encloser_nsec3p = closest_provable_encloser_nsec3;
512         }
513         else
514         {
515             *closest_provable_encloser_nsec3p = NULL;
516         }
517     }
518     else // the closest is the item itself ...
519     {
520         *wild_encloser_nsec3p = nsec3_label_extension_self(zone->apex->nsec.nsec3);
521         *closest_provable_encloser_nsec3p = NULL;
522     }
523 }
524 
525 /**
526  * Computes the closest closer proof for a name in a zone
527  * Results are returned in 3 pointers
528  * The last one of them can be set NULL if the information is not needed.
529  *
530  * @param zone
531  * @param qname the fqdn of the query
532  * @param apex_index the index of the apex in qname
533  * @param encloser_nsec3p will point to the encloser
534  * @param closest_provable_encloser_nsec3p will point to the closest provable encloser
535  * @param wild_closest_provable_encloser_nsec3p will point to the *.closest provable encloser
536  *
537  */
538 
539 void
nsec3_closest_encloser_proof(const zdb_zone * zone,const dnsname_vector * qname,s32 apex_index,const nsec3_zone_item ** encloser_nsec3p,const nsec3_zone_item ** closest_provable_encloser_nsec3p,const nsec3_zone_item ** wild_closest_provable_encloser_nsec3p)540 nsec3_closest_encloser_proof(
541                         const zdb_zone *zone,
542                         const dnsname_vector *qname, s32 apex_index,
543                         const nsec3_zone_item **encloser_nsec3p,
544                         const nsec3_zone_item **closest_provable_encloser_nsec3p,
545                         const nsec3_zone_item **wild_closest_provable_encloser_nsec3p
546                         )
547 {
548     u8 closest_provable_encloser[MAX_DOMAIN_LENGTH+1];
549     u8 encloser[MAX_DOMAIN_LENGTH+1];
550     u8 digest[64 + 1];
551     digest[0] = SHA_DIGEST_LENGTH;
552 
553     yassert(encloser_nsec3p != NULL);
554     yassert(closest_provable_encloser_nsec3p != NULL);
555     // wild_closest_provable_encloser_nsec3p can be NULL
556 
557     const_dnslabel_vector_reference qname_sections = qname->labels;
558     s32 closest_encloser_index_limit = qname->size - apex_index + 1; /* not "+1'" because it starts at the apex */
559 
560     const nsec3_zone* n3 = zone->nsec.nsec3;
561 
562 #if DEBUG
563     if((n3 == NULL) || (n3->items == NULL))
564     {
565         log_err("zone %{dnsname} has invalid NSEC3 data");
566         return;
567     }
568 #endif
569 
570     if(closest_encloser_index_limit > 0)
571     {
572         const zdb_rr_label* closest_provable_encloser_label = ((zdb_zone_get_flags(zone) & ZDB_ZONE_HAS_OPTOUT_COVERAGE) != 0)?
573                 nsec3_get_closest_provable_encloser_optout(zone->apex, qname_sections, &closest_encloser_index_limit):
574                 nsec3_get_closest_provable_encloser_optin(zone->apex, qname_sections, &closest_encloser_index_limit);
575 
576         //log_debug("closest_provable_encloser_label: %{dnslabel}: %{digest32h}", closest_provable_encloser_label->name, closest_provable_encloser_label->nsec.nsec3->self->digest);
577         //log_debug("*.closest_provable_encloser_label: %{dnslabel}: %{digest32h}", closest_provable_encloser_label->name, closest_provable_encloser_label->nsec.nsec3->star->digest);
578 
579         /*
580          * Convert from closest_encloser_label_bottom to name.size into a dnslabel
581          */
582 
583         /* Get ZONE NSEC3PARAM */
584         u16 iterations = nsec3_zone_get_iterations(n3);
585         u8 salt_len = NSEC3_ZONE_SALT_LEN(n3);
586         const u8* salt = NSEC3_ZONE_SALT(n3);
587         const nsec3_zone_item* encloser_nsec3 = NULL;
588 
589         nsec3_hash_function* const digestname = nsec3_hash_get_function(NSEC3_ZONE_ALGORITHM(n3)); /// @note 20150917 edf -- do not use nsec3_compute_digest_from_fqdn_with_len
590 
591         /** @note log_* cannot be used here (except yassert because if that one logs it will abort anyway ...) */
592 
593         // encloser_nsec3p
594 
595         if(closest_encloser_index_limit > 0) // if the closest encloser is itself, we should not be here
596         {
597             yassert(closest_provable_encloser_label != NULL);
598             dnsname_vector_sub_to_dnsname(qname, closest_encloser_index_limit - 1, encloser);
599             digestname(encloser, dnsname_len(encloser), salt, salt_len, iterations, &digest[1], FALSE);
600             encloser_nsec3 = nsec3_zone_item_find_encloser_start(n3, digest);
601             *encloser_nsec3p = encloser_nsec3;
602         }
603         else
604         {
605             *encloser_nsec3p = NULL; // the closest is itself (ie: missing type)
606         }
607 
608         // closest_provable_encloser_nsec3p
609 
610         dnsname_vector_sub_to_dnsname(qname, closest_encloser_index_limit  , closest_provable_encloser);
611 
612         const nsec3_zone_item* closest_provable_encloser_nsec3;
613 
614         if(!zdb_rr_label_nsec3_linked(closest_provable_encloser_label))
615         {
616             digestname(closest_provable_encloser, dnsname_len(closest_provable_encloser), salt, salt_len, iterations, &digest[1], FALSE);
617             closest_provable_encloser_nsec3 = nsec3_find(&n3->items, digest);
618         }
619         else
620         {
621             closest_provable_encloser_nsec3 = nsec3_label_extension_self(closest_provable_encloser_label->nsec.nsec3);
622         }
623         if(closest_provable_encloser_nsec3 == encloser_nsec3)
624         {
625             closest_provable_encloser_nsec3 = NULL;
626         }
627 
628         *closest_provable_encloser_nsec3p = closest_provable_encloser_nsec3;
629 
630         if(wild_closest_provable_encloser_nsec3p != NULL)
631         {
632             if(closest_provable_encloser_nsec3 == NULL)
633             {
634                 dnsname_vector_sub_to_dnsname(qname, closest_encloser_index_limit  , closest_provable_encloser);
635             }
636 
637             const nsec3_zone_item *wild_closest_provable_encloser_nsec3;
638 
639             if(!zdb_rr_label_nsec3_linked(closest_provable_encloser_label))
640             {
641                 digestname(closest_provable_encloser, dnsname_len(closest_provable_encloser), salt, salt_len, iterations, &digest[1], TRUE);
642                 wild_closest_provable_encloser_nsec3 = nsec3_find_interval_start(&n3->items, digest);
643             }
644             else
645             {
646                 wild_closest_provable_encloser_nsec3 = nsec3_label_extension_star(closest_provable_encloser_label->nsec.nsec3);
647             }
648 
649             if(wild_closest_provable_encloser_nsec3 == encloser_nsec3)
650             {
651                 wild_closest_provable_encloser_nsec3 = NULL;
652             }
653             else if(wild_closest_provable_encloser_nsec3 == closest_provable_encloser_nsec3)
654             {
655                 wild_closest_provable_encloser_nsec3 = NULL;
656             }
657 
658             *wild_closest_provable_encloser_nsec3p = wild_closest_provable_encloser_nsec3;
659         }
660     }
661     else // the closest is the item itself ...
662     {
663         *encloser_nsec3p = nsec3_label_extension_self(zone->apex->nsec.nsec3);
664         *closest_provable_encloser_nsec3p = nsec3_label_extension_self(zone->apex->nsec.nsec3);
665         if(wild_closest_provable_encloser_nsec3p != NULL)
666         {
667             *wild_closest_provable_encloser_nsec3p = nsec3_label_extension_self(zone->apex->nsec.nsec3);
668         }
669     }
670 }
671 
672 #if NSEC3_UPDATE_ZONE_DEBUG
673 
674 /**
675  * This is an internal integrity check
676  *
677  * For all owners of the NSEC3 record (aka nsec3_zone_item aka nsec3_node)
678  *   Check the label is not under a delegation (log debug only)
679  *   Check the label points back to the NSEC3 record
680  *
681  * @param item the NSEC3 record
682  * @param param_index_base the index of the chain of the NSEC3 record
683  */
684 
685 void
nsec3_check_item(nsec3_zone_item * item,u32 param_index_base)686 nsec3_check_item(nsec3_zone_item *item, u32 param_index_base)
687 {
688     yassert(item != NULL);
689 
690     u16 n = nsec3_owner_count(item);
691 
692     if(n == 0)
693     {
694         log_err("nsec3_check: %{digest32h} has no owner", item->digest);
695         logger_flush();
696         abort();
697     }
698 
699     for(u16 i = 0; i < n; i++)
700     {
701         zdb_rr_label *label = nsec3_item_owner_get(item, i);
702 
703         yassert(label != NULL && label->nsec.nsec3 != NULL);
704 
705         if(ZDB_LABEL_UNDERDELEGATION(label))
706         {
707             log_err("nsec3_check: %{digest32h} label nsec3 reference under a delegation (%{dnslabel})", item->digest, label);
708         }
709 
710         nsec3_label_extension *n3le = label->nsec.nsec3;
711 
712         u32 param_index = param_index_base;
713         while(param_index > 0)
714         {
715             yassert(n3le != NULL);
716 
717 
718 
719             n3le = nsec3_label_extension_next(n3le);
720 
721             param_index--;
722         }
723 
724         yassert(n3le != NULL);
725 
726 
727         // the nsec3 structure reference to the item linked to the label does not links back to the item
728 #if 0 /* fix */
729 #else
730         yassert(n3le->_self == item);
731 #endif
732     }
733 
734     n = nsec3_star_count(item);
735 
736     for(u16 i = 0; i < n; i++)
737     {
738         zdb_rr_label *label = nsec3_item_star_get(item, i);
739 
740         if(!((label != NULL) && (label->nsec.nsec3 != NULL)))
741         {
742             log_err("nsec3_check: %{digest32h} (#self=%d/#star=%d) corrupted", item->digest, item->rc, item->sc);
743         }
744 
745         yassert(label != NULL && label->nsec.nsec3 != NULL);
746 
747         if(ZDB_LABEL_UNDERDELEGATION(label))
748         {
749             log_err("nsec3_check: %{digest32h} *.label nsec3 reference under a delegation (%{dnslabel})", item->digest, label);
750         }
751 
752         nsec3_label_extension *n3le = label->nsec.nsec3;
753 
754         u32 param_index = param_index_base;
755         while(param_index > 0)
756         {
757             yassert(n3le != NULL);
758 
759 
760 
761             n3le = nsec3_label_extension_next(n3le);
762 
763             param_index--;
764         }
765 
766         yassert(n3le != NULL);
767 
768 
769 
770         if(nsec3_label_extension_star(n3le) != item)
771         {
772             if(nsec3_label_extension_star(n3le) != NULL)
773             {
774                 log_err("nsec3_check: %{digest32h} (#self=%d/#star=%d) failing %{dnslabel} expected %{digest32h}", item->digest, item->rc, item->sc, label->name, nsec3_label_extension_star(n3le)->digest);
775             }
776             else
777             {
778                 log_err("nsec3_check: %{digest32h} (#self=%d/#star=%d) *.%{dnslabel} is NULL", item->digest, item->rc, item->sc, label->name, nsec3_label_extension_star(n3le)->digest);
779             }
780         }
781 
782         if(nsec3_label_extension_self(n3le) == NULL)
783         {
784             log_err("nsec3_check: %{digest32h} (#self=%d/#star=%d) failing %{dnslabel}: no self", item->digest, item->rc, item->sc, label->name);
785         }
786 
787         if(nsec3_label_extension_star(n3le) != item)
788         {
789             log_err("nsec3_check: %{digest32h} *.label nsec3 reference does not point back to the nsec3 item (%{dnslabel})", item->digest, label);
790         }
791         if(nsec3_label_extension_self(n3le) == NULL)
792         {
793             log_err("nsec3_check: %{digest32h} *.label nsec3 reference self is NULL (%{dnslabel})", item->digest, label);
794         }
795     }
796 }
797 
798 /**
799  * This is an internal integrity check
800  *
801  * Checks all NSEC3 links to their owners back and forth.
802  *
803  * @param zone
804  */
805 
806 void
nsec3_check(zdb_zone * zone)807 nsec3_check(zdb_zone *zone)
808 {
809     log_debug("nsec3_check: %{dnsname}, from the NSEC3's reference", zone->origin);
810 
811     const nsec3_zone *n3 = zone->nsec.nsec3;
812 
813     if(n3 == NULL)
814     {
815         log_debug("nsec3_check: %{dnsname}: no NSEC3", zone->origin);
816 
817         return;
818     }
819 
820     /*
821      * For each node, check if the owners and stars are coherent
822      */
823 
824     u32 param_index = 0;
825 
826     while(n3 != NULL)
827     {
828         nsec3_iterator n3iter;
829         nsec3_iterator_init(&n3->items, &n3iter);
830         while(nsec3_iterator_hasnext(&n3iter))
831         {
832             nsec3_zone_item* item = nsec3_iterator_next_node(&n3iter);
833 
834             nsec3_check_item(item, param_index);
835         }
836 
837         param_index++;
838 
839         n3 = n3->next;
840     }
841 
842     log_debug("nsec3_check: %{dnsname}: from the label's reference", zone->origin);
843 
844     zdb_zone_label_iterator label_iterator;
845     u8 fqdn[MAX_DOMAIN_LENGTH + 1];
846 
847     zdb_zone_label_iterator_init(&label_iterator, zone);
848 
849     while(zdb_zone_label_iterator_hasnext(&label_iterator))
850     {
851         zdb_zone_label_iterator_nextname(&label_iterator, fqdn);
852         zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
853         nsec3_label_extension *n3le = label->nsec.nsec3;
854 
855         while(n3le != NULL)
856         {
857             if(n3le->_self != NULL)
858             {
859                 int found = 0;
860 
861                 for(s32 i = 0; i < n3le->_self->rc; ++i)
862                 {
863                     zdb_rr_label* self = nsec3_item_owner_get(n3le->_self, i);
864                     if(self == label)
865                     {
866                         ++found;
867                     }
868                 }
869 
870                 if(found == 0)
871                 {
872                     log_err("nsec3_check: %{dnsname}: %{dnsname} => %{digest32h} is one way", zone->origin, fqdn, n3le->_self->digest);
873                 }
874                 else if(found > 1)
875                 {
876                     log_err("nsec3_check: %{dnsname}: %{dnsname} => %{digest32h} is referenced back multiple times", zone->origin, fqdn, n3le->_self->digest);
877                 }
878             }
879 
880             if(n3le->_star != NULL)
881             {
882                 int found = 0;
883 
884                 for(s32 i = 0; i < n3le->_star->sc; ++i)
885                 {
886                     zdb_rr_label* star = nsec3_item_star_get(n3le->_star, i);
887                     if(star == label)
888                     {
889                         ++found;
890                     }
891                 }
892 
893                 if(found == 0)
894                 {
895                     log_err("nsec3_check: %{dnsname}: *.%{dnsname} => %{digest32h} is one way", zone->origin, fqdn, n3le->_star->digest);
896                 }
897                 else if(found > 1)
898                 {
899                     log_err("nsec3_check: %{dnsname}: *.%{dnsname} => %{digest32h} is referenced back multiple times", zone->origin, fqdn, n3le->_star->digest);
900                 }
901             }
902 
903             n3le = n3le->_next;
904         }
905     }
906 
907     log_debug("nsec3_check: %{dnsname} : done", zone->origin);
908 }
909 
910 #endif
911 
912 void
nsec3_compute_digest_from_fqdn_with_len(const nsec3_zone * n3,const u8 * fqdn,u32 fqdn_len,u8 * digest,bool isstar)913 nsec3_compute_digest_from_fqdn_with_len(const nsec3_zone *n3, const u8 *fqdn, u32 fqdn_len, u8 *digest, bool isstar)
914 {
915     digest[0] = nsec3_hash_len(NSEC3_ZONE_ALGORITHM(n3));
916 
917     nsec3_hash_get_function(NSEC3_ZONE_ALGORITHM(n3))(
918                                     fqdn,
919                                     fqdn_len,
920                                     NSEC3_ZONE_SALT(n3),
921                                     NSEC3_ZONE_SALT_LEN(n3),
922                                     nsec3_zone_get_iterations(n3),
923                                     &digest[1],
924                                     isstar);
925 }
926 
927 void
nsec3_zone_label_detach(zdb_rr_label * label)928 nsec3_zone_label_detach(zdb_rr_label *label)
929 {
930     yassert((label != NULL) && zdb_rr_label_flag_isset(label, (ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT)));
931 
932     nsec3_label_extension *n3le = label->nsec.nsec3;
933 
934     while(n3le != NULL)
935     {
936         // remove
937         if(nsec3_label_extension_self(n3le) != NULL)
938         {
939 #if DEBUG
940             nsec3_node *node_self = nsec3_label_extension_self(n3le);
941 #endif
942             nsec3_item_remove_owner(nsec3_label_extension_self(n3le), label);
943 #if DEBUG
944             log_debug1("nsec3_zone_label_detach(%{dnslabel}@%p) : nsec3 rc = %i", nsec3_owner_count(node_self));
945 #endif
946         }
947         if(nsec3_label_extension_star(n3le) != NULL)
948         {
949             nsec3_item_remove_star(nsec3_label_extension_star(n3le), label);
950         }
951         zdb_rr_label_flag_and(label, ~(ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT));
952         label->nsec.nsec3 = NULL;
953 
954 
955         nsec3_label_extension *tmp = n3le;
956         n3le = nsec3_label_extension_next(n3le);
957 
958         nsec3_label_extension_free(tmp);
959     }
960 
961     label->nsec.nsec3 = NULL;
962 }
963 
964 ya_result
nsec3_get_next_digest_from_rdata(const u8 * rdata,u32 rdata_size,u8 * digest,u32 digest_size)965 nsec3_get_next_digest_from_rdata(const u8 *rdata, u32 rdata_size, u8 *digest, u32 digest_size)
966 {
967     if((NSEC3_RDATA_ALGORITHM(rdata) == NSEC3_DIGEST_ALGORITHM_SHA1) && (rdata_size > 5 + 21))
968     {
969         u32 salt_size = rdata[4];
970         u32 hash_size = rdata[5 + salt_size];
971         if((hash_size < digest_size) && (hash_size + salt_size + 5 < rdata_size))
972         {
973             memcpy(digest, &rdata[5 + salt_size], hash_size + 1);
974             return hash_size + 1;
975         }
976     }
977 
978     return ERROR;
979 }
980 
981 // frees from back to front
982 
nsec3_zone_label_extension_remove(zdb_rr_label * label,nsec3_label_extension * n3le)983 static inline void nsec3_zone_label_extension_remove(zdb_rr_label *label, nsec3_label_extension *n3le)
984 {
985     if(nsec3_label_extension_next(n3le) != NULL)
986     {
987         nsec3_zone_label_extension_remove(label, nsec3_label_extension_next(n3le));
988         nsec3_label_extension_set_next(n3le, NULL);
989     }
990 
991     // remove
992     if(nsec3_label_extension_self(n3le) != NULL)
993     {
994         nsec3_item_remove_owner(nsec3_label_extension_self(n3le), label);
995     }
996 
997     if(nsec3_label_extension_star(n3le) != NULL)
998     {
999         nsec3_item_remove_star(nsec3_label_extension_star(n3le), label);
1000     }
1001 
1002     nsec3_label_extension_free(n3le);
1003 }
1004 
1005 void
nsec3_zone_label_update_chain_links(nsec3_zone * n3,zdb_rr_label * label,int count,u16 coverage_mask,const u8 * fqdn)1006 nsec3_zone_label_update_chain_links(nsec3_zone *n3, zdb_rr_label* label, int count, u16 coverage_mask, const u8 *fqdn)
1007 {
1008     nsec3_label_extension *n3le = label->nsec.nsec3;
1009     u8 digest[1 + MAX_DIGEST_LENGTH];
1010 
1011 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1012     log_info("link: %{dnsname} (DEBUG)", fqdn);
1013 #endif
1014 
1015     // coverage_mask tells what coverage is expected in the zone. It has only one bit set.
1016 
1017     bool should_be_covered  = zdb_rr_label_flag_isset(label, coverage_mask);
1018     u8 expected_optout_flag_value = (coverage_mask & ZDB_RR_LABEL_N3OCOVERED)?1:0;
1019 
1020     if(should_be_covered) // should be covered
1021     {
1022 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1023         log_info("link: %{dnsname}: should be covered (DEBUG)", fqdn);
1024 #endif
1025 
1026         if(n3le == NULL)    // has no extension
1027         {
1028             // add the extension list
1029 
1030             n3le = nsec3_label_extension_alloc_list(count);
1031 
1032             label->nsec.nsec3 = n3le;
1033 
1034             if(zdb_rr_label_flag_isset(label, ZDB_RR_LABEL_N3OCOVERED))
1035             {
1036                 zdb_rr_label_flag_or(label, ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT);
1037             }
1038             else
1039             {
1040                 zdb_rr_label_flag_or(label, ZDB_RR_LABEL_NSEC3);
1041             }
1042         }
1043 
1044         do
1045         {
1046             // are links missing ?
1047 
1048             if((nsec3_label_extension_self(n3le) == NULL) || (nsec3_label_extension_star(n3le) == NULL))
1049             {
1050                 // compute the digest(s) and link
1051 
1052                 s32 fqdn_len = dnsname_len(fqdn);
1053 
1054                 if(nsec3_label_extension_self(n3le) == NULL)
1055                 {
1056                     nsec3_zone_item *self = nsec3_label_link_seeknode(n3, fqdn, fqdn_len, digest);
1057                     if(self != NULL)
1058                     {
1059                         if(self->flags != expected_optout_flag_value)
1060                         {
1061                             log_warn("%{dnsname} NSEC3 coverage flag doesn't match expected value", fqdn);
1062                         }
1063 
1064                         nsec3_item_add_owner(self, label);
1065                         nsec3_label_extension_set_self(n3le, self);
1066 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1067                         log_info("link: %{dnsname}: self node %{digest32h} bound (DEBUG)", fqdn, digest);
1068 #endif
1069 #if HAS_SUPERDUMP
1070                         nsec3_superdump_integrity_check_label_nsec3_self_points_back(label,0);
1071                         nsec3_superdump_integrity_check_nsec3_owner_self_points_back(self,0);
1072 #endif
1073                     }
1074 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1075                     else
1076                     {
1077                         log_info("link: %{dnsname}: self node %{digest32h} not found (DEBUG)", fqdn, digest);
1078                     }
1079 #endif
1080                 }
1081 
1082                 if(nsec3_label_extension_star(n3le) == NULL)
1083                 {
1084                     nsec3_zone_item *star = nsec3_label_link_seekstar(n3, fqdn, fqdn_len, digest);
1085                     if(star != NULL)
1086                     {
1087                         //nsec3_superdump_integrity_check_label_nsec3_star_points_back(label,0);
1088                         nsec3_item_add_star(star, label);
1089                         nsec3_label_extension_set_star(n3le, star);
1090 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1091                         log_info("link: %{dnsname}: star node %{digest32h} bound (DEBUG)", fqdn, digest);
1092 #endif
1093 #if HAS_SUPERDUMP
1094                         nsec3_superdump_integrity_check_label_nsec3_star_points_back(label,0);
1095                         nsec3_superdump_integrity_check_nsec3_owner_star_points_back(star,0);
1096 #endif
1097                     }
1098 
1099 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1100                     else
1101                     {
1102                         log_info("link: %{dnsname}: star node %{digest32h} not found (DEBUG)", fqdn, digest);
1103                     }
1104 #endif
1105                 }
1106             }
1107 
1108             n3 = n3->next;
1109             nsec3_label_extension *next = nsec3_label_extension_next(n3le);
1110 
1111             if((next == NULL) && (n3 != NULL))
1112             {
1113                 // add
1114                 nsec3_label_extension_set_next(n3le, nsec3_label_extension_alloc_list(1));
1115             }
1116             else if((next != NULL) && (n3 == NULL))
1117             {
1118                 // extensions beyond the chain
1119 
1120                 nsec3_label_extension_set_next(n3le, NULL);
1121                 nsec3_zone_label_extension_remove(label, next);
1122                 next = NULL;
1123             }
1124 
1125             n3le = next;
1126         }
1127         while(n3le != NULL);
1128     }
1129     else // should not be covered
1130     {
1131 #if NSEC3_ZONE_LABEL_UPDATE_CHAIN_LINKS_DEBUG
1132         log_info("link: %{dnsname}: should not be covered (DEBUG)", fqdn);
1133 #endif
1134         if(n3le != NULL)
1135         {
1136             nsec3_zone_label_extension_remove(label, n3le);
1137 
1138             zdb_rr_label_flag_and(label, ~(ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT));
1139             label->nsec.nsec3 = NULL;
1140         }
1141     }
1142 }
1143 
1144 /**
1145  * Updates links for the first NSEC3 chain of the zone
1146  * Only links to existing NSEC3 records.
1147  * Only links label with an extension and self/wild set to NULL
1148  *
1149  * @param zone
1150  */
1151 
1152 void
nsec3_zone_update_chain0_links(zdb_zone * zone)1153 nsec3_zone_update_chain0_links(zdb_zone *zone)
1154 {
1155     nsec3_zone *n3 = zone->nsec.nsec3;
1156 
1157     if(n3 == NULL)
1158     {
1159         return;
1160     }
1161 
1162     u16 coverage_mask;
1163     u8 maintain_mode = zone_get_maintain_mode(zone);
1164     if(maintain_mode & ZDB_ZONE_HAS_OPTOUT_COVERAGE)
1165     {
1166         coverage_mask = ZDB_RR_LABEL_N3OCOVERED;
1167     }
1168     else
1169     {
1170         coverage_mask = ZDB_RR_LABEL_N3COVERED;
1171     }
1172 
1173     log_debug("nsec3_zone_update_chain0_links(%{dnsname}) maintain_mode=%x", zone->origin, maintain_mode);
1174 
1175     int n3_count = 1;
1176     //u16 structure_mask = (maintain_mode == ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT)?ZDB_RR_LABEL_NSEC3_OPTOUT:((maintain_mode == ZDB_ZONE_MAINTAIN_NSEC3)?ZDB_RR_LABEL_NSEC3:0);
1177 
1178     {
1179         const nsec3_zone *n3 = zone->nsec.nsec3->next;
1180 
1181         while(n3 != NULL)
1182         {
1183             ++n3_count;
1184             n3 = n3->next;
1185         }
1186     }
1187 
1188     zdb_zone_label_iterator label_iterator;
1189     u8 fqdn[MAX_DOMAIN_LENGTH + 1];
1190 #if 1
1191 #else
1192     u8 digest[1 + MAX_DIGEST_LENGTH];
1193 #endif
1194 
1195     zdb_zone_label_iterator_init(&label_iterator, zone);
1196 
1197     while(zdb_zone_label_iterator_hasnext(&label_iterator))
1198     {
1199         zdb_zone_label_iterator_nextname(&label_iterator, fqdn);
1200         zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
1201 #if 1
1202 #else
1203         nsec3_label_extension *n3le = label->nsec.nsec3;
1204 #endif
1205 #if 1
1206         nsec3_zone_label_update_chain_links(zone->nsec.nsec3, label, n3_count, coverage_mask, fqdn);
1207 #else
1208         if(zdb_rr_label_flag_isset(label, coverage_mask))
1209         {
1210             if(n3le == NULL)
1211             {
1212                 n3le = nsec3_label_extension_alloc();
1213                 ZEROMEMORY(n3le, sizeof(nsec3_label_extension));
1214                 label->nsec.nsec3 = n3le;
1215                 if(zdb_rr_label_flag_isset(label, ZDB_RR_LABEL_N3OCOVERED))
1216                 {
1217                     zdb_rr_label_flag_or(label, ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT);
1218                 }
1219                 else
1220                 {
1221                     zdb_rr_label_flag_or(label, ZDB_RR_LABEL_NSEC3);
1222                 }
1223             }
1224 
1225             if(nsec3_label_extension_self(n3le) == NULL || nsec3_label_extension_star(n3le) == NULL)
1226             {
1227                 s32 fqdn_len = dnsname_len(fqdn);
1228 
1229                 if(nsec3_label_extension_self(n3le) == NULL)
1230                 {
1231                     nsec3_zone_item *self = nsec3_label_link_seeknode(n3, fqdn, fqdn_len, digest);
1232                     if(self != NULL)
1233                     {
1234                         nsec3_item_add_owner(self, label);
1235                         nsec3_label_extension_set_self(n3le, self);
1236 #if HAS_SUPERDUMP
1237                         nsec3_superdump_integrity_check_label_nsec3_self_points_back(label,0);
1238                         nsec3_superdump_integrity_check_nsec3_owner_self_points_back(self,0);
1239 #endif
1240                     }
1241                 }
1242 
1243                 if(nsec3_label_extension_star(n3le) == NULL)
1244                 {
1245                     nsec3_zone_item *star = nsec3_label_link_seekstar(n3, fqdn, fqdn_len, digest);
1246                     if(star != NULL)
1247                     {
1248                         //nsec3_superdump_integrity_check_label_nsec3_star_points_back(label,0);
1249                         nsec3_item_add_star(star, label);
1250                         nsec3_label_extension_set_star(n3le, star);
1251 #if HAS_SUPERDUMP
1252                         nsec3_superdump_integrity_check_label_nsec3_star_points_back(label,0);
1253                         nsec3_superdump_integrity_check_nsec3_owner_star_points_back(star,0);
1254 #endif
1255                     }
1256                 }
1257             }
1258         }
1259         else
1260         {
1261             if(n3le != NULL)
1262             {
1263                 // remove
1264                 if(nsec3_label_extension_self(n3le) != NULL)
1265                 {
1266                     nsec3_item_remove_owner(nsec3_label_extension_self(n3le), label);
1267                 }
1268                 if(nsec3_label_extension_star(n3le) != NULL)
1269                 {
1270                     nsec3_item_remove_star(nsec3_label_extension_star(n3le), label);
1271                 }
1272                 nsec3_label_extension_free(n3le);
1273                 zdb_rr_label_flag_and(label->flags, ~(ZDB_RR_LABEL_NSEC3|ZDB_RR_LABEL_NSEC3_OPTOUT));
1274                 label->nsec.nsec3 = NULL;
1275             }
1276         }
1277 #endif
1278     }
1279 }
1280 
1281 #if ZDB_HAS_MASTER_SUPPORT
1282 /**
1283  * Sets the NSEC3 maintenance status for a specific chain.
1284  * Marks the zone using private records.
1285  *
1286  * The zone must be double-locked.
1287  *
1288  * @param zone
1289  * @param secondary_lock the secondary lock owner
1290  * @param algorithm
1291  * @param optout
1292  * @param salt
1293  * @param salt_len
1294  * @param iterations
1295  * @param status
1296  * @return
1297  */
1298 
1299 ya_result
nsec3_zone_set_status(zdb_zone * zone,u8 secondary_lock,u8 algorithm,u8 optout,u16 iterations,const u8 * salt,u8 salt_len,u8 status)1300 nsec3_zone_set_status(zdb_zone *zone, u8 secondary_lock, u8 algorithm, u8 optout, u16 iterations, const u8 *salt, u8 salt_len, u8 status)
1301 {
1302     dynupdate_message dmsg;
1303     packet_unpack_reader_data reader;
1304     dynupdate_message_init(&dmsg, zone->origin, CLASS_IN);
1305 
1306     u8 prev_status = 0;
1307 #ifndef WIN32
1308     u8 nsec3paramadd_rdata[5 + salt_len + 1];
1309 #else
1310     u8 nsec3paramadd_rdata[5 + 255 + 1];
1311 #endif
1312     nsec3paramadd_rdata[0] = algorithm;
1313     nsec3paramadd_rdata[1] = optout;
1314     SET_U16_AT(nsec3paramadd_rdata[2], htons(iterations));
1315     nsec3paramadd_rdata[4] = salt_len;
1316     memcpy(&nsec3paramadd_rdata[5], salt, salt_len);
1317     nsec3paramadd_rdata[5 + salt_len] = status;
1318 
1319     // look for the matching record
1320     if(nsec3_zone_get_status(zone, algorithm, optout, iterations, salt, salt_len, &prev_status) == 1)
1321     {
1322         // if the record exists, remove it and add it
1323         nsec3paramadd_rdata[5 + salt_len] = prev_status;
1324         if(prev_status == status)
1325         {
1326             // already set
1327 
1328             return SUCCESS;
1329         }
1330         dynupdate_message_del_record(&dmsg, zone->origin, TYPE_NSEC3CHAINSTATE, 0, 6 + salt_len, nsec3paramadd_rdata);
1331         nsec3paramadd_rdata[5 + salt_len] = status;
1332     }
1333 
1334     dynupdate_message_add_record(&dmsg, zone->origin, TYPE_NSEC3CHAINSTATE, 0, 6 + salt_len, nsec3paramadd_rdata);
1335 
1336     dynupdate_message_set_reader(&dmsg, &reader);
1337     u16 count = dynupdate_message_get_count(&dmsg);
1338 
1339     packet_reader_skip(&reader, DNS_HEADER_LENGTH); // checked below
1340     packet_reader_skip_fqdn(&reader);               // checked below
1341     packet_reader_skip(&reader, 4);             // checked below
1342 
1343     ya_result ret;
1344 
1345     if(!packet_reader_eof(&reader))
1346     {
1347 #if ZDB_HAS_DNSSEC_SUPPORT && ZDB_HAS_RRSIG_MANAGEMENT_SUPPORT
1348         if(zone_get_maintain_mode(zone) == 0)
1349         {
1350             zone_set_maintain_mode(zone, ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT);
1351         }
1352 #endif
1353 
1354         ret = dynupdate_diff(zone, &reader, count, secondary_lock, DYNUPDATE_DIFF_RUN);
1355 
1356         dynupdate_message_finalize(&dmsg);
1357 
1358         if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
1359         {
1360             // trigger a background store of the zone
1361 
1362             zdb_zone_info_background_store_zone(zone->origin);
1363         }
1364     }
1365     else
1366     {
1367         ret = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
1368     }
1369 
1370     return ret;
1371 }
1372 
1373 #endif
1374 
1375 /**
1376  * Gets the NSEC3 maintenance status for a specific chain.
1377  * Get the information from the zone using private records.
1378  *
1379  * The zone must be locked.
1380  *
1381  * @param zone
1382  * @param algorithm
1383  * @param optout
1384  * @param salt
1385  * @param salt_len
1386  * @param iterations
1387  * @param status
1388  * @return
1389  */
1390 
nsec3_zone_get_status(zdb_zone * zone,u8 algorithm,u8 optout,u16 iterations,const u8 * salt,u8 salt_len,u8 * statusp)1391 ya_result nsec3_zone_get_status(zdb_zone *zone, u8 algorithm, u8 optout, u16 iterations, const u8 *salt, u8 salt_len, u8 *statusp)
1392 {
1393     // get the TYPE_NSEC3PARAMADD record set
1394     // search for a record matching the chain
1395     zdb_packed_ttlrdata *rrset = zdb_record_find(&zone->apex->resource_record_set, TYPE_NSEC3CHAINSTATE);
1396     while(rrset != NULL)
1397     {
1398         if(rrset->rdata_size == 6 + salt_len)
1399         {
1400             if(rrset->rdata_start[0] == algorithm)
1401             {
1402                 if(rrset->rdata_start[1] == optout)
1403                 {
1404                     if(GET_U16_AT(rrset->rdata_start[2]) == htons(iterations))
1405                     {
1406                         if(rrset->rdata_start[4] == salt_len)
1407                         {
1408                             if(memcmp(&rrset->rdata_start[5], salt, salt_len) == 0)
1409                             {
1410                                 *statusp = rrset->rdata_start[5 + salt_len];
1411                                 return 1;
1412                             }
1413                         }
1414                     }
1415                 }
1416             }
1417             rrset = rrset->next;
1418         }
1419     }
1420 
1421     return 0;
1422 }
1423 
1424 /**
1425  * Gets the NSEC3 maintenance status for a specific chain.
1426  * Get the information from the zone using private records.
1427  *
1428  * The zone must be locked.
1429  *
1430  * @param zone
1431  * @param rdata
1432  * @param rdata_size
1433  * @param statusp
1434  * @return
1435  */
1436 
1437 ya_result
nsec3_zone_get_status_from_rdata(zdb_zone * zone,const u8 * rdata,u16 rdata_size,u8 * statusp)1438 nsec3_zone_get_status_from_rdata(zdb_zone *zone, const u8* rdata, u16 rdata_size, u8 *statusp)
1439 {
1440     // get the TYPE_NSEC3PARAMADD record set
1441     // search for a record matching the chain
1442     zdb_packed_ttlrdata *rrset = zdb_record_find(&zone->apex->resource_record_set, TYPE_NSEC3CHAINSTATE);
1443     while(rrset != NULL)
1444     {
1445         if(rrset->rdata_size == rdata_size + 1)
1446         {
1447             if(rrset->rdata_start[0] == rdata[0])
1448             {
1449                 if(GET_U16_AT(rrset->rdata_start[2]) == GET_U16_AT(rdata[2]))
1450                 {
1451                     if(rrset->rdata_start[4] == rdata[4])
1452                     {
1453                         if(memcmp(&rrset->rdata_start[5], &rdata[5], rdata[4]) == 0)
1454                         {
1455                             *statusp = rrset->rdata_start[5 + rdata[4]];
1456                             return 1;
1457                         }
1458                     }
1459                 }
1460             }
1461             rrset = rrset->next;
1462         }
1463     }
1464 
1465     return 0;
1466 }
1467 
1468 /**
1469  * Returns the number of known chains in the zone.
1470  * Inactive chains are also counted.
1471  * Zone must be locked.
1472  *
1473  * @param zone
1474  * @return
1475  */
1476 
1477 int
nsec3_zone_get_chain_count(zdb_zone * zone)1478 nsec3_zone_get_chain_count(zdb_zone *zone)
1479 {
1480     int ret = 0;
1481     nsec3_zone *n3 = zone->nsec.nsec3;
1482     while(n3 != NULL)
1483     {
1484         ++ret;
1485         n3 = n3->next;
1486     }
1487     return ret;
1488 }
1489 
1490 /**
1491  * Returns pointers to the chains from the zone.
1492  * Inactive chains are also counted.
1493  * Zone must be locked.
1494  *
1495  * @param zone
1496  * @param n3p
1497  * @param max_count
1498  * @return
1499  */
1500 
1501 int
nsec3_zone_get_chains(zdb_zone * zone,nsec3_zone ** n3p,int max_count)1502 nsec3_zone_get_chains(zdb_zone *zone, nsec3_zone **n3p, int max_count)
1503 {
1504     int ret = 0;
1505     nsec3_zone *n3 = zone->nsec.nsec3;
1506     while(n3 != NULL)
1507     {
1508         *n3p++ = n3;
1509         if(++ret == max_count)
1510         {
1511             break;
1512         }
1513         n3 = n3->next;
1514     }
1515     return ret;
1516 }
1517 
1518 struct nsec3_item_rrv_data_s
1519 {
1520     nsec3_zone *n3;
1521     nsec3_node *item;
1522     const u8 *origin;
1523     u8 *rdata;
1524     u16 rdata_size;
1525     u16 rdata_buffer_size;
1526     s32 ttl;
1527     u8 fqdn[256];
1528 };
1529 
1530 typedef struct nsec3_item_rrv_data_s nsec3_item_rrv_data_t;
1531 
1532 static void
nsec3_item_resource_record_view_data_item_set(nsec3_item_rrv_data_t * rrv_data,nsec3_node * item)1533 nsec3_item_resource_record_view_data_item_set(nsec3_item_rrv_data_t *rrv_data, nsec3_node *item)
1534 {
1535     u32 required_size = nsec3_zone_item_rdata_size(rrv_data->n3, item);
1536     if(rrv_data->rdata_buffer_size < required_size)
1537     {
1538         free(rrv_data->rdata);
1539         rrv_data->rdata_buffer_size = (required_size + 128) & ~127;
1540         MALLOC_OBJECT_ARRAY_OR_DIE(rrv_data->rdata, u8, rrv_data->rdata_buffer_size, RRVDATA_TAG);
1541     }
1542 
1543     rrv_data->rdata_size = nsec3_zone_item_to_rdata(rrv_data->n3, item, rrv_data->rdata, rrv_data->rdata_buffer_size);
1544     u32 b32_len = base32hex_encode(NSEC3_NODE_DIGEST_PTR(item), NSEC3_NODE_DIGEST_SIZE(item), (char*)&rrv_data->fqdn[1]);
1545     rrv_data->fqdn[0] = b32_len;
1546     dnsname_copy(&rrv_data->fqdn[b32_len + 1], rrv_data->origin);
1547     rrv_data->item = item;
1548 }
1549 
1550 static const u8 *
nsec3_item_rrv_get_fqdn(void * data,const void * p)1551 nsec3_item_rrv_get_fqdn(void *data, const void* p)
1552 {
1553     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)data;
1554     if(rrv_data->item != (nsec3_node*)p) nsec3_item_resource_record_view_data_item_set(rrv_data, (nsec3_node*)p);
1555     return rrv_data->fqdn;
1556 }
1557 
1558 static u16
nsec3_item_rrv_get_type(void * data,const void * p)1559 nsec3_item_rrv_get_type(void *data, const void* p)
1560 {
1561     (void)data;
1562     (void)p;
1563     return TYPE_NSEC3;
1564 }
1565 
1566 static u16
nsec3_item_rrv_get_class(void * data,const void * p)1567 nsec3_item_rrv_get_class(void *data, const void* p)
1568 {
1569     (void)data;
1570     (void)p;
1571     return CLASS_IN;
1572 }
1573 
1574 static s32
nsec3_item_rrv_get_ttl(void * data,const void * p)1575 nsec3_item_rrv_get_ttl(void *data, const void* p)
1576 {
1577     (void)p;
1578     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)data;
1579     return rrv_data->ttl;
1580 }
1581 
1582 static u16
nsec3_item_rrv_get_rdata_size(void * data,const void * p)1583 nsec3_item_rrv_get_rdata_size(void *data, const void* p)
1584 {
1585     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)data;
1586     if(rrv_data->item != (nsec3_node*)p) nsec3_item_resource_record_view_data_item_set(rrv_data, (nsec3_node*)p);
1587     return rrv_data->rdata_size;
1588 }
1589 
1590 static const u8 *
nsec3_item_rrv_get_rdata(void * data,const void * p)1591 nsec3_item_rrv_get_rdata(void *data, const void* p)
1592 {
1593     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)data;
1594     if(rrv_data->item != (nsec3_node*)p) nsec3_item_resource_record_view_data_item_set(rrv_data, (nsec3_node*)p);
1595     return rrv_data->rdata;
1596 }
1597 
1598 static void *
nsec3_item_rrv_new_instance(void * data,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size,const u8 * rdata)1599 nsec3_item_rrv_new_instance(void *data, const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size, const u8 *rdata)
1600 {
1601     (void)data;
1602     (void)fqdn;
1603     (void)rtype;
1604     (void)rclass;
1605     yassert(rtype == TYPE_RRSIG);
1606     struct zdb_packed_ttlrdata *ttlrdata;
1607     ZDB_RECORD_ZALLOC(ttlrdata, ttl, rdata_size, rdata);
1608     return ttlrdata;
1609 }
1610 
1611 static const struct resource_record_view_vtbl nsec3_item_rrv_vtbl =
1612 {
1613     nsec3_item_rrv_get_fqdn,
1614     nsec3_item_rrv_get_type,
1615     nsec3_item_rrv_get_class,
1616     nsec3_item_rrv_get_ttl,
1617     nsec3_item_rrv_get_rdata_size,
1618     nsec3_item_rrv_get_rdata,
1619     nsec3_item_rrv_new_instance
1620 };
1621 
1622 void
nsec3_item_resource_record_view_init(resource_record_view * rrv)1623 nsec3_item_resource_record_view_init(resource_record_view *rrv)
1624 {
1625     ZALLOC_OBJECT_OR_DIE(rrv->data, nsec3_item_rrv_data_t, N3IRRVDT_TAG);
1626     ZEROMEMORY(rrv->data, sizeof(nsec3_item_rrv_data_t));
1627     rrv->vtbl = &nsec3_item_rrv_vtbl;
1628 }
1629 
1630 void
nsec3_item_resource_record_view_origin_set(struct resource_record_view * rrv,const u8 * origin)1631 nsec3_item_resource_record_view_origin_set(struct resource_record_view *rrv, const u8 *origin)
1632 {
1633     yassert(rrv->vtbl == &nsec3_item_rrv_vtbl);
1634     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)rrv->data;
1635     rrv_data->origin = origin;
1636 }
1637 
1638 void
nsec3_item_resource_record_view_nsec3_zone_set(struct resource_record_view * rrv,nsec3_zone * n3)1639 nsec3_item_resource_record_view_nsec3_zone_set(struct resource_record_view *rrv, nsec3_zone *n3)
1640 {
1641     yassert(rrv->vtbl == &nsec3_item_rrv_vtbl);
1642     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)rrv->data;
1643     rrv_data->n3 = n3;
1644 }
1645 
1646 void
nsec3_item_resource_record_view_ttl_set(resource_record_view * rrv,s32 ttl)1647 nsec3_item_resource_record_view_ttl_set(resource_record_view *rrv, s32 ttl)
1648 {
1649     yassert(rrv->vtbl == &nsec3_item_rrv_vtbl);
1650     nsec3_item_rrv_data_t *rrv_data = (nsec3_item_rrv_data_t*)rrv->data;
1651     rrv_data->ttl = ttl;
1652 }
1653 
1654 void
nsec3_item_resource_record_finalize(resource_record_view * rrv)1655 nsec3_item_resource_record_finalize(resource_record_view *rrv)
1656 {
1657     yassert(rrv->vtbl == &nsec3_item_rrv_vtbl);
1658     ZFREE_OBJECT_OF_TYPE(rrv->data, nsec3_item_rrv_data_t);
1659     rrv->vtbl = NULL;
1660 }
1661 
1662 void
nsec3_superdump(zdb_zone * zone)1663 nsec3_superdump(zdb_zone *zone)
1664 {
1665     (void)zone;
1666 }
1667 
1668 /** @} */
1669