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