xref: /freebsd/contrib/ldns/dnssec_zone.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * special zone file structures and functions for better dnssec handling
37b5038d7SDag-Erling Smørgrav  */
47b5038d7SDag-Erling Smørgrav 
57b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
67b5038d7SDag-Erling Smørgrav 
77b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
8*5afab0e5SDag-Erling Smørgrav #include <ldns/internal.h>
97b5038d7SDag-Erling Smørgrav 
107b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs *
ldns_dnssec_rrs_new(void)117b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_new(void)
127b5038d7SDag-Erling Smørgrav {
137b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs *new_rrs;
147b5038d7SDag-Erling Smørgrav 	new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
157b5038d7SDag-Erling Smørgrav         if(!new_rrs) return NULL;
167b5038d7SDag-Erling Smørgrav 	new_rrs->rr = NULL;
177b5038d7SDag-Erling Smørgrav 	new_rrs->next = NULL;
187b5038d7SDag-Erling Smørgrav 	return new_rrs;
197b5038d7SDag-Erling Smørgrav }
207b5038d7SDag-Erling Smørgrav 
217b5038d7SDag-Erling Smørgrav INLINE void
ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs * rrs,int deep)227b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
237b5038d7SDag-Erling Smørgrav {
247b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs *next;
257b5038d7SDag-Erling Smørgrav 	while (rrs) {
267b5038d7SDag-Erling Smørgrav 		next = rrs->next;
277b5038d7SDag-Erling Smørgrav 		if (deep) {
287b5038d7SDag-Erling Smørgrav 			ldns_rr_free(rrs->rr);
297b5038d7SDag-Erling Smørgrav 		}
307b5038d7SDag-Erling Smørgrav 		LDNS_FREE(rrs);
317b5038d7SDag-Erling Smørgrav 		rrs = next;
327b5038d7SDag-Erling Smørgrav 	}
337b5038d7SDag-Erling Smørgrav }
347b5038d7SDag-Erling Smørgrav 
357b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrs_free(ldns_dnssec_rrs * rrs)367b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
377b5038d7SDag-Erling Smørgrav {
387b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs_free_internal(rrs, 0);
397b5038d7SDag-Erling Smørgrav }
407b5038d7SDag-Erling Smørgrav 
417b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs * rrs)427b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
437b5038d7SDag-Erling Smørgrav {
447b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs_free_internal(rrs, 1);
457b5038d7SDag-Erling Smørgrav }
467b5038d7SDag-Erling Smørgrav 
477b5038d7SDag-Erling Smørgrav ldns_status
ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs * rrs,ldns_rr * rr)487b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
497b5038d7SDag-Erling Smørgrav {
507b5038d7SDag-Erling Smørgrav 	int cmp;
517b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs *new_rrs;
527b5038d7SDag-Erling Smørgrav 	if (!rrs || !rr) {
537b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
547b5038d7SDag-Erling Smørgrav 	}
557b5038d7SDag-Erling Smørgrav 
567b5038d7SDag-Erling Smørgrav 	/* this could be done more efficiently; name and type should already
577b5038d7SDag-Erling Smørgrav 	   be equal */
5817d15b25SDag-Erling Smørgrav 	cmp = ldns_rr_compare(rrs->rr, rr);
5917d15b25SDag-Erling Smørgrav 	if (cmp < 0) {
607b5038d7SDag-Erling Smørgrav 		if (rrs->next) {
617b5038d7SDag-Erling Smørgrav 			return ldns_dnssec_rrs_add_rr(rrs->next, rr);
627b5038d7SDag-Erling Smørgrav 		} else {
637b5038d7SDag-Erling Smørgrav 			new_rrs = ldns_dnssec_rrs_new();
647b5038d7SDag-Erling Smørgrav 			new_rrs->rr = rr;
657b5038d7SDag-Erling Smørgrav 			rrs->next = new_rrs;
667b5038d7SDag-Erling Smørgrav 		}
677b5038d7SDag-Erling Smørgrav 	} else if (cmp > 0) {
687b5038d7SDag-Erling Smørgrav 		/* put the current old rr in the new next, put the new
697b5038d7SDag-Erling Smørgrav 		   rr in the current container */
707b5038d7SDag-Erling Smørgrav 		new_rrs = ldns_dnssec_rrs_new();
717b5038d7SDag-Erling Smørgrav 		new_rrs->rr = rrs->rr;
727b5038d7SDag-Erling Smørgrav 		new_rrs->next = rrs->next;
737b5038d7SDag-Erling Smørgrav 		rrs->rr = rr;
747b5038d7SDag-Erling Smørgrav 		rrs->next = new_rrs;
757b5038d7SDag-Erling Smørgrav 	}
7617d15b25SDag-Erling Smørgrav 	/* Silently ignore equal rr's */
777b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
787b5038d7SDag-Erling Smørgrav }
797b5038d7SDag-Erling Smørgrav 
807b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrs_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrs * rrs)817b5038d7SDag-Erling Smørgrav ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
82986ba33cSDag-Erling Smørgrav 	       const ldns_dnssec_rrs *rrs)
837b5038d7SDag-Erling Smørgrav {
847b5038d7SDag-Erling Smørgrav 	if (!rrs) {
857b5038d7SDag-Erling Smørgrav 		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
867b5038d7SDag-Erling Smørgrav 			fprintf(out, "; <void>");
877b5038d7SDag-Erling Smørgrav 	} else {
887b5038d7SDag-Erling Smørgrav 		if (rrs->rr) {
897b5038d7SDag-Erling Smørgrav 			ldns_rr_print_fmt(out, fmt, rrs->rr);
907b5038d7SDag-Erling Smørgrav 		}
917b5038d7SDag-Erling Smørgrav 		if (rrs->next) {
927b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
937b5038d7SDag-Erling Smørgrav 		}
947b5038d7SDag-Erling Smørgrav 	}
957b5038d7SDag-Erling Smørgrav }
967b5038d7SDag-Erling Smørgrav 
977b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrs_print(FILE * out,const ldns_dnssec_rrs * rrs)98986ba33cSDag-Erling Smørgrav ldns_dnssec_rrs_print(FILE *out, const ldns_dnssec_rrs *rrs)
997b5038d7SDag-Erling Smørgrav {
1007b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
1017b5038d7SDag-Erling Smørgrav }
1027b5038d7SDag-Erling Smørgrav 
1037b5038d7SDag-Erling Smørgrav 
1047b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets *
ldns_dnssec_rrsets_new(void)1057b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_new(void)
1067b5038d7SDag-Erling Smørgrav {
1077b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets *new_rrsets;
1087b5038d7SDag-Erling Smørgrav 	new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
1097b5038d7SDag-Erling Smørgrav         if(!new_rrsets) return NULL;
1107b5038d7SDag-Erling Smørgrav 	new_rrsets->rrs = NULL;
1117b5038d7SDag-Erling Smørgrav 	new_rrsets->type = 0;
1127b5038d7SDag-Erling Smørgrav 	new_rrsets->signatures = NULL;
1137b5038d7SDag-Erling Smørgrav 	new_rrsets->next = NULL;
1147b5038d7SDag-Erling Smørgrav 	return new_rrsets;
1157b5038d7SDag-Erling Smørgrav }
1167b5038d7SDag-Erling Smørgrav 
1177b5038d7SDag-Erling Smørgrav INLINE void
ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets * rrsets,int deep)1187b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
1197b5038d7SDag-Erling Smørgrav {
1207b5038d7SDag-Erling Smørgrav 	if (rrsets) {
1217b5038d7SDag-Erling Smørgrav 		if (rrsets->rrs) {
1227b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
1237b5038d7SDag-Erling Smørgrav 		}
1247b5038d7SDag-Erling Smørgrav 		if (rrsets->next) {
1257b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
1267b5038d7SDag-Erling Smørgrav 		}
1277b5038d7SDag-Erling Smørgrav 		if (rrsets->signatures) {
1287b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
1297b5038d7SDag-Erling Smørgrav 		}
1307b5038d7SDag-Erling Smørgrav 		LDNS_FREE(rrsets);
1317b5038d7SDag-Erling Smørgrav 	}
1327b5038d7SDag-Erling Smørgrav }
1337b5038d7SDag-Erling Smørgrav 
1347b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrsets_free(ldns_dnssec_rrsets * rrsets)1357b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
1367b5038d7SDag-Erling Smørgrav {
1377b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets_free_internal(rrsets, 0);
1387b5038d7SDag-Erling Smørgrav }
1397b5038d7SDag-Erling Smørgrav 
1407b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets * rrsets)1417b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
1427b5038d7SDag-Erling Smørgrav {
1437b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets_free_internal(rrsets, 1);
1447b5038d7SDag-Erling Smørgrav }
1457b5038d7SDag-Erling Smørgrav 
1467b5038d7SDag-Erling Smørgrav ldns_rr_type
ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets * rrsets)147986ba33cSDag-Erling Smørgrav ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets *rrsets)
1487b5038d7SDag-Erling Smørgrav {
1497b5038d7SDag-Erling Smørgrav 	if (rrsets) {
1507b5038d7SDag-Erling Smørgrav 		return rrsets->type;
1517b5038d7SDag-Erling Smørgrav 	} else {
1527b5038d7SDag-Erling Smørgrav 		return 0;
1537b5038d7SDag-Erling Smørgrav 	}
1547b5038d7SDag-Erling Smørgrav }
1557b5038d7SDag-Erling Smørgrav 
1567b5038d7SDag-Erling Smørgrav ldns_status
ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets * rrsets,ldns_rr_type type)1577b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
1587b5038d7SDag-Erling Smørgrav 					   ldns_rr_type type)
1597b5038d7SDag-Erling Smørgrav {
1607b5038d7SDag-Erling Smørgrav 	if (rrsets) {
1617b5038d7SDag-Erling Smørgrav 		rrsets->type = type;
1627b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
1637b5038d7SDag-Erling Smørgrav 	}
1647b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_ERR;
1657b5038d7SDag-Erling Smørgrav }
1667b5038d7SDag-Erling Smørgrav 
1677b5038d7SDag-Erling Smørgrav static ldns_dnssec_rrsets *
ldns_dnssec_rrsets_new_frm_rr(ldns_rr * rr)1687b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
1697b5038d7SDag-Erling Smørgrav {
1707b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets *new_rrsets;
1717b5038d7SDag-Erling Smørgrav 	ldns_rr_type rr_type;
1727b5038d7SDag-Erling Smørgrav 	bool rrsig;
1737b5038d7SDag-Erling Smørgrav 
1747b5038d7SDag-Erling Smørgrav 	new_rrsets = ldns_dnssec_rrsets_new();
1757b5038d7SDag-Erling Smørgrav 	rr_type = ldns_rr_get_type(rr);
1767b5038d7SDag-Erling Smørgrav 	if (rr_type == LDNS_RR_TYPE_RRSIG) {
1777b5038d7SDag-Erling Smørgrav 		rrsig = true;
1787b5038d7SDag-Erling Smørgrav 		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
1797b5038d7SDag-Erling Smørgrav 	} else {
1807b5038d7SDag-Erling Smørgrav 		rrsig = false;
1817b5038d7SDag-Erling Smørgrav 	}
1827b5038d7SDag-Erling Smørgrav 	if (!rrsig) {
1837b5038d7SDag-Erling Smørgrav 		new_rrsets->rrs = ldns_dnssec_rrs_new();
1847b5038d7SDag-Erling Smørgrav 		new_rrsets->rrs->rr = rr;
1857b5038d7SDag-Erling Smørgrav 	} else {
1867b5038d7SDag-Erling Smørgrav 		new_rrsets->signatures = ldns_dnssec_rrs_new();
1877b5038d7SDag-Erling Smørgrav 		new_rrsets->signatures->rr = rr;
1887b5038d7SDag-Erling Smørgrav 	}
1897b5038d7SDag-Erling Smørgrav 	new_rrsets->type = rr_type;
1907b5038d7SDag-Erling Smørgrav 	return new_rrsets;
1917b5038d7SDag-Erling Smørgrav }
1927b5038d7SDag-Erling Smørgrav 
1937b5038d7SDag-Erling Smørgrav ldns_status
ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets * rrsets,ldns_rr * rr)1947b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
1957b5038d7SDag-Erling Smørgrav {
1967b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets *new_rrsets;
1977b5038d7SDag-Erling Smørgrav 	ldns_rr_type rr_type;
1987b5038d7SDag-Erling Smørgrav 	bool rrsig = false;
1997b5038d7SDag-Erling Smørgrav 	ldns_status result = LDNS_STATUS_OK;
2007b5038d7SDag-Erling Smørgrav 
2017b5038d7SDag-Erling Smørgrav 	if (!rrsets || !rr) {
2027b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
2037b5038d7SDag-Erling Smørgrav 	}
2047b5038d7SDag-Erling Smørgrav 
2057b5038d7SDag-Erling Smørgrav 	rr_type = ldns_rr_get_type(rr);
2067b5038d7SDag-Erling Smørgrav 
2077b5038d7SDag-Erling Smørgrav 	if (rr_type == LDNS_RR_TYPE_RRSIG) {
2087b5038d7SDag-Erling Smørgrav 		rrsig = true;
2097b5038d7SDag-Erling Smørgrav 		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
2107b5038d7SDag-Erling Smørgrav 	}
2117b5038d7SDag-Erling Smørgrav 
2127b5038d7SDag-Erling Smørgrav 	if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
2137b5038d7SDag-Erling Smørgrav 		if (!rrsig) {
2147b5038d7SDag-Erling Smørgrav 			rrsets->rrs = ldns_dnssec_rrs_new();
2157b5038d7SDag-Erling Smørgrav 			rrsets->rrs->rr = rr;
2167b5038d7SDag-Erling Smørgrav 			rrsets->type = rr_type;
2177b5038d7SDag-Erling Smørgrav 		} else {
2187b5038d7SDag-Erling Smørgrav 			rrsets->signatures = ldns_dnssec_rrs_new();
2197b5038d7SDag-Erling Smørgrav 			rrsets->signatures->rr = rr;
2207b5038d7SDag-Erling Smørgrav 			rrsets->type = rr_type;
2217b5038d7SDag-Erling Smørgrav 		}
2227b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
2237b5038d7SDag-Erling Smørgrav 	}
2247b5038d7SDag-Erling Smørgrav 
2257b5038d7SDag-Erling Smørgrav 	if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
2267b5038d7SDag-Erling Smørgrav 		if (rrsets->next) {
2277b5038d7SDag-Erling Smørgrav 			result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
2287b5038d7SDag-Erling Smørgrav 		} else {
2297b5038d7SDag-Erling Smørgrav 			new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
2307b5038d7SDag-Erling Smørgrav 			rrsets->next = new_rrsets;
2317b5038d7SDag-Erling Smørgrav 		}
2327b5038d7SDag-Erling Smørgrav 	} else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
2337b5038d7SDag-Erling Smørgrav 		/* move the current one into the new next,
2347b5038d7SDag-Erling Smørgrav 		   replace field of current with data from new rr */
2357b5038d7SDag-Erling Smørgrav 		new_rrsets = ldns_dnssec_rrsets_new();
2367b5038d7SDag-Erling Smørgrav 		new_rrsets->rrs = rrsets->rrs;
2377b5038d7SDag-Erling Smørgrav 		new_rrsets->type = rrsets->type;
2387b5038d7SDag-Erling Smørgrav 		new_rrsets->signatures = rrsets->signatures;
2397b5038d7SDag-Erling Smørgrav 		new_rrsets->next = rrsets->next;
2407b5038d7SDag-Erling Smørgrav 		if (!rrsig) {
2417b5038d7SDag-Erling Smørgrav 			rrsets->rrs = ldns_dnssec_rrs_new();
2427b5038d7SDag-Erling Smørgrav 			rrsets->rrs->rr = rr;
2437b5038d7SDag-Erling Smørgrav 			rrsets->signatures = NULL;
2447b5038d7SDag-Erling Smørgrav 		} else {
2457b5038d7SDag-Erling Smørgrav 			rrsets->rrs = NULL;
2467b5038d7SDag-Erling Smørgrav 			rrsets->signatures = ldns_dnssec_rrs_new();
2477b5038d7SDag-Erling Smørgrav 			rrsets->signatures->rr = rr;
2487b5038d7SDag-Erling Smørgrav 		}
2497b5038d7SDag-Erling Smørgrav 		rrsets->type = rr_type;
2507b5038d7SDag-Erling Smørgrav 		rrsets->next = new_rrsets;
2517b5038d7SDag-Erling Smørgrav 	} else {
2527b5038d7SDag-Erling Smørgrav 		/* equal, add to current rrsets */
2537b5038d7SDag-Erling Smørgrav 		if (rrsig) {
2547b5038d7SDag-Erling Smørgrav 			if (rrsets->signatures) {
2557b5038d7SDag-Erling Smørgrav 				result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
2567b5038d7SDag-Erling Smørgrav 			} else {
2577b5038d7SDag-Erling Smørgrav 				rrsets->signatures = ldns_dnssec_rrs_new();
2587b5038d7SDag-Erling Smørgrav 				rrsets->signatures->rr = rr;
2597b5038d7SDag-Erling Smørgrav 			}
2607b5038d7SDag-Erling Smørgrav 		} else {
2617b5038d7SDag-Erling Smørgrav 			if (rrsets->rrs) {
2627b5038d7SDag-Erling Smørgrav 				result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
2637b5038d7SDag-Erling Smørgrav 			} else {
2647b5038d7SDag-Erling Smørgrav 				rrsets->rrs = ldns_dnssec_rrs_new();
2657b5038d7SDag-Erling Smørgrav 				rrsets->rrs->rr = rr;
2667b5038d7SDag-Erling Smørgrav 			}
2677b5038d7SDag-Erling Smørgrav 		}
2687b5038d7SDag-Erling Smørgrav 	}
2697b5038d7SDag-Erling Smørgrav 
2707b5038d7SDag-Erling Smørgrav 	return result;
2717b5038d7SDag-Erling Smørgrav }
2727b5038d7SDag-Erling Smørgrav 
2737b5038d7SDag-Erling Smørgrav static void
ldns_dnssec_rrsets_print_soa_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrsets * rrsets,bool follow,bool show_soa)2747b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
275986ba33cSDag-Erling Smørgrav 		const ldns_dnssec_rrsets *rrsets,
2767b5038d7SDag-Erling Smørgrav 		bool follow,
2777b5038d7SDag-Erling Smørgrav 		bool show_soa)
2787b5038d7SDag-Erling Smørgrav {
2797b5038d7SDag-Erling Smørgrav 	if (!rrsets) {
2807b5038d7SDag-Erling Smørgrav 		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
2817b5038d7SDag-Erling Smørgrav 			fprintf(out, "; <void>\n");
2827b5038d7SDag-Erling Smørgrav 	} else {
2837b5038d7SDag-Erling Smørgrav 		if (rrsets->rrs &&
2847b5038d7SDag-Erling Smørgrav 		    (show_soa ||
2857b5038d7SDag-Erling Smørgrav 			ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
2867b5038d7SDag-Erling Smørgrav 		    )
2877b5038d7SDag-Erling Smørgrav 		   ) {
2887b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
2897b5038d7SDag-Erling Smørgrav 			if (rrsets->signatures) {
2907b5038d7SDag-Erling Smørgrav 				ldns_dnssec_rrs_print_fmt(out, fmt,
2917b5038d7SDag-Erling Smørgrav 						rrsets->signatures);
2927b5038d7SDag-Erling Smørgrav 			}
2937b5038d7SDag-Erling Smørgrav 		}
2947b5038d7SDag-Erling Smørgrav 		if (follow && rrsets->next) {
2957b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
2967b5038d7SDag-Erling Smørgrav 					rrsets->next, follow, show_soa);
2977b5038d7SDag-Erling Smørgrav 		}
2987b5038d7SDag-Erling Smørgrav 	}
2997b5038d7SDag-Erling Smørgrav }
3007b5038d7SDag-Erling Smørgrav 
3017b5038d7SDag-Erling Smørgrav 
3027b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrsets_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrsets * rrsets,bool follow)3037b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
304986ba33cSDag-Erling Smørgrav 		const ldns_dnssec_rrsets *rrsets,
3057b5038d7SDag-Erling Smørgrav 		bool follow)
3067b5038d7SDag-Erling Smørgrav {
3077b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
3087b5038d7SDag-Erling Smørgrav }
3097b5038d7SDag-Erling Smørgrav 
3107b5038d7SDag-Erling Smørgrav void
ldns_dnssec_rrsets_print(FILE * out,const ldns_dnssec_rrsets * rrsets,bool follow)311986ba33cSDag-Erling Smørgrav ldns_dnssec_rrsets_print(FILE *out, const ldns_dnssec_rrsets *rrsets, bool follow)
3127b5038d7SDag-Erling Smørgrav {
3137b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
3147b5038d7SDag-Erling Smørgrav 			rrsets, follow);
3157b5038d7SDag-Erling Smørgrav }
3167b5038d7SDag-Erling Smørgrav 
3177b5038d7SDag-Erling Smørgrav ldns_dnssec_name *
ldns_dnssec_name_new(void)3187b5038d7SDag-Erling Smørgrav ldns_dnssec_name_new(void)
3197b5038d7SDag-Erling Smørgrav {
3207b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *new_name;
3217b5038d7SDag-Erling Smørgrav 
3227b5038d7SDag-Erling Smørgrav 	new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
3237b5038d7SDag-Erling Smørgrav 	if (!new_name) {
3247b5038d7SDag-Erling Smørgrav 		return NULL;
3257b5038d7SDag-Erling Smørgrav 	}
3267b5038d7SDag-Erling Smørgrav 	/*
327*5afab0e5SDag-Erling Smørgrav 	 * not needed anymore because CALLOC initializes everything to zero.
3287b5038d7SDag-Erling Smørgrav 
3297b5038d7SDag-Erling Smørgrav 	new_name->name = NULL;
3307b5038d7SDag-Erling Smørgrav 	new_name->rrsets = NULL;
3317b5038d7SDag-Erling Smørgrav 	new_name->name_alloced = false;
3327b5038d7SDag-Erling Smørgrav 	new_name->nsec = NULL;
3337b5038d7SDag-Erling Smørgrav 	new_name->nsec_signatures = NULL;
3347b5038d7SDag-Erling Smørgrav 
3357b5038d7SDag-Erling Smørgrav 	new_name->is_glue = false;
3367b5038d7SDag-Erling Smørgrav 	new_name->hashed_name = NULL;
3377b5038d7SDag-Erling Smørgrav 
3387b5038d7SDag-Erling Smørgrav 	 */
3397b5038d7SDag-Erling Smørgrav 	return new_name;
3407b5038d7SDag-Erling Smørgrav }
3417b5038d7SDag-Erling Smørgrav 
3427b5038d7SDag-Erling Smørgrav ldns_dnssec_name *
ldns_dnssec_name_new_frm_rr(ldns_rr * rr)3437b5038d7SDag-Erling Smørgrav ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
3447b5038d7SDag-Erling Smørgrav {
3457b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *new_name = ldns_dnssec_name_new();
3467b5038d7SDag-Erling Smørgrav 
3477b5038d7SDag-Erling Smørgrav 	new_name->name = ldns_rr_owner(rr);
3487b5038d7SDag-Erling Smørgrav 	if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
3497b5038d7SDag-Erling Smørgrav 		ldns_dnssec_name_free(new_name);
3507b5038d7SDag-Erling Smørgrav 		return NULL;
3517b5038d7SDag-Erling Smørgrav 	}
3527b5038d7SDag-Erling Smørgrav 
3537b5038d7SDag-Erling Smørgrav 	return new_name;
3547b5038d7SDag-Erling Smørgrav }
3557b5038d7SDag-Erling Smørgrav 
3567b5038d7SDag-Erling Smørgrav INLINE void
ldns_dnssec_name_free_internal(ldns_dnssec_name * name,int deep)3577b5038d7SDag-Erling Smørgrav ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
3587b5038d7SDag-Erling Smørgrav                                int deep)
3597b5038d7SDag-Erling Smørgrav {
3607b5038d7SDag-Erling Smørgrav 	if (name) {
3617b5038d7SDag-Erling Smørgrav 		if (name->name_alloced) {
3627b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(name->name);
3637b5038d7SDag-Erling Smørgrav 		}
3647b5038d7SDag-Erling Smørgrav 		if (name->rrsets) {
3657b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
3667b5038d7SDag-Erling Smørgrav 		}
3677b5038d7SDag-Erling Smørgrav 		if (name->nsec && deep) {
3687b5038d7SDag-Erling Smørgrav 			ldns_rr_free(name->nsec);
3697b5038d7SDag-Erling Smørgrav 		}
3707b5038d7SDag-Erling Smørgrav 		if (name->nsec_signatures) {
3717b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
3727b5038d7SDag-Erling Smørgrav 		}
3737b5038d7SDag-Erling Smørgrav 		if (name->hashed_name) {
374*5afab0e5SDag-Erling Smørgrav 			/* Hashed name is always allocated when signing,
375*5afab0e5SDag-Erling Smørgrav 			 * so always deep free
376*5afab0e5SDag-Erling Smørgrav 			 */
3777b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(name->hashed_name);
3787b5038d7SDag-Erling Smørgrav 		}
3797b5038d7SDag-Erling Smørgrav 		LDNS_FREE(name);
3807b5038d7SDag-Erling Smørgrav 	}
3817b5038d7SDag-Erling Smørgrav }
3827b5038d7SDag-Erling Smørgrav 
3837b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_free(ldns_dnssec_name * name)3847b5038d7SDag-Erling Smørgrav ldns_dnssec_name_free(ldns_dnssec_name *name)
3857b5038d7SDag-Erling Smørgrav {
3867b5038d7SDag-Erling Smørgrav   ldns_dnssec_name_free_internal(name, 0);
3877b5038d7SDag-Erling Smørgrav }
3887b5038d7SDag-Erling Smørgrav 
3897b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_deep_free(ldns_dnssec_name * name)3907b5038d7SDag-Erling Smørgrav ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
3917b5038d7SDag-Erling Smørgrav {
3927b5038d7SDag-Erling Smørgrav   ldns_dnssec_name_free_internal(name, 1);
3937b5038d7SDag-Erling Smørgrav }
3947b5038d7SDag-Erling Smørgrav 
3957b5038d7SDag-Erling Smørgrav ldns_rdf *
ldns_dnssec_name_name(const ldns_dnssec_name * name)396986ba33cSDag-Erling Smørgrav ldns_dnssec_name_name(const ldns_dnssec_name *name)
3977b5038d7SDag-Erling Smørgrav {
3987b5038d7SDag-Erling Smørgrav 	if (name) {
3997b5038d7SDag-Erling Smørgrav 		return name->name;
4007b5038d7SDag-Erling Smørgrav 	}
4017b5038d7SDag-Erling Smørgrav 	return NULL;
4027b5038d7SDag-Erling Smørgrav }
4037b5038d7SDag-Erling Smørgrav 
4047b5038d7SDag-Erling Smørgrav bool
ldns_dnssec_name_is_glue(const ldns_dnssec_name * name)405986ba33cSDag-Erling Smørgrav ldns_dnssec_name_is_glue(const ldns_dnssec_name *name)
4067b5038d7SDag-Erling Smørgrav {
4077b5038d7SDag-Erling Smørgrav 	if (name) {
4087b5038d7SDag-Erling Smørgrav 		return name->is_glue;
4097b5038d7SDag-Erling Smørgrav 	}
4107b5038d7SDag-Erling Smørgrav 	return false;
4117b5038d7SDag-Erling Smørgrav }
4127b5038d7SDag-Erling Smørgrav 
4137b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_set_name(ldns_dnssec_name * rrset,ldns_rdf * dname)4147b5038d7SDag-Erling Smørgrav ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
4157b5038d7SDag-Erling Smørgrav 					 ldns_rdf *dname)
4167b5038d7SDag-Erling Smørgrav {
4177b5038d7SDag-Erling Smørgrav 	if (rrset && dname) {
4187b5038d7SDag-Erling Smørgrav 		rrset->name = dname;
4197b5038d7SDag-Erling Smørgrav 	}
4207b5038d7SDag-Erling Smørgrav }
4217b5038d7SDag-Erling Smørgrav 
4227b5038d7SDag-Erling Smørgrav 
4237b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_set_nsec(ldns_dnssec_name * rrset,ldns_rr * nsec)4247b5038d7SDag-Erling Smørgrav ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
4257b5038d7SDag-Erling Smørgrav {
4267b5038d7SDag-Erling Smørgrav 	if (rrset && nsec) {
4277b5038d7SDag-Erling Smørgrav 		rrset->nsec = nsec;
4287b5038d7SDag-Erling Smørgrav 	}
4297b5038d7SDag-Erling Smørgrav }
4307b5038d7SDag-Erling Smørgrav 
4317b5038d7SDag-Erling Smørgrav int
ldns_dnssec_name_cmp(const void * a,const void * b)4327b5038d7SDag-Erling Smørgrav ldns_dnssec_name_cmp(const void *a, const void *b)
4337b5038d7SDag-Erling Smørgrav {
4347b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *na = (ldns_dnssec_name *) a;
4357b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
4367b5038d7SDag-Erling Smørgrav 
4377b5038d7SDag-Erling Smørgrav 	if (na && nb) {
4387b5038d7SDag-Erling Smørgrav 		return ldns_dname_compare(ldns_dnssec_name_name(na),
4397b5038d7SDag-Erling Smørgrav 							 ldns_dnssec_name_name(nb));
4407b5038d7SDag-Erling Smørgrav 	} else if (na) {
4417b5038d7SDag-Erling Smørgrav 		return 1;
4427b5038d7SDag-Erling Smørgrav 	} else if (nb) {
4437b5038d7SDag-Erling Smørgrav 		return -1;
4447b5038d7SDag-Erling Smørgrav 	} else {
4457b5038d7SDag-Erling Smørgrav 		return 0;
4467b5038d7SDag-Erling Smørgrav 	}
4477b5038d7SDag-Erling Smørgrav }
4487b5038d7SDag-Erling Smørgrav 
4497b5038d7SDag-Erling Smørgrav ldns_status
ldns_dnssec_name_add_rr(ldns_dnssec_name * name,ldns_rr * rr)4507b5038d7SDag-Erling Smørgrav ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
4517b5038d7SDag-Erling Smørgrav 				    ldns_rr *rr)
4527b5038d7SDag-Erling Smørgrav {
4537b5038d7SDag-Erling Smørgrav 	ldns_status result = LDNS_STATUS_OK;
4547b5038d7SDag-Erling Smørgrav 	ldns_rr_type rr_type;
4557b5038d7SDag-Erling Smørgrav 	ldns_rr_type typecovered = 0;
4567b5038d7SDag-Erling Smørgrav 
4577b5038d7SDag-Erling Smørgrav 	/* special handling for NSEC3 and NSECX covering RRSIGS */
4587b5038d7SDag-Erling Smørgrav 
4597b5038d7SDag-Erling Smørgrav 	if (!name || !rr) {
4607b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
4617b5038d7SDag-Erling Smørgrav 	}
4627b5038d7SDag-Erling Smørgrav 
4637b5038d7SDag-Erling Smørgrav 	rr_type = ldns_rr_get_type(rr);
4647b5038d7SDag-Erling Smørgrav 
4657b5038d7SDag-Erling Smørgrav 	if (rr_type == LDNS_RR_TYPE_RRSIG) {
4667b5038d7SDag-Erling Smørgrav 		typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
4677b5038d7SDag-Erling Smørgrav 	}
4687b5038d7SDag-Erling Smørgrav 
4697b5038d7SDag-Erling Smørgrav 	if (rr_type == LDNS_RR_TYPE_NSEC ||
4707b5038d7SDag-Erling Smørgrav 	    rr_type == LDNS_RR_TYPE_NSEC3) {
4717b5038d7SDag-Erling Smørgrav 		/* XX check if is already set (and error?) */
4727b5038d7SDag-Erling Smørgrav 		name->nsec = rr;
4737b5038d7SDag-Erling Smørgrav 	} else if (typecovered == LDNS_RR_TYPE_NSEC ||
4747b5038d7SDag-Erling Smørgrav 			 typecovered == LDNS_RR_TYPE_NSEC3) {
4757b5038d7SDag-Erling Smørgrav 		if (name->nsec_signatures) {
4767b5038d7SDag-Erling Smørgrav 			result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
4777b5038d7SDag-Erling Smørgrav 		} else {
4787b5038d7SDag-Erling Smørgrav 			name->nsec_signatures = ldns_dnssec_rrs_new();
4797b5038d7SDag-Erling Smørgrav 			name->nsec_signatures->rr = rr;
4807b5038d7SDag-Erling Smørgrav 		}
4817b5038d7SDag-Erling Smørgrav 	} else {
4827b5038d7SDag-Erling Smørgrav 		/* it's a 'normal' RR, add it to the right rrset */
4837b5038d7SDag-Erling Smørgrav 		if (name->rrsets) {
4847b5038d7SDag-Erling Smørgrav 			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
4857b5038d7SDag-Erling Smørgrav 		} else {
4867b5038d7SDag-Erling Smørgrav 			name->rrsets = ldns_dnssec_rrsets_new();
4877b5038d7SDag-Erling Smørgrav 			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
4887b5038d7SDag-Erling Smørgrav 		}
4897b5038d7SDag-Erling Smørgrav 	}
4907b5038d7SDag-Erling Smørgrav 	return result;
4917b5038d7SDag-Erling Smørgrav }
4927b5038d7SDag-Erling Smørgrav 
4937b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets *
ldns_dnssec_name_find_rrset(const ldns_dnssec_name * name,ldns_rr_type type)494986ba33cSDag-Erling Smørgrav ldns_dnssec_name_find_rrset(const ldns_dnssec_name *name,
4957b5038d7SDag-Erling Smørgrav 					   ldns_rr_type type) {
4967b5038d7SDag-Erling Smørgrav 	ldns_dnssec_rrsets *result;
4977b5038d7SDag-Erling Smørgrav 
4987b5038d7SDag-Erling Smørgrav 	result = name->rrsets;
4997b5038d7SDag-Erling Smørgrav 	while (result) {
5007b5038d7SDag-Erling Smørgrav 		if (result->type == type) {
5017b5038d7SDag-Erling Smørgrav 			return result;
5027b5038d7SDag-Erling Smørgrav 		} else {
5037b5038d7SDag-Erling Smørgrav 			result = result->next;
5047b5038d7SDag-Erling Smørgrav 		}
5057b5038d7SDag-Erling Smørgrav 	}
5067b5038d7SDag-Erling Smørgrav 	return NULL;
5077b5038d7SDag-Erling Smørgrav }
5087b5038d7SDag-Erling Smørgrav 
5097b5038d7SDag-Erling Smørgrav ldns_dnssec_rrsets *
ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone * zone,const ldns_rdf * dname,ldns_rr_type type)510986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone *zone,
511986ba33cSDag-Erling Smørgrav 					   const ldns_rdf *dname,
5127b5038d7SDag-Erling Smørgrav 					   ldns_rr_type type)
5137b5038d7SDag-Erling Smørgrav {
5147b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node;
5157b5038d7SDag-Erling Smørgrav 
516986ba33cSDag-Erling Smørgrav 	if (!zone || !dname || !zone->names) {
5177b5038d7SDag-Erling Smørgrav 		return NULL;
5187b5038d7SDag-Erling Smørgrav 	}
5197b5038d7SDag-Erling Smørgrav 
5207b5038d7SDag-Erling Smørgrav 	node = ldns_rbtree_search(zone->names, dname);
5217b5038d7SDag-Erling Smørgrav 	if (node) {
5227b5038d7SDag-Erling Smørgrav 		return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
5237b5038d7SDag-Erling Smørgrav 									type);
5247b5038d7SDag-Erling Smørgrav 	} else {
5257b5038d7SDag-Erling Smørgrav 		return NULL;
5267b5038d7SDag-Erling Smørgrav 	}
5277b5038d7SDag-Erling Smørgrav }
5287b5038d7SDag-Erling Smørgrav 
5297b5038d7SDag-Erling Smørgrav static void
ldns_dnssec_name_print_soa_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_name * name,bool show_soa)5307b5038d7SDag-Erling Smørgrav ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
531986ba33cSDag-Erling Smørgrav 		const ldns_dnssec_name *name,
5327b5038d7SDag-Erling Smørgrav 		bool show_soa)
5337b5038d7SDag-Erling Smørgrav {
5347b5038d7SDag-Erling Smørgrav 	if (name) {
5357b5038d7SDag-Erling Smørgrav 		if(name->rrsets) {
5367b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
5377b5038d7SDag-Erling Smørgrav 					name->rrsets, true, show_soa);
5387b5038d7SDag-Erling Smørgrav 		} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
5397b5038d7SDag-Erling Smørgrav 			fprintf(out, ";; Empty nonterminal: ");
5407b5038d7SDag-Erling Smørgrav 			ldns_rdf_print(out, name->name);
5417b5038d7SDag-Erling Smørgrav 			fprintf(out, "\n");
5427b5038d7SDag-Erling Smørgrav 		}
5437b5038d7SDag-Erling Smørgrav 		if(name->nsec) {
5447b5038d7SDag-Erling Smørgrav 			ldns_rr_print_fmt(out, fmt, name->nsec);
5457b5038d7SDag-Erling Smørgrav 		}
5467b5038d7SDag-Erling Smørgrav 		if (name->nsec_signatures) {
5477b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrs_print_fmt(out, fmt,
5487b5038d7SDag-Erling Smørgrav 					name->nsec_signatures);
5497b5038d7SDag-Erling Smørgrav 		}
5507b5038d7SDag-Erling Smørgrav 	} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
5517b5038d7SDag-Erling Smørgrav 		fprintf(out, "; <void>\n");
5527b5038d7SDag-Erling Smørgrav 	}
5537b5038d7SDag-Erling Smørgrav }
5547b5038d7SDag-Erling Smørgrav 
5557b5038d7SDag-Erling Smørgrav 
5567b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_name * name)5577b5038d7SDag-Erling Smørgrav ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
558986ba33cSDag-Erling Smørgrav 		const ldns_dnssec_name *name)
5597b5038d7SDag-Erling Smørgrav {
5607b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
5617b5038d7SDag-Erling Smørgrav }
5627b5038d7SDag-Erling Smørgrav 
5637b5038d7SDag-Erling Smørgrav void
ldns_dnssec_name_print(FILE * out,const ldns_dnssec_name * name)564986ba33cSDag-Erling Smørgrav ldns_dnssec_name_print(FILE *out, const ldns_dnssec_name *name)
5657b5038d7SDag-Erling Smørgrav {
5667b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
5677b5038d7SDag-Erling Smørgrav }
5687b5038d7SDag-Erling Smørgrav 
5697b5038d7SDag-Erling Smørgrav 
5707b5038d7SDag-Erling Smørgrav ldns_dnssec_zone *
ldns_dnssec_zone_new(void)5717b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_new(void)
5727b5038d7SDag-Erling Smørgrav {
5737b5038d7SDag-Erling Smørgrav 	ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
5747b5038d7SDag-Erling Smørgrav         if(!zone) return NULL;
5757b5038d7SDag-Erling Smørgrav 	zone->soa = NULL;
5767b5038d7SDag-Erling Smørgrav 	zone->names = NULL;
57717d15b25SDag-Erling Smørgrav 	zone->hashed_names = NULL;
57817d15b25SDag-Erling Smørgrav 	zone->_nsec3params = NULL;
5797b5038d7SDag-Erling Smørgrav 
5807b5038d7SDag-Erling Smørgrav 	return zone;
5817b5038d7SDag-Erling Smørgrav }
5827b5038d7SDag-Erling Smørgrav 
5837b5038d7SDag-Erling Smørgrav static bool
rr_is_rrsig_covering(ldns_rr * rr,ldns_rr_type t)5847b5038d7SDag-Erling Smørgrav rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
5857b5038d7SDag-Erling Smørgrav {
5867b5038d7SDag-Erling Smørgrav 	return     ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
5877b5038d7SDag-Erling Smørgrav 		&& ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
5887b5038d7SDag-Erling Smørgrav }
5897b5038d7SDag-Erling Smørgrav 
5907b5038d7SDag-Erling Smørgrav /* When the zone is first read into an list and then inserted into an
5917b5038d7SDag-Erling Smørgrav  * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
5927b5038d7SDag-Erling Smørgrav  * to each other. Because ldns-verify-zone (the only program that uses this
593*5afab0e5SDag-Erling Smørgrav  * function) uses the rbtree mostly for sequential walking, this results
5947b5038d7SDag-Erling Smørgrav  * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
5957b5038d7SDag-Erling Smørgrav  */
5967b5038d7SDag-Erling Smørgrav #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
5977b5038d7SDag-Erling Smørgrav 
598986ba33cSDag-Erling Smørgrav static ldns_status
599986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_add_empty_nonterminals_nsec3(
600986ba33cSDag-Erling Smørgrav 		ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s);
601986ba33cSDag-Erling Smørgrav 
602986ba33cSDag-Erling Smørgrav static void
ldns_todo_nsec3_ents_node_free(ldns_rbnode_t * node,void * arg)603986ba33cSDag-Erling Smørgrav ldns_todo_nsec3_ents_node_free(ldns_rbnode_t *node, void *arg) {
604986ba33cSDag-Erling Smørgrav 	(void) arg;
605986ba33cSDag-Erling Smørgrav 	ldns_rdf_deep_free((ldns_rdf *)node->key);
606986ba33cSDag-Erling Smørgrav 	LDNS_FREE(node);
607986ba33cSDag-Erling Smørgrav }
608986ba33cSDag-Erling Smørgrav 
6097b5038d7SDag-Erling Smørgrav ldns_status
ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone ** z,FILE * fp,const ldns_rdf * origin,uint32_t default_ttl,ldns_rr_class ATTR_UNUSED (c),int * line_nr)610986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
611*5afab0e5SDag-Erling Smørgrav 		uint32_t default_ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
6127b5038d7SDag-Erling Smørgrav {
6137b5038d7SDag-Erling Smørgrav 	ldns_rr* cur_rr;
6147b5038d7SDag-Erling Smørgrav 	size_t i;
6157b5038d7SDag-Erling Smørgrav 
6167b5038d7SDag-Erling Smørgrav 	ldns_rdf *my_origin = NULL;
6177b5038d7SDag-Erling Smørgrav 	ldns_rdf *my_prev = NULL;
6187b5038d7SDag-Erling Smørgrav 
6197b5038d7SDag-Erling Smørgrav 	ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
620986ba33cSDag-Erling Smørgrav 	/* NSEC3s may occur before the names they refer to. We must remember
621986ba33cSDag-Erling Smørgrav 	   them and add them to the name later on, after the name is read.
622986ba33cSDag-Erling Smørgrav 	   We track not yet  matching NSEC3s*n the todo_nsec3s list */
623986ba33cSDag-Erling Smørgrav 	ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
6247b5038d7SDag-Erling Smørgrav 	/* when reading NSEC3s, there is a chance that we encounter nsecs
6257b5038d7SDag-Erling Smørgrav 	   for empty nonterminals, whose nonterminals we cannot derive yet
626986ba33cSDag-Erling Smørgrav 	   because the needed information is to be read later.
627986ba33cSDag-Erling Smørgrav 
628986ba33cSDag-Erling Smørgrav 	   nsec3_ents (where ent is e.n.t.; i.e. empty non terminal) will
629986ba33cSDag-Erling Smørgrav 	   hold the NSEC3s that still didn't have a matching name in the
630986ba33cSDag-Erling Smørgrav 	   zone tree, even after all names were read.  They can only match
631*5afab0e5SDag-Erling Smørgrav 	   after the zone is equipped with all the empty non terminals. */
632986ba33cSDag-Erling Smørgrav 	ldns_rbtree_t todo_nsec3_ents;
633986ba33cSDag-Erling Smørgrav 	ldns_rbnode_t *new_node;
6347b5038d7SDag-Erling Smørgrav 	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
6357b5038d7SDag-Erling Smørgrav 
636986ba33cSDag-Erling Smørgrav 	ldns_status status;
6377b5038d7SDag-Erling Smørgrav 
6387b5038d7SDag-Erling Smørgrav #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
6397b5038d7SDag-Erling Smørgrav 	ldns_zone* zone = NULL;
6407b5038d7SDag-Erling Smørgrav #else
641*5afab0e5SDag-Erling Smørgrav 	ldns_rr  *prev_rr = NULL;
642*5afab0e5SDag-Erling Smørgrav 	uint32_t   my_ttl = default_ttl;
643*5afab0e5SDag-Erling Smørgrav 	/* RFC 1035 Section 5.1, says 'Omitted class and TTL values are default
644*5afab0e5SDag-Erling Smørgrav 	 * to the last explicitly stated values.'
645*5afab0e5SDag-Erling Smørgrav 	 */
646*5afab0e5SDag-Erling Smørgrav 	bool ttl_from_TTL = false;
647*5afab0e5SDag-Erling Smørgrav 	bool explicit_ttl = false;
6487b5038d7SDag-Erling Smørgrav #endif
6497b5038d7SDag-Erling Smørgrav 
650986ba33cSDag-Erling Smørgrav 	ldns_rbtree_init(&todo_nsec3_ents, ldns_dname_compare_v);
6517b5038d7SDag-Erling Smørgrav 
652986ba33cSDag-Erling Smørgrav #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
653*5afab0e5SDag-Erling Smørgrav 	status = ldns_zone_new_frm_fp_l(&zone, fp, origin, default_ttl, c, line_nr);
654986ba33cSDag-Erling Smørgrav 	if (status != LDNS_STATUS_OK)
655986ba33cSDag-Erling Smørgrav 		goto error;
656986ba33cSDag-Erling Smørgrav #endif
657986ba33cSDag-Erling Smørgrav 	if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) {
658986ba33cSDag-Erling Smørgrav 		status = LDNS_STATUS_MEM_ERR;
659986ba33cSDag-Erling Smørgrav 		goto error;
660986ba33cSDag-Erling Smørgrav 	}
6617b5038d7SDag-Erling Smørgrav 	if (origin) {
662986ba33cSDag-Erling Smørgrav 		if (!(my_origin = ldns_rdf_clone(origin))) {
663986ba33cSDag-Erling Smørgrav 			status = LDNS_STATUS_MEM_ERR;
664986ba33cSDag-Erling Smørgrav 			goto error;
665986ba33cSDag-Erling Smørgrav 		}
666986ba33cSDag-Erling Smørgrav 		if (!(my_prev   = ldns_rdf_clone(origin))) {
667986ba33cSDag-Erling Smørgrav 			status = LDNS_STATUS_MEM_ERR;
668986ba33cSDag-Erling Smørgrav 			goto error;
669986ba33cSDag-Erling Smørgrav 		}
6707b5038d7SDag-Erling Smørgrav 	}
6717b5038d7SDag-Erling Smørgrav 
6727b5038d7SDag-Erling Smørgrav #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
673986ba33cSDag-Erling Smørgrav 	if (ldns_zone_soa(zone)) {
674986ba33cSDag-Erling Smørgrav 		status = ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone));
675986ba33cSDag-Erling Smørgrav 		if (status != LDNS_STATUS_OK)
676986ba33cSDag-Erling Smørgrav 			goto error;
677986ba33cSDag-Erling Smørgrav 	}
6787b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
6797b5038d7SDag-Erling Smørgrav 		cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
6807b5038d7SDag-Erling Smørgrav 		status = LDNS_STATUS_OK;
6817b5038d7SDag-Erling Smørgrav #else
6827b5038d7SDag-Erling Smørgrav 	while (!feof(fp)) {
683*5afab0e5SDag-Erling Smørgrav 		/* If ttl came from $TTL line, then it should be the default.
684*5afab0e5SDag-Erling Smørgrav 		 * (RFC 2308 Section 4)
685*5afab0e5SDag-Erling Smørgrav 		 * Otherwise it "defaults to the last explicitly stated value"
686*5afab0e5SDag-Erling Smørgrav 		 * (RFC 1035 Section 5.1)
687*5afab0e5SDag-Erling Smørgrav 		 */
688*5afab0e5SDag-Erling Smørgrav 		if (ttl_from_TTL)
689*5afab0e5SDag-Erling Smørgrav 			my_ttl = default_ttl;
6907b5038d7SDag-Erling Smørgrav 		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
691*5afab0e5SDag-Erling Smørgrav 				&my_prev, line_nr, &explicit_ttl);
6927b5038d7SDag-Erling Smørgrav #endif
6937b5038d7SDag-Erling Smørgrav 		switch (status) {
6947b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_OK:
695*5afab0e5SDag-Erling Smørgrav #ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
696*5afab0e5SDag-Erling Smørgrav 			if (explicit_ttl) {
697*5afab0e5SDag-Erling Smørgrav 				if (!ttl_from_TTL) {
698*5afab0e5SDag-Erling Smørgrav 					/* No $TTL, so ttl "defaults to the
699*5afab0e5SDag-Erling Smørgrav 					 * last explicitly stated value"
700*5afab0e5SDag-Erling Smørgrav 					 * (RFC 1035 Section 5.1)
701*5afab0e5SDag-Erling Smørgrav 					 */
702*5afab0e5SDag-Erling Smørgrav 					my_ttl = ldns_rr_ttl(cur_rr);
703*5afab0e5SDag-Erling Smørgrav 				}
704*5afab0e5SDag-Erling Smørgrav 			/* When ttl is implicit, try to adhere to the rules as
705*5afab0e5SDag-Erling Smørgrav 			 * much as possible. (also for compatibility with bind)
706*5afab0e5SDag-Erling Smørgrav 			 * This was changed when fixing an issue with ZONEMD
707*5afab0e5SDag-Erling Smørgrav 			 * which hashes the TTL too.
708*5afab0e5SDag-Erling Smørgrav 			 */
709*5afab0e5SDag-Erling Smørgrav 			} else if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SIG
710*5afab0e5SDag-Erling Smørgrav 			       ||  ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_RRSIG) {
711*5afab0e5SDag-Erling Smørgrav 				if (ldns_rr_rd_count(cur_rr) >= 4
712*5afab0e5SDag-Erling Smørgrav 				&&  ldns_rdf_get_type(ldns_rr_rdf(cur_rr, 3)) == LDNS_RDF_TYPE_INT32)
7137b5038d7SDag-Erling Smørgrav 
714*5afab0e5SDag-Erling Smørgrav 					/* SIG without explicit ttl get ttl
715*5afab0e5SDag-Erling Smørgrav 					 * from the original_ttl field
716*5afab0e5SDag-Erling Smørgrav 					 * (RFC 2535 Section 7.2)
717*5afab0e5SDag-Erling Smørgrav 					 *
718*5afab0e5SDag-Erling Smørgrav 					 * Similarly for RRSIG, but stated less
719*5afab0e5SDag-Erling Smørgrav 					 * specifically in the spec.
720*5afab0e5SDag-Erling Smørgrav 					 * (RFC 4034 Section 3)
721*5afab0e5SDag-Erling Smørgrav 					 */
722*5afab0e5SDag-Erling Smørgrav 					ldns_rr_set_ttl(cur_rr,
723*5afab0e5SDag-Erling Smørgrav 					    ldns_rdf2native_int32(
724*5afab0e5SDag-Erling Smørgrav 					        ldns_rr_rdf(rr, 3)));
725*5afab0e5SDag-Erling Smørgrav 
726*5afab0e5SDag-Erling Smørgrav 			} else if (prev_rr
727*5afab0e5SDag-Erling Smørgrav 			       &&  ldns_rr_get_type(prev_rr) == ldns_rr_get_type(cur_rr)
728*5afab0e5SDag-Erling Smørgrav 			       &&  ldns_dname_compare( ldns_rr_owner(prev_rr)
729*5afab0e5SDag-Erling Smørgrav 			                             , ldns_rr_owner(cur_rr)) == 0)
730*5afab0e5SDag-Erling Smørgrav 
731*5afab0e5SDag-Erling Smørgrav 				/* "TTLs of all RRs in an RRSet must be the same"
732*5afab0e5SDag-Erling Smørgrav 				 * (RFC 2881 Section 5.2)
733*5afab0e5SDag-Erling Smørgrav 				 */
734*5afab0e5SDag-Erling Smørgrav 				ldns_rr_set_ttl(cur_rr, ldns_rr_ttl(prev_rr));
735*5afab0e5SDag-Erling Smørgrav 
736*5afab0e5SDag-Erling Smørgrav 			prev_rr = cur_rr;
737*5afab0e5SDag-Erling Smørgrav #endif
7387b5038d7SDag-Erling Smørgrav 			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
7397b5038d7SDag-Erling Smørgrav 			if (status ==
7407b5038d7SDag-Erling Smørgrav 				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
7417b5038d7SDag-Erling Smørgrav 
7427b5038d7SDag-Erling Smørgrav 				if (rr_is_rrsig_covering(cur_rr,
7437b5038d7SDag-Erling Smørgrav 							LDNS_RR_TYPE_NSEC3)){
7447b5038d7SDag-Erling Smørgrav 					ldns_rr_list_push_rr(todo_nsec3_rrsigs,
7457b5038d7SDag-Erling Smørgrav 							cur_rr);
7467b5038d7SDag-Erling Smørgrav 				} else {
7477b5038d7SDag-Erling Smørgrav 					ldns_rr_list_push_rr(todo_nsec3s,
7487b5038d7SDag-Erling Smørgrav 						       	cur_rr);
7497b5038d7SDag-Erling Smørgrav 				}
75017d15b25SDag-Erling Smørgrav 				status = LDNS_STATUS_OK;
75117d15b25SDag-Erling Smørgrav 
7527b5038d7SDag-Erling Smørgrav 			} else if (status != LDNS_STATUS_OK)
7537b5038d7SDag-Erling Smørgrav 				goto error;
7547b5038d7SDag-Erling Smørgrav 
7557b5038d7SDag-Erling Smørgrav 			break;
7567b5038d7SDag-Erling Smørgrav 
757*5afab0e5SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
758*5afab0e5SDag-Erling Smørgrav #ifndef FASTER_DNSSEC_ZONE_NEW_FRM_FP
759*5afab0e5SDag-Erling Smørgrav 			default_ttl = my_ttl;
760*5afab0e5SDag-Erling Smørgrav 			ttl_from_TTL = true;
761*5afab0e5SDag-Erling Smørgrav #endif
762*5afab0e5SDag-Erling Smørgrav 			status = LDNS_STATUS_OK;
763*5afab0e5SDag-Erling Smørgrav 			break;
764*5afab0e5SDag-Erling Smørgrav 
7657b5038d7SDag-Erling Smørgrav 
7667b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
7677b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
7682787e39aSDag-Erling Smørgrav 			status = LDNS_STATUS_OK;
7697b5038d7SDag-Erling Smørgrav 			break;
7707b5038d7SDag-Erling Smørgrav 
7717b5038d7SDag-Erling Smørgrav 		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
7727b5038d7SDag-Erling Smørgrav 			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
7737b5038d7SDag-Erling Smørgrav 			break;
7747b5038d7SDag-Erling Smørgrav 
7757b5038d7SDag-Erling Smørgrav 		default:
7767b5038d7SDag-Erling Smørgrav 			goto error;
7777b5038d7SDag-Erling Smørgrav 		}
7787b5038d7SDag-Erling Smørgrav 	}
7797b5038d7SDag-Erling Smørgrav 
7802787e39aSDag-Erling Smørgrav 	for (i = 0; status == LDNS_STATUS_OK &&
7812787e39aSDag-Erling Smørgrav 			i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
7827b5038d7SDag-Erling Smørgrav 		cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
7837b5038d7SDag-Erling Smørgrav 		status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
784986ba33cSDag-Erling Smørgrav 		if (status == LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
785986ba33cSDag-Erling Smørgrav 			if (!(new_node = LDNS_MALLOC(ldns_rbnode_t))) {
786986ba33cSDag-Erling Smørgrav 				status = LDNS_STATUS_MEM_ERR;
787986ba33cSDag-Erling Smørgrav 				break;
788986ba33cSDag-Erling Smørgrav 			}
789986ba33cSDag-Erling Smørgrav 			new_node->key  = ldns_dname_label(ldns_rr_owner(cur_rr), 0);
790986ba33cSDag-Erling Smørgrav 			new_node->data = cur_rr;
791986ba33cSDag-Erling Smørgrav 			if (!ldns_rbtree_insert(&todo_nsec3_ents, new_node)) {
792986ba33cSDag-Erling Smørgrav 				LDNS_FREE(new_node);
793986ba33cSDag-Erling Smørgrav 				status = LDNS_STATUS_MEM_ERR;
794986ba33cSDag-Erling Smørgrav 				break;
795986ba33cSDag-Erling Smørgrav 			}
796986ba33cSDag-Erling Smørgrav 			status = LDNS_STATUS_OK;
7977b5038d7SDag-Erling Smørgrav 		}
7987b5038d7SDag-Erling Smørgrav 	}
799986ba33cSDag-Erling Smørgrav 	if (todo_nsec3_ents.count > 0)
800986ba33cSDag-Erling Smørgrav 		(void) ldns_dnssec_zone_add_empty_nonterminals_nsec3(
801986ba33cSDag-Erling Smørgrav 				newzone, &todo_nsec3_ents);
8022787e39aSDag-Erling Smørgrav 	for (i = 0; status == LDNS_STATUS_OK &&
803986ba33cSDag-Erling Smørgrav 			i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++) {
8047b5038d7SDag-Erling Smørgrav 		cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
8057b5038d7SDag-Erling Smørgrav 		status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
8067b5038d7SDag-Erling Smørgrav 	}
8077b5038d7SDag-Erling Smørgrav 	if (z) {
8087b5038d7SDag-Erling Smørgrav 		*z = newzone;
8092787e39aSDag-Erling Smørgrav 		newzone = NULL;
8107b5038d7SDag-Erling Smørgrav 	} else {
8117b5038d7SDag-Erling Smørgrav 		ldns_dnssec_zone_free(newzone);
812*5afab0e5SDag-Erling Smørgrav 		newzone = NULL;
8137b5038d7SDag-Erling Smørgrav 	}
8147b5038d7SDag-Erling Smørgrav 
8157b5038d7SDag-Erling Smørgrav error:
8167b5038d7SDag-Erling Smørgrav #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
8177b5038d7SDag-Erling Smørgrav 	if (zone) {
8187b5038d7SDag-Erling Smørgrav 		ldns_zone_free(zone);
8197b5038d7SDag-Erling Smørgrav 	}
8207b5038d7SDag-Erling Smørgrav #endif
8212787e39aSDag-Erling Smørgrav 	ldns_rr_list_free(todo_nsec3_rrsigs);
822986ba33cSDag-Erling Smørgrav 	ldns_traverse_postorder(&todo_nsec3_ents,
823986ba33cSDag-Erling Smørgrav 			ldns_todo_nsec3_ents_node_free, NULL);
8242787e39aSDag-Erling Smørgrav 	ldns_rr_list_free(todo_nsec3s);
8252787e39aSDag-Erling Smørgrav 
8267b5038d7SDag-Erling Smørgrav 	if (my_origin) {
8277b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_origin);
8287b5038d7SDag-Erling Smørgrav 	}
8297b5038d7SDag-Erling Smørgrav 	if (my_prev) {
8307b5038d7SDag-Erling Smørgrav 		ldns_rdf_deep_free(my_prev);
8317b5038d7SDag-Erling Smørgrav 	}
8327b5038d7SDag-Erling Smørgrav 	if (newzone) {
8337b5038d7SDag-Erling Smørgrav 		ldns_dnssec_zone_free(newzone);
8347b5038d7SDag-Erling Smørgrav 	}
8357b5038d7SDag-Erling Smørgrav 	return status;
8367b5038d7SDag-Erling Smørgrav }
8377b5038d7SDag-Erling Smørgrav 
8387b5038d7SDag-Erling Smørgrav ldns_status
839986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
8407b5038d7SDag-Erling Smørgrav 		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
8417b5038d7SDag-Erling Smørgrav {
8427b5038d7SDag-Erling Smørgrav 	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
8437b5038d7SDag-Erling Smørgrav }
8447b5038d7SDag-Erling Smørgrav 
8457b5038d7SDag-Erling Smørgrav static void
8467b5038d7SDag-Erling Smørgrav ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
8477b5038d7SDag-Erling Smørgrav 	(void) arg;
8487b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
8497b5038d7SDag-Erling Smørgrav 	LDNS_FREE(node);
8507b5038d7SDag-Erling Smørgrav }
8517b5038d7SDag-Erling Smørgrav 
8527b5038d7SDag-Erling Smørgrav static void
8537b5038d7SDag-Erling Smørgrav ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
8547b5038d7SDag-Erling Smørgrav 	(void) arg;
8557b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
8567b5038d7SDag-Erling Smørgrav 	LDNS_FREE(node);
8577b5038d7SDag-Erling Smørgrav }
8587b5038d7SDag-Erling Smørgrav 
859*5afab0e5SDag-Erling Smørgrav static void
860*5afab0e5SDag-Erling Smørgrav ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
861*5afab0e5SDag-Erling Smørgrav 	(void) arg;
862*5afab0e5SDag-Erling Smørgrav 	LDNS_FREE(node);
863*5afab0e5SDag-Erling Smørgrav }
864*5afab0e5SDag-Erling Smørgrav 
8657b5038d7SDag-Erling Smørgrav void
8667b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
8677b5038d7SDag-Erling Smørgrav {
8687b5038d7SDag-Erling Smørgrav 	if (zone) {
869*5afab0e5SDag-Erling Smørgrav 		if (zone->hashed_names) {
870*5afab0e5SDag-Erling Smørgrav 			ldns_traverse_postorder(zone->hashed_names,
871*5afab0e5SDag-Erling Smørgrav 					ldns_hashed_names_node_free, NULL);
872*5afab0e5SDag-Erling Smørgrav 			LDNS_FREE(zone->hashed_names);
873*5afab0e5SDag-Erling Smørgrav 		}
8747b5038d7SDag-Erling Smørgrav 		if (zone->names) {
8757b5038d7SDag-Erling Smørgrav 			/* destroy all name structures within the tree */
8767b5038d7SDag-Erling Smørgrav 			ldns_traverse_postorder(zone->names,
8777b5038d7SDag-Erling Smørgrav 						    ldns_dnssec_name_node_free,
8787b5038d7SDag-Erling Smørgrav 						    NULL);
8797b5038d7SDag-Erling Smørgrav 			LDNS_FREE(zone->names);
8807b5038d7SDag-Erling Smørgrav 		}
8817b5038d7SDag-Erling Smørgrav 		LDNS_FREE(zone);
8827b5038d7SDag-Erling Smørgrav 	}
8837b5038d7SDag-Erling Smørgrav }
8847b5038d7SDag-Erling Smørgrav 
8857b5038d7SDag-Erling Smørgrav void
8867b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
8877b5038d7SDag-Erling Smørgrav {
8887b5038d7SDag-Erling Smørgrav 	if (zone) {
889*5afab0e5SDag-Erling Smørgrav 		if (zone->hashed_names) {
890*5afab0e5SDag-Erling Smørgrav 			ldns_traverse_postorder(zone->hashed_names,
891*5afab0e5SDag-Erling Smørgrav 					ldns_hashed_names_node_free, NULL);
892*5afab0e5SDag-Erling Smørgrav 			LDNS_FREE(zone->hashed_names);
893*5afab0e5SDag-Erling Smørgrav 		}
8947b5038d7SDag-Erling Smørgrav 		if (zone->names) {
8957b5038d7SDag-Erling Smørgrav 			/* destroy all name structures within the tree */
8967b5038d7SDag-Erling Smørgrav 			ldns_traverse_postorder(zone->names,
8977b5038d7SDag-Erling Smørgrav 						    ldns_dnssec_name_node_deep_free,
8987b5038d7SDag-Erling Smørgrav 						    NULL);
8997b5038d7SDag-Erling Smørgrav 			LDNS_FREE(zone->names);
9007b5038d7SDag-Erling Smørgrav 		}
9017b5038d7SDag-Erling Smørgrav 		LDNS_FREE(zone);
9027b5038d7SDag-Erling Smørgrav 	}
9037b5038d7SDag-Erling Smørgrav }
9047b5038d7SDag-Erling Smørgrav 
9057b5038d7SDag-Erling Smørgrav /* use for dname comparison in tree */
906d6e492feSDag-Erling Smørgrav int
9077b5038d7SDag-Erling Smørgrav ldns_dname_compare_v(const void *a, const void *b) {
9087b5038d7SDag-Erling Smørgrav 	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
9097b5038d7SDag-Erling Smørgrav }
9107b5038d7SDag-Erling Smørgrav 
91117d15b25SDag-Erling Smørgrav static void
91217d15b25SDag-Erling Smørgrav ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
91317d15b25SDag-Erling Smørgrav 		ldns_dnssec_name* name, ldns_rr* nsec3rr);
91417d15b25SDag-Erling Smørgrav 
91517d15b25SDag-Erling Smørgrav static void
91617d15b25SDag-Erling Smørgrav ldns_dnssec_zone_hashed_names_from_nsec3(
91717d15b25SDag-Erling Smørgrav 		ldns_dnssec_zone* zone, ldns_rr* nsec3rr)
91817d15b25SDag-Erling Smørgrav {
91917d15b25SDag-Erling Smørgrav 	ldns_rbnode_t* current_node;
9207b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name* current_name;
92117d15b25SDag-Erling Smørgrav 
92217d15b25SDag-Erling Smørgrav 	assert(zone != NULL);
92317d15b25SDag-Erling Smørgrav 	assert(nsec3rr != NULL);
92417d15b25SDag-Erling Smørgrav 
92517d15b25SDag-Erling Smørgrav 	if (zone->hashed_names) {
92617d15b25SDag-Erling Smørgrav 		ldns_traverse_postorder(zone->hashed_names,
92717d15b25SDag-Erling Smørgrav 				ldns_hashed_names_node_free, NULL);
92817d15b25SDag-Erling Smørgrav 		LDNS_FREE(zone->hashed_names);
92917d15b25SDag-Erling Smørgrav 	}
93017d15b25SDag-Erling Smørgrav 	zone->_nsec3params = nsec3rr;
93117d15b25SDag-Erling Smørgrav 
93217d15b25SDag-Erling Smørgrav 	/* So this is a NSEC3 zone.
93317d15b25SDag-Erling Smørgrav 	* Calculate hashes for all names already in the zone
93417d15b25SDag-Erling Smørgrav 	*/
93517d15b25SDag-Erling Smørgrav 	zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
93617d15b25SDag-Erling Smørgrav 	if (zone->hashed_names == NULL) {
93717d15b25SDag-Erling Smørgrav 		return;
93817d15b25SDag-Erling Smørgrav 	}
93917d15b25SDag-Erling Smørgrav 	for ( current_node  = ldns_rbtree_first(zone->names)
94017d15b25SDag-Erling Smørgrav 	    ; current_node != LDNS_RBTREE_NULL
94117d15b25SDag-Erling Smørgrav 	    ; current_node  = ldns_rbtree_next(current_node)
94217d15b25SDag-Erling Smørgrav 	    ) {
94317d15b25SDag-Erling Smørgrav 		current_name = (ldns_dnssec_name *) current_node->data;
94417d15b25SDag-Erling Smørgrav 		ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr);
94517d15b25SDag-Erling Smørgrav 
94617d15b25SDag-Erling Smørgrav 	}
94717d15b25SDag-Erling Smørgrav }
94817d15b25SDag-Erling Smørgrav 
94917d15b25SDag-Erling Smørgrav static void
95017d15b25SDag-Erling Smørgrav ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
95117d15b25SDag-Erling Smørgrav 		ldns_dnssec_name* name, ldns_rr* nsec3rr)
95217d15b25SDag-Erling Smørgrav {
95317d15b25SDag-Erling Smørgrav 	ldns_rbnode_t* new_node;
95417d15b25SDag-Erling Smørgrav 
95517d15b25SDag-Erling Smørgrav 	assert(name != NULL);
95617d15b25SDag-Erling Smørgrav 	if (! zone->_nsec3params) {
95717d15b25SDag-Erling Smørgrav 		if (! nsec3rr) {
95817d15b25SDag-Erling Smørgrav 			return;
95917d15b25SDag-Erling Smørgrav 		}
96017d15b25SDag-Erling Smørgrav 		ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr);
96117d15b25SDag-Erling Smørgrav 
96217d15b25SDag-Erling Smørgrav 	} else if (! nsec3rr) {
96317d15b25SDag-Erling Smørgrav 		nsec3rr = zone->_nsec3params;
96417d15b25SDag-Erling Smørgrav 	}
96517d15b25SDag-Erling Smørgrav 	name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name);
96617d15b25SDag-Erling Smørgrav 
96717d15b25SDag-Erling Smørgrav 	/* Also store in zone->hashed_names */
96817d15b25SDag-Erling Smørgrav 	if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) {
96917d15b25SDag-Erling Smørgrav 
97017d15b25SDag-Erling Smørgrav 		new_node->key  = name->hashed_name;
97117d15b25SDag-Erling Smørgrav 		new_node->data = name;
97217d15b25SDag-Erling Smørgrav 
97317d15b25SDag-Erling Smørgrav 		if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) {
97417d15b25SDag-Erling Smørgrav 
97517d15b25SDag-Erling Smørgrav 				LDNS_FREE(new_node);
97617d15b25SDag-Erling Smørgrav 		}
97717d15b25SDag-Erling Smørgrav 	}
97817d15b25SDag-Erling Smørgrav }
97917d15b25SDag-Erling Smørgrav 
98017d15b25SDag-Erling Smørgrav 
98117d15b25SDag-Erling Smørgrav static ldns_rbnode_t *
98217d15b25SDag-Erling Smørgrav ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) {
9837b5038d7SDag-Erling Smørgrav 	ldns_rdf *hashed_name;
984*5afab0e5SDag-Erling Smørgrav 	ldns_rbnode_t *to_return;
9857b5038d7SDag-Erling Smørgrav 
98617d15b25SDag-Erling Smørgrav 	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){
9877b5038d7SDag-Erling Smørgrav 
98817d15b25SDag-Erling Smørgrav 		ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr);
9897b5038d7SDag-Erling Smørgrav 	}
99017d15b25SDag-Erling Smørgrav 	if (zone->hashed_names == NULL) {
9917b5038d7SDag-Erling Smørgrav 		return NULL;
9927b5038d7SDag-Erling Smørgrav 	}
993*5afab0e5SDag-Erling Smørgrav 	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
994*5afab0e5SDag-Erling Smørgrav 	if (hashed_name == NULL) {
995*5afab0e5SDag-Erling Smørgrav 		return NULL;
996*5afab0e5SDag-Erling Smørgrav 	}
997*5afab0e5SDag-Erling Smørgrav 	to_return = ldns_rbtree_search(zone->hashed_names, hashed_name);
998*5afab0e5SDag-Erling Smørgrav 	ldns_rdf_deep_free(hashed_name);
999*5afab0e5SDag-Erling Smørgrav 	return to_return;
100017d15b25SDag-Erling Smørgrav }
10017b5038d7SDag-Erling Smørgrav 
10027b5038d7SDag-Erling Smørgrav ldns_status
10037b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
10047b5038d7SDag-Erling Smørgrav {
10057b5038d7SDag-Erling Smørgrav 	ldns_status result = LDNS_STATUS_OK;
10067b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *cur_name;
10077b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *cur_node;
10087b5038d7SDag-Erling Smørgrav 	ldns_rr_type type_covered = 0;
10097b5038d7SDag-Erling Smørgrav 
10107b5038d7SDag-Erling Smørgrav 	if (!zone || !rr) {
10117b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
10127b5038d7SDag-Erling Smørgrav 	}
10137b5038d7SDag-Erling Smørgrav 
10147b5038d7SDag-Erling Smørgrav 	if (!zone->names) {
10157b5038d7SDag-Erling Smørgrav 		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
10167b5038d7SDag-Erling Smørgrav                 if(!zone->names) return LDNS_STATUS_MEM_ERR;
10177b5038d7SDag-Erling Smørgrav 	}
10187b5038d7SDag-Erling Smørgrav 
10197b5038d7SDag-Erling Smørgrav 	/* we need the original of the hashed name if this is
10207b5038d7SDag-Erling Smørgrav 	   an NSEC3, or an RRSIG that covers an NSEC3 */
10217b5038d7SDag-Erling Smørgrav 	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
10227b5038d7SDag-Erling Smørgrav 		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
10237b5038d7SDag-Erling Smørgrav 	}
10247b5038d7SDag-Erling Smørgrav 	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
10257b5038d7SDag-Erling Smørgrav 	    type_covered == LDNS_RR_TYPE_NSEC3) {
102617d15b25SDag-Erling Smørgrav 		cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr);
10277b5038d7SDag-Erling Smørgrav 		if (!cur_node) {
10287b5038d7SDag-Erling Smørgrav 			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
10297b5038d7SDag-Erling Smørgrav 		}
10307b5038d7SDag-Erling Smørgrav 	} else {
10317b5038d7SDag-Erling Smørgrav 		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
10327b5038d7SDag-Erling Smørgrav 	}
10337b5038d7SDag-Erling Smørgrav 	if (!cur_node) {
10347b5038d7SDag-Erling Smørgrav 		/* add */
10357b5038d7SDag-Erling Smørgrav 		cur_name = ldns_dnssec_name_new_frm_rr(rr);
10367b5038d7SDag-Erling Smørgrav                 if(!cur_name) return LDNS_STATUS_MEM_ERR;
10377b5038d7SDag-Erling Smørgrav 		cur_node = LDNS_MALLOC(ldns_rbnode_t);
10387b5038d7SDag-Erling Smørgrav                 if(!cur_node) {
10397b5038d7SDag-Erling Smørgrav                         ldns_dnssec_name_free(cur_name);
10407b5038d7SDag-Erling Smørgrav                         return LDNS_STATUS_MEM_ERR;
10417b5038d7SDag-Erling Smørgrav                 }
10427b5038d7SDag-Erling Smørgrav 		cur_node->key = ldns_rr_owner(rr);
10437b5038d7SDag-Erling Smørgrav 		cur_node->data = cur_name;
10447b5038d7SDag-Erling Smørgrav 		(void)ldns_rbtree_insert(zone->names, cur_node);
104517d15b25SDag-Erling Smørgrav 		ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL);
10467b5038d7SDag-Erling Smørgrav 	} else {
10477b5038d7SDag-Erling Smørgrav 		cur_name = (ldns_dnssec_name *) cur_node->data;
10487b5038d7SDag-Erling Smørgrav 		result = ldns_dnssec_name_add_rr(cur_name, rr);
10497b5038d7SDag-Erling Smørgrav 	}
10507b5038d7SDag-Erling Smørgrav 	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
10517b5038d7SDag-Erling Smørgrav 		zone->soa = cur_name;
10527b5038d7SDag-Erling Smørgrav 	}
10537b5038d7SDag-Erling Smørgrav 	return result;
10547b5038d7SDag-Erling Smørgrav }
10557b5038d7SDag-Erling Smørgrav 
10567b5038d7SDag-Erling Smørgrav void
10577b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
1058986ba33cSDag-Erling Smørgrav 		const ldns_rbtree_t *tree,
10597b5038d7SDag-Erling Smørgrav 		bool print_soa)
10607b5038d7SDag-Erling Smørgrav {
10617b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *node;
10627b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *name;
10637b5038d7SDag-Erling Smørgrav 
10647b5038d7SDag-Erling Smørgrav 	node = ldns_rbtree_first(tree);
10657b5038d7SDag-Erling Smørgrav 	while (node != LDNS_RBTREE_NULL) {
10667b5038d7SDag-Erling Smørgrav 		name = (ldns_dnssec_name *) node->data;
10677b5038d7SDag-Erling Smørgrav 		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
10687b5038d7SDag-Erling Smørgrav 		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
10697b5038d7SDag-Erling Smørgrav 			fprintf(out, ";\n");
10707b5038d7SDag-Erling Smørgrav 		node = ldns_rbtree_next(node);
10717b5038d7SDag-Erling Smørgrav 	}
10727b5038d7SDag-Erling Smørgrav }
10737b5038d7SDag-Erling Smørgrav 
10747b5038d7SDag-Erling Smørgrav void
1075986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_names_print(FILE *out, const ldns_rbtree_t *tree, bool print_soa)
10767b5038d7SDag-Erling Smørgrav {
10777b5038d7SDag-Erling Smørgrav 	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
10787b5038d7SDag-Erling Smørgrav 		       tree, print_soa);
10797b5038d7SDag-Erling Smørgrav }
10807b5038d7SDag-Erling Smørgrav 
10817b5038d7SDag-Erling Smørgrav void
10827b5038d7SDag-Erling Smørgrav ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
1083986ba33cSDag-Erling Smørgrav 	       const ldns_dnssec_zone *zone)
10847b5038d7SDag-Erling Smørgrav {
10857b5038d7SDag-Erling Smørgrav 	if (zone) {
10867b5038d7SDag-Erling Smørgrav 		if (zone->soa) {
10877b5038d7SDag-Erling Smørgrav 			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
10887b5038d7SDag-Erling Smørgrav 				fprintf(out, ";; Zone: ");
10897b5038d7SDag-Erling Smørgrav 				ldns_rdf_print(out, ldns_dnssec_name_name(
10907b5038d7SDag-Erling Smørgrav 							zone->soa));
10917b5038d7SDag-Erling Smørgrav 				fprintf(out, "\n;\n");
10927b5038d7SDag-Erling Smørgrav 			}
10937b5038d7SDag-Erling Smørgrav 			ldns_dnssec_rrsets_print_fmt(out, fmt,
10947b5038d7SDag-Erling Smørgrav 					ldns_dnssec_name_find_rrset(
10957b5038d7SDag-Erling Smørgrav 						zone->soa,
10967b5038d7SDag-Erling Smørgrav 						LDNS_RR_TYPE_SOA),
10977b5038d7SDag-Erling Smørgrav 					false);
10987b5038d7SDag-Erling Smørgrav 			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
10997b5038d7SDag-Erling Smørgrav 				fprintf(out, ";\n");
11007b5038d7SDag-Erling Smørgrav 		}
11017b5038d7SDag-Erling Smørgrav 
11027b5038d7SDag-Erling Smørgrav 		if (zone->names) {
11037b5038d7SDag-Erling Smørgrav 			ldns_dnssec_zone_names_print_fmt(out, fmt,
11047b5038d7SDag-Erling Smørgrav 					zone->names, false);
11057b5038d7SDag-Erling Smørgrav 		}
11067b5038d7SDag-Erling Smørgrav 	}
11077b5038d7SDag-Erling Smørgrav }
11087b5038d7SDag-Erling Smørgrav 
11097b5038d7SDag-Erling Smørgrav void
1110986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_print(FILE *out, const ldns_dnssec_zone *zone)
11117b5038d7SDag-Erling Smørgrav {
11127b5038d7SDag-Erling Smørgrav 	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
11137b5038d7SDag-Erling Smørgrav }
11147b5038d7SDag-Erling Smørgrav 
1115986ba33cSDag-Erling Smørgrav static ldns_status
1116986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_add_empty_nonterminals_nsec3(
1117986ba33cSDag-Erling Smørgrav 		ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s)
11187b5038d7SDag-Erling Smørgrav {
11197b5038d7SDag-Erling Smørgrav 	ldns_dnssec_name *new_name;
11207b5038d7SDag-Erling Smørgrav 	ldns_rdf *cur_name;
11217b5038d7SDag-Erling Smørgrav 	ldns_rdf *next_name;
11227b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t *cur_node, *next_node, *new_node;
11237b5038d7SDag-Erling Smørgrav 
11247b5038d7SDag-Erling Smørgrav 	/* for the detection */
11257b5038d7SDag-Erling Smørgrav 	uint16_t i, cur_label_count, next_label_count;
11267b5038d7SDag-Erling Smørgrav 	uint16_t soa_label_count = 0;
11277b5038d7SDag-Erling Smørgrav 	ldns_rdf *l1, *l2;
11287b5038d7SDag-Erling Smørgrav 	int lpos;
11297b5038d7SDag-Erling Smørgrav 
11307b5038d7SDag-Erling Smørgrav 	if (!zone) {
11317b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
11327b5038d7SDag-Erling Smørgrav 	}
11337b5038d7SDag-Erling Smørgrav 	if (zone->soa && zone->soa->name) {
11347b5038d7SDag-Erling Smørgrav 		soa_label_count = ldns_dname_label_count(zone->soa->name);
11357b5038d7SDag-Erling Smørgrav 	}
11367b5038d7SDag-Erling Smørgrav 
11377b5038d7SDag-Erling Smørgrav 	cur_node = ldns_rbtree_first(zone->names);
11387b5038d7SDag-Erling Smørgrav 	while (cur_node != LDNS_RBTREE_NULL) {
11397b5038d7SDag-Erling Smørgrav 		next_node = ldns_rbtree_next(cur_node);
11407b5038d7SDag-Erling Smørgrav 
11417b5038d7SDag-Erling Smørgrav 		/* skip glue */
11427b5038d7SDag-Erling Smørgrav 		while (next_node != LDNS_RBTREE_NULL &&
11437b5038d7SDag-Erling Smørgrav 		       next_node->data &&
11447b5038d7SDag-Erling Smørgrav 		       ((ldns_dnssec_name *)next_node->data)->is_glue
11457b5038d7SDag-Erling Smørgrav 		) {
11467b5038d7SDag-Erling Smørgrav 			next_node = ldns_rbtree_next(next_node);
11477b5038d7SDag-Erling Smørgrav 		}
11487b5038d7SDag-Erling Smørgrav 
11497b5038d7SDag-Erling Smørgrav 		if (next_node == LDNS_RBTREE_NULL) {
11507b5038d7SDag-Erling Smørgrav 			next_node = ldns_rbtree_first(zone->names);
11517b5038d7SDag-Erling Smørgrav 		}
11522787e39aSDag-Erling Smørgrav 		if (! cur_node->data || ! next_node->data) {
11532787e39aSDag-Erling Smørgrav 			return LDNS_STATUS_ERR;
11542787e39aSDag-Erling Smørgrav 		}
11557b5038d7SDag-Erling Smørgrav 		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
11567b5038d7SDag-Erling Smørgrav 		next_name = ((ldns_dnssec_name *)next_node->data)->name;
11577b5038d7SDag-Erling Smørgrav 		cur_label_count = ldns_dname_label_count(cur_name);
11587b5038d7SDag-Erling Smørgrav 		next_label_count = ldns_dname_label_count(next_name);
11597b5038d7SDag-Erling Smørgrav 
11607b5038d7SDag-Erling Smørgrav 		/* Since the names are in canonical order, we can
11617b5038d7SDag-Erling Smørgrav 		 * recognize empty non-terminals by their labels;
11627b5038d7SDag-Erling Smørgrav 		 * every label after the first one on the next owner
11637b5038d7SDag-Erling Smørgrav 		 * name is a non-terminal if it either does not exist
11647b5038d7SDag-Erling Smørgrav 		 * in the current name or is different from the same
11657b5038d7SDag-Erling Smørgrav 		 * label in the current name (counting from the end)
11667b5038d7SDag-Erling Smørgrav 		 */
11677b5038d7SDag-Erling Smørgrav 		for (i = 1; i < next_label_count - soa_label_count; i++) {
11687b5038d7SDag-Erling Smørgrav 			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
11697b5038d7SDag-Erling Smørgrav 			if (lpos >= 0) {
11707b5038d7SDag-Erling Smørgrav 				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
11717b5038d7SDag-Erling Smørgrav 			} else {
11727b5038d7SDag-Erling Smørgrav 				l1 = NULL;
11737b5038d7SDag-Erling Smørgrav 			}
11747b5038d7SDag-Erling Smørgrav 			l2 = ldns_dname_clone_from(next_name, i);
11757b5038d7SDag-Erling Smørgrav 
11767b5038d7SDag-Erling Smørgrav 			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
11777b5038d7SDag-Erling Smørgrav 				/* We have an empty nonterminal, add it to the
11787b5038d7SDag-Erling Smørgrav 				 * tree
11797b5038d7SDag-Erling Smørgrav 				 */
1180986ba33cSDag-Erling Smørgrav 				ldns_rbnode_t *node = NULL;
1181986ba33cSDag-Erling Smørgrav 				ldns_rdf *ent_name;
1182986ba33cSDag-Erling Smørgrav 
1183986ba33cSDag-Erling Smørgrav 				if (!(ent_name = ldns_dname_clone_from(
1184*5afab0e5SDag-Erling Smørgrav 						next_name, i))) {
1185*5afab0e5SDag-Erling Smørgrav 
1186*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l1);
1187*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l2);
1188986ba33cSDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
1189*5afab0e5SDag-Erling Smørgrav 				}
1190986ba33cSDag-Erling Smørgrav 
1191986ba33cSDag-Erling Smørgrav 				if (nsec3s && zone->_nsec3params) {
1192986ba33cSDag-Erling Smørgrav 					ldns_rdf *ent_hashed_name;
1193986ba33cSDag-Erling Smørgrav 
1194986ba33cSDag-Erling Smørgrav 					if (!(ent_hashed_name =
1195986ba33cSDag-Erling Smørgrav 					    ldns_nsec3_hash_name_frm_nsec3(
1196986ba33cSDag-Erling Smørgrav 							zone->_nsec3params,
1197*5afab0e5SDag-Erling Smørgrav 							ent_name))) {
1198*5afab0e5SDag-Erling Smørgrav 						ldns_rdf_deep_free(l1);
1199*5afab0e5SDag-Erling Smørgrav 						ldns_rdf_deep_free(l2);
1200*5afab0e5SDag-Erling Smørgrav 						ldns_rdf_deep_free(ent_name);
1201986ba33cSDag-Erling Smørgrav 						return LDNS_STATUS_MEM_ERR;
1202*5afab0e5SDag-Erling Smørgrav 					}
1203986ba33cSDag-Erling Smørgrav 					node = ldns_rbtree_search(nsec3s,
1204986ba33cSDag-Erling Smørgrav 							ent_hashed_name);
1205*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(ent_hashed_name);
1206986ba33cSDag-Erling Smørgrav 					if (!node) {
1207986ba33cSDag-Erling Smørgrav 						ldns_rdf_deep_free(l1);
1208986ba33cSDag-Erling Smørgrav 						ldns_rdf_deep_free(l2);
1209*5afab0e5SDag-Erling Smørgrav 						ldns_rdf_deep_free(ent_name);
1210986ba33cSDag-Erling Smørgrav 						continue;
1211986ba33cSDag-Erling Smørgrav 					}
1212986ba33cSDag-Erling Smørgrav 				}
12137b5038d7SDag-Erling Smørgrav 				new_name = ldns_dnssec_name_new();
12147b5038d7SDag-Erling Smørgrav 				if (!new_name) {
1215*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l1);
1216*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l2);
1217*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(ent_name);
12187b5038d7SDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
12197b5038d7SDag-Erling Smørgrav 				}
1220986ba33cSDag-Erling Smørgrav 				new_name->name = ent_name;
12217b5038d7SDag-Erling Smørgrav 				new_name->name_alloced = true;
12227b5038d7SDag-Erling Smørgrav 				new_node = LDNS_MALLOC(ldns_rbnode_t);
12237b5038d7SDag-Erling Smørgrav 				if (!new_node) {
1224*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l1);
1225*5afab0e5SDag-Erling Smørgrav 					ldns_rdf_deep_free(l2);
12267b5038d7SDag-Erling Smørgrav 					ldns_dnssec_name_free(new_name);
12277b5038d7SDag-Erling Smørgrav 					return LDNS_STATUS_MEM_ERR;
12287b5038d7SDag-Erling Smørgrav 				}
12297b5038d7SDag-Erling Smørgrav 				new_node->key = new_name->name;
12307b5038d7SDag-Erling Smørgrav 				new_node->data = new_name;
12317b5038d7SDag-Erling Smørgrav 				(void)ldns_rbtree_insert(zone->names, new_node);
123217d15b25SDag-Erling Smørgrav 				ldns_dnssec_name_make_hashed_name(
123317d15b25SDag-Erling Smørgrav 						zone, new_name, NULL);
1234986ba33cSDag-Erling Smørgrav 				if (node)
1235986ba33cSDag-Erling Smørgrav 					(void) ldns_dnssec_zone_add_rr(zone,
1236986ba33cSDag-Erling Smørgrav 							(ldns_rr *)node->data);
12377b5038d7SDag-Erling Smørgrav 			}
12387b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(l1);
12397b5038d7SDag-Erling Smørgrav 			ldns_rdf_deep_free(l2);
12407b5038d7SDag-Erling Smørgrav 		}
12417b5038d7SDag-Erling Smørgrav 
12427b5038d7SDag-Erling Smørgrav 		/* we might have inserted a new node after
12437b5038d7SDag-Erling Smørgrav 		 * the current one so we can't just use next()
12447b5038d7SDag-Erling Smørgrav 		 */
12457b5038d7SDag-Erling Smørgrav 		if (next_node != ldns_rbtree_first(zone->names)) {
12467b5038d7SDag-Erling Smørgrav 			cur_node = next_node;
12477b5038d7SDag-Erling Smørgrav 		} else {
12487b5038d7SDag-Erling Smørgrav 			cur_node = LDNS_RBTREE_NULL;
12497b5038d7SDag-Erling Smørgrav 		}
12507b5038d7SDag-Erling Smørgrav 	}
12517b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
12527b5038d7SDag-Erling Smørgrav }
12537b5038d7SDag-Erling Smørgrav 
1254986ba33cSDag-Erling Smørgrav ldns_status
1255986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
1256986ba33cSDag-Erling Smørgrav {
1257986ba33cSDag-Erling Smørgrav 	return ldns_dnssec_zone_add_empty_nonterminals_nsec3(zone, NULL);
1258986ba33cSDag-Erling Smørgrav }
1259986ba33cSDag-Erling Smørgrav 
12607b5038d7SDag-Erling Smørgrav bool
1261986ba33cSDag-Erling Smørgrav ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone)
12627b5038d7SDag-Erling Smørgrav {
12637b5038d7SDag-Erling Smørgrav 	ldns_rr* nsec3;
12647b5038d7SDag-Erling Smørgrav 	ldns_rbnode_t* node;
12657b5038d7SDag-Erling Smørgrav 
12667b5038d7SDag-Erling Smørgrav 	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
12677b5038d7SDag-Erling Smørgrav 		node = ldns_rbtree_first(zone->names);
12687b5038d7SDag-Erling Smørgrav 		while (node != LDNS_RBTREE_NULL) {
12697b5038d7SDag-Erling Smørgrav 			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
12707b5038d7SDag-Erling Smørgrav 			if (nsec3 &&ldns_rr_get_type(nsec3)
12717b5038d7SDag-Erling Smørgrav 					== LDNS_RR_TYPE_NSEC3 &&
12727b5038d7SDag-Erling Smørgrav 					ldns_nsec3_optout(nsec3)) {
12737b5038d7SDag-Erling Smørgrav 				return true;
12747b5038d7SDag-Erling Smørgrav 			}
12757b5038d7SDag-Erling Smørgrav 			node = ldns_rbtree_next(node);
12767b5038d7SDag-Erling Smørgrav 		}
12777b5038d7SDag-Erling Smørgrav 	}
12787b5038d7SDag-Erling Smørgrav 	return false;
12797b5038d7SDag-Erling Smørgrav }
1280*5afab0e5SDag-Erling Smørgrav 
1281*5afab0e5SDag-Erling Smørgrav /*
1282*5afab0e5SDag-Erling Smørgrav  * Stuff for calculating and verifying zone digests
1283*5afab0e5SDag-Erling Smørgrav  */
1284*5afab0e5SDag-Erling Smørgrav typedef enum dnssec_zone_rr_iter_state {
1285*5afab0e5SDag-Erling Smørgrav 	  DNSSEC_ZONE_RR_ITER_LT_RRSIG
1286*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
1287*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_REST
1288*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC
1289*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST
1290*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_NSEC3
1291*5afab0e5SDag-Erling Smørgrav 	, DNSSEC_ZONE_RR_ITER_FINI
1292*5afab0e5SDag-Erling Smørgrav } dnssec_zone_rr_iter_state;
1293*5afab0e5SDag-Erling Smørgrav 
1294*5afab0e5SDag-Erling Smørgrav typedef struct dnssec_zone_rr_iter {
1295*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_zone         *zone;
1296*5afab0e5SDag-Erling Smørgrav 	ldns_rbnode_t            *node;
1297*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_name         *name;
1298*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets       *rrsets;
1299*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrs          *rrs;
1300*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets       *rrsets4rrsigs;
1301*5afab0e5SDag-Erling Smørgrav 	ldns_rbnode_t            *nsec3_node;
1302*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_name         *nsec3_name;
1303*5afab0e5SDag-Erling Smørgrav 	dnssec_zone_rr_iter_state state;
1304*5afab0e5SDag-Erling Smørgrav 	ldns_rdf                 *apex_name;
1305*5afab0e5SDag-Erling Smørgrav 	uint8_t                   apex_labs;
1306*5afab0e5SDag-Erling Smørgrav } dnssec_zone_rr_iter;
1307*5afab0e5SDag-Erling Smørgrav 
1308*5afab0e5SDag-Erling Smørgrav INLINE void
1309*5afab0e5SDag-Erling Smørgrav dnssec_zone_rr_iter_set_state_for_next_name(dnssec_zone_rr_iter *i)
1310*5afab0e5SDag-Erling Smørgrav {
1311*5afab0e5SDag-Erling Smørgrav 	/* Make sure the i->name is "in zone" (i.e. below the apex) */
1312*5afab0e5SDag-Erling Smørgrav 	if (i->apex_name) {
1313*5afab0e5SDag-Erling Smørgrav 		ldns_rdf *name = (ldns_rdf *)i->node->key;
1314*5afab0e5SDag-Erling Smørgrav 
1315*5afab0e5SDag-Erling Smørgrav 		while (i->name && name != i->apex_name        /* not apex */
1316*5afab0e5SDag-Erling Smørgrav 
1317*5afab0e5SDag-Erling Smørgrav 		&& (  ldns_dname_label_count(name) != i->apex_labs
1318*5afab0e5SDag-Erling Smørgrav 		   || ldns_dname_compare(name, i->apex_name)) /* not apex */
1319*5afab0e5SDag-Erling Smørgrav 
1320*5afab0e5SDag-Erling Smørgrav 		&& !ldns_dname_is_subdomain(name, i->apex_name) /* no sub */) {
1321*5afab0e5SDag-Erling Smørgrav 
1322*5afab0e5SDag-Erling Smørgrav 			/* next name */
1323*5afab0e5SDag-Erling Smørgrav 			i->node = ldns_rbtree_next(i->node);
1324*5afab0e5SDag-Erling Smørgrav 			if (i->node == LDNS_RBTREE_NULL)
1325*5afab0e5SDag-Erling Smørgrav 				i->name = NULL;
1326*5afab0e5SDag-Erling Smørgrav 			else {
1327*5afab0e5SDag-Erling Smørgrav 				i->name = (ldns_dnssec_name *)i->node->data;
1328*5afab0e5SDag-Erling Smørgrav 				name = (ldns_rdf *)i->node->key;
1329*5afab0e5SDag-Erling Smørgrav 			}
1330*5afab0e5SDag-Erling Smørgrav 		}
1331*5afab0e5SDag-Erling Smørgrav 	}
1332*5afab0e5SDag-Erling Smørgrav 	/* determine state */
1333*5afab0e5SDag-Erling Smørgrav 	if (!i->name) {
1334*5afab0e5SDag-Erling Smørgrav 		if (!i->nsec3_name)
1335*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_FINI;
1336*5afab0e5SDag-Erling Smørgrav 		else {
1337*5afab0e5SDag-Erling Smørgrav 			i->rrs = i->nsec3_name->nsec_signatures;
1338*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_NSEC3;
1339*5afab0e5SDag-Erling Smørgrav 		}
1340*5afab0e5SDag-Erling Smørgrav 	} else if (!i->nsec3_name) {
1341*5afab0e5SDag-Erling Smørgrav 		i->rrsets = i->name->rrsets;
1342*5afab0e5SDag-Erling Smørgrav 		i->state = DNSSEC_ZONE_RR_ITER_LT_RRSIG;
1343*5afab0e5SDag-Erling Smørgrav 
1344*5afab0e5SDag-Erling Smørgrav 	} else if (ldns_dname_compare( ldns_rr_owner(i->nsec3_name->nsec)
1345*5afab0e5SDag-Erling Smørgrav 	                             , (ldns_rdf *)i->node->key) < 0) {
1346*5afab0e5SDag-Erling Smørgrav 		i->rrs = i->nsec3_name->nsec_signatures;
1347*5afab0e5SDag-Erling Smørgrav 		i->state = DNSSEC_ZONE_RR_ITER_NSEC3;
1348*5afab0e5SDag-Erling Smørgrav 	} else {
1349*5afab0e5SDag-Erling Smørgrav 		i->rrsets = i->name->rrsets;
1350*5afab0e5SDag-Erling Smørgrav 		i->state = DNSSEC_ZONE_RR_ITER_LT_RRSIG;
1351*5afab0e5SDag-Erling Smørgrav 	}
1352*5afab0e5SDag-Erling Smørgrav }
1353*5afab0e5SDag-Erling Smørgrav 
1354*5afab0e5SDag-Erling Smørgrav /**
1355*5afab0e5SDag-Erling Smørgrav  * Iterate over the RR's in the ldns_dnssec_zone in canonical order.
1356*5afab0e5SDag-Erling Smørgrav  * There are three possible paths through the RR's in a ldns_dnssec_name.
1357*5afab0e5SDag-Erling Smørgrav  *
1358*5afab0e5SDag-Erling Smørgrav  * 1. There is no NSEC:
1359*5afab0e5SDag-Erling Smørgrav  *
1360*5afab0e5SDag-Erling Smørgrav  *    1.1. All the RRs in the name->rrsets with type < RRSIG,
1361*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_LT_RRSIG
1362*5afab0e5SDag-Erling Smørgrav  *
1363*5afab0e5SDag-Erling Smørgrav  *    1.2. Then all the RRSIGs from name->rrsets (likely none)
1364*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
1365*5afab0e5SDag-Erling Smørgrav  *
1366*5afab0e5SDag-Erling Smørgrav  *    1.3. Finally the remaining RRs in name->rrsets (type > RRSIG)
1367*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_REST
1368*5afab0e5SDag-Erling Smørgrav  *
1369*5afab0e5SDag-Erling Smørgrav  *
1370*5afab0e5SDag-Erling Smørgrav  * 2. There is a NSEC of type NSEC with this name:
1371*5afab0e5SDag-Erling Smørgrav  *
1372*5afab0e5SDag-Erling Smørgrav  *    2.1. All the RRs in the name->rrsets with type < RRSIG,
1373*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_LT_RRSIG
1374*5afab0e5SDag-Erling Smørgrav  *
1375*5afab0e5SDag-Erling Smørgrav  *    2.2. Then all the RRSIGs from name->rrsets with type < NSEC
1376*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
1377*5afab0e5SDag-Erling Smørgrav  *
1378*5afab0e5SDag-Erling Smørgrav  *    2.3. Then the signatures of the NSEC RR, followed by
1379*5afab0e5SDag-Erling Smørgrav  *         the signatures of the remaining name->rrsets (type > NSEC),
1380*5afab0e5SDag-Erling Smørgrav  *         followed by the NSEC rr.
1381*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC
1382*5afab0e5SDag-Erling Smørgrav  *
1383*5afab0e5SDag-Erling Smørgrav  *    2.4. Finally the remaining RRs in name->rrsets (type > RRSIG)
1384*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_REST
1385*5afab0e5SDag-Erling Smørgrav  *
1386*5afab0e5SDag-Erling Smørgrav  *
1387*5afab0e5SDag-Erling Smørgrav  * 3. There is a NSEC of type NSEC3 for this name:
1388*5afab0e5SDag-Erling Smørgrav  *
1389*5afab0e5SDag-Erling Smørgrav  *    3.1. If the NSEC3 name is before the name for other RRsets in the zone,
1390*5afab0e5SDag-Erling Smørgrav  *         Then all signatures of the NSEC3 RR, followed by the NSEC3
1391*5afab0e5SDag-Erling Smørgrav  *         state: DNSSEC_ZONE_RR_ITER_NSEC3
1392*5afab0e5SDag-Erling Smørgrav  *
1393*5afab0e5SDag-Erling Smørgrav  *         otherwise follow path for "no NSEC" for the name for other RRsets
1394*5afab0e5SDag-Erling Smørgrav  */
1395*5afab0e5SDag-Erling Smørgrav static ldns_rr *
1396*5afab0e5SDag-Erling Smørgrav dnssec_zone_rr_iter_next(dnssec_zone_rr_iter *i)
1397*5afab0e5SDag-Erling Smørgrav {
1398*5afab0e5SDag-Erling Smørgrav 	ldns_rr *nsec3;
1399*5afab0e5SDag-Erling Smørgrav 
1400*5afab0e5SDag-Erling Smørgrav 	for (;;) {
1401*5afab0e5SDag-Erling Smørgrav 		if (i->rrs) {
1402*5afab0e5SDag-Erling Smørgrav 			ldns_rr *rr = i->rrs->rr;
1403*5afab0e5SDag-Erling Smørgrav 			i->rrs = i->rrs->next;
1404*5afab0e5SDag-Erling Smørgrav 			return rr;
1405*5afab0e5SDag-Erling Smørgrav 		}
1406*5afab0e5SDag-Erling Smørgrav 		switch (i->state) {
1407*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_LT_RRSIG:
1408*5afab0e5SDag-Erling Smørgrav 			if (i->rrsets
1409*5afab0e5SDag-Erling Smørgrav 			&&  i->rrsets->type < LDNS_RR_TYPE_RRSIG) {
1410*5afab0e5SDag-Erling Smørgrav 
1411*5afab0e5SDag-Erling Smørgrav 				i->rrs = i->rrsets->rrs;
1412*5afab0e5SDag-Erling Smørgrav 				i->rrsets = i->rrsets->next;
1413*5afab0e5SDag-Erling Smørgrav 				break;
1414*5afab0e5SDag-Erling Smørgrav 			}
1415*5afab0e5SDag-Erling Smørgrav 			i->rrsets4rrsigs = i->name->rrsets;
1416*5afab0e5SDag-Erling Smørgrav 			if (i->name->nsec && ldns_rr_get_type(i->name->nsec)
1417*5afab0e5SDag-Erling Smørgrav 			                               == LDNS_RR_TYPE_NSEC) {
1418*5afab0e5SDag-Erling Smørgrav 
1419*5afab0e5SDag-Erling Smørgrav 				i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC;
1420*5afab0e5SDag-Erling Smørgrav 				break;
1421*5afab0e5SDag-Erling Smørgrav 			}
1422*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC;
1423*5afab0e5SDag-Erling Smørgrav 			/* fallthrough */
1424*5afab0e5SDag-Erling Smørgrav 
1425*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_RRSIGs_NO_NSEC:
1426*5afab0e5SDag-Erling Smørgrav 			if (i->rrsets4rrsigs) {
1427*5afab0e5SDag-Erling Smørgrav 				i->rrs = i->rrsets4rrsigs->signatures;
1428*5afab0e5SDag-Erling Smørgrav 				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
1429*5afab0e5SDag-Erling Smørgrav 				break;
1430*5afab0e5SDag-Erling Smørgrav 			}
1431*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_REST;
1432*5afab0e5SDag-Erling Smørgrav 			/* fallthrough */
1433*5afab0e5SDag-Erling Smørgrav 
1434*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_REST:
1435*5afab0e5SDag-Erling Smørgrav 			if (i->rrsets) {
1436*5afab0e5SDag-Erling Smørgrav 				i->rrs = i->rrsets->rrs;
1437*5afab0e5SDag-Erling Smørgrav 				i->rrsets = i->rrsets->next;
1438*5afab0e5SDag-Erling Smørgrav 				break;
1439*5afab0e5SDag-Erling Smørgrav 			}
1440*5afab0e5SDag-Erling Smørgrav 			/* next name */
1441*5afab0e5SDag-Erling Smørgrav 			i->node = ldns_rbtree_next(i->node);
1442*5afab0e5SDag-Erling Smørgrav 			i->name = i->node == LDNS_RBTREE_NULL ? NULL
1443*5afab0e5SDag-Erling Smørgrav 				: (ldns_dnssec_name *)i->node->data;
1444*5afab0e5SDag-Erling Smørgrav 
1445*5afab0e5SDag-Erling Smørgrav 			dnssec_zone_rr_iter_set_state_for_next_name(i);
1446*5afab0e5SDag-Erling Smørgrav 			break;
1447*5afab0e5SDag-Erling Smørgrav 
1448*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC:
1449*5afab0e5SDag-Erling Smørgrav 			if (i->rrsets4rrsigs
1450*5afab0e5SDag-Erling Smørgrav 			&&  i->rrsets4rrsigs->type < LDNS_RR_TYPE_NSEC) {
1451*5afab0e5SDag-Erling Smørgrav 
1452*5afab0e5SDag-Erling Smørgrav 				i->rrs = i->rrsets4rrsigs->signatures;
1453*5afab0e5SDag-Erling Smørgrav 				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
1454*5afab0e5SDag-Erling Smørgrav 				break;
1455*5afab0e5SDag-Erling Smørgrav 			}
1456*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST;
1457*5afab0e5SDag-Erling Smørgrav 			i->rrs = i->name->nsec_signatures;
1458*5afab0e5SDag-Erling Smørgrav 			break;
1459*5afab0e5SDag-Erling Smørgrav 
1460*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_RRSIGs_NSEC_REST:
1461*5afab0e5SDag-Erling Smørgrav 			if (i->rrsets4rrsigs) {
1462*5afab0e5SDag-Erling Smørgrav 				i->rrs = i->rrsets4rrsigs->signatures;
1463*5afab0e5SDag-Erling Smørgrav 				i->rrsets4rrsigs = i->rrsets4rrsigs->next;
1464*5afab0e5SDag-Erling Smørgrav 				break;
1465*5afab0e5SDag-Erling Smørgrav 			}
1466*5afab0e5SDag-Erling Smørgrav 			i->state = DNSSEC_ZONE_RR_ITER_REST;
1467*5afab0e5SDag-Erling Smørgrav 			return i->name->nsec;
1468*5afab0e5SDag-Erling Smørgrav 
1469*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_NSEC3:
1470*5afab0e5SDag-Erling Smørgrav 			nsec3 = i->nsec3_name->nsec;
1471*5afab0e5SDag-Erling Smørgrav 
1472*5afab0e5SDag-Erling Smørgrav 			/* next nsec3 */
1473*5afab0e5SDag-Erling Smørgrav 			do {
1474*5afab0e5SDag-Erling Smørgrav 				i->nsec3_node
1475*5afab0e5SDag-Erling Smørgrav 				    = ldns_rbtree_next(i->nsec3_node);
1476*5afab0e5SDag-Erling Smørgrav 				i->nsec3_name
1477*5afab0e5SDag-Erling Smørgrav 				    = i->nsec3_node == LDNS_RBTREE_NULL ? NULL
1478*5afab0e5SDag-Erling Smørgrav 				    : (ldns_dnssec_name*)i->nsec3_node->data;
1479*5afab0e5SDag-Erling Smørgrav 
1480*5afab0e5SDag-Erling Smørgrav 				/* names for glue can be in the hashed_names
1481*5afab0e5SDag-Erling Smørgrav 				 * tree, but will not have a NSEC3
1482*5afab0e5SDag-Erling Smørgrav 				 */
1483*5afab0e5SDag-Erling Smørgrav 			} while (i->nsec3_name && !i->nsec3_name->nsec);
1484*5afab0e5SDag-Erling Smørgrav 
1485*5afab0e5SDag-Erling Smørgrav 			dnssec_zone_rr_iter_set_state_for_next_name(i);
1486*5afab0e5SDag-Erling Smørgrav 			return nsec3;
1487*5afab0e5SDag-Erling Smørgrav 
1488*5afab0e5SDag-Erling Smørgrav 		case DNSSEC_ZONE_RR_ITER_FINI:
1489*5afab0e5SDag-Erling Smørgrav 			return NULL;
1490*5afab0e5SDag-Erling Smørgrav 		}
1491*5afab0e5SDag-Erling Smørgrav 	}
1492*5afab0e5SDag-Erling Smørgrav }
1493*5afab0e5SDag-Erling Smørgrav 
1494*5afab0e5SDag-Erling Smørgrav static ldns_rr *
1495*5afab0e5SDag-Erling Smørgrav dnssec_zone_rr_iter_first(dnssec_zone_rr_iter *i, ldns_dnssec_zone *zone)
1496*5afab0e5SDag-Erling Smørgrav {
1497*5afab0e5SDag-Erling Smørgrav 	if (!i || !zone)
1498*5afab0e5SDag-Erling Smørgrav 		return NULL;
1499*5afab0e5SDag-Erling Smørgrav 
1500*5afab0e5SDag-Erling Smørgrav 	memset(i, 0, sizeof(*i));
1501*5afab0e5SDag-Erling Smørgrav 	i->zone = zone;
1502*5afab0e5SDag-Erling Smørgrav 	if (zone->soa && zone->soa->name) {
1503*5afab0e5SDag-Erling Smørgrav 		i->apex_name = zone->soa->name;
1504*5afab0e5SDag-Erling Smørgrav 		i->apex_labs = ldns_dname_label_count(i->apex_name);
1505*5afab0e5SDag-Erling Smørgrav 	} else
1506*5afab0e5SDag-Erling Smørgrav 		i->apex_name = NULL;
1507*5afab0e5SDag-Erling Smørgrav 
1508*5afab0e5SDag-Erling Smørgrav 
1509*5afab0e5SDag-Erling Smørgrav 	i->node = ldns_rbtree_first(zone->names);
1510*5afab0e5SDag-Erling Smørgrav 	i->name = i->node == LDNS_RBTREE_NULL ? NULL
1511*5afab0e5SDag-Erling Smørgrav 		: (ldns_dnssec_name *)i->node->data;
1512*5afab0e5SDag-Erling Smørgrav 
1513*5afab0e5SDag-Erling Smørgrav 	if (zone->hashed_names) {
1514*5afab0e5SDag-Erling Smørgrav 		do {
1515*5afab0e5SDag-Erling Smørgrav 			i->nsec3_node = ldns_rbtree_first(zone->hashed_names);
1516*5afab0e5SDag-Erling Smørgrav 			i->nsec3_name = i->nsec3_node == LDNS_RBTREE_NULL ?NULL
1517*5afab0e5SDag-Erling Smørgrav 				      : (ldns_dnssec_name*)i->nsec3_node->data;
1518*5afab0e5SDag-Erling Smørgrav 		} while (i->nsec3_name && !i->nsec3_name->nsec);
1519*5afab0e5SDag-Erling Smørgrav 	}
1520*5afab0e5SDag-Erling Smørgrav 	dnssec_zone_rr_iter_set_state_for_next_name(i);
1521*5afab0e5SDag-Erling Smørgrav 	return dnssec_zone_rr_iter_next(i);
1522*5afab0e5SDag-Erling Smørgrav }
1523*5afab0e5SDag-Erling Smørgrav 
1524*5afab0e5SDag-Erling Smørgrav enum enum_zonemd_scheme {
1525*5afab0e5SDag-Erling Smørgrav         ZONEMD_SCHEME_FIRST  = 1,
1526*5afab0e5SDag-Erling Smørgrav         ZONEMD_SCHEME_SIMPLE = 1,
1527*5afab0e5SDag-Erling Smørgrav         ZONEMD_SCHEME_LAST   = 1
1528*5afab0e5SDag-Erling Smørgrav };
1529*5afab0e5SDag-Erling Smørgrav typedef enum enum_zonemd_scheme zonemd_scheme;
1530*5afab0e5SDag-Erling Smørgrav 
1531*5afab0e5SDag-Erling Smørgrav enum enum_zonemd_hash {
1532*5afab0e5SDag-Erling Smørgrav         ZONEMD_HASH_FIRST  = 1,
1533*5afab0e5SDag-Erling Smørgrav         ZONEMD_HASH_SHA384 = 1,
1534*5afab0e5SDag-Erling Smørgrav         ZONEMD_HASH_SHA512 = 2,
1535*5afab0e5SDag-Erling Smørgrav         ZONEMD_HASH_LAST   = 2
1536*5afab0e5SDag-Erling Smørgrav };
1537*5afab0e5SDag-Erling Smørgrav typedef enum enum_zonemd_hash zonemd_hash;
1538*5afab0e5SDag-Erling Smørgrav 
1539*5afab0e5SDag-Erling Smørgrav struct struct_zone_digester {
1540*5afab0e5SDag-Erling Smørgrav         ldns_sha384_CTX sha384_CTX;
1541*5afab0e5SDag-Erling Smørgrav         ldns_sha512_CTX sha512_CTX;
1542*5afab0e5SDag-Erling Smørgrav         unsigned simple_sha384 : 1;
1543*5afab0e5SDag-Erling Smørgrav         unsigned simple_sha512 : 1;
1544*5afab0e5SDag-Erling Smørgrav         unsigned double_sha384 : 1;
1545*5afab0e5SDag-Erling Smørgrav         unsigned double_sha512 : 1;
1546*5afab0e5SDag-Erling Smørgrav };
1547*5afab0e5SDag-Erling Smørgrav typedef struct struct_zone_digester zone_digester;
1548*5afab0e5SDag-Erling Smørgrav 
1549*5afab0e5SDag-Erling Smørgrav INLINE bool zone_digester_set(zone_digester *zd)
1550*5afab0e5SDag-Erling Smørgrav { return zd && (zd->simple_sha384 || zd->simple_sha512); }
1551*5afab0e5SDag-Erling Smørgrav 
1552*5afab0e5SDag-Erling Smørgrav INLINE void zone_digester_init(zone_digester *zd)
1553*5afab0e5SDag-Erling Smørgrav { memset(zd, 0, sizeof(*zd)); }
1554*5afab0e5SDag-Erling Smørgrav 
1555*5afab0e5SDag-Erling Smørgrav static ldns_status
1556*5afab0e5SDag-Erling Smørgrav zone_digester_add(zone_digester *zd, zonemd_scheme scheme, zonemd_hash hash)
1557*5afab0e5SDag-Erling Smørgrav {
1558*5afab0e5SDag-Erling Smørgrav 	if (!zd)
1559*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
1560*5afab0e5SDag-Erling Smørgrav 
1561*5afab0e5SDag-Erling Smørgrav 	switch (scheme) {
1562*5afab0e5SDag-Erling Smørgrav 	case ZONEMD_SCHEME_SIMPLE:
1563*5afab0e5SDag-Erling Smørgrav 		switch (hash) {
1564*5afab0e5SDag-Erling Smørgrav 		case ZONEMD_HASH_SHA384:
1565*5afab0e5SDag-Erling Smørgrav 			if (zd->double_sha384)
1566*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
1567*5afab0e5SDag-Erling Smørgrav 
1568*5afab0e5SDag-Erling Smørgrav 			else if (zd->simple_sha384) {
1569*5afab0e5SDag-Erling Smørgrav 				zd->simple_sha384 = 0;
1570*5afab0e5SDag-Erling Smørgrav 				zd->double_sha384 = 1;
1571*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
1572*5afab0e5SDag-Erling Smørgrav 			}
1573*5afab0e5SDag-Erling Smørgrav 			ldns_sha384_init(&zd->sha384_CTX);
1574*5afab0e5SDag-Erling Smørgrav 			zd->simple_sha384 = 1;
1575*5afab0e5SDag-Erling Smørgrav 			break;
1576*5afab0e5SDag-Erling Smørgrav 
1577*5afab0e5SDag-Erling Smørgrav 		case ZONEMD_HASH_SHA512:
1578*5afab0e5SDag-Erling Smørgrav 			if (zd->double_sha512)
1579*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
1580*5afab0e5SDag-Erling Smørgrav 
1581*5afab0e5SDag-Erling Smørgrav 			else if (zd->simple_sha512) {
1582*5afab0e5SDag-Erling Smørgrav 				zd->simple_sha512 = 0;
1583*5afab0e5SDag-Erling Smørgrav 				zd->double_sha512 = 1;
1584*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_ZONEMD_DOUBLE_OCCURRENCE;
1585*5afab0e5SDag-Erling Smørgrav 			}
1586*5afab0e5SDag-Erling Smørgrav 			ldns_sha512_init(&zd->sha512_CTX);
1587*5afab0e5SDag-Erling Smørgrav 			zd->simple_sha512 = 1;
1588*5afab0e5SDag-Erling Smørgrav 			break;
1589*5afab0e5SDag-Erling Smørgrav 		default:
1590*5afab0e5SDag-Erling Smørgrav 			return LDNS_STATUS_ZONEMD_UNKNOWN_HASH;
1591*5afab0e5SDag-Erling Smørgrav 		}
1592*5afab0e5SDag-Erling Smørgrav 		break;
1593*5afab0e5SDag-Erling Smørgrav 	default:
1594*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_ZONEMD_UNKNOWN_SCHEME;
1595*5afab0e5SDag-Erling Smørgrav 	}
1596*5afab0e5SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
1597*5afab0e5SDag-Erling Smørgrav }
1598*5afab0e5SDag-Erling Smørgrav 
1599*5afab0e5SDag-Erling Smørgrav static ldns_status
1600*5afab0e5SDag-Erling Smørgrav zone_digester_update(zone_digester *zd, ldns_rr *rr)
1601*5afab0e5SDag-Erling Smørgrav {
1602*5afab0e5SDag-Erling Smørgrav 	uint8_t data[65536];
1603*5afab0e5SDag-Erling Smørgrav 	ldns_buffer buf;
1604*5afab0e5SDag-Erling Smørgrav 	ldns_status st;
1605*5afab0e5SDag-Erling Smørgrav 
1606*5afab0e5SDag-Erling Smørgrav 	buf._data = data;
1607*5afab0e5SDag-Erling Smørgrav 	buf._position = 0;
1608*5afab0e5SDag-Erling Smørgrav 	buf._limit = sizeof(data);
1609*5afab0e5SDag-Erling Smørgrav 	buf._capacity = sizeof(data);
1610*5afab0e5SDag-Erling Smørgrav 	buf._fixed = 1;
1611*5afab0e5SDag-Erling Smørgrav 	buf._status = LDNS_STATUS_OK;
1612*5afab0e5SDag-Erling Smørgrav 
1613*5afab0e5SDag-Erling Smørgrav 	if ((st = ldns_rr2buffer_wire_canonical(&buf, rr, LDNS_SECTION_ANSWER)))
1614*5afab0e5SDag-Erling Smørgrav 		return st;
1615*5afab0e5SDag-Erling Smørgrav 
1616*5afab0e5SDag-Erling Smørgrav 	if (zd->simple_sha384)
1617*5afab0e5SDag-Erling Smørgrav 		ldns_sha384_update(&zd->sha384_CTX, data, buf._position);
1618*5afab0e5SDag-Erling Smørgrav 
1619*5afab0e5SDag-Erling Smørgrav 	if (zd->simple_sha512)
1620*5afab0e5SDag-Erling Smørgrav 		ldns_sha512_update(&zd->sha512_CTX, data, buf._position);
1621*5afab0e5SDag-Erling Smørgrav 
1622*5afab0e5SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
1623*5afab0e5SDag-Erling Smørgrav }
1624*5afab0e5SDag-Erling Smørgrav 
1625*5afab0e5SDag-Erling Smørgrav INLINE ldns_rr *
1626*5afab0e5SDag-Erling Smørgrav new_zonemd(ldns_rr *soa, zonemd_hash hash)
1627*5afab0e5SDag-Erling Smørgrav {
1628*5afab0e5SDag-Erling Smørgrav 	ldns_rr  *rr     = NULL;
1629*5afab0e5SDag-Erling Smørgrav 	uint8_t  *data   = NULL;
1630*5afab0e5SDag-Erling Smørgrav 	ldns_rdf *rdf;
1631*5afab0e5SDag-Erling Smørgrav 	size_t    md_len = hash == ZONEMD_HASH_SHA384
1632*5afab0e5SDag-Erling Smørgrav 	                 ? LDNS_SHA384_DIGEST_LENGTH
1633*5afab0e5SDag-Erling Smørgrav 	                 : LDNS_SHA512_DIGEST_LENGTH;
1634*5afab0e5SDag-Erling Smørgrav 
1635*5afab0e5SDag-Erling Smørgrav 	if (!(rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_ZONEMD)))
1636*5afab0e5SDag-Erling Smørgrav 		return NULL;
1637*5afab0e5SDag-Erling Smørgrav 
1638*5afab0e5SDag-Erling Smørgrav 	if (!(rdf = ldns_rdf_clone(ldns_rr_owner(soa))))
1639*5afab0e5SDag-Erling Smørgrav 		goto error;
1640*5afab0e5SDag-Erling Smørgrav 
1641*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_owner(rr, rdf);
1642*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_class(rr, ldns_rr_get_class(soa));
1643*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_ttl(rr, ldns_rr_ttl(soa));
1644*5afab0e5SDag-Erling Smørgrav 
1645*5afab0e5SDag-Erling Smørgrav 	if (!(rdf = ldns_rdf_clone(ldns_rr_rdf(soa, 2))))
1646*5afab0e5SDag-Erling Smørgrav 		goto error;
1647*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_rdf(rr, rdf, 0);
1648*5afab0e5SDag-Erling Smørgrav 
1649*5afab0e5SDag-Erling Smørgrav 	if (!(rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, 1)))
1650*5afab0e5SDag-Erling Smørgrav 		goto error;
1651*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_rdf(rr, rdf, 1);
1652*5afab0e5SDag-Erling Smørgrav 
1653*5afab0e5SDag-Erling Smørgrav 	if (!(rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, hash)))
1654*5afab0e5SDag-Erling Smørgrav 		goto error;
1655*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_rdf(rr, rdf, 2);
1656*5afab0e5SDag-Erling Smørgrav 
1657*5afab0e5SDag-Erling Smørgrav 	if (!(data = LDNS_XMALLOC(uint8_t, md_len)))
1658*5afab0e5SDag-Erling Smørgrav 		goto error;
1659*5afab0e5SDag-Erling Smørgrav 
1660*5afab0e5SDag-Erling Smørgrav 	if (!(rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, md_len, data)))
1661*5afab0e5SDag-Erling Smørgrav 		goto error;
1662*5afab0e5SDag-Erling Smørgrav 	ldns_rr_set_rdf(rr, rdf, 3);
1663*5afab0e5SDag-Erling Smørgrav 
1664*5afab0e5SDag-Erling Smørgrav 	return rr;
1665*5afab0e5SDag-Erling Smørgrav error:
1666*5afab0e5SDag-Erling Smørgrav 	if (data)
1667*5afab0e5SDag-Erling Smørgrav 		LDNS_FREE(data);
1668*5afab0e5SDag-Erling Smørgrav 	ldns_rr_free(rr);
1669*5afab0e5SDag-Erling Smørgrav 	return NULL;
1670*5afab0e5SDag-Erling Smørgrav }
1671*5afab0e5SDag-Erling Smørgrav 
1672*5afab0e5SDag-Erling Smørgrav static ldns_rr_list *
1673*5afab0e5SDag-Erling Smørgrav zone_digester_export(
1674*5afab0e5SDag-Erling Smørgrav 		zone_digester *zd, ldns_rr *soa, ldns_status *ret_st)
1675*5afab0e5SDag-Erling Smørgrav {
1676*5afab0e5SDag-Erling Smørgrav 	ldns_status st = LDNS_STATUS_OK;
1677*5afab0e5SDag-Erling Smørgrav 	ldns_rr_list *rr_list = NULL;
1678*5afab0e5SDag-Erling Smørgrav 	ldns_rr *sha384 = NULL;
1679*5afab0e5SDag-Erling Smørgrav 	ldns_rr *sha512 = NULL;
1680*5afab0e5SDag-Erling Smørgrav 
1681*5afab0e5SDag-Erling Smørgrav 	if (!zd || !soa)
1682*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_NULL;
1683*5afab0e5SDag-Erling Smørgrav 
1684*5afab0e5SDag-Erling Smørgrav 	else if (ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA
1685*5afab0e5SDag-Erling Smørgrav 	     ||  ldns_rr_rd_count(soa) < 3)
1686*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_ZONEMD_INVALID_SOA;
1687*5afab0e5SDag-Erling Smørgrav 
1688*5afab0e5SDag-Erling Smørgrav 	else if (!(rr_list = ldns_rr_list_new()))
1689*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_MEM_ERR;
1690*5afab0e5SDag-Erling Smørgrav 
1691*5afab0e5SDag-Erling Smørgrav 	else if (zd->simple_sha384
1692*5afab0e5SDag-Erling Smørgrav 	     && !(sha384 = new_zonemd(soa, ZONEMD_HASH_SHA384)))
1693*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_MEM_ERR;
1694*5afab0e5SDag-Erling Smørgrav 
1695*5afab0e5SDag-Erling Smørgrav 	else if (zd->simple_sha512
1696*5afab0e5SDag-Erling Smørgrav 	     && !(sha512 = new_zonemd(soa, ZONEMD_HASH_SHA512)))
1697*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_MEM_ERR;
1698*5afab0e5SDag-Erling Smørgrav 
1699*5afab0e5SDag-Erling Smørgrav 	else if (zd->simple_sha384
1700*5afab0e5SDag-Erling Smørgrav 	     && !ldns_rr_list_push_rr(rr_list, sha384))
1701*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_MEM_ERR;
1702*5afab0e5SDag-Erling Smørgrav 
1703*5afab0e5SDag-Erling Smørgrav 	else if (zd->simple_sha512
1704*5afab0e5SDag-Erling Smørgrav 	     && !ldns_rr_list_push_rr(rr_list, sha512)) {
1705*5afab0e5SDag-Erling Smørgrav 		if (zd->simple_sha384)
1706*5afab0e5SDag-Erling Smørgrav 			sha384 = NULL; /* deleted by ldns_rr_list_deep_free */
1707*5afab0e5SDag-Erling Smørgrav 		st = LDNS_STATUS_MEM_ERR;
1708*5afab0e5SDag-Erling Smørgrav 
1709*5afab0e5SDag-Erling Smørgrav 	} else {
1710*5afab0e5SDag-Erling Smørgrav 		if (sha384)
1711*5afab0e5SDag-Erling Smørgrav 			ldns_sha384_final( ldns_rdf_data(ldns_rr_rdf(sha384,3))
1712*5afab0e5SDag-Erling Smørgrav 			                 , &zd->sha384_CTX);
1713*5afab0e5SDag-Erling Smørgrav 		if (sha512)
1714*5afab0e5SDag-Erling Smørgrav 			ldns_sha512_final( ldns_rdf_data(ldns_rr_rdf(sha512,3))
1715*5afab0e5SDag-Erling Smørgrav 			                 , &zd->sha512_CTX);
1716*5afab0e5SDag-Erling Smørgrav 		return rr_list;
1717*5afab0e5SDag-Erling Smørgrav 	}
1718*5afab0e5SDag-Erling Smørgrav 	if (ret_st)
1719*5afab0e5SDag-Erling Smørgrav 		*ret_st = st;
1720*5afab0e5SDag-Erling Smørgrav 	if (sha384)
1721*5afab0e5SDag-Erling Smørgrav 		ldns_rr_free(sha384);
1722*5afab0e5SDag-Erling Smørgrav 	if (sha512)
1723*5afab0e5SDag-Erling Smørgrav 		ldns_rr_free(sha512);
1724*5afab0e5SDag-Erling Smørgrav 	if (rr_list)
1725*5afab0e5SDag-Erling Smørgrav 		ldns_rr_list_deep_free(rr_list);
1726*5afab0e5SDag-Erling Smørgrav 	return NULL;
1727*5afab0e5SDag-Erling Smørgrav }
1728*5afab0e5SDag-Erling Smørgrav 
1729*5afab0e5SDag-Erling Smørgrav static ldns_status
1730*5afab0e5SDag-Erling Smørgrav ldns_digest_zone(ldns_dnssec_zone *zone, zone_digester *zd)
1731*5afab0e5SDag-Erling Smørgrav {
1732*5afab0e5SDag-Erling Smørgrav 	ldns_status st = LDNS_STATUS_OK;
1733*5afab0e5SDag-Erling Smørgrav 	dnssec_zone_rr_iter rr_iter;
1734*5afab0e5SDag-Erling Smørgrav 	ldns_rr *rr;
1735*5afab0e5SDag-Erling Smørgrav 	ldns_rdf *apex_name; /* name of zone apex */
1736*5afab0e5SDag-Erling Smørgrav 
1737*5afab0e5SDag-Erling Smørgrav 	if (!zone || !zd || !zone->soa || !zone->soa->name)
1738*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
1739*5afab0e5SDag-Erling Smørgrav 
1740*5afab0e5SDag-Erling Smørgrav 	apex_name = zone->soa->name;
1741*5afab0e5SDag-Erling Smørgrav 	for ( rr = dnssec_zone_rr_iter_first(&rr_iter, zone)
1742*5afab0e5SDag-Erling Smørgrav 	    ; rr && !st
1743*5afab0e5SDag-Erling Smørgrav 	    ; rr = dnssec_zone_rr_iter_next(&rr_iter)) {
1744*5afab0e5SDag-Erling Smørgrav 		/* Skip apex ZONEMD RRs */
1745*5afab0e5SDag-Erling Smørgrav 		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_ZONEMD
1746*5afab0e5SDag-Erling Smørgrav 		&& !ldns_dname_compare(ldns_rr_owner(rr), apex_name))
1747*5afab0e5SDag-Erling Smørgrav 			continue;
1748*5afab0e5SDag-Erling Smørgrav 		/* Skip RRSIGs for apex ZONEMD RRs */
1749*5afab0e5SDag-Erling Smørgrav 		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
1750*5afab0e5SDag-Erling Smørgrav 		&&  LDNS_RR_TYPE_ZONEMD == ldns_rdf2rr_type(
1751*5afab0e5SDag-Erling Smørgrav 				ldns_rr_rrsig_typecovered(rr))
1752*5afab0e5SDag-Erling Smørgrav 		&& !ldns_dname_compare(ldns_rr_owner(rr), apex_name))
1753*5afab0e5SDag-Erling Smørgrav 			continue;
1754*5afab0e5SDag-Erling Smørgrav 		st = zone_digester_update(zd, rr);
1755*5afab0e5SDag-Erling Smørgrav 	}
1756*5afab0e5SDag-Erling Smørgrav 	return st;
1757*5afab0e5SDag-Erling Smørgrav }
1758*5afab0e5SDag-Erling Smørgrav 
1759*5afab0e5SDag-Erling Smørgrav ldns_status
1760*5afab0e5SDag-Erling Smørgrav ldns_dnssec_zone_verify_zonemd(ldns_dnssec_zone *zone)
1761*5afab0e5SDag-Erling Smørgrav {
1762*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets *zonemd, *soa;
1763*5afab0e5SDag-Erling Smørgrav 	zone_digester zd;
1764*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrs *rrs;
1765*5afab0e5SDag-Erling Smørgrav 	ldns_rr *soa_rr;
1766*5afab0e5SDag-Erling Smørgrav 	ldns_status st;
1767*5afab0e5SDag-Erling Smørgrav 	uint8_t simple_sha384[LDNS_SHA384_DIGEST_LENGTH];
1768*5afab0e5SDag-Erling Smørgrav 	uint8_t simple_sha512[LDNS_SHA512_DIGEST_LENGTH];
1769*5afab0e5SDag-Erling Smørgrav 	size_t valid_zonemds;
1770*5afab0e5SDag-Erling Smørgrav 
1771*5afab0e5SDag-Erling Smørgrav 	if (!zone)
1772*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
1773*5afab0e5SDag-Erling Smørgrav 
1774*5afab0e5SDag-Erling Smørgrav 	zonemd = ldns_dnssec_zone_find_rrset(
1775*5afab0e5SDag-Erling Smørgrav 			zone, zone->soa->name, LDNS_RR_TYPE_ZONEMD);
1776*5afab0e5SDag-Erling Smørgrav 	if (!zonemd) {
1777*5afab0e5SDag-Erling Smørgrav 		ldns_rbnode_t *nsec3_node;
1778*5afab0e5SDag-Erling Smørgrav 
1779*5afab0e5SDag-Erling Smørgrav 		/* we need proof of non-existence for ZONEMD at the apex */
1780*5afab0e5SDag-Erling Smørgrav 		if (zone->soa->nsec) {
1781*5afab0e5SDag-Erling Smørgrav 			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(
1782*5afab0e5SDag-Erling Smørgrav 							zone->soa->nsec),
1783*5afab0e5SDag-Erling Smørgrav 					       	LDNS_RR_TYPE_ZONEMD))
1784*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_NO_ZONEMD;
1785*5afab0e5SDag-Erling Smørgrav 
1786*5afab0e5SDag-Erling Smørgrav 		} else if (!zone->soa->hashed_name || !zone->hashed_names)
1787*5afab0e5SDag-Erling Smørgrav 			return LDNS_STATUS_NO_ZONEMD;
1788*5afab0e5SDag-Erling Smørgrav 
1789*5afab0e5SDag-Erling Smørgrav 		else if (LDNS_RBTREE_NULL ==
1790*5afab0e5SDag-Erling Smørgrav 		    (nsec3_node = ldns_rbtree_search( zone->hashed_names
1791*5afab0e5SDag-Erling Smørgrav 						    , zone->soa->hashed_name)))
1792*5afab0e5SDag-Erling Smørgrav 			return LDNS_STATUS_NO_ZONEMD;
1793*5afab0e5SDag-Erling Smørgrav 		else {
1794*5afab0e5SDag-Erling Smørgrav 			ldns_dnssec_name *nsec3
1795*5afab0e5SDag-Erling Smørgrav 				= (ldns_dnssec_name *)nsec3_node->data;
1796*5afab0e5SDag-Erling Smørgrav 			if (ldns_nsec_bitmap_covers_type(ldns_nsec_get_bitmap(
1797*5afab0e5SDag-Erling Smørgrav 							nsec3->nsec),
1798*5afab0e5SDag-Erling Smørgrav 						LDNS_RR_TYPE_ZONEMD))
1799*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_NO_ZONEMD;
1800*5afab0e5SDag-Erling Smørgrav 		}
1801*5afab0e5SDag-Erling Smørgrav 		/* ZONEMD at apex does really not exist */
1802*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
1803*5afab0e5SDag-Erling Smørgrav 	}
1804*5afab0e5SDag-Erling Smørgrav 	soa = ldns_dnssec_zone_find_rrset(
1805*5afab0e5SDag-Erling Smørgrav 			zone, zone->soa->name, LDNS_RR_TYPE_SOA);
1806*5afab0e5SDag-Erling Smørgrav 	if (!soa || !soa->rrs || !soa->rrs->rr)
1807*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_ZONEMD_INVALID_SOA;
1808*5afab0e5SDag-Erling Smørgrav 
1809*5afab0e5SDag-Erling Smørgrav 	soa_rr = soa->rrs->rr;
1810*5afab0e5SDag-Erling Smørgrav 	if (ldns_rr_get_type(soa_rr) != LDNS_RR_TYPE_SOA
1811*5afab0e5SDag-Erling Smørgrav 	||  ldns_rr_rd_count(soa_rr) < 3)
1812*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_ZONEMD_INVALID_SOA;
1813*5afab0e5SDag-Erling Smørgrav 
1814*5afab0e5SDag-Erling Smørgrav 	zone_digester_init(&zd);
1815*5afab0e5SDag-Erling Smørgrav 	for (rrs = zonemd->rrs; rrs; rrs = rrs->next) {
1816*5afab0e5SDag-Erling Smørgrav 		if (!rrs->rr
1817*5afab0e5SDag-Erling Smørgrav 		||  ldns_rr_get_type(rrs->rr) != LDNS_RR_TYPE_ZONEMD
1818*5afab0e5SDag-Erling Smørgrav 		||  ldns_rr_rd_count(rrs->rr) < 4)
1819*5afab0e5SDag-Erling Smørgrav 			continue;
1820*5afab0e5SDag-Erling Smørgrav 
1821*5afab0e5SDag-Erling Smørgrav 		/* serial should match SOA's serial */
1822*5afab0e5SDag-Erling Smørgrav 		if (ldns_rdf2native_int32(ldns_rr_rdf(soa_rr, 2))
1823*5afab0e5SDag-Erling Smørgrav 		    != ldns_rdf2native_int32(ldns_rr_rdf(rrs->rr, 0)))
1824*5afab0e5SDag-Erling Smørgrav 			continue;
1825*5afab0e5SDag-Erling Smørgrav 
1826*5afab0e5SDag-Erling Smørgrav 		/* Add (scheme, hash) to digester */
1827*5afab0e5SDag-Erling Smørgrav 		zone_digester_add(&zd,
1828*5afab0e5SDag-Erling Smørgrav 				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 1)),
1829*5afab0e5SDag-Erling Smørgrav 				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 2)));
1830*5afab0e5SDag-Erling Smørgrav 	}
1831*5afab0e5SDag-Erling Smørgrav 	if (!zone_digester_set(&zd))
1832*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_NO_VALID_ZONEMD;
1833*5afab0e5SDag-Erling Smørgrav 
1834*5afab0e5SDag-Erling Smørgrav 	if ((st = ldns_digest_zone(zone, &zd)))
1835*5afab0e5SDag-Erling Smørgrav 		return st;
1836*5afab0e5SDag-Erling Smørgrav 
1837*5afab0e5SDag-Erling Smørgrav 	if (zd.simple_sha384)
1838*5afab0e5SDag-Erling Smørgrav 		ldns_sha384_final(simple_sha384, &zd.sha384_CTX);
1839*5afab0e5SDag-Erling Smørgrav 	if (zd.simple_sha512)
1840*5afab0e5SDag-Erling Smørgrav 		ldns_sha512_final(simple_sha512, &zd.sha512_CTX);
1841*5afab0e5SDag-Erling Smørgrav 
1842*5afab0e5SDag-Erling Smørgrav 	valid_zonemds = 0;
1843*5afab0e5SDag-Erling Smørgrav 	for (rrs = zonemd->rrs; rrs; rrs = rrs->next) {
1844*5afab0e5SDag-Erling Smørgrav 		if (!rrs->rr
1845*5afab0e5SDag-Erling Smørgrav 		||  ldns_rr_get_type(rrs->rr) != LDNS_RR_TYPE_ZONEMD
1846*5afab0e5SDag-Erling Smørgrav 		||  ldns_rr_rd_count(rrs->rr) < 4)
1847*5afab0e5SDag-Erling Smørgrav 			continue;
1848*5afab0e5SDag-Erling Smørgrav 
1849*5afab0e5SDag-Erling Smørgrav 		/* serial should match SOA's serial */
1850*5afab0e5SDag-Erling Smørgrav 		if (ldns_rdf2native_int32(ldns_rr_rdf(soa_rr, 2))
1851*5afab0e5SDag-Erling Smørgrav 		    != ldns_rdf2native_int32(ldns_rr_rdf(rrs->rr, 0)))
1852*5afab0e5SDag-Erling Smørgrav 			continue;
1853*5afab0e5SDag-Erling Smørgrav 
1854*5afab0e5SDag-Erling Smørgrav 		if (ZONEMD_SCHEME_SIMPLE !=
1855*5afab0e5SDag-Erling Smørgrav 				ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr, 1)))
1856*5afab0e5SDag-Erling Smørgrav 			continue;
1857*5afab0e5SDag-Erling Smørgrav 
1858*5afab0e5SDag-Erling Smørgrav 		if (ZONEMD_HASH_SHA384
1859*5afab0e5SDag-Erling Smørgrav 				== ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr,2))
1860*5afab0e5SDag-Erling Smørgrav 		&&  LDNS_SHA384_DIGEST_LENGTH
1861*5afab0e5SDag-Erling Smørgrav 				== ldns_rdf_size(ldns_rr_rdf(rrs->rr, 3))
1862*5afab0e5SDag-Erling Smørgrav 		&&  memcmp( simple_sha384
1863*5afab0e5SDag-Erling Smørgrav 			  , ldns_rdf_data(ldns_rr_rdf(rrs->rr, 3))
1864*5afab0e5SDag-Erling Smørgrav 		          , LDNS_SHA384_DIGEST_LENGTH) == 0)
1865*5afab0e5SDag-Erling Smørgrav 
1866*5afab0e5SDag-Erling Smørgrav 			valid_zonemds += 1;
1867*5afab0e5SDag-Erling Smørgrav 
1868*5afab0e5SDag-Erling Smørgrav 		if (ZONEMD_HASH_SHA512
1869*5afab0e5SDag-Erling Smørgrav 				== ldns_rdf2native_int8(ldns_rr_rdf(rrs->rr,2))
1870*5afab0e5SDag-Erling Smørgrav 		&&  LDNS_SHA512_DIGEST_LENGTH
1871*5afab0e5SDag-Erling Smørgrav 				== ldns_rdf_size(ldns_rr_rdf(rrs->rr, 3))
1872*5afab0e5SDag-Erling Smørgrav 		&&  memcmp( simple_sha512
1873*5afab0e5SDag-Erling Smørgrav 			  , ldns_rdf_data(ldns_rr_rdf(rrs->rr, 3))
1874*5afab0e5SDag-Erling Smørgrav 		          , LDNS_SHA512_DIGEST_LENGTH) == 0)
1875*5afab0e5SDag-Erling Smørgrav 
1876*5afab0e5SDag-Erling Smørgrav 			valid_zonemds += 1;
1877*5afab0e5SDag-Erling Smørgrav 	}
1878*5afab0e5SDag-Erling Smørgrav 	return valid_zonemds ? LDNS_STATUS_OK : LDNS_STATUS_NO_VALID_ZONEMD;
1879*5afab0e5SDag-Erling Smørgrav }
1880*5afab0e5SDag-Erling Smørgrav 
1881*5afab0e5SDag-Erling Smørgrav #ifdef HAVE_SSL
1882*5afab0e5SDag-Erling Smørgrav static ldns_status
1883*5afab0e5SDag-Erling Smørgrav rr_list2dnssec_rrs(ldns_rr_list *rr_list, ldns_dnssec_rrs **rrs,
1884*5afab0e5SDag-Erling Smørgrav 		ldns_rr_list *new_rrs)
1885*5afab0e5SDag-Erling Smørgrav {
1886*5afab0e5SDag-Erling Smørgrav 	ldns_rr *rr = NULL;
1887*5afab0e5SDag-Erling Smørgrav 
1888*5afab0e5SDag-Erling Smørgrav 	if (!rr_list || !rrs)
1889*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_NULL;
1890*5afab0e5SDag-Erling Smørgrav 
1891*5afab0e5SDag-Erling Smørgrav 	if (ldns_rr_list_rr_count(rr_list) == 0)
1892*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_OK;
1893*5afab0e5SDag-Erling Smørgrav 
1894*5afab0e5SDag-Erling Smørgrav 	if (!*rrs) {
1895*5afab0e5SDag-Erling Smørgrav 		if (!(*rrs = ldns_dnssec_rrs_new()))
1896*5afab0e5SDag-Erling Smørgrav 			return LDNS_STATUS_MEM_ERR;
1897*5afab0e5SDag-Erling Smørgrav 		(*rrs)->rr = ldns_rr_list_pop_rr(rr_list);
1898*5afab0e5SDag-Erling Smørgrav 		if (new_rrs)
1899*5afab0e5SDag-Erling Smørgrav 			ldns_rr_list_push_rr(new_rrs, (*rrs)->rr);
1900*5afab0e5SDag-Erling Smørgrav 	}
1901*5afab0e5SDag-Erling Smørgrav 	while ((rr = ldns_rr_list_pop_rr(rr_list))) {
1902*5afab0e5SDag-Erling Smørgrav 		ldns_status st;
1903*5afab0e5SDag-Erling Smørgrav 
1904*5afab0e5SDag-Erling Smørgrav 		if ((st = ldns_dnssec_rrs_add_rr(*rrs, rr))) {
1905*5afab0e5SDag-Erling Smørgrav 			ldns_rr_list_push_rr(rr_list, rr);
1906*5afab0e5SDag-Erling Smørgrav 			return st;
1907*5afab0e5SDag-Erling Smørgrav 		} else if (new_rrs)
1908*5afab0e5SDag-Erling Smørgrav 			ldns_rr_list_push_rr(new_rrs, rr);
1909*5afab0e5SDag-Erling Smørgrav 	}
1910*5afab0e5SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
1911*5afab0e5SDag-Erling Smørgrav }
1912*5afab0e5SDag-Erling Smørgrav 
1913*5afab0e5SDag-Erling Smørgrav 
1914*5afab0e5SDag-Erling Smørgrav ldns_status
1915*5afab0e5SDag-Erling Smørgrav dnssec_zone_equip_zonemd(ldns_dnssec_zone *zone,
1916*5afab0e5SDag-Erling Smørgrav 		ldns_rr_list *new_rrs, ldns_key_list *key_list, int signflags)
1917*5afab0e5SDag-Erling Smørgrav {
1918*5afab0e5SDag-Erling Smørgrav 	ldns_status st = LDNS_STATUS_OK;
1919*5afab0e5SDag-Erling Smørgrav 	zone_digester zd;
1920*5afab0e5SDag-Erling Smørgrav 	ldns_rr_list *zonemd_rr_list = NULL;
1921*5afab0e5SDag-Erling Smørgrav 	ldns_rr_list *zonemd_rrsigs = NULL;
1922*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets *soa_rrset;
1923*5afab0e5SDag-Erling Smørgrav 	ldns_rr *soa_rr = NULL;
1924*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets **rrset_ref;
1925*5afab0e5SDag-Erling Smørgrav 	ldns_dnssec_rrsets *zonemd_rrset;
1926*5afab0e5SDag-Erling Smørgrav 
1927*5afab0e5SDag-Erling Smørgrav 	zone_digester_init(&zd);
1928*5afab0e5SDag-Erling Smørgrav 	if (signflags & LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA384)
1929*5afab0e5SDag-Erling Smørgrav 		zone_digester_add(&zd, ZONEMD_SCHEME_SIMPLE
1930*5afab0e5SDag-Erling Smørgrav 		                     , ZONEMD_HASH_SHA384);
1931*5afab0e5SDag-Erling Smørgrav 
1932*5afab0e5SDag-Erling Smørgrav 	if (signflags & LDNS_SIGN_WITH_ZONEMD_SIMPLE_SHA512)
1933*5afab0e5SDag-Erling Smørgrav 		zone_digester_add(&zd, ZONEMD_SCHEME_SIMPLE
1934*5afab0e5SDag-Erling Smørgrav 		                     , ZONEMD_HASH_SHA512);
1935*5afab0e5SDag-Erling Smørgrav 
1936*5afab0e5SDag-Erling Smørgrav 	if ((st = ldns_digest_zone(zone, &zd)))
1937*5afab0e5SDag-Erling Smørgrav 		return st;
1938*5afab0e5SDag-Erling Smørgrav 
1939*5afab0e5SDag-Erling Smørgrav 	soa_rrset = ldns_dnssec_zone_find_rrset(
1940*5afab0e5SDag-Erling Smørgrav 			zone, zone->soa->name, LDNS_RR_TYPE_SOA);
1941*5afab0e5SDag-Erling Smørgrav 	if (!soa_rrset || !soa_rrset->rrs || !soa_rrset->rrs->rr)
1942*5afab0e5SDag-Erling Smørgrav 		return LDNS_STATUS_ZONEMD_INVALID_SOA;
1943*5afab0e5SDag-Erling Smørgrav 	soa_rr = soa_rrset->rrs->rr;
1944*5afab0e5SDag-Erling Smørgrav 
1945*5afab0e5SDag-Erling Smørgrav 	if (!(zonemd_rr_list = zone_digester_export(&zd, soa_rr, &st)))
1946*5afab0e5SDag-Erling Smørgrav 		return st;
1947*5afab0e5SDag-Erling Smørgrav 
1948*5afab0e5SDag-Erling Smørgrav 	/* - replace or add ZONEMD rrset */
1949*5afab0e5SDag-Erling Smørgrav 	rrset_ref = &zone->soa->rrsets; /* scan rrsets at apex */
1950*5afab0e5SDag-Erling Smørgrav 	while (*rrset_ref && (*rrset_ref)->type < LDNS_RR_TYPE_ZONEMD)
1951*5afab0e5SDag-Erling Smørgrav 		rrset_ref = &(*rrset_ref)->next;
1952*5afab0e5SDag-Erling Smørgrav 	if (*rrset_ref && (*rrset_ref)->type == LDNS_RR_TYPE_ZONEMD) {
1953*5afab0e5SDag-Erling Smørgrav 		/* reuse zonemd rrset */
1954*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset = *rrset_ref;
1955*5afab0e5SDag-Erling Smørgrav 		ldns_dnssec_rrs_free(zonemd_rrset->rrs);
1956*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset->rrs = NULL;
1957*5afab0e5SDag-Erling Smørgrav 		ldns_dnssec_rrs_free(zonemd_rrset->signatures);
1958*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset->signatures = NULL;
1959*5afab0e5SDag-Erling Smørgrav 	} else {
1960*5afab0e5SDag-Erling Smørgrav 		/* insert zonemd rrset */
1961*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset = ldns_dnssec_rrsets_new();
1962*5afab0e5SDag-Erling Smørgrav 		if (!zonemd_rrset) {
1963*5afab0e5SDag-Erling Smørgrav 			ldns_rr_list_deep_free(zonemd_rr_list);
1964*5afab0e5SDag-Erling Smørgrav 			return LDNS_STATUS_MEM_ERR;
1965*5afab0e5SDag-Erling Smørgrav 		}
1966*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset->type = LDNS_RR_TYPE_ZONEMD;
1967*5afab0e5SDag-Erling Smørgrav 		zonemd_rrset->next = *rrset_ref;
1968*5afab0e5SDag-Erling Smørgrav 		*rrset_ref = zonemd_rrset;
1969*5afab0e5SDag-Erling Smørgrav 	}
1970*5afab0e5SDag-Erling Smørgrav 	if ((zonemd_rrsigs = ldns_sign_public(zonemd_rr_list, key_list)))
1971*5afab0e5SDag-Erling Smørgrav 		st = rr_list2dnssec_rrs(  zonemd_rrsigs
1972*5afab0e5SDag-Erling Smørgrav 		                       , &zonemd_rrset->signatures, new_rrs);
1973*5afab0e5SDag-Erling Smørgrav 	if (!st)
1974*5afab0e5SDag-Erling Smørgrav 		st = rr_list2dnssec_rrs(  zonemd_rr_list
1975*5afab0e5SDag-Erling Smørgrav 		                       , &zonemd_rrset->rrs, new_rrs);
1976*5afab0e5SDag-Erling Smørgrav 	ldns_rr_list_deep_free(zonemd_rr_list);
1977*5afab0e5SDag-Erling Smørgrav 	ldns_rr_list_deep_free(zonemd_rrsigs);
1978*5afab0e5SDag-Erling Smørgrav 	return st;
1979*5afab0e5SDag-Erling Smørgrav }
1980*5afab0e5SDag-Erling Smørgrav 
1981*5afab0e5SDag-Erling Smørgrav #endif /* HAVE_SSL */
1982*5afab0e5SDag-Erling Smørgrav 
1983