2 * special zone file structures and functions for better dnssec handling
5 #include <ldns/config.h>
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()
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;
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);
302 ldns_dnssec_rrsets_print_soa(FILE *out,
303 ldns_dnssec_rrsets *rrsets,
307 ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default,
308 rrsets, follow, show_soa);
313 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
314 ldns_dnssec_rrsets *rrsets,
317 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
321 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
323 ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
328 ldns_dnssec_name_new()
330 ldns_dnssec_name *new_name;
332 new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
337 * not needed anymore because CALLOC initalizes everything to zero.
339 new_name->name = NULL;
340 new_name->rrsets = NULL;
341 new_name->name_alloced = false;
342 new_name->nsec = NULL;
343 new_name->nsec_signatures = NULL;
345 new_name->is_glue = false;
346 new_name->hashed_name = NULL;
353 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
355 ldns_dnssec_name *new_name = ldns_dnssec_name_new();
357 new_name->name = ldns_rr_owner(rr);
358 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
359 ldns_dnssec_name_free(new_name);
367 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
371 if (name->name_alloced) {
372 ldns_rdf_deep_free(name->name);
375 ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
377 if (name->nsec && deep) {
378 ldns_rr_free(name->nsec);
380 if (name->nsec_signatures) {
381 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
383 if (name->hashed_name) {
385 ldns_rdf_deep_free(name->hashed_name);
393 ldns_dnssec_name_free(ldns_dnssec_name *name)
395 ldns_dnssec_name_free_internal(name, 0);
399 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
401 ldns_dnssec_name_free_internal(name, 1);
405 ldns_dnssec_name_name(ldns_dnssec_name *name)
414 ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
417 return name->is_glue;
423 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
426 if (rrset && dname) {
432 ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
441 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
449 ldns_dnssec_name_cmp(const void *a, const void *b)
451 ldns_dnssec_name *na = (ldns_dnssec_name *) a;
452 ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
455 return ldns_dname_compare(ldns_dnssec_name_name(na),
456 ldns_dnssec_name_name(nb));
467 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
470 ldns_status result = LDNS_STATUS_OK;
472 bool hashed_name = false;
473 ldns_rr_type rr_type;
474 ldns_rr_type typecovered = 0;
476 /* special handling for NSEC3 and NSECX covering RRSIGS */
479 return LDNS_STATUS_ERR;
482 rr_type = ldns_rr_get_type(rr);
484 if (rr_type == LDNS_RR_TYPE_RRSIG) {
485 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
489 if (rr_type == LDNS_RR_TYPE_NSEC3 ||
490 typecovered == LDNS_RR_TYPE_NSEC3) {
491 name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
492 ldns_dnssec_name_name(name));
495 name_name = ldns_dnssec_name_name(name);
498 name_name = ldns_dnssec_name_name(name);
499 #endif /* HAVE_SSL */
501 if (rr_type == LDNS_RR_TYPE_NSEC ||
502 rr_type == LDNS_RR_TYPE_NSEC3) {
503 /* XX check if is already set (and error?) */
505 } else if (typecovered == LDNS_RR_TYPE_NSEC ||
506 typecovered == LDNS_RR_TYPE_NSEC3) {
507 if (name->nsec_signatures) {
508 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
510 name->nsec_signatures = ldns_dnssec_rrs_new();
511 name->nsec_signatures->rr = rr;
514 /* it's a 'normal' RR, add it to the right rrset */
516 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
518 name->rrsets = ldns_dnssec_rrsets_new();
519 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
524 ldns_rdf_deep_free(name_name);
531 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
533 ldns_dnssec_rrsets *result;
535 result = name->rrsets;
537 if (result->type == type) {
540 result = result->next;
547 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
553 if (!zone || !dname) {
557 node = ldns_rbtree_search(zone->names, dname);
559 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
567 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
568 ldns_dnssec_name *name,
573 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
574 name->rrsets, true, show_soa);
575 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
576 fprintf(out, ";; Empty nonterminal: ");
577 ldns_rdf_print(out, name->name);
581 ldns_rr_print_fmt(out, fmt, name->nsec);
583 if (name->nsec_signatures) {
584 ldns_dnssec_rrs_print_fmt(out, fmt,
585 name->nsec_signatures);
587 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
588 fprintf(out, "; <void>\n");
593 ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
595 ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default,
600 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
601 ldns_dnssec_name *name)
603 ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
607 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
609 ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
614 ldns_dnssec_zone_new()
616 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
617 if(!zone) return NULL;
625 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
627 ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
632 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
634 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
639 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
643 /* destroy all name structures within the tree */
644 ldns_traverse_postorder(zone->names,
645 ldns_dnssec_name_node_free,
654 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
658 /* destroy all name structures within the tree */
659 ldns_traverse_postorder(zone->names,
660 ldns_dnssec_name_node_deep_free,
668 /* use for dname comparison in tree */
670 ldns_dname_compare_v(const void *a, const void *b) {
671 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
676 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
678 ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
679 ldns_dnssec_name *current_name;
680 ldns_rdf *hashed_name;
682 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
684 while (current_node != LDNS_RBTREE_NULL) {
685 current_name = (ldns_dnssec_name *) current_node->data;
686 if (!current_name->hashed_name) {
687 current_name->hashed_name =
688 ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
690 if (ldns_dname_compare(hashed_name,
691 current_name->hashed_name)
693 ldns_rdf_deep_free(hashed_name);
696 current_node = ldns_rbtree_next(current_node);
698 ldns_rdf_deep_free(hashed_name);
703 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
705 ldns_status result = LDNS_STATUS_OK;
706 ldns_dnssec_name *cur_name;
707 ldns_rbnode_t *cur_node;
708 ldns_rr_type type_covered = 0;
711 return LDNS_STATUS_ERR;
715 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
716 if(!zone->names) return LDNS_STATUS_MEM_ERR;
719 /* we need the original of the hashed name if this is
720 an NSEC3, or an RRSIG that covers an NSEC3 */
721 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
722 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
724 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
725 type_covered == LDNS_RR_TYPE_NSEC3) {
726 cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
729 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
732 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
737 cur_name = ldns_dnssec_name_new_frm_rr(rr);
738 if(!cur_name) return LDNS_STATUS_MEM_ERR;
739 cur_node = LDNS_MALLOC(ldns_rbnode_t);
741 ldns_dnssec_name_free(cur_name);
742 return LDNS_STATUS_MEM_ERR;
744 cur_node->key = ldns_rr_owner(rr);
745 cur_node->data = cur_name;
746 (void)ldns_rbtree_insert(zone->names, cur_node);
748 cur_name = (ldns_dnssec_name *) cur_node->data;
749 result = ldns_dnssec_name_add_rr(cur_name, rr);
752 if (result != LDNS_STATUS_OK) {
753 fprintf(stderr, "error adding rr: ");
754 ldns_rr_print(stderr, rr);
757 /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
758 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
759 zone->soa = cur_name;
764 #endif /* HAVE_SSL */
767 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
772 ldns_dnssec_name *name;
774 node = ldns_rbtree_first(tree);
775 while (node != LDNS_RBTREE_NULL) {
776 name = (ldns_dnssec_name *) node->data;
777 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
778 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
780 node = ldns_rbtree_next(node);
785 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
787 ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
792 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
793 ldns_dnssec_zone *zone)
797 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
798 fprintf(out, ";; Zone: ");
799 ldns_rdf_print(out, ldns_dnssec_name_name(
801 fprintf(out, "\n;\n");
803 ldns_dnssec_rrsets_print_fmt(out, fmt,
804 ldns_dnssec_name_find_rrset(
808 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
813 ldns_dnssec_zone_names_print_fmt(out, fmt,
820 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
822 ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
826 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
828 ldns_dnssec_name *new_name;
831 ldns_rbnode_t *cur_node, *next_node, *new_node;
833 /* for the detection */
834 uint16_t i, cur_label_count, next_label_count;
835 uint16_t soa_label_count = 0;
840 return LDNS_STATUS_ERR;
842 if (zone->soa && zone->soa->name) {
843 soa_label_count = ldns_dname_label_count(zone->soa->name);
846 cur_node = ldns_rbtree_first(zone->names);
847 while (cur_node != LDNS_RBTREE_NULL) {
848 next_node = ldns_rbtree_next(cur_node);
851 while (next_node != LDNS_RBTREE_NULL &&
853 ((ldns_dnssec_name *)next_node->data)->is_glue
855 next_node = ldns_rbtree_next(next_node);
858 if (next_node == LDNS_RBTREE_NULL) {
859 next_node = ldns_rbtree_first(zone->names);
862 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
863 next_name = ((ldns_dnssec_name *)next_node->data)->name;
864 cur_label_count = ldns_dname_label_count(cur_name);
865 next_label_count = ldns_dname_label_count(next_name);
867 /* Since the names are in canonical order, we can
868 * recognize empty non-terminals by their labels;
869 * every label after the first one on the next owner
870 * name is a non-terminal if it either does not exist
871 * in the current name or is different from the same
872 * label in the current name (counting from the end)
874 for (i = 1; i < next_label_count - soa_label_count; i++) {
875 lpos = (int)cur_label_count - (int)next_label_count + (int)i;
877 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
881 l2 = ldns_dname_clone_from(next_name, i);
883 if (!l1 || ldns_dname_compare(l1, l2) != 0) {
884 /* We have an empty nonterminal, add it to the
887 new_name = ldns_dnssec_name_new();
889 return LDNS_STATUS_MEM_ERR;
891 new_name->name = ldns_dname_clone_from(next_name,
893 if (!new_name->name) {
894 ldns_dnssec_name_free(new_name);
895 return LDNS_STATUS_MEM_ERR;
897 new_name->name_alloced = true;
898 new_node = LDNS_MALLOC(ldns_rbnode_t);
900 ldns_dnssec_name_free(new_name);
901 return LDNS_STATUS_MEM_ERR;
903 new_node->key = new_name->name;
904 new_node->data = new_name;
905 (void)ldns_rbtree_insert(zone->names, new_node);
907 ldns_rdf_deep_free(l1);
908 ldns_rdf_deep_free(l2);
911 /* we might have inserted a new node after
912 * the current one so we can't just use next()
914 if (next_node != ldns_rbtree_first(zone->names)) {
915 cur_node = next_node;
917 cur_node = LDNS_RBTREE_NULL;
920 return LDNS_STATUS_OK;