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(FILE *out, ldns_dnssec_rrs *rrs)
84 fprintf(out, "<void>");
87 ldns_rr_print(out, rrs->rr);
90 ldns_dnssec_rrs_print(out, rrs->next);
96 ldns_dnssec_rrsets_new()
98 ldns_dnssec_rrsets *new_rrsets;
99 new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
100 if(!new_rrsets) return NULL;
101 new_rrsets->rrs = NULL;
102 new_rrsets->type = 0;
103 new_rrsets->signatures = NULL;
104 new_rrsets->next = NULL;
109 ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
113 ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
116 ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
118 if (rrsets->signatures) {
119 ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
126 ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
128 ldns_dnssec_rrsets_free_internal(rrsets, 0);
132 ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
134 ldns_dnssec_rrsets_free_internal(rrsets, 1);
138 ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
148 ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
153 return LDNS_STATUS_OK;
155 return LDNS_STATUS_ERR;
159 ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
161 ldns_dnssec_rrsets *new_rrsets;
162 ldns_rr_type rr_type;
165 new_rrsets = ldns_dnssec_rrsets_new();
166 rr_type = ldns_rr_get_type(rr);
167 if (rr_type == LDNS_RR_TYPE_RRSIG) {
169 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
174 new_rrsets->rrs = ldns_dnssec_rrs_new();
175 new_rrsets->rrs->rr = rr;
177 new_rrsets->signatures = ldns_dnssec_rrs_new();
178 new_rrsets->signatures->rr = rr;
180 new_rrsets->type = rr_type;
185 ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
187 ldns_dnssec_rrsets *new_rrsets;
188 ldns_rr_type rr_type;
190 ldns_status result = LDNS_STATUS_OK;
192 if (!rrsets || !rr) {
193 return LDNS_STATUS_ERR;
196 rr_type = ldns_rr_get_type(rr);
198 if (rr_type == LDNS_RR_TYPE_RRSIG) {
200 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
203 if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
205 rrsets->rrs = ldns_dnssec_rrs_new();
206 rrsets->rrs->rr = rr;
207 rrsets->type = rr_type;
209 rrsets->signatures = ldns_dnssec_rrs_new();
210 rrsets->signatures->rr = rr;
211 rrsets->type = rr_type;
213 return LDNS_STATUS_OK;
216 if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
218 result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
220 new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
221 rrsets->next = new_rrsets;
223 } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
224 /* move the current one into the new next,
225 replace field of current with data from new rr */
226 new_rrsets = ldns_dnssec_rrsets_new();
227 new_rrsets->rrs = rrsets->rrs;
228 new_rrsets->type = rrsets->type;
229 new_rrsets->signatures = rrsets->signatures;
230 new_rrsets->next = rrsets->next;
232 rrsets->rrs = ldns_dnssec_rrs_new();
233 rrsets->rrs->rr = rr;
234 rrsets->signatures = NULL;
237 rrsets->signatures = ldns_dnssec_rrs_new();
238 rrsets->signatures->rr = rr;
240 rrsets->type = rr_type;
241 rrsets->next = new_rrsets;
243 /* equal, add to current rrsets */
245 if (rrsets->signatures) {
246 result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
248 rrsets->signatures = ldns_dnssec_rrs_new();
249 rrsets->signatures->rr = rr;
253 result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
255 rrsets->rrs = ldns_dnssec_rrs_new();
256 rrsets->rrs->rr = rr;
265 ldns_dnssec_rrsets_print_soa(FILE *out,
266 ldns_dnssec_rrsets *rrsets,
271 fprintf(out, "<void>\n");
275 ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
278 ldns_dnssec_rrs_print(out, rrsets->rrs);
279 if (rrsets->signatures) {
280 ldns_dnssec_rrs_print(out, rrsets->signatures);
283 if (follow && rrsets->next) {
284 ldns_dnssec_rrsets_print_soa(out, rrsets->next, follow, show_soa);
290 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
292 ldns_dnssec_rrsets_print_soa(out, rrsets, follow, true);
296 ldns_dnssec_name_new()
298 ldns_dnssec_name *new_name;
300 new_name = LDNS_MALLOC(ldns_dnssec_name);
305 new_name->name = NULL;
306 new_name->rrsets = NULL;
307 new_name->name_alloced = false;
308 new_name->nsec = NULL;
309 new_name->nsec_signatures = NULL;
311 new_name->is_glue = false;
312 new_name->hashed_name = NULL;
318 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
320 ldns_dnssec_name *new_name = ldns_dnssec_name_new();
322 new_name->name = ldns_rr_owner(rr);
323 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
324 ldns_dnssec_name_free(new_name);
332 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
336 if (name->name_alloced) {
337 ldns_rdf_deep_free(name->name);
340 ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
342 if (name->nsec && deep) {
343 ldns_rr_free(name->nsec);
345 if (name->nsec_signatures) {
346 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
348 if (name->hashed_name) {
350 ldns_rdf_deep_free(name->hashed_name);
358 ldns_dnssec_name_free(ldns_dnssec_name *name)
360 ldns_dnssec_name_free_internal(name, 0);
364 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
366 ldns_dnssec_name_free_internal(name, 1);
370 ldns_dnssec_name_name(ldns_dnssec_name *name)
379 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
382 if (rrset && dname) {
388 ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
397 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
405 ldns_dnssec_name_cmp(const void *a, const void *b)
407 ldns_dnssec_name *na = (ldns_dnssec_name *) a;
408 ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
411 return ldns_dname_compare(ldns_dnssec_name_name(na),
412 ldns_dnssec_name_name(nb));
423 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
426 ldns_status result = LDNS_STATUS_OK;
428 bool hashed_name = false;
429 ldns_rr_type rr_type;
430 ldns_rr_type typecovered = 0;
432 /* special handling for NSEC3 and NSECX covering RRSIGS */
435 return LDNS_STATUS_ERR;
438 rr_type = ldns_rr_get_type(rr);
440 if (rr_type == LDNS_RR_TYPE_RRSIG) {
441 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
445 if (rr_type == LDNS_RR_TYPE_NSEC3 ||
446 typecovered == LDNS_RR_TYPE_NSEC3) {
447 name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
448 ldns_dnssec_name_name(name));
451 name_name = ldns_dnssec_name_name(name);
454 name_name = ldns_dnssec_name_name(name);
455 #endif /* HAVE_SSL */
457 if (rr_type == LDNS_RR_TYPE_NSEC ||
458 rr_type == LDNS_RR_TYPE_NSEC3) {
459 /* XX check if is already set (and error?) */
461 } else if (typecovered == LDNS_RR_TYPE_NSEC ||
462 typecovered == LDNS_RR_TYPE_NSEC3) {
463 if (name->nsec_signatures) {
464 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
466 name->nsec_signatures = ldns_dnssec_rrs_new();
467 name->nsec_signatures->rr = rr;
470 /* it's a 'normal' RR, add it to the right rrset */
472 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
474 name->rrsets = ldns_dnssec_rrsets_new();
475 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
480 ldns_rdf_deep_free(name_name);
487 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
489 ldns_dnssec_rrsets *result;
491 result = name->rrsets;
493 if (result->type == type) {
496 result = result->next;
503 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
509 if (!zone || !dname) {
513 node = ldns_rbtree_search(zone->names, dname);
515 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
523 ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
527 ldns_dnssec_rrsets_print_soa(out, name->rrsets, true, show_soa);
529 fprintf(out, ";; Empty nonterminal: ");
530 ldns_rdf_print(out, name->name);
534 ldns_rr_print(out, name->nsec);
536 if (name->nsec_signatures) {
537 ldns_dnssec_rrs_print(out, name->nsec_signatures);
540 fprintf(out, "<void>\n");
545 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
547 ldns_dnssec_name_print_soa(out, name, true);
551 ldns_dnssec_zone_new()
553 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
554 if(!zone) return NULL;
562 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
564 ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
569 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
571 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
576 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
580 /* destroy all name structures within the tree */
581 ldns_traverse_postorder(zone->names,
582 ldns_dnssec_name_node_free,
591 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
595 /* destroy all name structures within the tree */
596 ldns_traverse_postorder(zone->names,
597 ldns_dnssec_name_node_deep_free,
605 /* use for dname comparison in tree */
607 ldns_dname_compare_v(const void *a, const void *b) {
608 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
613 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
615 ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
616 ldns_dnssec_name *current_name;
617 ldns_rdf *hashed_name;
619 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
621 while (current_node != LDNS_RBTREE_NULL) {
622 current_name = (ldns_dnssec_name *) current_node->data;
623 if (!current_name->hashed_name) {
624 current_name->hashed_name =
625 ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
627 if (ldns_dname_compare(hashed_name,
628 current_name->hashed_name)
630 ldns_rdf_deep_free(hashed_name);
633 current_node = ldns_rbtree_next(current_node);
635 ldns_rdf_deep_free(hashed_name);
640 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
642 ldns_status result = LDNS_STATUS_OK;
643 ldns_dnssec_name *cur_name;
644 ldns_rbnode_t *cur_node;
645 ldns_rr_type type_covered = 0;
648 return LDNS_STATUS_ERR;
652 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
653 if(!zone->names) return LDNS_STATUS_MEM_ERR;
656 /* we need the original of the hashed name if this is
657 an NSEC3, or an RRSIG that covers an NSEC3 */
658 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
659 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
661 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
662 type_covered == LDNS_RR_TYPE_NSEC3) {
663 cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
666 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
669 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
674 cur_name = ldns_dnssec_name_new_frm_rr(rr);
675 if(!cur_name) return LDNS_STATUS_MEM_ERR;
676 cur_node = LDNS_MALLOC(ldns_rbnode_t);
678 ldns_dnssec_name_free(cur_name);
679 return LDNS_STATUS_MEM_ERR;
681 cur_node->key = ldns_rr_owner(rr);
682 cur_node->data = cur_name;
683 (void)ldns_rbtree_insert(zone->names, cur_node);
685 cur_name = (ldns_dnssec_name *) cur_node->data;
686 result = ldns_dnssec_name_add_rr(cur_name, rr);
689 if (result != LDNS_STATUS_OK) {
690 fprintf(stderr, "error adding rr: ");
691 ldns_rr_print(stderr, rr);
694 /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
695 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
696 zone->soa = cur_name;
701 #endif /* HAVE_SSL */
704 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
707 ldns_dnssec_name *name;
709 node = ldns_rbtree_first(tree);
710 while (node != LDNS_RBTREE_NULL) {
711 name = (ldns_dnssec_name *) node->data;
712 ldns_dnssec_name_print_soa(out, name, print_soa);
714 node = ldns_rbtree_next(node);
719 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
723 fprintf(out, ";; Zone: ");
724 ldns_rdf_print(out, ldns_dnssec_name_name(zone->soa));
725 fprintf(out, "\n;\n");
726 ldns_dnssec_rrsets_print(
728 ldns_dnssec_name_find_rrset(zone->soa,
735 ldns_dnssec_zone_names_print(out, zone->names, false);
741 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
743 ldns_dnssec_name *new_name;
746 ldns_rbnode_t *cur_node, *next_node, *new_node;
748 /* for the detection */
749 uint16_t i, cur_label_count, next_label_count;
750 uint16_t soa_label_count = 0;
755 return LDNS_STATUS_ERR;
757 if (zone->soa && zone->soa->name) {
758 soa_label_count = ldns_dname_label_count(zone->soa->name);
761 cur_node = ldns_rbtree_first(zone->names);
762 while (cur_node != LDNS_RBTREE_NULL) {
763 next_node = ldns_rbtree_next(cur_node);
766 while (next_node != LDNS_RBTREE_NULL &&
768 ((ldns_dnssec_name *)next_node->data)->is_glue
770 next_node = ldns_rbtree_next(next_node);
773 if (next_node == LDNS_RBTREE_NULL) {
774 next_node = ldns_rbtree_first(zone->names);
777 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
778 next_name = ((ldns_dnssec_name *)next_node->data)->name;
779 cur_label_count = ldns_dname_label_count(cur_name);
780 next_label_count = ldns_dname_label_count(next_name);
782 /* Since the names are in canonical order, we can
783 * recognize empty non-terminals by their labels;
784 * every label after the first one on the next owner
785 * name is a non-terminal if it either does not exist
786 * in the current name or is different from the same
787 * label in the current name (counting from the end)
789 for (i = 1; i < next_label_count - soa_label_count; i++) {
790 lpos = (int)cur_label_count - (int)next_label_count + (int)i;
792 l1 = ldns_dname_label(cur_name, (uint8_t)lpos);
796 l2 = ldns_dname_label(next_name, i);
798 if (!l1 || ldns_dname_compare(l1, l2) != 0) {
799 /* We have an empty nonterminal, add it to the
802 new_name = ldns_dnssec_name_new();
804 return LDNS_STATUS_MEM_ERR;
806 new_name->name = ldns_dname_clone_from(next_name,
809 ldns_dnssec_name_free(new_name);
810 return LDNS_STATUS_MEM_ERR;
812 new_name->name_alloced = true;
813 new_node = LDNS_MALLOC(ldns_rbnode_t);
815 ldns_dnssec_name_free(new_name);
816 return LDNS_STATUS_MEM_ERR;
818 new_node->key = new_name->name;
819 new_node->data = new_name;
820 (void)ldns_rbtree_insert(zone->names, new_node);
822 ldns_rdf_deep_free(l1);
823 ldns_rdf_deep_free(l2);
826 /* we might have inserted a new node after
827 * the current one so we can't just use next()
829 if (next_node != ldns_rbtree_first(zone->names)) {
830 cur_node = next_node;
832 cur_node = LDNS_RBTREE_NULL;
835 return LDNS_STATUS_OK;