2 * special zone file structures and functions for better dnssec handling
5 #include <ldns/config.h>
10 ldns_dnssec_rrs_new(void)
12 ldns_dnssec_rrs *new_rrs;
13 new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
14 if(!new_rrs) return NULL;
21 ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
23 ldns_dnssec_rrs *next;
27 ldns_rr_free(rrs->rr);
35 ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
37 ldns_dnssec_rrs_free_internal(rrs, 0);
41 ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
43 ldns_dnssec_rrs_free_internal(rrs, 1);
47 ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
50 ldns_dnssec_rrs *new_rrs;
52 return LDNS_STATUS_ERR;
55 /* this could be done more efficiently; name and type should already
57 cmp = ldns_rr_compare(rrs->rr, rr);
60 return ldns_dnssec_rrs_add_rr(rrs->next, rr);
62 new_rrs = ldns_dnssec_rrs_new();
67 /* put the current old rr in the new next, put the new
68 rr in the current container */
69 new_rrs = ldns_dnssec_rrs_new();
70 new_rrs->rr = rrs->rr;
71 new_rrs->next = rrs->next;
75 /* Silently ignore equal rr's */
76 return LDNS_STATUS_OK;
80 ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
84 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
85 fprintf(out, "; <void>");
88 ldns_rr_print_fmt(out, fmt, rrs->rr);
91 ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
97 ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs)
99 ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
104 ldns_dnssec_rrsets_new(void)
106 ldns_dnssec_rrsets *new_rrsets;
107 new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
108 if(!new_rrsets) return NULL;
109 new_rrsets->rrs = NULL;
110 new_rrsets->type = 0;
111 new_rrsets->signatures = NULL;
112 new_rrsets->next = NULL;
117 ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
121 ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
124 ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
126 if (rrsets->signatures) {
127 ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
134 ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
136 ldns_dnssec_rrsets_free_internal(rrsets, 0);
140 ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
142 ldns_dnssec_rrsets_free_internal(rrsets, 1);
146 ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
156 ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
161 return LDNS_STATUS_OK;
163 return LDNS_STATUS_ERR;
166 static ldns_dnssec_rrsets *
167 ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
169 ldns_dnssec_rrsets *new_rrsets;
170 ldns_rr_type rr_type;
173 new_rrsets = ldns_dnssec_rrsets_new();
174 rr_type = ldns_rr_get_type(rr);
175 if (rr_type == LDNS_RR_TYPE_RRSIG) {
177 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
182 new_rrsets->rrs = ldns_dnssec_rrs_new();
183 new_rrsets->rrs->rr = rr;
185 new_rrsets->signatures = ldns_dnssec_rrs_new();
186 new_rrsets->signatures->rr = rr;
188 new_rrsets->type = rr_type;
193 ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
195 ldns_dnssec_rrsets *new_rrsets;
196 ldns_rr_type rr_type;
198 ldns_status result = LDNS_STATUS_OK;
200 if (!rrsets || !rr) {
201 return LDNS_STATUS_ERR;
204 rr_type = ldns_rr_get_type(rr);
206 if (rr_type == LDNS_RR_TYPE_RRSIG) {
208 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
211 if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
213 rrsets->rrs = ldns_dnssec_rrs_new();
214 rrsets->rrs->rr = rr;
215 rrsets->type = rr_type;
217 rrsets->signatures = ldns_dnssec_rrs_new();
218 rrsets->signatures->rr = rr;
219 rrsets->type = rr_type;
221 return LDNS_STATUS_OK;
224 if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
226 result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
228 new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
229 rrsets->next = new_rrsets;
231 } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
232 /* move the current one into the new next,
233 replace field of current with data from new rr */
234 new_rrsets = ldns_dnssec_rrsets_new();
235 new_rrsets->rrs = rrsets->rrs;
236 new_rrsets->type = rrsets->type;
237 new_rrsets->signatures = rrsets->signatures;
238 new_rrsets->next = rrsets->next;
240 rrsets->rrs = ldns_dnssec_rrs_new();
241 rrsets->rrs->rr = rr;
242 rrsets->signatures = NULL;
245 rrsets->signatures = ldns_dnssec_rrs_new();
246 rrsets->signatures->rr = rr;
248 rrsets->type = rr_type;
249 rrsets->next = new_rrsets;
251 /* equal, add to current rrsets */
253 if (rrsets->signatures) {
254 result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
256 rrsets->signatures = ldns_dnssec_rrs_new();
257 rrsets->signatures->rr = rr;
261 result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
263 rrsets->rrs = ldns_dnssec_rrs_new();
264 rrsets->rrs->rr = rr;
273 ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
274 ldns_dnssec_rrsets *rrsets,
279 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
280 fprintf(out, "; <void>\n");
284 ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
287 ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
288 if (rrsets->signatures) {
289 ldns_dnssec_rrs_print_fmt(out, fmt,
293 if (follow && rrsets->next) {
294 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
295 rrsets->next, follow, show_soa);
302 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
303 ldns_dnssec_rrsets *rrsets,
306 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
310 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
312 ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
317 ldns_dnssec_name_new(void)
319 ldns_dnssec_name *new_name;
321 new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
326 * not needed anymore because CALLOC initalizes everything to zero.
328 new_name->name = NULL;
329 new_name->rrsets = NULL;
330 new_name->name_alloced = false;
331 new_name->nsec = NULL;
332 new_name->nsec_signatures = NULL;
334 new_name->is_glue = false;
335 new_name->hashed_name = NULL;
342 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
344 ldns_dnssec_name *new_name = ldns_dnssec_name_new();
346 new_name->name = ldns_rr_owner(rr);
347 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
348 ldns_dnssec_name_free(new_name);
356 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
360 if (name->name_alloced) {
361 ldns_rdf_deep_free(name->name);
364 ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
366 if (name->nsec && deep) {
367 ldns_rr_free(name->nsec);
369 if (name->nsec_signatures) {
370 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
372 if (name->hashed_name) {
374 ldns_rdf_deep_free(name->hashed_name);
382 ldns_dnssec_name_free(ldns_dnssec_name *name)
384 ldns_dnssec_name_free_internal(name, 0);
388 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
390 ldns_dnssec_name_free_internal(name, 1);
394 ldns_dnssec_name_name(ldns_dnssec_name *name)
403 ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
406 return name->is_glue;
412 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
415 if (rrset && dname) {
422 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
430 ldns_dnssec_name_cmp(const void *a, const void *b)
432 ldns_dnssec_name *na = (ldns_dnssec_name *) a;
433 ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
436 return ldns_dname_compare(ldns_dnssec_name_name(na),
437 ldns_dnssec_name_name(nb));
448 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
451 ldns_status result = LDNS_STATUS_OK;
452 ldns_rr_type rr_type;
453 ldns_rr_type typecovered = 0;
455 /* special handling for NSEC3 and NSECX covering RRSIGS */
458 return LDNS_STATUS_ERR;
461 rr_type = ldns_rr_get_type(rr);
463 if (rr_type == LDNS_RR_TYPE_RRSIG) {
464 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
467 if (rr_type == LDNS_RR_TYPE_NSEC ||
468 rr_type == LDNS_RR_TYPE_NSEC3) {
469 /* XX check if is already set (and error?) */
471 } else if (typecovered == LDNS_RR_TYPE_NSEC ||
472 typecovered == LDNS_RR_TYPE_NSEC3) {
473 if (name->nsec_signatures) {
474 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
476 name->nsec_signatures = ldns_dnssec_rrs_new();
477 name->nsec_signatures->rr = rr;
480 /* it's a 'normal' RR, add it to the right rrset */
482 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
484 name->rrsets = ldns_dnssec_rrsets_new();
485 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
492 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
494 ldns_dnssec_rrsets *result;
496 result = name->rrsets;
498 if (result->type == type) {
501 result = result->next;
508 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
514 if (!zone || !dname) {
518 node = ldns_rbtree_search(zone->names, dname);
520 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
528 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
529 ldns_dnssec_name *name,
534 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
535 name->rrsets, true, show_soa);
536 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
537 fprintf(out, ";; Empty nonterminal: ");
538 ldns_rdf_print(out, name->name);
542 ldns_rr_print_fmt(out, fmt, name->nsec);
544 if (name->nsec_signatures) {
545 ldns_dnssec_rrs_print_fmt(out, fmt,
546 name->nsec_signatures);
548 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
549 fprintf(out, "; <void>\n");
555 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
556 ldns_dnssec_name *name)
558 ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
562 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
564 ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
569 ldns_dnssec_zone_new(void)
571 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
572 if(!zone) return NULL;
575 zone->hashed_names = NULL;
576 zone->_nsec3params = NULL;
582 rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
584 return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
585 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
588 /* When the zone is first read into an list and then inserted into an
589 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
590 * to each other. Because ldns-verify-zone (the only program that uses this
591 * function) uses the rbtree mostly for sequentual walking, this results
592 * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
594 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
597 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
598 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
603 ldns_rdf *my_origin = NULL;
604 ldns_rdf *my_prev = NULL;
606 ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
607 /* when reading NSEC3s, there is a chance that we encounter nsecs
608 for empty nonterminals, whose nonterminals we cannot derive yet
609 because the needed information is to be read later. in that case
610 we keep a list of those nsec3's and retry to add them later */
611 ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
612 ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
614 ldns_status status = LDNS_STATUS_MEM_ERR;
616 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
617 ldns_zone* zone = NULL;
618 if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
619 != LDNS_STATUS_OK) goto error;
621 uint32_t my_ttl = ttl;
624 if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
627 if (!(my_origin = ldns_rdf_clone(origin))) goto error;
628 if (!(my_prev = ldns_rdf_clone(origin))) goto error;
631 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
632 if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
633 != LDNS_STATUS_OK) goto error;
635 for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
636 cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
637 status = LDNS_STATUS_OK;
640 status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
647 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
649 LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
651 if (rr_is_rrsig_covering(cur_rr,
652 LDNS_RR_TYPE_NSEC3)){
653 ldns_rr_list_push_rr(todo_nsec3_rrsigs,
656 ldns_rr_list_push_rr(todo_nsec3s,
659 status = LDNS_STATUS_OK;
661 } else if (status != LDNS_STATUS_OK)
667 case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */
668 case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/
669 case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/
670 status = LDNS_STATUS_OK;
673 case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
674 status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
682 if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
683 (void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
684 for (i = 0; status == LDNS_STATUS_OK &&
685 i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
686 cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
687 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
690 if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
691 for (i = 0; status == LDNS_STATUS_OK &&
692 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
694 cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
695 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
703 ldns_dnssec_zone_free(newzone);
707 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
709 ldns_zone_free(zone);
712 ldns_rr_list_free(todo_nsec3_rrsigs);
713 ldns_rr_list_free(todo_nsec3s);
716 ldns_rdf_deep_free(my_origin);
719 ldns_rdf_deep_free(my_prev);
722 ldns_dnssec_zone_free(newzone);
728 ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
729 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
731 return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
735 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
737 ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
742 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
744 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
749 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
753 /* destroy all name structures within the tree */
754 ldns_traverse_postorder(zone->names,
755 ldns_dnssec_name_node_free,
757 LDNS_FREE(zone->names);
764 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
768 /* destroy all name structures within the tree */
769 ldns_traverse_postorder(zone->names,
770 ldns_dnssec_name_node_deep_free,
772 LDNS_FREE(zone->names);
778 /* use for dname comparison in tree */
780 ldns_dname_compare_v(const void *a, const void *b) {
781 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
785 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
786 ldns_dnssec_name* name, ldns_rr* nsec3rr);
789 ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
795 ldns_dnssec_zone_hashed_names_from_nsec3(
796 ldns_dnssec_zone* zone, ldns_rr* nsec3rr)
798 ldns_rbnode_t* current_node;
799 ldns_dnssec_name* current_name;
801 assert(zone != NULL);
802 assert(nsec3rr != NULL);
804 if (zone->hashed_names) {
805 ldns_traverse_postorder(zone->hashed_names,
806 ldns_hashed_names_node_free, NULL);
807 LDNS_FREE(zone->hashed_names);
809 zone->_nsec3params = nsec3rr;
811 /* So this is a NSEC3 zone.
812 * Calculate hashes for all names already in the zone
814 zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
815 if (zone->hashed_names == NULL) {
818 for ( current_node = ldns_rbtree_first(zone->names)
819 ; current_node != LDNS_RBTREE_NULL
820 ; current_node = ldns_rbtree_next(current_node)
822 current_name = (ldns_dnssec_name *) current_node->data;
823 ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr);
829 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
830 ldns_dnssec_name* name, ldns_rr* nsec3rr)
832 ldns_rbnode_t* new_node;
834 assert(name != NULL);
835 if (! zone->_nsec3params) {
839 ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr);
841 } else if (! nsec3rr) {
842 nsec3rr = zone->_nsec3params;
844 name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name);
846 /* Also store in zone->hashed_names */
847 if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) {
849 new_node->key = name->hashed_name;
850 new_node->data = name;
852 if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) {
860 static ldns_rbnode_t *
861 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) {
862 ldns_rdf *hashed_name;
864 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
865 if (hashed_name == NULL) {
868 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){
870 ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr);
872 if (zone->hashed_names == NULL) {
873 ldns_rdf_deep_free(hashed_name);
876 return ldns_rbtree_search(zone->hashed_names, hashed_name);
880 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
882 ldns_status result = LDNS_STATUS_OK;
883 ldns_dnssec_name *cur_name;
884 ldns_rbnode_t *cur_node;
885 ldns_rr_type type_covered = 0;
888 return LDNS_STATUS_ERR;
892 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
893 if(!zone->names) return LDNS_STATUS_MEM_ERR;
896 /* we need the original of the hashed name if this is
897 an NSEC3, or an RRSIG that covers an NSEC3 */
898 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
899 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
901 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
902 type_covered == LDNS_RR_TYPE_NSEC3) {
903 cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr);
905 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
908 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
912 cur_name = ldns_dnssec_name_new_frm_rr(rr);
913 if(!cur_name) return LDNS_STATUS_MEM_ERR;
914 cur_node = LDNS_MALLOC(ldns_rbnode_t);
916 ldns_dnssec_name_free(cur_name);
917 return LDNS_STATUS_MEM_ERR;
919 cur_node->key = ldns_rr_owner(rr);
920 cur_node->data = cur_name;
921 (void)ldns_rbtree_insert(zone->names, cur_node);
922 ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL);
924 cur_name = (ldns_dnssec_name *) cur_node->data;
925 result = ldns_dnssec_name_add_rr(cur_name, rr);
927 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
928 zone->soa = cur_name;
934 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
939 ldns_dnssec_name *name;
941 node = ldns_rbtree_first(tree);
942 while (node != LDNS_RBTREE_NULL) {
943 name = (ldns_dnssec_name *) node->data;
944 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
945 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
947 node = ldns_rbtree_next(node);
952 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
954 ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
959 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
960 ldns_dnssec_zone *zone)
964 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
965 fprintf(out, ";; Zone: ");
966 ldns_rdf_print(out, ldns_dnssec_name_name(
968 fprintf(out, "\n;\n");
970 ldns_dnssec_rrsets_print_fmt(out, fmt,
971 ldns_dnssec_name_find_rrset(
975 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
980 ldns_dnssec_zone_names_print_fmt(out, fmt,
987 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
989 ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
993 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
995 ldns_dnssec_name *new_name;
998 ldns_rbnode_t *cur_node, *next_node, *new_node;
1000 /* for the detection */
1001 uint16_t i, cur_label_count, next_label_count;
1002 uint16_t soa_label_count = 0;
1007 return LDNS_STATUS_ERR;
1009 if (zone->soa && zone->soa->name) {
1010 soa_label_count = ldns_dname_label_count(zone->soa->name);
1013 cur_node = ldns_rbtree_first(zone->names);
1014 while (cur_node != LDNS_RBTREE_NULL) {
1015 next_node = ldns_rbtree_next(cur_node);
1018 while (next_node != LDNS_RBTREE_NULL &&
1020 ((ldns_dnssec_name *)next_node->data)->is_glue
1022 next_node = ldns_rbtree_next(next_node);
1025 if (next_node == LDNS_RBTREE_NULL) {
1026 next_node = ldns_rbtree_first(zone->names);
1028 if (! cur_node->data || ! next_node->data) {
1029 return LDNS_STATUS_ERR;
1031 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1032 next_name = ((ldns_dnssec_name *)next_node->data)->name;
1033 cur_label_count = ldns_dname_label_count(cur_name);
1034 next_label_count = ldns_dname_label_count(next_name);
1036 /* Since the names are in canonical order, we can
1037 * recognize empty non-terminals by their labels;
1038 * every label after the first one on the next owner
1039 * name is a non-terminal if it either does not exist
1040 * in the current name or is different from the same
1041 * label in the current name (counting from the end)
1043 for (i = 1; i < next_label_count - soa_label_count; i++) {
1044 lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1046 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1050 l2 = ldns_dname_clone_from(next_name, i);
1052 if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1053 /* We have an empty nonterminal, add it to the
1056 new_name = ldns_dnssec_name_new();
1058 return LDNS_STATUS_MEM_ERR;
1060 new_name->name = ldns_dname_clone_from(next_name,
1062 if (!new_name->name) {
1063 ldns_dnssec_name_free(new_name);
1064 return LDNS_STATUS_MEM_ERR;
1066 new_name->name_alloced = true;
1067 new_node = LDNS_MALLOC(ldns_rbnode_t);
1069 ldns_dnssec_name_free(new_name);
1070 return LDNS_STATUS_MEM_ERR;
1072 new_node->key = new_name->name;
1073 new_node->data = new_name;
1074 (void)ldns_rbtree_insert(zone->names, new_node);
1075 ldns_dnssec_name_make_hashed_name(
1076 zone, new_name, NULL);
1078 ldns_rdf_deep_free(l1);
1079 ldns_rdf_deep_free(l2);
1082 /* we might have inserted a new node after
1083 * the current one so we can't just use next()
1085 if (next_node != ldns_rbtree_first(zone->names)) {
1086 cur_node = next_node;
1088 cur_node = LDNS_RBTREE_NULL;
1091 return LDNS_STATUS_OK;
1095 ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1098 ldns_rbnode_t* node;
1100 if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1101 node = ldns_rbtree_first(zone->names);
1102 while (node != LDNS_RBTREE_NULL) {
1103 nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1104 if (nsec3 &&ldns_rr_get_type(nsec3)
1105 == LDNS_RR_TYPE_NSEC3 &&
1106 ldns_nsec3_optout(nsec3)) {
1109 node = ldns_rbtree_next(node);