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 records_labels Internal functions for the database: zoned resource records label.
36  *  @ingroup dnsdb
37  *  @brief Internal functions for the database: zoned resource records label.
38  *
39  *  Internal functions for the database: zoned resource records label.
40  *
41  * @{
42  */
43 
44 #include "dnsdb/dnsdb-config.h"
45 
46 
47 
48 #include <dnscore/format.h>
49 
50 #include "dnsdb/zdb_types.h"
51 #include "dnsdb/zdb_record.h"
52 #include "dnsdb/zdb_rr_label.h"
53 #include "dnsdb/zdb_utils.h"
54 #include "dnsdb/zdb_error.h"
55 #include "dnsdb/zdb-zone-lock.h"
56 #include "dnsdb/nsec3_types.h"
57 
58 #include "dnsdb/dictionary.h"
59 
60 #include <dnscore/logger.h>
61 
62 void nsec3_zone_label_detach(zdb_rr_label *label);
63 void nsec_zone_label_detach(zdb_rr_label *label);
64 
65 extern logger_handle* g_database_logger;
66 #define MODULE_MSG_HANDLE g_database_logger
67 
68 static void zdb_rr_label_destroy_callback(dictionary_node* rr_label_record, void* arg);
69 
70 /**
71  * Removes the "under delegation" flag for all labels under rr_label
72  */
73 
zdb_rr_label_clear_underdelegation_under(zdb_rr_label * rr_label)74 static void zdb_rr_label_clear_underdelegation_under(zdb_rr_label *rr_label)
75 {
76     dictionary_iterator iter;
77     dictionary_iterator_init(&rr_label->sub, &iter);
78     while(dictionary_iterator_hasnext(&iter))
79     {
80         zdb_rr_label** sub_labelp = (zdb_rr_label**)dictionary_iterator_next(&iter);
81         zdb_rr_label_flag_and(*sub_labelp, ~ZDB_RR_LABEL_UNDERDELEGATION);
82 
83 
84         if(!zdb_rr_label_has_rrset(*sub_labelp, TYPE_NS))
85         {
86             zdb_rr_label_clear_underdelegation_under(*sub_labelp);
87         }
88         else // we reached a sub-delegation
89         {
90             zdb_rr_label_flag_or(*sub_labelp, ZDB_RR_LABEL_DELEGATION);
91         }
92     }
93 }
94 
95 //typedef ya_result zdb_rr_label_forall_cb(zdb_rr_label *rr_label, const u8 *rr_label_fqdn, void *data);
96 
97 struct zdb_rr_label_forall_children_of_fqdn_recurse_parm
98 {
99     zdb_rr_label_forall_cb *callback;
100     void *data;
101     u8 *fqdn;
102     u8 fqdn_storage[256];
103 };
104 
105 static ya_result
zdb_rr_label_forall_children_of_fqdn_recurse(zdb_rr_label * rr_label,struct zdb_rr_label_forall_children_of_fqdn_recurse_parm * parms)106 zdb_rr_label_forall_children_of_fqdn_recurse(zdb_rr_label *rr_label, struct zdb_rr_label_forall_children_of_fqdn_recurse_parm* parms)
107 {
108     ya_result ret = 0;
109 
110     dictionary_iterator iter;
111     dictionary_iterator_init(&rr_label->sub, &iter);
112     while(dictionary_iterator_hasnext(&iter))
113     {
114         zdb_rr_label** sub_labelp = (zdb_rr_label**)dictionary_iterator_next(&iter);
115 
116         u8* sub_fqdn = parms->fqdn;
117         sub_fqdn -= (*sub_labelp)->name[0] + 1;
118         if(sub_fqdn < &parms->fqdn_storage[0])
119         {
120             break;
121         }
122 
123         memcpy(sub_fqdn, (*sub_labelp)->name, (*sub_labelp)->name[0] + 1);
124 
125         parms->callback(*sub_labelp, sub_fqdn, parms->data);
126 
127         if(zdb_rr_label_has_children(rr_label))
128         {
129             parms->fqdn = sub_fqdn;
130 
131             ret += zdb_rr_label_forall_children_of_fqdn_recurse(*sub_labelp, parms);
132 
133             parms->fqdn += sub_fqdn[0] + 1;
134         }
135     }
136 
137     return ret;
138 }
139 
140 ya_result
zdb_rr_label_forall_children_of_fqdn(zdb_rr_label * rr_label,const u8 * rr_label_fqdn,zdb_rr_label_forall_cb * callback,void * data)141 zdb_rr_label_forall_children_of_fqdn(zdb_rr_label *rr_label, const u8 *rr_label_fqdn, zdb_rr_label_forall_cb *callback, void *data)
142 {
143     if(!zdb_rr_label_has_children(rr_label))
144     {
145         return 0;
146     }
147 
148     struct zdb_rr_label_forall_children_of_fqdn_recurse_parm parms;
149     parms.callback = callback;
150     parms.data = data;
151 
152     int len = dnsname_len(rr_label_fqdn);
153     parms.fqdn = &parms.fqdn_storage[256 - len];
154     memcpy(parms.fqdn, rr_label_fqdn, len);
155 
156     ya_result ret = zdb_rr_label_forall_children_of_fqdn_recurse(rr_label, &parms);
157 
158     return ret;
159 }
160 
161 /**
162  *  NSEC3: Zone possible
163  *
164  * @note The zdb_rr_label_free functions handles the NSEC3 extension.
165  *
166  */
167 static inline void
zdb_rr_label_free(zdb_zone * zone,zdb_rr_label * label)168 zdb_rr_label_free(zdb_zone* zone, zdb_rr_label* label)
169 {
170 #if DEBUG
171     bool must_keep = zdb_rr_label_must_keep(label);
172     yassert(!must_keep);
173 #endif
174 
175     dictionary_destroy_ex(&(label)->sub, zdb_rr_label_destroy_callback, zone);
176     zdb_record_destroy(&(label)->resource_record_set); /// @note not an edition, use only for cleanup/delete
177 
178 #if ZDB_HAS_NSEC_SUPPORT
179     if(zdb_rr_label_nsec_linked(label))
180     {
181         /*
182          * Here, if there are NSEC nodes pointing to the label they MUST have been destroyed
183          */
184 
185         nsec_zone_label_detach(label);
186 
187 #if DEBUG
188         yassert(label->nsec.nsec.node == NULL);
189 #endif
190     }
191 
192 #else // ZDB_HAS_NSEC_SUPPORT
193     if(FALSE)
194 #endif // ZDB_HAS_NSEC_SUPPORT
195 
196 #if ZDB_HAS_NSEC3_SUPPORT
197 
198     else if(zdb_rr_label_nsec3any_linked(label))
199     {
200         /*
201          * Here, if there are NSEC3 nodes pointing to the label they MUST be destroyed
202          */
203 
204         if(label->nsec.nsec3 != NULL)
205         {
206             //yassert(nsec3_label_extension_self(label->nsec.nsec3) == NULL);
207             //yassert(nsec3_label_extension_star(label->nsec.nsec3) == NULL);
208 
209             // free the nsec3 label extension of the label being freed
210             // nsec3_label_extension_free(label->nsec.nsec3);
211 
212             nsec3_zone_label_detach(label);
213 
214 #if DEBUG
215             label->nsec.nsec3 = (nsec3_label_extension*)0xbad;
216 #endif
217         }
218     }
219 #else // ZDB_HAS_NSEC3_SUPPORT
220     else if(FALSE)
221     {
222     }
223 #endif // ZDB_HAS_NSEC3_SUPPORT
224 
225 #if DEBUG
226     else
227     {
228         yassert(label->nsec.dnssec == NULL);
229     }
230 #endif
231 
232     u32 len = label->name[0]; /* get the memory required to store the label name */
233     len++;
234     u32 pad = (len > 2)?0:2-len;
235 
236     ZFREE_ARRAY(label, sizeof(zdb_rr_label) - 1 + len + pad);
237 
238     (void)pad; // silence warnings in some setups
239 }
240 
241 /**
242  * @brief INTERNAL callback
243  */
244 
245 static void
zdb_rr_label_destroy_callback(dictionary_node * rr_label_record,void * zone)246 zdb_rr_label_destroy_callback(dictionary_node* rr_label_record, void* zone)
247 {
248     if(rr_label_record == NULL)
249     {
250         return;
251     }
252 
253     zdb_rr_label *rr_label = (zdb_rr_label*)rr_label_record;
254 
255     /* detach is made by destroy */
256 
257     /* dictionary destroy will take every item in the dictionary and
258      * iterate through it calling the passed function.
259      *
260      * Maybe I should use the iterator directly instead.
261      */
262 
263     zdb_rr_label_free((zdb_zone*)zone, rr_label); // valid call because in a delete
264 }
265 
266 /**
267  * @brief INTERNAL callback
268  */
269 
270 /* NSEC3: Zone possible */
271 static int
zdb_rr_label_zlabel_match(const void * label,const dictionary_node * node)272 zdb_rr_label_zlabel_match(const void* label, const dictionary_node* node)
273 {
274     const zdb_rr_label *rr_label = (const zdb_rr_label*)node;
275     return dnslabel_equals(rr_label->name, label);
276 }
277 
278 zdb_rr_label*
zdb_rr_label_new_instance(const u8 * label_name)279 zdb_rr_label_new_instance(const u8* label_name)
280 {
281     zdb_rr_label *rr_label;
282 
283     u32 len = label_name[0]; /* get the memory required to store the label name */
284     len++;
285     u32 pad = (len > 2)?0:2-len;
286     ZALLOC_ARRAY_OR_DIE(zdb_rr_label*, rr_label, sizeof(zdb_rr_label) - 1 + len + pad, ZDB_RRLABEL_TAG);
287 
288 #if DEBUG
289     memset(rr_label, 0xac, sizeof(zdb_rr_label) - 1 + len);
290 #endif
291     rr_label->name[1] = (u8)0xee;   // this slot is guaranteed by pad, and used by the wild card 16 bits test
292                                     // specifically written a byte here avoid a valgrind check
293                                     // (otherwise harmless : 8 bytes are allocated at least, no overrun is possible)
294     MEMCOPY(rr_label->name, label_name, len);
295 
296     rr_label->next = NULL;
297     btree_init(&rr_label->resource_record_set);
298     dictionary_init(&rr_label->sub);
299 
300     rr_label->_flags = 0;
301 
302 #if ZDB_HAS_DNSSEC_SUPPORT
303     /* I have to clean this pointer, the caller will be responsible
304      * for setting it up.
305      */
306     rr_label->nsec.dnssec = NULL;
307 
308 #endif
309 
310     return rr_label;
311 }
312 
313 /**
314  * @brief INTERNAL callback
315  */
316 
317 static dictionary_node*
zdb_rr_label_create_callback(const void * data)318 zdb_rr_label_create_callback(const void* data)
319 {
320     zdb_rr_label *rr_label = zdb_rr_label_new_instance((const u8*)data);
321 
322     return (dictionary_node*)rr_label;
323 }
324 
325 /**
326  * @brief Destroys an rr label and its contents
327  *
328  * Destroys an rr label and its contents
329  *
330  * @param[in] zone_labep a pointer to a pointer to the label to destroy
331  *
332  */
333 
334 /* NSEC3: Zone possible */
335 void
zdb_rr_label_destroy(zdb_zone * zone,zdb_rr_label ** rr_labelp)336 zdb_rr_label_destroy(zdb_zone* zone, zdb_rr_label** rr_labelp)
337 {
338     yassert(rr_labelp != NULL);
339 
340     zdb_rr_label *rr_label = *rr_labelp;
341 
342     if(rr_label != NULL)
343     {
344         zdb_rr_label_free(zone, rr_label); // valid call because in a delete
345         *rr_labelp = NULL;
346     }
347 }
348 
349 /**
350  * @brief Destroys an rr label and its contents
351  *
352  * Destroys an rr label and its contents
353  *
354  * @param[in] zone_labep a pointer to a pointer to the label to destroy
355  *
356  */
357 
358 /* NSEC3: Zone possible */
359 void
zdb_rr_label_truncate(zdb_zone * zone,zdb_rr_label * rr_label)360 zdb_rr_label_truncate(zdb_zone* zone, zdb_rr_label *rr_label)
361 {
362     if(rr_label != NULL)
363     {
364         dictionary_destroy_ex(&rr_label->sub, zdb_rr_label_destroy_callback, zone);
365         zdb_record_destroy(&rr_label->resource_record_set); /// @note not an edition, use only for cleanup/delete
366     }
367 }
368 
369 /**
370  * @brief Finds the resource record label matching a path of labels starting from another rr label
371  *
372  * Finds the resource record label matching a path of labels starting from another rr label
373  * Typically the starting label is a zone cut.
374  *
375  * @param[in] apex the starting label
376  * @param[in] path a stack of labels
377  * @param[in] path_index the index of the top of the stack
378  *
379  * @return the matching label or NULL if it has not been found
380  */
381 
382 zdb_rr_label*
zdb_rr_label_find_exact(zdb_rr_label * apex,dnslabel_vector_reference sections,s32 index)383 zdb_rr_label_find_exact(zdb_rr_label* apex, dnslabel_vector_reference sections, s32 index)
384 {
385     zdb_rr_label *rr_label = apex; /* the zone cut */
386 
387     /* look into the sub level*/
388 
389     while(rr_label != NULL && index >= 0)
390     {
391         const u8* label = sections[index];
392         hashcode hash = hash_dnslabel(label);
393         rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match);
394 
395         index--;
396     }
397 
398     return rr_label;
399 }
400 
401 zdb_rr_label*
zdb_rr_label_find_child(zdb_rr_label * parent,const u8 * dns_label)402 zdb_rr_label_find_child(zdb_rr_label* parent, const u8* dns_label)
403 {
404     hashcode hash = hash_dnslabel(dns_label);
405 
406     zdb_rr_label *rr_label = (zdb_rr_label*)dictionary_find(&parent->sub, hash, dns_label, zdb_rr_label_zlabel_match);
407 
408     return rr_label;
409 }
410 
411 zdb_rr_label*
zdb_rr_label_stack_find(zdb_rr_label * apex,const_dnslabel_stack_reference sections,s32 pos,s32 index)412 zdb_rr_label_stack_find(zdb_rr_label* apex, const_dnslabel_stack_reference sections, s32 pos, s32 index)
413 {
414     zdb_rr_label *rr_label = apex; /* the zone cut */
415 
416     /* look into the sub level*/
417 
418     while(rr_label != NULL && index <= pos)
419     {
420         const u8* label = sections[index];
421         hashcode hash = hash_dnslabel(label);
422 
423         rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match);
424 
425         index++;
426     }
427 
428     return rr_label;
429 }
430 
431 /**
432  * @brief Finds the resource record label matching a path of labels starting from another rr label or the wildcard label
433  *
434  * Finds the resource record label matching a path of labels starting from another rr label or the wildcard label
435  * Typically the starting label is a zone cut.
436  *
437  * @param[in] apex the starting label
438  * @param[in] path a stack of labels
439  * @param[in] path_index the index of the top of the stack
440  *
441  * @return the matching label, the * label or NULL if none of them has not been found
442  */
443 
444 zdb_rr_label*
zdb_rr_label_find(zdb_rr_label * apex,dnslabel_vector_reference sections,s32 index)445 zdb_rr_label_find(zdb_rr_label* apex, dnslabel_vector_reference sections, s32 index)
446 {
447     yassert(apex != NULL);
448 
449     zdb_rr_label *rr_label = apex; /* the zone cut */
450 
451     /* look into the sub level*/
452 
453     while(index >= 0)
454     {
455         const u8* label = sections[index];
456         hashcode hash = hash_dnslabel(label);
457 
458         zdb_rr_label* sub_rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match);
459 
460         if(sub_rr_label == NULL)
461         {
462             /* If the label does not exist BUT we got a wildcard, THEN it is what we are looking for */
463 
464             if(zdb_rr_label_flag_isset(rr_label, ZDB_RR_LABEL_GOT_WILD))
465             {
466                 rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, WILD_HASH, (void*)WILD_LABEL, zdb_rr_label_zlabel_match);
467 
468                 return rr_label;
469             }
470 
471             return sub_rr_label; /* NULL */
472         }
473 
474         rr_label = sub_rr_label;
475 
476         index--;
477     }
478 
479     return rr_label;
480 }
481 
482 int
zdb_rr_label_find_path(zdb_rr_label * apex,dnslabel_vector_reference sections,s32 index,zdb_rr_label ** out_array_64)483 zdb_rr_label_find_path(zdb_rr_label* apex, dnslabel_vector_reference sections, s32 index, zdb_rr_label** out_array_64)
484 {
485     yassert(apex != NULL);
486 
487     zdb_rr_label *rr_label = apex; /* the zone cut */
488 
489     zdb_rr_label **p = out_array_64;
490 
491     /* look into the sub level*/
492 
493     while(index >= 0)
494     {
495         const u8* label = sections[index];
496         hashcode hash = hash_dnslabel(label);
497 
498         zdb_rr_label* sub_rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match);
499 
500         if(sub_rr_label != NULL)
501         {
502             *p++ = sub_rr_label;
503             rr_label = sub_rr_label;
504             --index;
505         }
506         else
507         {
508             /* If the label does not exist BUT we got a wildcard, THEN it is what we are looking for */
509 
510             if(zdb_rr_label_flag_isset(rr_label, ZDB_RR_LABEL_GOT_WILD))
511             {
512                 sub_rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, WILD_HASH, (void*)WILD_LABEL, zdb_rr_label_zlabel_match); // VS false positive: can't be NULL
513 
514                 if(sub_rr_label != NULL)
515                 {
516                     *p++ = sub_rr_label;
517                 }
518             }
519 
520             break;
521         }
522     }
523 
524     return p - out_array_64;
525 }
526 
527 zdb_rr_label*
zdb_rr_label_find_from_name(zdb_zone * zone,const u8 * fqdn)528 zdb_rr_label_find_from_name(zdb_zone* zone, const u8 *fqdn)
529 {
530     s32 top;
531     dnslabel_vector name;
532     top = dnsname_to_dnslabel_vector(fqdn, name);
533     top -= zone->origin_vector.size + 1;
534     zdb_rr_label *label = zdb_rr_label_find(zone->apex, name, top);
535     return label;
536 }
537 
538 int
zdb_rr_label_find_path_from_name(zdb_zone * zone,const u8 * fqdn,zdb_rr_label ** out_array_64)539 zdb_rr_label_find_path_from_name(zdb_zone *zone, const u8 *fqdn, zdb_rr_label** out_array_64)
540 {
541     s32 top;
542     dnslabel_vector name;
543     top = dnsname_to_dnslabel_vector(fqdn, name);
544     top -= zone->origin_vector.size + 1;
545     int ret = zdb_rr_label_find_path(zone->apex, name, top, out_array_64);
546     return ret;
547 }
548 
549 zdb_rr_label*
zdb_rr_label_find_from_name_delete_empty_terminal(zdb_zone * zone,const u8 * fqdn)550 zdb_rr_label_find_from_name_delete_empty_terminal(zdb_zone* zone, const u8 *fqdn)
551 {
552     s32 top;
553     dnslabel_vector name;
554     top = dnsname_to_dnslabel_vector(fqdn, name);
555     top -= zone->origin_vector.size + 1;
556     zdb_rr_label *label = zdb_rr_label_find(zone->apex, name, top);
557 
558     if((label != NULL) && zdb_rr_label_can_be_deleted(label))
559     {
560         ya_result ret;
561 
562         if(ISOK(ret = zdb_rr_label_delete_record_and_empty_terminal(zone, name, top - zone->origin_vector.size, TYPE_ANY)))
563         //if(ISOK(ret = zdb_rr_label_delete_record(zone, name, top - zone->origin_vector.size, TYPE_ANY)))
564         {
565             label = NULL;
566         }
567         else
568         {
569             log_err("zdb_rr_label: %{dnsname} is an empty terminal but could not be removed from the zone: %r", fqdn, ret);
570         }
571     }
572 
573     return label;
574 }
575 
576 zdb_rr_label*
zdb_rr_label_find_ext(zdb_rr_label * apex,dnslabel_vector_reference sections,s32 index_,zdb_rr_label_find_ext_data * ext)577 zdb_rr_label_find_ext(zdb_rr_label* apex, dnslabel_vector_reference sections, s32 index_, zdb_rr_label_find_ext_data *ext)
578 {
579     yassert(apex != NULL && sections != NULL);
580 
581     s32 index = index_;
582     zdb_rr_label *rr_label = apex; /* the zone cut */
583 
584     zdb_rr_label* authority = apex;
585     zdb_rr_label* closest = apex;
586     s32 authority_index = index_ + 1;
587     s32 closest_index = index_ + 1;
588 
589     /* look into the sub level*/
590 
591     while(index >= 0)
592     {
593         const u8* label = sections[index];
594         hashcode hash = hash_dnslabel(label);
595 
596         rr_label = (zdb_rr_label*)dictionary_find(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match);
597 
598         if(rr_label == NULL)
599         {
600             /* If the label does not exist BUT we got a wildcard, THEN it is what we are looking for */
601 
602             if(zdb_rr_label_flag_isset(closest, ZDB_RR_LABEL_GOT_WILD))
603             {
604                 /* got it all anyway, from previous node ... */
605 
606                 rr_label = (zdb_rr_label*)dictionary_find(&closest->sub, WILD_HASH, (void*)WILD_LABEL, zdb_rr_label_zlabel_match);
607                 closest_index = 0;
608             }
609 
610             break;
611         }
612 
613         if(zdb_rr_label_flag_isset(rr_label, ZDB_RR_LABEL_DELEGATION))
614         {
615             authority = rr_label;
616             authority_index = index;
617         }
618 
619         closest = rr_label;
620         closest_index = index;
621 
622         index--;
623     }
624 
625     ext->authority = authority;
626     ext->closest = closest;
627     ext->answer = rr_label;
628     ext->authority_index = authority_index;
629     ext->closest_index = closest_index;
630 
631     return rr_label;
632 }
633 
634 /**
635  * @brief Adds the resource record label matching a (relative) path of labels starting from another rr label
636  *
637  * Adds the resource record label matching a path of labels starting from another rr label
638  * Typically the starting label is the apex of the zone.
639  *
640  * @param[in] apex the starting label
641  * @param[in] path a stack of labels
642  * @param[in] path_index the index of the top of the stack
643  *
644  * @return the matching label or NULL if it has not been found
645  */
646 
647 zdb_rr_label*
zdb_rr_label_add(zdb_zone * zone,dnslabel_vector_reference labels,s32 labels_top)648 zdb_rr_label_add(zdb_zone* zone, dnslabel_vector_reference labels, s32 labels_top)
649 {
650     yassert(zdb_zone_iswritelocked(zone));
651 
652     zdb_rr_label *rr_label = zone->apex; /* the zone cut */
653 
654     /* look into the sub level*/
655 
656     u16 or_flags = 0;
657 
658     while(labels_top >= 0)
659     {
660         const u8* label = labels[labels_top];
661         hashcode hash = hash_dnslabel(label);
662 
663         /* If the current label is '*' (wild) then the parent is marked as owner of a wildcard. */
664 
665         if(IS_WILD_LABEL(label))
666         {
667             zdb_rr_label_flag_or(rr_label, ZDB_RR_LABEL_GOT_WILD);
668         }
669 
670         rr_label = (zdb_rr_label*)dictionary_add(&rr_label->sub, hash, label, zdb_rr_label_zlabel_match, zdb_rr_label_create_callback);
671 
672         zdb_rr_label_flag_or(rr_label, or_flags);
673 
674         if(zdb_rr_label_flag_isset(rr_label, ZDB_RR_LABEL_DELEGATION))
675         {
676             /* the next one down is under a delegation */
677 
678             or_flags = ZDB_RR_LABEL_UNDERDELEGATION;
679         }
680 
681         labels_top--;
682     }
683 
684     return rr_label;
685 }
686 
687 /* once */
688 
689 typedef struct zdb_rr_label_delete_record_process_callback_args zdb_rr_label_delete_record_process_callback_args;
690 
691 struct zdb_rr_label_delete_record_process_callback_args
692 {
693     dnslabel_vector_reference sections;
694     zdb_zone* zone;
695     s32 top;
696     u16 type;
697 };
698 
699 /**
700  * @brief INTERNAL callback
701  */
702 
703 static ya_result
zdb_rr_label_delete_record_process_callback(void * a,dictionary_node * node)704 zdb_rr_label_delete_record_process_callback(void* a, dictionary_node* node)
705 {
706     yassert(node != NULL);
707 
708     zdb_rr_label *rr_label = (zdb_rr_label*)node;
709 
710     zdb_rr_label_delete_record_process_callback_args* args = (zdb_rr_label_delete_record_process_callback_args*)a;
711 
712     /*
713      * a points to a kind of dnsname and we are going in
714      *
715      * we go down and down each time calling the dictionnary process for the next level
716      *
717      * at the last level we return the "delete" code
718      *
719      * from there, the dictionnary processor will remove the entry
720      *
721      * at that point the calling dictionnary will know if he has to delete his node or not
722      *
723      * and so on and so forth ...
724      *
725      */
726 
727     s32 top = args->top;
728     const u8* label = args->sections[top];
729 
730     if(!dnslabel_equals(rr_label->name, label))
731     {
732         return COLLECTION_PROCESS_NEXT;
733     }
734 
735     /* match */
736 
737     if(top > 0)
738     {
739         /* go to the next level */
740 
741         label = args->sections[--args->top];
742         hashcode hash = hash_dnslabel(label);
743 
744         ya_result err;
745         if((err = dictionary_process(&rr_label->sub, hash, args, zdb_rr_label_delete_record_process_callback)) == COLLECTION_PROCESS_DELETENODE)
746         {
747             /* check the node for relevance, return "delete" if irrelevant */
748 
749             if(zdb_rr_label_can_be_deleted(rr_label))
750             {
751                 zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
752 
753                 return COLLECTION_PROCESS_DELETENODE;
754             }
755 
756             if(rr_label->resource_record_set == NULL)
757             {
758                 zdb_rr_label_flag_and(rr_label, ~(ZDB_RR_LABEL_HASCNAME|ZDB_RR_LABEL_DROPCNAME));
759             }
760 
761             /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
762 
763             if(IS_WILD_LABEL(label))
764             {
765                 zdb_rr_label_flag_and(rr_label, ~ZDB_RR_LABEL_GOT_WILD);
766             }
767 
768             return COLLECTION_PROCESS_STOP;
769         }
770 
771         /* or ... stop */
772 
773         return err;
774     }
775 
776     /* We are at the right place for the record */
777 
778     ya_result err;
779 
780     if(ISOK(err = zdb_record_delete(&rr_label->resource_record_set, args->type))) /* FB done */
781     {
782         if(zdb_rr_label_cannot_be_deleted(rr_label))
783         {
784             /* If the type was XXXX and we deleted the last one the flag may change.
785              * NS => not a delegation anymore
786              * CNAME => no cname anymore
787              * ANY => nothing anymore (and should not be relevant anymore either ...)
788              */
789 
790             u16 clear_mask = 0;
791             switch(args->type)
792             {
793                 case TYPE_NS:
794                     clear_mask = ~ZDB_RR_LABEL_DELEGATION; // will clear "delegation"
795 
796                     if(!ZDB_LABEL_UNDERDELEGATION(rr_label))
797                     {
798                         // must clear ZDB_RR_LABEL_UNDERDELEGATION from everything under this one
799                         zdb_rr_label_clear_underdelegation_under(rr_label);
800                     }
801 
802                     break;
803                 case TYPE_CNAME:
804                     clear_mask = ~ZDB_RR_LABEL_HASCNAME; // will clear "has cname"
805                     break;
806                 case TYPE_ANY:
807                     clear_mask = ~(ZDB_RR_LABEL_DELEGATION|ZDB_RR_LABEL_DROPCNAME|ZDB_RR_LABEL_HASCNAME); // will clear "delegation", "drop cname" and "has cname"
808                     break;
809                 case TYPE_RRSIG:
810                 case TYPE_NSEC:
811                     break;
812                 default:
813                     // checks if there are any other types than CNAME, RRSIG and NSEC, clears DROPCNAME if it's true
814                     clear_mask = ~ZDB_RR_LABEL_DROPCNAME; // will clear "drop cname"
815                     break;
816             }
817 
818             zdb_rr_label_flag_and(rr_label, clear_mask); // clears the bits using the mask
819 
820             return COLLECTION_PROCESS_STOP;
821         }
822         else
823         {
824             if(zdb_rr_label_has_dnssec_extension(rr_label))
825             {
826                 // remove the extension
827 
828                 if(zdb_rr_label_nsec3any_linked(rr_label))
829                 {
830                     // detach then destroy the ext
831                     nsec3_zone_label_detach(rr_label);
832                 }
833                 else if(zdb_rr_label_nsec_linked(rr_label))
834                 {
835                     nsec_zone_label_detach(rr_label);
836                 }
837 #if DEBUG
838                 else
839                 {
840                     yassert(rr_label->nsec.dnssec == NULL);
841                 }
842 #endif
843             }
844         }
845 
846         /* NOTE: the 'detach' is made by destroy : do not touch to the "next" field */
847         /* NOTE: the free of the node is made by destroy : do not do it */
848 
849         /* dictionary destroy will take every item in the dictionary and
850          * iterate through it calling the passed function.
851          */
852 
853         zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
854 
855         return COLLECTION_PROCESS_DELETENODE;
856     }
857 
858     return err /*COLLECTION_PROCESS_RETURNERROR*/;
859 }
860 
861 /**
862  * @brief Deletes the resource record of the given type on the label matching a path of labels starting from another rr label
863  *
864  * Deletes the resource record of the given type on the label matching a path of labels starting from another rr label
865  * Typically the starting label is a zone cut.
866  *
867  * @param[in] apex the starting label
868  * @param[in] path a stack of labels
869  * @param[in] path_index the index of the top of the stack
870  *
871  * @return the matching label or NULL if it has not been found
872  */
873 
874 ya_result
zdb_rr_label_delete_record(zdb_zone * zone,dnslabel_vector_reference path,s32 path_index,u16 type)875 zdb_rr_label_delete_record(zdb_zone* zone, dnslabel_vector_reference path, s32 path_index, u16 type)
876 {
877     yassert(zone != NULL && path != NULL && path_index >= -1);
878     yassert(zdb_zone_iswritelocked(zone));
879 
880     zdb_rr_label* apex = zone->apex;
881 
882     if(apex == NULL)
883     {
884         return ZDB_ERROR_DELETEFROMEMPTY;
885     }
886 
887     if(path_index < 0)
888     {
889         if(ISOK(zdb_record_delete(&apex->resource_record_set, type))) /* FB done, APEX : no delegation */
890         {
891             return ZDB_RR_LABEL_DELETE_NODE;
892         }
893 
894         return ZDB_ERROR_KEY_NOTFOUND;
895     }
896 
897     zdb_rr_label_delete_record_process_callback_args args;
898     args.sections = path;
899     args.zone = zone;
900     args.top = path_index;
901     args.type = type;
902 
903     hashcode hash = hash_dnslabel(args.sections[args.top]);
904 
905     ya_result err;
906 
907     if((err = dictionary_process(&apex->sub, hash, &args, zdb_rr_label_delete_record_process_callback)) == COLLECTION_PROCESS_DELETENODE)
908     {
909         if(RR_LABEL_IRRELEVANT(apex))
910         {
911             zdb_rr_label_free(zone, apex); // valid call because in a delete
912             zone->apex = NULL;
913 
914             return ZDB_RR_LABEL_DELETE_TREE;
915         }
916 
917         /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
918 
919         if(IS_WILD_LABEL(args.sections[args.top]))
920         {
921             zdb_rr_label_flag_and(apex, ~ZDB_RR_LABEL_GOT_WILD);
922         }
923 
924         return ZDB_RR_LABEL_DELETE_NODE;
925     }
926 
927     return err;
928 }
929 
930 /**
931  * @brief INTERNAL callback
932  */
933 
934 static ya_result
zdb_rr_label_delete_record_and_empty_terminal_process_callback(void * a,dictionary_node * node)935 zdb_rr_label_delete_record_and_empty_terminal_process_callback(void* a, dictionary_node* node)
936 {
937     yassert(node != NULL);
938 
939     zdb_rr_label *rr_label = (zdb_rr_label*)node;
940 
941     zdb_rr_label_delete_record_process_callback_args* args = (zdb_rr_label_delete_record_process_callback_args*)a;
942 
943     /*
944      * a points to a kind of dnsname and we are going in
945      *
946      * we go down and down each time calling the dictionnary process for the next level
947      *
948      * at the last level we return the "delete" code
949      *
950      * from there, the dictionnary processor will remove the entry
951      *
952      * at that point the calling dictionnary will know if he has to delete his node or not
953      *
954      * and so on and so forth ...
955      *
956      */
957 
958     s32 top = args->top;
959     const u8* label = args->sections[top];
960 
961     if(!dnslabel_equals(rr_label->name, label))
962     {
963         return COLLECTION_PROCESS_NEXT;
964     }
965 
966     /* match */
967 
968     if(top > 0)
969     {
970         /* go to the next level */
971 
972         label = args->sections[--args->top];
973         hashcode hash = hash_dnslabel(label);
974 
975         ya_result err;
976         if((err = dictionary_process(&rr_label->sub, hash, args, zdb_rr_label_delete_record_process_callback)) == COLLECTION_PROCESS_DELETENODE)
977         {
978             /* check the node for relevance, return "delete" if irrelevant */
979 
980             if(zdb_rr_label_can_be_deleted(rr_label))
981             {
982                 zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
983 
984                 return COLLECTION_PROCESS_DELETENODE;
985             }
986 
987             if(rr_label->resource_record_set == NULL)
988             {
989                 zdb_rr_label_flag_and(rr_label, ~(ZDB_RR_LABEL_HASCNAME|ZDB_RR_LABEL_DROPCNAME));
990             }
991 
992             /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
993 
994             if(IS_WILD_LABEL(label))
995             {
996                 zdb_rr_label_flag_and(rr_label, ~ZDB_RR_LABEL_GOT_WILD);
997             }
998 
999             return COLLECTION_PROCESS_STOP;
1000         }
1001 
1002         /* or ... stop */
1003 
1004         return err;
1005     }
1006 
1007     /* We are at the right place for the record */
1008 
1009     ya_result err;
1010 
1011     if(ISOK(err = zdb_record_delete(&rr_label->resource_record_set, args->type))) /* FB done */
1012     {
1013         if(zdb_rr_label_cannot_be_deleted(rr_label))
1014         {
1015             /* If the type was XXXX and we deleted the last one the flag may change.
1016              * NS => not a delegation anymore
1017              * CNAME => no cname anymore
1018              * ANY => nothing anymore (and should not be relevant anymore either ...)
1019              */
1020 
1021             u16 clear_mask = 0;
1022             switch(args->type)
1023             {
1024                 case TYPE_NS:
1025                     clear_mask = ~ZDB_RR_LABEL_DELEGATION; // will clear "delegation"
1026 
1027                     if(!ZDB_LABEL_UNDERDELEGATION(rr_label))
1028                     {
1029                         // must clear ZDB_RR_LABEL_UNDERDELEGATION from everything under this one
1030                         zdb_rr_label_clear_underdelegation_under(rr_label);
1031                     }
1032 
1033                     break;
1034                 case TYPE_CNAME:
1035                     clear_mask = ~ZDB_RR_LABEL_HASCNAME; // will clear "has cname"
1036                     break;
1037                 case TYPE_ANY:
1038                     clear_mask = ~(ZDB_RR_LABEL_DELEGATION|ZDB_RR_LABEL_DROPCNAME|ZDB_RR_LABEL_HASCNAME); // will clear "delegation", "drop cname" and "has cname"
1039                     break;
1040                 case TYPE_RRSIG:
1041                 case TYPE_NSEC:
1042                     break;
1043                 default:
1044                     // checks if there are any other types than CNAME, RRSIG and NSEC, clears DROPCNAME if it's true
1045                     clear_mask = ~ZDB_RR_LABEL_DROPCNAME; // will clear "drop cname"
1046                     break;
1047             }
1048 
1049             zdb_rr_label_flag_and(rr_label, clear_mask); // clears the bits using the mask
1050 
1051             return COLLECTION_PROCESS_STOP;
1052         }
1053         else
1054         {
1055             if(zdb_rr_label_has_dnssec_extension(rr_label))
1056             {
1057                 // remove the extension
1058 
1059                 if(zdb_rr_label_nsec3any_linked(rr_label))
1060                 {
1061                     // detach then destroy the ext
1062                     nsec3_zone_label_detach(rr_label);
1063                 }
1064                 else if(zdb_rr_label_nsec_linked(rr_label))
1065                 {
1066                     nsec_zone_label_detach(rr_label);
1067                 }
1068 #if DEBUG
1069                 else
1070                 {
1071                     yassert(rr_label->nsec.dnssec == NULL);
1072                 }
1073 #endif
1074             }
1075         }
1076 
1077         /* NOTE: the 'detach' is made by destroy : do not touch to the "next" field */
1078         /* NOTE: the free of the node is made by destroy : do not do it */
1079 
1080         /* dictionary destroy will take every item in the dictionary and
1081          * iterate through it calling the passed function.
1082          */
1083 
1084         zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
1085 
1086         return COLLECTION_PROCESS_DELETENODE;
1087     }
1088 
1089     return err /*COLLECTION_PROCESS_RETURNERROR*/;
1090 }
1091 
1092 ya_result
zdb_rr_label_delete_record_and_empty_terminal(zdb_zone * zone,dnslabel_vector_reference path,s32 path_index,u16 type)1093 zdb_rr_label_delete_record_and_empty_terminal(zdb_zone* zone, dnslabel_vector_reference path, s32 path_index, u16 type)
1094 {
1095     yassert(zone != NULL && path != NULL && path_index >= -1);
1096     yassert(zdb_zone_iswritelocked(zone));
1097 
1098     zdb_rr_label* apex = zone->apex;
1099 
1100     if(apex == NULL)
1101     {
1102         return ZDB_ERROR_DELETEFROMEMPTY;
1103     }
1104 
1105     if(path_index < 0)
1106     {
1107         if(ISOK(zdb_record_delete(&apex->resource_record_set, type))) /* FB done, APEX : no delegation */
1108         {
1109             return ZDB_RR_LABEL_DELETE_NODE;
1110         }
1111 
1112         return ZDB_ERROR_KEY_NOTFOUND;
1113     }
1114 
1115     zdb_rr_label_delete_record_process_callback_args args;
1116     args.sections = path;
1117     args.zone = zone;
1118     args.top = path_index;
1119     args.type = type;
1120 
1121     hashcode hash = hash_dnslabel(args.sections[args.top]);
1122 
1123     ya_result err;
1124 
1125     if((err = dictionary_process(&apex->sub, hash, &args, zdb_rr_label_delete_record_and_empty_terminal_process_callback)) == COLLECTION_PROCESS_DELETENODE)
1126     {
1127         if(zdb_rr_label_can_be_deleted(apex))
1128         {
1129             zdb_rr_label_free(zone, apex); // valid call because in a delete
1130             zone->apex = NULL;
1131 
1132             return ZDB_RR_LABEL_DELETE_TREE;
1133         }
1134 
1135         /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
1136 
1137         if(IS_WILD_LABEL(args.sections[args.top]))
1138         {
1139             zdb_rr_label_flag_and(apex, ~ZDB_RR_LABEL_GOT_WILD);
1140         }
1141 
1142         return ZDB_RR_LABEL_DELETE_NODE;
1143     }
1144 
1145     return err;
1146 }
1147 
1148 
1149 typedef struct zdb_rr_label_delete_record_exact_process_callback_args zdb_rr_label_delete_record_exact_process_callback_args;
1150 
1151 struct zdb_rr_label_delete_record_exact_process_callback_args
1152 {
1153     dnslabel_vector_reference sections;
1154     const zdb_ttlrdata* ttlrdata;
1155     zdb_zone* zone;
1156     s32 top;
1157     u16 type;
1158     u8  flags;
1159 };
1160 
1161 /**
1162  * @brief INTERNAL callback
1163  */
1164 
1165 /* NSEC3: Zone possible */
1166 static ya_result
zdb_rr_label_delete_record_exact_process_callback(void * a,dictionary_node * node)1167 zdb_rr_label_delete_record_exact_process_callback(void* a, dictionary_node* node)
1168 {
1169     yassert(node != NULL);
1170 
1171     zdb_rr_label *rr_label = (zdb_rr_label*)node;
1172 
1173     zdb_rr_label_delete_record_exact_process_callback_args* args = (zdb_rr_label_delete_record_exact_process_callback_args*)a;
1174 
1175     /*
1176      * a points to a kind of dnsname and we are going in
1177      *
1178      * we go down and down each time calling the dictionnary process for the next level
1179      *
1180      * at the last level we return the "delete" code
1181      *
1182      * from there, the dictionnary processor will remove the entry
1183      *
1184      * at that point the calling dictionnary will know if he has to delete his node or not
1185      *
1186      * and so on and so forth ...
1187      *
1188      */
1189 
1190     s32 top = args->top;
1191     const u8* label = args->sections[top];
1192 
1193     if(!dnslabel_equals(rr_label->name, label))
1194     {
1195         return COLLECTION_PROCESS_NEXT;
1196     }
1197 
1198     /* match */
1199 
1200     if(top > 0)
1201     {
1202         /* go to the next level */
1203 
1204         label = args->sections[--args->top];
1205         hashcode hash = hash_dnslabel(label);
1206 
1207         ya_result return_code;
1208 
1209         if((return_code = dictionary_process(&rr_label->sub, hash, args, zdb_rr_label_delete_record_exact_process_callback)) == COLLECTION_PROCESS_DELETENODE)
1210         {
1211             /* check the node for relevance, return "delete" if irrelevant */
1212 
1213             if(zdb_rr_label_can_be_deleted(rr_label))
1214             {
1215                 zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
1216 
1217                 args->flags |= 2;
1218 
1219                 return COLLECTION_PROCESS_DELETENODE;
1220             }
1221 
1222             if(rr_label->resource_record_set == NULL)
1223             {
1224                 zdb_rr_label_flag_and(rr_label, ~(ZDB_RR_LABEL_HASCNAME|ZDB_RR_LABEL_DROPCNAME));
1225             }
1226 
1227             /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
1228 
1229             if(IS_WILD_LABEL(label))
1230             {
1231                 zdb_rr_label_flag_and(rr_label, ~ZDB_RR_LABEL_GOT_WILD);
1232             }
1233 
1234             return COLLECTION_PROCESS_STOP;
1235         }
1236 
1237         /* or ... stop */
1238 
1239         return return_code;
1240     }
1241 
1242     /* We are at the right place for the record */
1243 
1244     ya_result delete_return_code;
1245 
1246     if(ISOK(delete_return_code = zdb_record_delete_exact(&rr_label->resource_record_set, args->type, args->ttlrdata))) /* FB done */
1247     {
1248         /*
1249          * @NOTE delete_return_code can be either SUCCESS_STILL_RECORDS or SUCCESS_LAST_RECORD
1250          */
1251 
1252         if(zdb_rr_label_cannot_be_deleted(rr_label))
1253         {
1254             /* If the type was XXXX and we deleted the last one the flag may change.
1255              * NS => not a delegation anymore
1256              * CNAME => no cname anymore
1257              * ANY => nothing anymore (and should not be relevant anymore either ...)
1258              */
1259 
1260             if(delete_return_code == SUCCESS_LAST_RECORD)
1261             {
1262                 u16 clear_mask = ~0;
1263                 switch(args->type)
1264                 {
1265                     case TYPE_NS:
1266                         clear_mask = ~ZDB_RR_LABEL_DELEGATION; // will clear "delegation"
1267 
1268                         if(!ZDB_LABEL_UNDERDELEGATION(rr_label))
1269                         {
1270                             // must clear ZDB_RR_LABEL_UNDERDELEGATION from everything under this one
1271                             zdb_rr_label_clear_underdelegation_under(rr_label);
1272                         }
1273 
1274                         break;
1275                     case TYPE_CNAME:
1276                         clear_mask = ~ZDB_RR_LABEL_HASCNAME; // will clear "has cname"
1277                         break;
1278                     case TYPE_ANY:
1279                         clear_mask = ~(ZDB_RR_LABEL_DELEGATION|ZDB_RR_LABEL_DROPCNAME|ZDB_RR_LABEL_HASCNAME); // will clear "delegation", "drop cname" and "has cname"
1280                         break;
1281                     case TYPE_RRSIG:
1282                     case TYPE_NSEC:
1283                         break;
1284                     default:
1285                         // checks if there are any other types than CNAME, RRSIG and NSEC, clears DROPCNAME if it's true
1286                         clear_mask = ~ZDB_RR_LABEL_DROPCNAME; // will clear "drop cname"
1287                         break;
1288                 }
1289 
1290                 zdb_rr_label_flag_and(rr_label, clear_mask);
1291             }
1292 
1293             return COLLECTION_PROCESS_STOP;
1294         }
1295         else
1296         {
1297             if(zdb_rr_label_has_dnssec_extension(rr_label))
1298             {
1299                 // remove the extension
1300 
1301                 if(zdb_rr_label_nsec3any_linked(rr_label))
1302                 {
1303                     // detach then destroy the ext
1304                     nsec3_zone_label_detach(rr_label);
1305                 }
1306                 else if(zdb_rr_label_nsec_linked(rr_label))
1307                 {
1308                     nsec_zone_label_detach(rr_label);
1309                 }
1310 #if DEBUG
1311                 else
1312                 {
1313                     yassert(rr_label->nsec.dnssec == NULL);
1314                 }
1315 #endif
1316             }
1317         }
1318 
1319         /* NOTE: the 'detach' is made by destroy : do not touch to the "next" field */
1320         /* NOTE: the free of the node is made by destroy : do not do it */
1321 
1322         /* dictionary destroy will take every item in the dictionary and
1323          * iterate through it calling the passed function.
1324          */
1325 
1326         zdb_rr_label_free(args->zone, rr_label); // valid call because in a delete
1327 
1328         args->flags |= 1;
1329 
1330         return COLLECTION_PROCESS_DELETENODE;
1331     }
1332 
1333     return delete_return_code /*COLLECTION_PROCESS_RETURNERROR*/;
1334 }
1335 
1336 /**
1337  * @brief Deletes the resource record of the given type, ttl and rdata on the label matching a path of labels starting from another rr label
1338  *
1339  * Deletes the resource record of the given type, ttl and rdata on the label matching a path of labels starting from another rr label
1340  * Typically the starting label is a zone cut.
1341  *
1342  * @param[in] apex the starting label
1343  * @param[in] path a stack of labels
1344  * @param[in] path_index the index of the top of the stack
1345  *
1346  * @return the matching label or NULL if it has not been found
1347  */
1348 
1349 /* NSEC3: Zone possible */
1350 ya_result
zdb_rr_label_delete_record_exact(zdb_zone * zone,dnslabel_vector_reference path,s32 path_index,u16 type,const zdb_ttlrdata * ttlrdata)1351 zdb_rr_label_delete_record_exact(zdb_zone* zone, dnslabel_vector_reference path, s32 path_index, u16 type, const zdb_ttlrdata *ttlrdata)
1352 {
1353     yassert(zdb_zone_iswritelocked(zone));
1354 
1355     zdb_rr_label* apex = zone->apex;
1356 
1357     if(apex == NULL)
1358     {
1359         return ZDB_ERROR_DELETEFROMEMPTY;
1360     }
1361 
1362     /* Are we working on the apex ? */
1363 
1364     if(path_index < 0)
1365     {
1366         if(ISOK(zdb_record_delete_exact(&apex->resource_record_set, type, ttlrdata))) /* FB done, APEX : no delegation */
1367         {
1368             if(RR_LABEL_IRRELEVANT(apex))
1369             {
1370                 zdb_rr_label_free(zone, apex); // valid call because in a delete
1371                 zone->apex = NULL;
1372 
1373                 return ZDB_RR_LABEL_DELETE_TREE;
1374             }
1375 
1376             return ZDB_RR_LABEL_DELETE_NODE;
1377         }
1378 
1379         return ZDB_ERROR_KEY_NOTFOUND;
1380     }
1381 
1382     /* We are not working on the apex */
1383 
1384     zdb_rr_label_delete_record_exact_process_callback_args args;
1385     args.sections = path;
1386     args.ttlrdata = ttlrdata;
1387     args.zone = zone;
1388     args.top = path_index;
1389     args.type = type;
1390     args.flags = 0;
1391 
1392     hashcode hash = hash_dnslabel(args.sections[args.top]);
1393 
1394     ya_result err;
1395 
1396     err = dictionary_process(&apex->sub, hash, &args, zdb_rr_label_delete_record_exact_process_callback);
1397 
1398     if(ISOK(err)) //  == COLLECTION_PROCESS_DELETENODE
1399     {
1400         if(err == COLLECTION_PROCESS_DELETENODE)
1401         {
1402             if(RR_LABEL_IRRELEVANT(apex))
1403             {
1404                 zdb_rr_label_free(zone, apex); // valid call because in a delete
1405                 zone->apex = NULL;
1406 
1407                 return COLLECTION_PROCESS_DELETENODE;
1408             }
1409 
1410             /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
1411 
1412             if(IS_WILD_LABEL(args.sections[args.top]))
1413             {
1414                 zdb_rr_label_flag_and(apex, ~ZDB_RR_LABEL_GOT_WILD);
1415             }
1416         }
1417 
1418         /* If the label just removed is a wildcard, then the parent is marked as not having a wildcard. */
1419 
1420         if(args.flags & 1)
1421         {
1422             return COLLECTION_PROCESS_DELETENODE; // LEAF
1423         }
1424         else
1425         {
1426             return COLLECTION_PROCESS_STOP;
1427         }
1428     }
1429 
1430     return err;
1431 }
1432 
zdb_rr_label_bitmap_type_init(zdb_rr_label * rr_label,type_bit_maps_context * bitmap)1433 u16 zdb_rr_label_bitmap_type_init(zdb_rr_label *rr_label, type_bit_maps_context *bitmap)
1434 {
1435     const zdb_rr_collection collection = rr_label->resource_record_set;
1436 
1437     type_bit_maps_init(bitmap);
1438 
1439     btree_iterator iter;
1440     btree_iterator_init(collection, &iter);
1441 
1442     if(ZDB_LABEL_ATORUNDERDELEGATION(rr_label))
1443     {
1444         while(btree_iterator_hasnext(&iter))
1445         {
1446             btree_node* node = btree_iterator_next_node(&iter);
1447             u16 type = node->hash;
1448             if((type != TYPE_A) && (type != TYPE_AAAA))
1449             {
1450                 type_bit_maps_set_type(bitmap, type);
1451             }
1452         }
1453     }
1454     else
1455     {
1456         while(btree_iterator_hasnext(&iter))
1457         {
1458             btree_node* node = btree_iterator_next_node(&iter);
1459             u16 type = node->hash;
1460             type_bit_maps_set_type(bitmap, type);
1461         }
1462     }
1463 
1464     u16 bitmap_size = type_bit_maps_update_size(bitmap);
1465 
1466     return bitmap_size;
1467 }
1468 
1469 void
zdb_rr_label_print_indented(const zdb_rr_label * rr_label,output_stream * os,int indent)1470 zdb_rr_label_print_indented(const zdb_rr_label *rr_label, output_stream *os, int indent)
1471 {
1472     osformatln(os, "%tl: '%{dnslabel}'(%u) #[%08x]", indent, rr_label->name, zdb_rr_label_flag_get(rr_label), hash_dnslabel(rr_label->name));
1473 
1474     indent++;
1475 
1476     zdb_record_print_indented(rr_label->resource_record_set, os, indent);
1477 
1478     dictionary_iterator iter;
1479     dictionary_iterator_init(&rr_label->sub, &iter);
1480     while(dictionary_iterator_hasnext(&iter))
1481     {
1482         zdb_rr_label** sub_labelp = (zdb_rr_label**)dictionary_iterator_next(&iter);
1483 
1484         zdb_rr_label_print_indented(*sub_labelp, os, indent);
1485     }
1486 }
1487 
1488 void
zdb_rr_label_print(const zdb_rr_label * rr_label,output_stream * os)1489 zdb_rr_label_print(const zdb_rr_label *rr_label, output_stream *os)
1490 {
1491     zdb_rr_label_print_indented(rr_label, os, 0);
1492 }
1493