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