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  * Owners & Stars
40  *
41  * @{
42  */
43 /*------------------------------------------------------------------------------
44  *
45  * USE INCLUDES */
46 #include "dnsdb/dnsdb-config.h"
47 #include <stdio.h>
48 #include <stdlib.h>
49 
50 #include "dnsdb/zdb_types.h"
51 #include "dnsdb/nsec3_owner.h"
52 
53 #if 0 /* fix */
54 #else
55 #define NSEC3_OWNER_DEBUG 0
56 #endif
57 
58 //#if NSEC3_OWNER_DEBUG
59 #include <dnscore/logger.h>
60 
61 #define MODULE_MSG_HANDLE g_dnssec_logger
62 extern logger_handle *g_dnssec_logger;
63 
64 //#endif
65 
66 #define OWNER_NAME(owner_) (((owner_) != NULL))?(owner_)->name:(u8*)"\011NULLOWNER"
67 #define ITEM_DIGEST(item__) (((item__) != NULL)?(item__)->digest:NULL)
68 
69 /******************************************************************************
70  *
71  * NSEC3 - tools : owners & stars
72  *
73  *****************************************************************************/
74 
75 /**
76  * Changes the value of the nsec3 extension of a label from a value to another.
77  *
78  *
79  * @param n3ext the nsec3 extension of the label
80  * @param item the old nsec3 item, CANNOT BE NULL
81  * @param value the new nsec3 item, can be NULL
82  *
83  * 2 uses
84  */
85 
86 static int
nsec3_label_extension_replace_self(nsec3_label_extension * n3ext,const nsec3_zone_item * item,nsec3_zone_item * value)87 nsec3_label_extension_replace_self(nsec3_label_extension* n3ext, const nsec3_zone_item *item, nsec3_zone_item *value)
88 {
89     yassert(n3ext != NULL);
90     yassert(item != NULL);
91     // yassert(value != NULL); // can be NULL
92 
93     /*
94      * This loops should only be run once or twice
95      * Still it annoys me a lot.
96      *
97      * I'll have to find a better, dynamic, way to handle
98      * multiple NSEC3PARAM.
99      * (And of course memory usage and fragmentation is the
100      * first enemy)
101      */
102 
103 #if NSEC3_OWNER_DEBUG
104     log_debug("nsec3_label_extension_set_self: %p, %{digest32h} @ %p, %{digest32h} @ %p", n3ext, ITEM_DIGEST(item), item, ITEM_DIGEST(value), value);
105 #endif
106 
107     int ret = 0;
108 
109     do
110     {
111         if(nsec3_label_extension_self(n3ext) == item)
112         {
113             yassert((value != NULL) || (nsec3_label_extension_self(n3ext) != NULL));
114 
115             nsec3_label_extension_set_self(n3ext, value); /* Official way to change the "self" */
116             return ret;
117         }
118 
119 #if NSEC3_OWNER_DEBUG
120 
121         if(value != NULL && nsec3_label_extension_self(n3ext) == value)
122         {
123             yassert((value != NULL) || (nsec3_label_extension_self(n3ext) != NULL));
124 
125             log_debug("nsec3_label_extension_set_self: already %{digest32h} @ %p ???", ITEM_DIGEST(nsec3_label_extension_star(n3ext)), nsec3_label_extension_star(n3ext));
126             return ret;
127         }
128 
129         log_debug("nsec3_label_extension_set_self: skipped %{digest32h} @ %p", ITEM_DIGEST(nsec3_label_extension_self(n3ext)), nsec3_label_extension_self(n3ext));
130 #endif
131 
132         ++ret;
133         n3ext = nsec3_label_extension_next(n3ext);
134     }
135     while(n3ext != NULL);
136 
137     /* NULL means we didn't found the link back */
138 
139 #if NSEC3_OWNER_DEBUG
140     log_debug("nsec3_label_extension_set_self: reference not found (something is wrong)");
141 #endif
142 
143     logger_flush();
144     abort();
145 }
146 
147 /**
148  * Changes the star value of the nsec3 extension of a label from a value to another.
149  *
150  * @param n3ext the nsec3 extension of the label
151  * @param item the old nsec3 item, CANNOT BE NULL
152  * @param value the new nsec3 item, can be NULL
153  *
154  * 6 uses
155  */
156 
157 
158 
159 static void
nsec3_label_extension_replace_star(nsec3_label_extension * n3ext,const nsec3_zone_item * item,nsec3_zone_item * value)160 nsec3_label_extension_replace_star(nsec3_label_extension* n3ext, const nsec3_zone_item *item, nsec3_zone_item* value)
161 {
162     yassert(n3ext != NULL);
163     yassert(item != NULL);
164     // yassert(value != NULL); @note value can be NULL
165 
166 
167 
168 #if NSEC3_OWNER_DEBUG
169     log_debug("nsec3_label_extension_replace_star: %p, %{digest32h} @%p, %{digest32h} @%p", n3ext, ITEM_DIGEST(item), item, ITEM_DIGEST(value), value);
170 #endif
171 
172     do
173     {
174 #if NSEC3_OWNER_DEBUG
175         log_debug("nsec3_label_extension_replace_star: %{digest32h} @%p",
176                   ITEM_DIGEST(nsec3_label_extension_self(n3ext)),  nsec3_label_extension_self(n3ext), ITEM_DIGEST(nsec3_label_extension_star(n3ext)), nsec3_label_extension_star(n3ext));
177 #endif
178         if(nsec3_label_extension_star(n3ext) == item)
179         {
180             nsec3_label_extension_set_star(n3ext, value);
181             return;
182         }
183 
184 #if NSEC3_OWNER_DEBUG
185 
186         if(nsec3_label_extension_star(n3ext) == value)
187         {
188             log_debug("nsec3_label_extension_replace_star: already %{digest32h} @%p ???", ITEM_DIGEST(nsec3_label_extension_star(n3ext)), nsec3_label_extension_star(n3ext));
189             return;
190         }
191 
192         log_debug("nsec3_label_extension_replace_star: skipped %{digest32h} @%p", ITEM_DIGEST(nsec3_label_extension_star(n3ext)), nsec3_label_extension_star(n3ext));
193 #endif
194 
195         n3ext = nsec3_label_extension_next(n3ext);
196     }
197     while(n3ext != NULL);
198 
199     /* NULL means we didn't found the link back */
200 
201     if(value != NULL)
202     {
203         log_err("nsec3_label_extension_replace_star: did not found %{digest32h} NSEC3, while trying to replace it with (another) %{digest32h} NSEC3", item->digest, value->digest);
204     }
205     else
206     {
207         log_err("nsec3_label_extension_replace_star: did not found %{digest32h} NSEC3, while trying to remove it", item->digest);
208     }
209 
210     logger_flush();
211     abort();
212 }
213 
214 /**
215  * Adds an entry to the "owner" array (of an item)
216  *
217  * @param ownersp
218  * @param countp
219  * @param owner
220  *
221  * 2 uses
222  */
223 
224 static void
nsec3_item_label_owner_add(nsec3_item_label_owner_array * ownersp,s32 * countp,const zdb_rr_label * owner)225 nsec3_item_label_owner_add(nsec3_item_label_owner_array* ownersp, s32* countp, const zdb_rr_label *owner)
226 {
227     yassert(ownersp != NULL);
228     yassert(countp != NULL);
229     yassert(owner != NULL);
230 
231     if(*countp == 0)
232     {
233         (*ownersp).owner = (zdb_rr_label*)owner;
234         *countp = 1;
235 #if NSEC3_OWNER_DEBUG
236         log_debug("nsec3_label_add: 1 '%{dnslabel}'", OWNER_NAME(owner));
237 #endif
238     }
239     else if(*countp == 1)
240     {
241         /*
242          * We had one item : adding one will require using an array
243          */
244         if((*ownersp).owner != owner)
245         {
246             *countp = 2;
247 
248             nsec3_item_label_owner_array owners;
249 
250             ZALLOC_ARRAY_OR_DIE(zdb_rr_label**, owners.owners, sizeof(zdb_rr_label*) * 2, NSEC3_LABELPTRARRAY_TAG);
251 
252             owners.owners[0] = (*ownersp).owner;
253             owners.owners[1] = (zdb_rr_label*)owner;
254 
255             (*ownersp).owners = owners.owners;
256 
257 #if NSEC3_OWNER_DEBUG
258             log_debug("nsec3_label_add: 2 '%{dnslabel}' '%{dnslabel}'", OWNER_NAME(owners.owners[0]), OWNER_NAME(owners.owners[1]));
259 #endif
260         }
261         else
262         {
263 #if NSEC3_OWNER_DEBUG
264             log_debug("nsec3_label_add: 1+1 '%{dnslabel}' already owned", OWNER_NAME(owner));
265 #endif
266         }
267     }
268     else
269     {
270         /*
271          * Just resize the current array to contain ONE more pointer
272          */
273 
274         s32 count = *countp;
275 
276         for(s32 i = 0; i < count; ++i) // count >= 2 so the loop runs at least twice (or returns)
277         {
278             if((*ownersp).owners[i] == owner)
279             {
280 #if NSEC3_OWNER_DEBUG
281                   log_debug("nsec3_label_add: %hi+1 '%{dnslabel}' already owned", count, OWNER_NAME(owner));
282 #endif
283                   return;
284             }
285         }
286 
287         /** @note ZALLOC_ARRAY_RESIZE does change the value of "count" to "count+1" */
288 
289         ZALLOC_ARRAY_RESIZE(zdb_rr_label*, (*ownersp).owners, count, count + 1);
290         (*ownersp).owners[count-1] = (zdb_rr_label*)owner; /// @note count is already set to count + 1 by the macro; scan-build false positive, VS false positive
291         *countp = count;
292 
293 #if NSEC3_OWNER_DEBUG
294         log_debug("nsec3_label_add: %i", count);
295         for(s32 i = 0; i < count; i++)
296         {
297             log_debug(" + '%{dnslabel}'", OWNER_NAME((*ownersp).owners[i]));
298         }
299 #endif
300     }
301 }
302 
303 /**
304  * Removes an entry from the "owner" array (of an item)
305  * Raw collection change, does not propagates.
306  *
307  * @param ownersp
308  * @param countp
309  * @param owner
310  *
311  * 2 uses
312  */
313 
314 static void
nsec3_item_label_owner_remove(nsec3_item_label_owner_array * ownersp,s32 * countp,const zdb_rr_label * owner)315 nsec3_item_label_owner_remove(nsec3_item_label_owner_array* ownersp, s32* countp, const zdb_rr_label *owner)
316 {
317     yassert(ownersp != NULL);
318     yassert(countp != NULL);
319     yassert(owner != NULL);
320 
321     yassert(*countp > 0);
322 
323     if(*countp == 1)
324     {
325         /*
326          * We had one item, We will have none.
327          * Set the pointer to NULL and the RC to 0
328          *
329          * Also, the label's reference will have to be set to NULL
330          * If the label's star reference was NULL already, then
331          * free the owner->nsec.nsec3
332          */
333 
334         yassert((*ownersp).owner == owner);
335 
336         (*ownersp).owner = NULL;
337         *countp = 0;
338     }
339     else if(*countp == 2)
340     {
341         /*
342          * We had one item, we will get one.
343          * Keep the last pointer instead of the array.
344          * Destroy the array
345          */
346         zdb_rr_label* last_owner;
347 
348         if((*ownersp).owners[0] == owner)
349         {
350             last_owner = (*ownersp).owners[1];
351         }
352         else
353         {
354             last_owner = (*ownersp).owners[0];
355         }
356 
357         ZFREE_ARRAY((*ownersp).owners, sizeof(zdb_rr_label*) * 2);
358 
359         (*ownersp).owner = last_owner;
360         *countp = 1;
361     }
362     else
363     {
364         /*
365          * We had more than 2
366          *
367          * Find it,
368          * replace it by the last one in the array,
369          * shrink the array (resize)
370          *
371          */
372 
373         s32 idx;
374         s32 n = *countp;
375 
376         /*
377          * Look for the owner
378          */
379 
380         for(idx = 0; idx < n; idx++)
381         {
382             if((*ownersp).owners[idx] == owner)
383             {
384                 /*
385                  * Overwrite it by the next owner.
386                  * Move all following owners one step down
387                  */
388                 n--;
389 
390                 while(idx < n)
391                 {
392                     (*ownersp).owners[idx] = (*ownersp).owners[idx + 1];
393                     idx++;
394                 }
395                 break;
396             }
397         }
398 
399         /*
400          * Reduce the memory used by one count
401          * Note : this macro will also set *countp to *countp - 1
402          */
403 
404         ZALLOC_ARRAY_RESIZE(zdb_rr_label*, (*ownersp).owners, *countp, *countp - 1);
405     }
406 }
407 
408 /**
409  * Returns TRUE if item is owned by owner
410  *
411  * @param item
412  * @param owner
413  * @return
414  *
415  * 1 use
416  */
417 
418 bool
nsec3_item_is_owned_by_label(const nsec3_zone_item * item,const zdb_rr_label * owner)419 nsec3_item_is_owned_by_label(const nsec3_zone_item *item, const zdb_rr_label *owner)
420 {
421     yassert(item != NULL);
422     yassert(owner != NULL);
423     yassert(item->rc >= 0);
424 
425     if(item->rc == 1)
426     {
427         return (item->label.owner == owner);
428     }
429     else if(item->rc != 0)
430     {
431         zdb_rr_label* const * ownerp = item->label.owners;
432         s32 i = item->rc;
433         do
434         {
435             if(*ownerp++ == owner)
436             {
437                 return TRUE;
438             }
439         }
440         while(--i > 0);
441     }
442 
443     return FALSE;
444 }
445 
446 /**
447  * Adds an owner to the NSEC3 item
448  *
449  * To be absolutely clear: links NSEC3 to LABEL, but does NOT links LABEL to NSEC3
450  * The label still has to be updated after this call.
451  *
452  * @param item
453  * @param owner
454  *
455  * 6 uses
456  */
457 
458 void
nsec3_item_add_owner(nsec3_zone_item * item,const zdb_rr_label * owner)459 nsec3_item_add_owner(nsec3_zone_item *item, const zdb_rr_label *owner)
460 {
461     yassert(item != NULL);
462     yassert(owner != NULL);
463 
464 #if NSEC3_OWNER_DEBUG
465     log_debug("nsec3_add_owner: %{digest32h} @ %p, '%{dnslabel}' RC=%i", ITEM_DIGEST(item), item, OWNER_NAME(owner), item->rc);
466     s32 rc = item->rc;
467 #endif
468 
469     nsec3_item_label_owner_add(&item->label, &item->rc, owner);
470 
471 #if NSEC3_OWNER_DEBUG
472     if(item->rc - rc != 1)
473     {
474         log_debug("nsec3_add_owner: %{digest32h} @ %p, '%{dnslabel}' RC went from %i to %i", ITEM_DIGEST(item), item, OWNER_NAME(owner), rc, item->rc);
475     }
476 #endif
477 }
478 
479 /**
480  * Removes an owner from the NSEC3 item
481  *
482  * The entry MUST have been set before
483  *
484  * @param item
485  * @param owner
486  *
487  * 1 use
488  */
489 void
nsec3_item_remove_owner(nsec3_zone_item * item,const zdb_rr_label * owner)490 nsec3_item_remove_owner(nsec3_zone_item *item, const zdb_rr_label *owner)
491 {
492     yassert(item != NULL);
493     yassert(owner != NULL);
494     yassert(nsec3_owner_count(item) >= 0);
495 #if NSEC3_OWNER_DEBUG
496     log_debug("nsec3_remove_owner: %{digest32h} @ %p, '%{dnslabel}' RC=%i", ITEM_DIGEST(item), item, OWNER_NAME(owner), item->rc);
497     s32 rc = item->rc;
498 #endif
499     nsec3_item_label_owner_remove(&item->label, &item->rc, owner);
500 #if NSEC3_OWNER_DEBUG
501     if(rc - item->rc != 1)
502     {
503         log_debug("nsec3_remove_owner: %{digest32h} @ %p, '%{dnslabel}' RC went from %i to %i", ITEM_DIGEST(item), item, OWNER_NAME(owner), rc, item->rc);
504     }
505 #endif
506 }
507 
508 /**
509  * Removes all owners from the NSEC3 item
510  *
511  * The entry MUST have been set before
512  *
513  * @param item
514  *
515  * 3 uses
516  */
517 
518 void
nsec3_item_remove_all_owners(nsec3_zone_item * item)519 nsec3_item_remove_all_owners(nsec3_zone_item *item)
520 {
521     yassert(item != NULL);
522 
523 #if NSEC3_OWNER_DEBUG
524     log_debug("nsec3_remove_all_owners: %{digest32h} @ %p", ITEM_DIGEST(item), item);
525 #endif
526 
527     if(item->rc > 0)
528     {
529         if(item->rc == 1)
530         {
531             zdb_rr_label* label = item->label.owner;
532 
533             if(label != NULL)
534             {
535 #if NSEC3_OWNER_DEBUG
536                 log_debug("nsec3_remove_all_owners: 1 : %p '%{dnslabel}'", item, label->name);
537 #endif
538                 // if an nsec3_label_extension is attached to the label
539 
540                 if(label->nsec.nsec3 != NULL)
541                 {
542                     // replace the self-NSEC3 link to 'item' by NULL, and retrieve the chain index
543 
544                     int item_chain_index = nsec3_label_extension_replace_self(label->nsec.nsec3, item, NULL);
545 
546                     // grab the nsec3_label_extension for the chain
547 
548                     nsec3_label_extension *n3e = nsec3_label_extension_get_from_label(label, item_chain_index);
549 
550                     if(nsec3_label_extension_star(n3e) != NULL)
551                     {
552                         // if there is a star reference, it needs to go
553 
554                         // remove the star-reference to the label
555                         nsec3_item_remove_star(nsec3_label_extension_star(n3e), label);
556 
557                         // and replace the star-reference from the nsec3_label_extension by NULL
558                         nsec3_label_extension_replace_star(n3e, nsec3_label_extension_star(n3e), NULL);
559                     }
560                 }
561                 else
562                 {
563                     log_warn("nsec3_remove_all_owners: label %{dnslabel} has no NSEC3 (flags=%04x)", label->name, zdb_rr_label_flag_get(label));
564                 }
565 
566                 // the label has no star reference as far as this is concerned
567 
568                 // update the NSEC3 flags on the label
569 
570                 u16 is_still_nsec3_mask = ~ZDB_RR_LABEL_NSEC3;
571                 struct nsec3_label_extension* n3e = label->nsec.nsec3;
572                 while(n3e != NULL)
573                 {
574                     if(nsec3_label_extension_self(n3e) != NULL)
575                     {
576                         is_still_nsec3_mask = ~0;
577                         break;
578                     }
579                     n3e = nsec3_label_extension_next(n3e);
580                 }
581 
582                 zdb_rr_label_flag_and(label, is_still_nsec3_mask);
583 
584                 item->label.owner = NULL;
585             }
586         }
587         else
588         {
589             s32 n = item->rc;
590 
591 #if NSEC3_OWNER_DEBUG
592             log_debug("nsec3_remove_all_owners: n : %p (%u)", item, n);
593 #endif
594             // for all owner labels
595 
596             for(s32 i = 0; i < n; i++)
597             {
598                 zdb_rr_label* label = item->label.owners[i];
599 
600                 if(label != NULL)
601                 {
602 #if NSEC3_OWNER_DEBUG
603                     log_debug("nsec3_remove_all_owners: n : %p '%{dnslabel}'", item, label->name);
604 #endif
605                     if(label->nsec.nsec3 != NULL)
606                     {
607                         // replace the self-NSEC3 link to 'item' by NULL, and retrieve the chain index
608 
609                         int item_chain_index = nsec3_label_extension_replace_self(label->nsec.nsec3, item, NULL);
610 
611                         nsec3_label_extension *n3e = nsec3_label_extension_get_from_label(label, item_chain_index);
612 
613                         if(nsec3_label_extension_star(n3e) != NULL)
614                         {
615                             nsec3_item_remove_star(nsec3_label_extension_star(n3e), label);
616                             nsec3_label_extension_replace_star(n3e, nsec3_label_extension_star(label->nsec.nsec3), NULL);
617                         }
618                     }
619                     else
620                     {
621                         log_warn("nsec3_remove_all_owners: label %{dnslabel} has no NSEC3 (flags=%04x)", label->name, zdb_rr_label_flag_get(label));
622                     }
623 
624                     // update the NSEC3 flags on the label
625 
626                     u16 is_still_nsec3_mask = ~ZDB_RR_LABEL_NSEC3;
627                     struct nsec3_label_extension* n3e = label->nsec.nsec3;
628                     while(n3e != NULL)
629                     {
630                         if(nsec3_label_extension_self(n3e) != NULL)
631                         {
632                             is_still_nsec3_mask = ~0;
633                             break;
634                         }
635                         n3e = nsec3_label_extension_next(n3e);
636                     }
637 
638                     zdb_rr_label_flag_and(label, is_still_nsec3_mask);
639 
640                     item->label.owners[i] = NULL;
641                 }
642             }
643 
644             ZFREE_ARRAY(item->label.owners, sizeof(zdb_rr_label*) * n);
645 
646             item->label.owners = NULL;
647         }
648 
649         item->rc = 0;
650     }
651 }
652 
653 /**
654  *
655  * Returns the nth label owner for this item.
656  *
657  * @param item an NSEC3 item
658  * @param idx the index of the label for this hash (usually 0, except if there are collisions of digest(transform(label))
659  *
660  * @return the owner
661  *
662  * 1 use
663  */
664 
665 zdb_rr_label*
nsec3_item_owner_get(const nsec3_zone_item * item,s32 idx)666 nsec3_item_owner_get(const nsec3_zone_item *item, s32 idx)
667 {
668     yassert(item != NULL);
669 
670     if(item->rc == 1)
671     {
672         return item->label.owner;
673     }
674     else if(idx < item->rc)
675     {
676         return item->label.owners[idx];
677     }
678 
679     return NULL;
680 }
681 
682 /*
683  * Adds a "star" to the NSEC3 item
684  *
685  * 5 uses
686  */
687 
688 void
nsec3_item_add_star(nsec3_zone_item * item,const zdb_rr_label * owner)689 nsec3_item_add_star(nsec3_zone_item *item, const zdb_rr_label *owner)
690 {
691     yassert(item != NULL);
692     yassert(owner != NULL);
693 
694 #if NSEC3_OWNER_DEBUG
695     log_debug("nsec3_add_star: %{digest32h} @ %p, %p '%{dnslabel}' SC=%hu", ITEM_DIGEST(item), item, owner, owner->name, item->sc);
696     s32 sc = item->sc;
697 #endif
698 
699     nsec3_item_label_owner_add(&item->star_label, &item->sc, owner);
700 
701 #if NSEC3_OWNER_DEBUG
702     if(item->sc - sc != 1)
703     {
704         log_debug("nsec3_add_star: %{digest32h} @ %p, %p '%{dnslabel}' SC went from %hu to %hu", ITEM_DIGEST(item), item, owner, owner->name, sc, item->sc);
705     }
706 #endif
707 
708 }
709 
710 /**
711  * Removes a star from the NSEC3 item
712  *
713  * The entry MUST have been set before
714  *
715  * @param item
716  * @param owner
717  * 3 uses
718  */
719 
720 void
nsec3_item_remove_star(nsec3_zone_item * item,const zdb_rr_label * owner)721 nsec3_item_remove_star(nsec3_zone_item *item, const zdb_rr_label *owner)
722 {
723     yassert(item != NULL);
724     yassert(owner != NULL);
725 
726 #if NSEC3_OWNER_DEBUG
727     log_debug("nsec3_remove_star: %{digest32h}@ @ %p '%{dnslabel}' SC=%hu", ITEM_DIGEST(item), item, owner->name, item->sc);
728     s32 sc = item->sc;
729 #endif
730     nsec3_item_label_owner_remove(&item->star_label, &item->sc, owner);
731 #if NSEC3_OWNER_DEBUG
732 
733     if(sc - item->sc != 1)
734     {
735         log_err("nsec3_remove_star: %{digest32h}@ @ %p '%{dnslabel}' SC went from %hu to %hu", ITEM_DIGEST(item), item, owner->name, sc, item->sc);
736     }
737 #endif
738 }
739 
740 /**
741  * Removes all stars from the NSEC3 item
742  *
743  * The entry MUST have been set before
744  *
745  * @param item
746  *
747  * 5 uses
748  */
749 
750 void
nsec3_item_remove_all_star(nsec3_zone_item * item)751 nsec3_item_remove_all_star(nsec3_zone_item *item)
752 {
753     yassert(item != NULL);
754 
755 #if NSEC3_OWNER_DEBUG
756     log_debug("nsec3_remove_all_star(%{digest32h} @ %p)", ITEM_DIGEST(item), item);
757 #endif
758 
759     if(item->sc > 0)
760     {
761         if(item->sc == 1)
762         {
763             zdb_rr_label *label = item->star_label.owner;
764 
765             if(label != NULL)
766             {
767 #if NSEC3_OWNER_DEBUG
768                 log_debug("nsec3_remove_all_star: n = 1 : %p '%{dnslabel}'", label, label->name);
769 #endif
770 
771                 if(label->nsec.nsec3 != NULL)
772                 {
773                     nsec3_label_extension_replace_star(label->nsec.nsec3, item, NULL);
774                 }
775                 else
776                 {
777                     log_warn("nsec3_remove_all_star: label %{dnslabel} has no NSEC3 (flags=%04x)", label->name, zdb_rr_label_flag_get(label));
778                 }
779 
780                 item->star_label.owner = NULL;
781             }
782         }
783         else
784         {
785             u32 n = (u32)item->sc; // sc > 0
786 
787 #if NSEC3_OWNER_DEBUG
788             log_debug("nsec3_remove_all_star: n = %u", n);
789             for(u32 i = 0; i < n; i++)
790             {
791                 log_debug("\tlabel[%i] = %p '%{dnslabel}'", i, item->star_label.owners[i], item->star_label.owners[i]->name);
792             }
793 #endif
794 
795             for(u32 i = 0; i < n; i++)
796             {
797                 zdb_rr_label *label = item->star_label.owners[i];
798 
799                 if(label != NULL)
800                 {
801                     if(label->nsec.nsec3 != NULL)
802                     {
803 #if NSEC3_OWNER_DEBUG
804                             log_debug("nsec3_remove_all_star: %i/%i %p '%{dnslabel}'", i, n, label, label->name);
805 #endif
806                             nsec3_label_extension_replace_star(label->nsec.nsec3, item, NULL);
807                     }
808 
809                     item->star_label.owners[i] = NULL;
810                 }
811             }
812 
813             ZFREE_ARRAY(item->star_label.owners, sizeof(zdb_rr_label*) * n);
814 
815             item->star_label.owners = NULL;
816         }
817 
818         item->sc = 0;
819     }
820 }
821 
822 /**
823  * Moves all stars from one NSEC3 item to another.
824  *
825  * This is used when an NSEC3 item is removed: All its NSEC3 must be moved
826  * to his predecessor.
827  *
828  * @param src
829  * @param dst
830  *
831  * 3 uses
832  */
833 
834 void
nsec3_item_move_all_star_to_nsec3_item(nsec3_zone_item * src,nsec3_zone_item * dst)835 nsec3_item_move_all_star_to_nsec3_item(nsec3_zone_item* src, nsec3_zone_item* dst)
836 {
837     yassert(src != NULL);
838     yassert(dst != NULL);
839 
840 #if NSEC3_OWNER_DEBUG
841     log_debug("nsec3_move_all_star(%{digest32h} @ %p SC=%i, %{digest32h} @ %p SC=%i)", ITEM_DIGEST(src), src, src->sc, ITEM_DIGEST(dst), dst, dst->sc);
842     s32 sum = src->sc + dst->sc;
843 #endif
844 
845 
846 
847     yassert(src != dst);
848 
849     if(src->sc == 0)
850     {
851         /* nothing to move */
852 
853         return;
854     }
855 
856     // If there were no star in the dest : just move the star collection and update the referrenced labels
857 
858     if(dst->sc == 0)
859     {
860         dst->star_label.owner = src->star_label.owner;
861         dst->sc = src->sc;
862         for(s32 i = 0; i < src->sc; i++)
863         {
864             zdb_rr_label *label = nsec3_item_star_get(src, i);
865             nsec3_label_extension_replace_star(label->nsec.nsec3, src, dst);
866         }
867     }
868     else
869     {
870         // will merge both in dst
871 
872         nsec3_item_label_owner_array owners;
873 
874         s64 total = src->sc;
875         total += dst->sc;
876 
877         yassert(total < (s64)(1ULL << (sizeof(src->sc) * 8)));
878 
879         /*
880          * rc > 0 and sc > 0, so total of 2 means rc = 1 and sc = 1
881          */
882 
883         ZALLOC_ARRAY_OR_DIE(zdb_rr_label**, owners.owners, sizeof(zdb_rr_label*) * total, NSEC3_LABELPTRARRAY_TAG);
884 
885         for(s32 i = 0; i < dst->sc; i++) // VS false positive: dst cannot be NULL
886         {
887             zdb_rr_label *label = nsec3_item_star_get(dst, i);
888 
889             log_debug("nsec3_move_all_star: %{digest32h} @%p %{dnslabel} @%p %i -> %i", ITEM_DIGEST(dst), dst, label->name, label, i, i);
890 
891             owners.owners[i] = label;
892         }
893 
894         if(dst->sc > 1) // if it's a real array, free it
895         {
896             s32 len = dst->sc * sizeof(zdb_rr_label*);
897             ZFREE_ARRAY(dst->star_label.owners, len);
898         }
899 
900         /* change the star link of each label from src to dst */
901         for(s32 i = 0; i < src->sc; i++) // VS false positive: SRC cannot be NULL
902         {
903             zdb_rr_label *label = nsec3_item_star_get(src, i);
904 
905             log_debug("nsec3_move_all_star: %{digest32h} @%p %{dnslabel} @%p %i -> %i", ITEM_DIGEST(src), src, label->name, label, i, dst->sc + i);
906 
907             nsec3_label_extension_replace_star(label->nsec.nsec3, src, dst);
908             owners.owners[dst->sc + i] = label;
909         }
910 
911         if(src->sc > 1) // if it's a real array, free it
912         {
913             s32 len = src->sc * sizeof(zdb_rr_label*);
914             ZFREE_ARRAY(src->star_label.owners, len);
915         }
916 
917         dst->star_label.owners = owners.owners; // owner when 1 item, owners when multiple. False positives from static analysers.
918         dst->sc = total;
919     }
920 
921     src->star_label.owners = NULL;
922     src->sc = 0;
923 
924 #if NSEC3_OWNER_DEBUG
925     if(dst->sc != sum)
926     {
927         log_debug("nsec3_move_all_star(%{digest32h} @ %p, %{digest32h} @ %p SC went %i instead of %i)", ITEM_DIGEST(src), src, ITEM_DIGEST(dst), dst, dst->sc, sum);
928     }
929 #endif
930 }
931 
932 /**
933  *
934  * Returns the nth star label owner for this item.
935  *
936  * @param item an NSEC3 item
937  * @param idx the index of the label for this hash (usually 0, except if there are collisions of digest(transform(label))
938  *
939  * @return the owner
940  *
941  * 4 uses
942  */
943 
944 zdb_rr_label *
nsec3_item_star_get(const nsec3_zone_item * item,s32 idx)945 nsec3_item_star_get(const nsec3_zone_item *item, s32 idx)
946 {
947     yassert(item != NULL);
948 
949     if(item->sc == 1)
950     {
951         return item->star_label.owner;
952     }
953     else if(idx < item->sc)
954     {
955         return item->star_label.owners[idx];
956     }
957 
958     return NULL;
959 }
960 
961 /** @} */
962