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,
59 /* should we error on equal? */
62 return ldns_dnssec_rrs_add_rr(rrs->next, rr);
64 new_rrs = ldns_dnssec_rrs_new();
69 /* put the current old rr in the new next, put the new
70 rr in the current container */
71 new_rrs = ldns_dnssec_rrs_new();
72 new_rrs->rr = rrs->rr;
73 new_rrs->next = rrs->next;
77 return LDNS_STATUS_OK;
81 ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
85 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
86 fprintf(out, "; <void>");
89 ldns_rr_print_fmt(out, fmt, rrs->rr);
92 ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
98 ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs)
100 ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
105 ldns_dnssec_rrsets_new(void)
107 ldns_dnssec_rrsets *new_rrsets;
108 new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
109 if(!new_rrsets) return NULL;
110 new_rrsets->rrs = NULL;
111 new_rrsets->type = 0;
112 new_rrsets->signatures = NULL;
113 new_rrsets->next = NULL;
118 ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
122 ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
125 ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
127 if (rrsets->signatures) {
128 ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
135 ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
137 ldns_dnssec_rrsets_free_internal(rrsets, 0);
141 ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
143 ldns_dnssec_rrsets_free_internal(rrsets, 1);
147 ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
157 ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
162 return LDNS_STATUS_OK;
164 return LDNS_STATUS_ERR;
167 static ldns_dnssec_rrsets *
168 ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
170 ldns_dnssec_rrsets *new_rrsets;
171 ldns_rr_type rr_type;
174 new_rrsets = ldns_dnssec_rrsets_new();
175 rr_type = ldns_rr_get_type(rr);
176 if (rr_type == LDNS_RR_TYPE_RRSIG) {
178 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
183 new_rrsets->rrs = ldns_dnssec_rrs_new();
184 new_rrsets->rrs->rr = rr;
186 new_rrsets->signatures = ldns_dnssec_rrs_new();
187 new_rrsets->signatures->rr = rr;
189 new_rrsets->type = rr_type;
194 ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
196 ldns_dnssec_rrsets *new_rrsets;
197 ldns_rr_type rr_type;
199 ldns_status result = LDNS_STATUS_OK;
201 if (!rrsets || !rr) {
202 return LDNS_STATUS_ERR;
205 rr_type = ldns_rr_get_type(rr);
207 if (rr_type == LDNS_RR_TYPE_RRSIG) {
209 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
212 if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
214 rrsets->rrs = ldns_dnssec_rrs_new();
215 rrsets->rrs->rr = rr;
216 rrsets->type = rr_type;
218 rrsets->signatures = ldns_dnssec_rrs_new();
219 rrsets->signatures->rr = rr;
220 rrsets->type = rr_type;
222 return LDNS_STATUS_OK;
225 if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
227 result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
229 new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
230 rrsets->next = new_rrsets;
232 } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
233 /* move the current one into the new next,
234 replace field of current with data from new rr */
235 new_rrsets = ldns_dnssec_rrsets_new();
236 new_rrsets->rrs = rrsets->rrs;
237 new_rrsets->type = rrsets->type;
238 new_rrsets->signatures = rrsets->signatures;
239 new_rrsets->next = rrsets->next;
241 rrsets->rrs = ldns_dnssec_rrs_new();
242 rrsets->rrs->rr = rr;
243 rrsets->signatures = NULL;
246 rrsets->signatures = ldns_dnssec_rrs_new();
247 rrsets->signatures->rr = rr;
249 rrsets->type = rr_type;
250 rrsets->next = new_rrsets;
252 /* equal, add to current rrsets */
254 if (rrsets->signatures) {
255 result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
257 rrsets->signatures = ldns_dnssec_rrs_new();
258 rrsets->signatures->rr = rr;
262 result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
264 rrsets->rrs = ldns_dnssec_rrs_new();
265 rrsets->rrs->rr = rr;
274 ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
275 ldns_dnssec_rrsets *rrsets,
280 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
281 fprintf(out, "; <void>\n");
285 ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
288 ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
289 if (rrsets->signatures) {
290 ldns_dnssec_rrs_print_fmt(out, fmt,
294 if (follow && rrsets->next) {
295 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
296 rrsets->next, follow, show_soa);
303 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
304 ldns_dnssec_rrsets *rrsets,
307 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
311 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
313 ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
318 ldns_dnssec_name_new(void)
320 ldns_dnssec_name *new_name;
322 new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
327 * not needed anymore because CALLOC initalizes everything to zero.
329 new_name->name = NULL;
330 new_name->rrsets = NULL;
331 new_name->name_alloced = false;
332 new_name->nsec = NULL;
333 new_name->nsec_signatures = NULL;
335 new_name->is_glue = false;
336 new_name->hashed_name = NULL;
343 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
345 ldns_dnssec_name *new_name = ldns_dnssec_name_new();
347 new_name->name = ldns_rr_owner(rr);
348 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
349 ldns_dnssec_name_free(new_name);
357 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
361 if (name->name_alloced) {
362 ldns_rdf_deep_free(name->name);
365 ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
367 if (name->nsec && deep) {
368 ldns_rr_free(name->nsec);
370 if (name->nsec_signatures) {
371 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
373 if (name->hashed_name) {
375 ldns_rdf_deep_free(name->hashed_name);
383 ldns_dnssec_name_free(ldns_dnssec_name *name)
385 ldns_dnssec_name_free_internal(name, 0);
389 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
391 ldns_dnssec_name_free_internal(name, 1);
395 ldns_dnssec_name_name(ldns_dnssec_name *name)
404 ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
407 return name->is_glue;
413 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
416 if (rrset && dname) {
423 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
431 ldns_dnssec_name_cmp(const void *a, const void *b)
433 ldns_dnssec_name *na = (ldns_dnssec_name *) a;
434 ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
437 return ldns_dname_compare(ldns_dnssec_name_name(na),
438 ldns_dnssec_name_name(nb));
449 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
452 ldns_status result = LDNS_STATUS_OK;
454 bool hashed_name = false;
455 ldns_rr_type rr_type;
456 ldns_rr_type typecovered = 0;
458 /* special handling for NSEC3 and NSECX covering RRSIGS */
461 return LDNS_STATUS_ERR;
464 rr_type = ldns_rr_get_type(rr);
466 if (rr_type == LDNS_RR_TYPE_RRSIG) {
467 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
471 if (rr_type == LDNS_RR_TYPE_NSEC3 ||
472 typecovered == LDNS_RR_TYPE_NSEC3) {
473 name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
474 ldns_dnssec_name_name(name));
477 name_name = ldns_dnssec_name_name(name);
480 name_name = ldns_dnssec_name_name(name);
481 #endif /* HAVE_SSL */
483 if (rr_type == LDNS_RR_TYPE_NSEC ||
484 rr_type == LDNS_RR_TYPE_NSEC3) {
485 /* XX check if is already set (and error?) */
487 } else if (typecovered == LDNS_RR_TYPE_NSEC ||
488 typecovered == LDNS_RR_TYPE_NSEC3) {
489 if (name->nsec_signatures) {
490 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
492 name->nsec_signatures = ldns_dnssec_rrs_new();
493 name->nsec_signatures->rr = rr;
496 /* it's a 'normal' RR, add it to the right rrset */
498 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
500 name->rrsets = ldns_dnssec_rrsets_new();
501 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
506 ldns_rdf_deep_free(name_name);
513 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
515 ldns_dnssec_rrsets *result;
517 result = name->rrsets;
519 if (result->type == type) {
522 result = result->next;
529 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
535 if (!zone || !dname) {
539 node = ldns_rbtree_search(zone->names, dname);
541 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
549 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
550 ldns_dnssec_name *name,
555 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
556 name->rrsets, true, show_soa);
557 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
558 fprintf(out, ";; Empty nonterminal: ");
559 ldns_rdf_print(out, name->name);
563 ldns_rr_print_fmt(out, fmt, name->nsec);
565 if (name->nsec_signatures) {
566 ldns_dnssec_rrs_print_fmt(out, fmt,
567 name->nsec_signatures);
569 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
570 fprintf(out, "; <void>\n");
576 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
577 ldns_dnssec_name *name)
579 ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
583 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
585 ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
590 ldns_dnssec_zone_new(void)
592 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
593 if(!zone) return NULL;
601 rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
603 return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
604 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
607 /* When the zone is first read into an list and then inserted into an
608 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
609 * to each other. Because ldns-verify-zone (the only program that uses this
610 * function) uses the rbtree mostly for sequentual walking, this results
611 * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
613 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
616 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
617 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
622 ldns_rdf *my_origin = NULL;
623 ldns_rdf *my_prev = NULL;
625 ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
626 /* when reading NSEC3s, there is a chance that we encounter nsecs
627 for empty nonterminals, whose nonterminals we cannot derive yet
628 because the needed information is to be read later. in that case
629 we keep a list of those nsec3's and retry to add them later */
630 ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
631 ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
633 ldns_status status = LDNS_STATUS_MEM_ERR;
635 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
636 ldns_zone* zone = NULL;
637 if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
638 != LDNS_STATUS_OK) goto error;
640 uint32_t my_ttl = ttl;
643 if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
646 if (!(my_origin = ldns_rdf_clone(origin))) goto error;
647 if (!(my_prev = ldns_rdf_clone(origin))) goto error;
650 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
651 if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
652 != LDNS_STATUS_OK) goto error;
654 for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
655 cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
656 status = LDNS_STATUS_OK;
659 status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
666 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
668 LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
670 if (rr_is_rrsig_covering(cur_rr,
671 LDNS_RR_TYPE_NSEC3)){
672 ldns_rr_list_push_rr(todo_nsec3_rrsigs,
675 ldns_rr_list_push_rr(todo_nsec3s,
678 } else if (status != LDNS_STATUS_OK)
684 case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */
685 case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/
686 case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/
687 status = LDNS_STATUS_OK;
690 case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
691 status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
699 if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
700 (void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
701 for (i = 0; status == LDNS_STATUS_OK &&
702 i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
703 cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
704 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
706 for (i = 0; status == LDNS_STATUS_OK &&
707 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
709 cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
710 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
712 } else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
713 for (i = 0; status == LDNS_STATUS_OK &&
714 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
716 cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
717 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
725 ldns_dnssec_zone_free(newzone);
729 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
731 ldns_zone_free(zone);
734 ldns_rr_list_free(todo_nsec3_rrsigs);
735 ldns_rr_list_free(todo_nsec3s);
738 ldns_rdf_deep_free(my_origin);
741 ldns_rdf_deep_free(my_prev);
744 ldns_dnssec_zone_free(newzone);
750 ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
751 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
753 return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
757 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
759 ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
764 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
766 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
771 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
775 /* destroy all name structures within the tree */
776 ldns_traverse_postorder(zone->names,
777 ldns_dnssec_name_node_free,
779 LDNS_FREE(zone->names);
786 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
790 /* destroy all name structures within the tree */
791 ldns_traverse_postorder(zone->names,
792 ldns_dnssec_name_node_deep_free,
794 LDNS_FREE(zone->names);
800 /* use for dname comparison in tree */
802 ldns_dname_compare_v(const void *a, const void *b) {
803 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
806 static ldns_rbnode_t *
807 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
809 ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
810 ldns_dnssec_name *current_name;
811 ldns_rdf *hashed_name;
813 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
815 while (current_node != LDNS_RBTREE_NULL) {
816 current_name = (ldns_dnssec_name *) current_node->data;
817 if (!current_name->hashed_name) {
818 current_name->hashed_name =
819 ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
821 if (ldns_dname_compare(hashed_name,
822 current_name->hashed_name)
824 ldns_rdf_deep_free(hashed_name);
827 current_node = ldns_rbtree_next(current_node);
829 ldns_rdf_deep_free(hashed_name);
834 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
836 ldns_status result = LDNS_STATUS_OK;
837 ldns_dnssec_name *cur_name;
838 ldns_rbnode_t *cur_node;
839 ldns_rr_type type_covered = 0;
842 return LDNS_STATUS_ERR;
846 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
847 if(!zone->names) return LDNS_STATUS_MEM_ERR;
850 /* we need the original of the hashed name if this is
851 an NSEC3, or an RRSIG that covers an NSEC3 */
852 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
853 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
855 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
856 type_covered == LDNS_RR_TYPE_NSEC3) {
857 cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
860 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
863 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
868 cur_name = ldns_dnssec_name_new_frm_rr(rr);
869 if(!cur_name) return LDNS_STATUS_MEM_ERR;
870 cur_node = LDNS_MALLOC(ldns_rbnode_t);
872 ldns_dnssec_name_free(cur_name);
873 return LDNS_STATUS_MEM_ERR;
875 cur_node->key = ldns_rr_owner(rr);
876 cur_node->data = cur_name;
877 (void)ldns_rbtree_insert(zone->names, cur_node);
879 cur_name = (ldns_dnssec_name *) cur_node->data;
880 result = ldns_dnssec_name_add_rr(cur_name, rr);
883 if (result != LDNS_STATUS_OK) {
884 fprintf(stderr, "error adding rr: ");
885 ldns_rr_print(stderr, rr);
888 /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
889 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
890 zone->soa = cur_name;
897 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
902 ldns_dnssec_name *name;
904 node = ldns_rbtree_first(tree);
905 while (node != LDNS_RBTREE_NULL) {
906 name = (ldns_dnssec_name *) node->data;
907 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
908 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
910 node = ldns_rbtree_next(node);
915 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
917 ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
922 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
923 ldns_dnssec_zone *zone)
927 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
928 fprintf(out, ";; Zone: ");
929 ldns_rdf_print(out, ldns_dnssec_name_name(
931 fprintf(out, "\n;\n");
933 ldns_dnssec_rrsets_print_fmt(out, fmt,
934 ldns_dnssec_name_find_rrset(
938 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
943 ldns_dnssec_zone_names_print_fmt(out, fmt,
950 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
952 ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
956 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
958 ldns_dnssec_name *new_name;
961 ldns_rbnode_t *cur_node, *next_node, *new_node;
963 /* for the detection */
964 uint16_t i, cur_label_count, next_label_count;
965 uint16_t soa_label_count = 0;
970 return LDNS_STATUS_ERR;
972 if (zone->soa && zone->soa->name) {
973 soa_label_count = ldns_dname_label_count(zone->soa->name);
976 cur_node = ldns_rbtree_first(zone->names);
977 while (cur_node != LDNS_RBTREE_NULL) {
978 next_node = ldns_rbtree_next(cur_node);
981 while (next_node != LDNS_RBTREE_NULL &&
983 ((ldns_dnssec_name *)next_node->data)->is_glue
985 next_node = ldns_rbtree_next(next_node);
988 if (next_node == LDNS_RBTREE_NULL) {
989 next_node = ldns_rbtree_first(zone->names);
991 if (! cur_node->data || ! next_node->data) {
992 return LDNS_STATUS_ERR;
994 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
995 next_name = ((ldns_dnssec_name *)next_node->data)->name;
996 cur_label_count = ldns_dname_label_count(cur_name);
997 next_label_count = ldns_dname_label_count(next_name);
999 /* Since the names are in canonical order, we can
1000 * recognize empty non-terminals by their labels;
1001 * every label after the first one on the next owner
1002 * name is a non-terminal if it either does not exist
1003 * in the current name or is different from the same
1004 * label in the current name (counting from the end)
1006 for (i = 1; i < next_label_count - soa_label_count; i++) {
1007 lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1009 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1013 l2 = ldns_dname_clone_from(next_name, i);
1015 if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1016 /* We have an empty nonterminal, add it to the
1019 new_name = ldns_dnssec_name_new();
1021 return LDNS_STATUS_MEM_ERR;
1023 new_name->name = ldns_dname_clone_from(next_name,
1025 if (!new_name->name) {
1026 ldns_dnssec_name_free(new_name);
1027 return LDNS_STATUS_MEM_ERR;
1029 new_name->name_alloced = true;
1030 new_node = LDNS_MALLOC(ldns_rbnode_t);
1032 ldns_dnssec_name_free(new_name);
1033 return LDNS_STATUS_MEM_ERR;
1035 new_node->key = new_name->name;
1036 new_node->data = new_name;
1037 (void)ldns_rbtree_insert(zone->names, new_node);
1039 ldns_rdf_deep_free(l1);
1040 ldns_rdf_deep_free(l2);
1043 /* we might have inserted a new node after
1044 * the current one so we can't just use next()
1046 if (next_node != ldns_rbtree_first(zone->names)) {
1047 cur_node = next_node;
1049 cur_node = LDNS_RBTREE_NULL;
1052 return LDNS_STATUS_OK;
1056 ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1059 ldns_rbnode_t* node;
1061 if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1062 node = ldns_rbtree_first(zone->names);
1063 while (node != LDNS_RBTREE_NULL) {
1064 nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1065 if (nsec3 &&ldns_rr_get_type(nsec3)
1066 == LDNS_RR_TYPE_NSEC3 &&
1067 ldns_nsec3_optout(nsec3)) {
1070 node = ldns_rbtree_next(node);