dnssec_zone.c revision 238104
1238104Sdes/*
2238104Sdes * special zone file structures and functions for better dnssec handling
3238104Sdes */
4238104Sdes
5238104Sdes#include <ldns/config.h>
6238104Sdes
7238104Sdes#include <ldns/ldns.h>
8238104Sdes
9238104Sdesldns_dnssec_rrs *
10238104Sdesldns_dnssec_rrs_new()
11238104Sdes{
12238104Sdes	ldns_dnssec_rrs *new_rrs;
13238104Sdes	new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
14238104Sdes        if(!new_rrs) return NULL;
15238104Sdes	new_rrs->rr = NULL;
16238104Sdes	new_rrs->next = NULL;
17238104Sdes	return new_rrs;
18238104Sdes}
19238104Sdes
20238104SdesINLINE void
21238104Sdesldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
22238104Sdes{
23238104Sdes	ldns_dnssec_rrs *next;
24238104Sdes	while (rrs) {
25238104Sdes		next = rrs->next;
26238104Sdes		if (deep) {
27238104Sdes			ldns_rr_free(rrs->rr);
28238104Sdes		}
29238104Sdes		LDNS_FREE(rrs);
30238104Sdes		rrs = next;
31238104Sdes	}
32238104Sdes}
33238104Sdes
34238104Sdesvoid
35238104Sdesldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
36238104Sdes{
37238104Sdes	ldns_dnssec_rrs_free_internal(rrs, 0);
38238104Sdes}
39238104Sdes
40238104Sdesvoid
41238104Sdesldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
42238104Sdes{
43238104Sdes	ldns_dnssec_rrs_free_internal(rrs, 1);
44238104Sdes}
45238104Sdes
46238104Sdesldns_status
47238104Sdesldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
48238104Sdes{
49238104Sdes	int cmp;
50238104Sdes	ldns_dnssec_rrs *new_rrs;
51238104Sdes	if (!rrs || !rr) {
52238104Sdes		return LDNS_STATUS_ERR;
53238104Sdes	}
54238104Sdes
55238104Sdes	/* this could be done more efficiently; name and type should already
56238104Sdes	   be equal */
57238104Sdes	cmp = ldns_rr_compare(rrs->rr,
58238104Sdes					  rr);
59238104Sdes	/* should we error on equal? */
60238104Sdes	if (cmp <= 0) {
61238104Sdes		if (rrs->next) {
62238104Sdes			return ldns_dnssec_rrs_add_rr(rrs->next, rr);
63238104Sdes		} else {
64238104Sdes			new_rrs = ldns_dnssec_rrs_new();
65238104Sdes			new_rrs->rr = rr;
66238104Sdes			rrs->next = new_rrs;
67238104Sdes		}
68238104Sdes	} else if (cmp > 0) {
69238104Sdes		/* put the current old rr in the new next, put the new
70238104Sdes		   rr in the current container */
71238104Sdes		new_rrs = ldns_dnssec_rrs_new();
72238104Sdes		new_rrs->rr = rrs->rr;
73238104Sdes		new_rrs->next = rrs->next;
74238104Sdes		rrs->rr = rr;
75238104Sdes		rrs->next = new_rrs;
76238104Sdes	}
77238104Sdes	return LDNS_STATUS_OK;
78238104Sdes}
79238104Sdes
80238104Sdesvoid
81238104Sdesldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
82238104Sdes	       ldns_dnssec_rrs *rrs)
83238104Sdes{
84238104Sdes	if (!rrs) {
85238104Sdes		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
86238104Sdes			fprintf(out, "; <void>");
87238104Sdes	} else {
88238104Sdes		if (rrs->rr) {
89238104Sdes			ldns_rr_print_fmt(out, fmt, rrs->rr);
90238104Sdes		}
91238104Sdes		if (rrs->next) {
92238104Sdes			ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
93238104Sdes		}
94238104Sdes	}
95238104Sdes}
96238104Sdes
97238104Sdesvoid
98238104Sdesldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs)
99238104Sdes{
100238104Sdes	ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
101238104Sdes}
102238104Sdes
103238104Sdes
104238104Sdesldns_dnssec_rrsets *
105238104Sdesldns_dnssec_rrsets_new()
106238104Sdes{
107238104Sdes	ldns_dnssec_rrsets *new_rrsets;
108238104Sdes	new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
109238104Sdes        if(!new_rrsets) return NULL;
110238104Sdes	new_rrsets->rrs = NULL;
111238104Sdes	new_rrsets->type = 0;
112238104Sdes	new_rrsets->signatures = NULL;
113238104Sdes	new_rrsets->next = NULL;
114238104Sdes	return new_rrsets;
115238104Sdes}
116238104Sdes
117238104SdesINLINE void
118238104Sdesldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
119238104Sdes{
120238104Sdes	if (rrsets) {
121238104Sdes		if (rrsets->rrs) {
122238104Sdes			ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
123238104Sdes		}
124238104Sdes		if (rrsets->next) {
125238104Sdes			ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
126238104Sdes		}
127238104Sdes		if (rrsets->signatures) {
128238104Sdes			ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
129238104Sdes		}
130238104Sdes		LDNS_FREE(rrsets);
131238104Sdes	}
132238104Sdes}
133238104Sdes
134238104Sdesvoid
135238104Sdesldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
136238104Sdes{
137238104Sdes	ldns_dnssec_rrsets_free_internal(rrsets, 0);
138238104Sdes}
139238104Sdes
140238104Sdesvoid
141238104Sdesldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
142238104Sdes{
143238104Sdes	ldns_dnssec_rrsets_free_internal(rrsets, 1);
144238104Sdes}
145238104Sdes
146238104Sdesldns_rr_type
147238104Sdesldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
148238104Sdes{
149238104Sdes	if (rrsets) {
150238104Sdes		return rrsets->type;
151238104Sdes	} else {
152238104Sdes		return 0;
153238104Sdes	}
154238104Sdes}
155238104Sdes
156238104Sdesldns_status
157238104Sdesldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
158238104Sdes					   ldns_rr_type type)
159238104Sdes{
160238104Sdes	if (rrsets) {
161238104Sdes		rrsets->type = type;
162238104Sdes		return LDNS_STATUS_OK;
163238104Sdes	}
164238104Sdes	return LDNS_STATUS_ERR;
165238104Sdes}
166238104Sdes
167238104Sdesldns_dnssec_rrsets *
168238104Sdesldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
169238104Sdes{
170238104Sdes	ldns_dnssec_rrsets *new_rrsets;
171238104Sdes	ldns_rr_type rr_type;
172238104Sdes	bool rrsig;
173238104Sdes
174238104Sdes	new_rrsets = ldns_dnssec_rrsets_new();
175238104Sdes	rr_type = ldns_rr_get_type(rr);
176238104Sdes	if (rr_type == LDNS_RR_TYPE_RRSIG) {
177238104Sdes		rrsig = true;
178238104Sdes		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
179238104Sdes	} else {
180238104Sdes		rrsig = false;
181238104Sdes	}
182238104Sdes	if (!rrsig) {
183238104Sdes		new_rrsets->rrs = ldns_dnssec_rrs_new();
184238104Sdes		new_rrsets->rrs->rr = rr;
185238104Sdes	} else {
186238104Sdes		new_rrsets->signatures = ldns_dnssec_rrs_new();
187238104Sdes		new_rrsets->signatures->rr = rr;
188238104Sdes	}
189238104Sdes	new_rrsets->type = rr_type;
190238104Sdes	return new_rrsets;
191238104Sdes}
192238104Sdes
193238104Sdesldns_status
194238104Sdesldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
195238104Sdes{
196238104Sdes	ldns_dnssec_rrsets *new_rrsets;
197238104Sdes	ldns_rr_type rr_type;
198238104Sdes	bool rrsig = false;
199238104Sdes	ldns_status result = LDNS_STATUS_OK;
200238104Sdes
201238104Sdes	if (!rrsets || !rr) {
202238104Sdes		return LDNS_STATUS_ERR;
203238104Sdes	}
204238104Sdes
205238104Sdes	rr_type = ldns_rr_get_type(rr);
206238104Sdes
207238104Sdes	if (rr_type == LDNS_RR_TYPE_RRSIG) {
208238104Sdes		rrsig = true;
209238104Sdes		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
210238104Sdes	}
211238104Sdes
212238104Sdes	if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
213238104Sdes		if (!rrsig) {
214238104Sdes			rrsets->rrs = ldns_dnssec_rrs_new();
215238104Sdes			rrsets->rrs->rr = rr;
216238104Sdes			rrsets->type = rr_type;
217238104Sdes		} else {
218238104Sdes			rrsets->signatures = ldns_dnssec_rrs_new();
219238104Sdes			rrsets->signatures->rr = rr;
220238104Sdes			rrsets->type = rr_type;
221238104Sdes		}
222238104Sdes		return LDNS_STATUS_OK;
223238104Sdes	}
224238104Sdes
225238104Sdes	if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
226238104Sdes		if (rrsets->next) {
227238104Sdes			result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
228238104Sdes		} else {
229238104Sdes			new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
230238104Sdes			rrsets->next = new_rrsets;
231238104Sdes		}
232238104Sdes	} else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
233238104Sdes		/* move the current one into the new next,
234238104Sdes		   replace field of current with data from new rr */
235238104Sdes		new_rrsets = ldns_dnssec_rrsets_new();
236238104Sdes		new_rrsets->rrs = rrsets->rrs;
237238104Sdes		new_rrsets->type = rrsets->type;
238238104Sdes		new_rrsets->signatures = rrsets->signatures;
239238104Sdes		new_rrsets->next = rrsets->next;
240238104Sdes		if (!rrsig) {
241238104Sdes			rrsets->rrs = ldns_dnssec_rrs_new();
242238104Sdes			rrsets->rrs->rr = rr;
243238104Sdes			rrsets->signatures = NULL;
244238104Sdes		} else {
245238104Sdes			rrsets->rrs = NULL;
246238104Sdes			rrsets->signatures = ldns_dnssec_rrs_new();
247238104Sdes			rrsets->signatures->rr = rr;
248238104Sdes		}
249238104Sdes		rrsets->type = rr_type;
250238104Sdes		rrsets->next = new_rrsets;
251238104Sdes	} else {
252238104Sdes		/* equal, add to current rrsets */
253238104Sdes		if (rrsig) {
254238104Sdes			if (rrsets->signatures) {
255238104Sdes				result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
256238104Sdes			} else {
257238104Sdes				rrsets->signatures = ldns_dnssec_rrs_new();
258238104Sdes				rrsets->signatures->rr = rr;
259238104Sdes			}
260238104Sdes		} else {
261238104Sdes			if (rrsets->rrs) {
262238104Sdes				result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
263238104Sdes			} else {
264238104Sdes				rrsets->rrs = ldns_dnssec_rrs_new();
265238104Sdes				rrsets->rrs->rr = rr;
266238104Sdes			}
267238104Sdes		}
268238104Sdes	}
269238104Sdes
270238104Sdes	return result;
271238104Sdes}
272238104Sdes
273238104Sdesvoid
274238104Sdesldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
275238104Sdes		ldns_dnssec_rrsets *rrsets,
276238104Sdes		bool follow,
277238104Sdes		bool show_soa)
278238104Sdes{
279238104Sdes	if (!rrsets) {
280238104Sdes		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
281238104Sdes			fprintf(out, "; <void>\n");
282238104Sdes	} else {
283238104Sdes		if (rrsets->rrs &&
284238104Sdes		    (show_soa ||
285238104Sdes			ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
286238104Sdes		    )
287238104Sdes		   ) {
288238104Sdes			ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
289238104Sdes			if (rrsets->signatures) {
290238104Sdes				ldns_dnssec_rrs_print_fmt(out, fmt,
291238104Sdes						rrsets->signatures);
292238104Sdes			}
293238104Sdes		}
294238104Sdes		if (follow && rrsets->next) {
295238104Sdes			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
296238104Sdes					rrsets->next, follow, show_soa);
297238104Sdes		}
298238104Sdes	}
299238104Sdes}
300238104Sdes
301238104Sdesvoid
302238104Sdesldns_dnssec_rrsets_print_soa(FILE *out,
303238104Sdes		ldns_dnssec_rrsets *rrsets,
304238104Sdes		bool follow,
305238104Sdes		bool show_soa)
306238104Sdes{
307238104Sdes	ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default,
308238104Sdes		       	rrsets, follow, show_soa);
309238104Sdes}
310238104Sdes
311238104Sdes
312238104Sdesvoid
313238104Sdesldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
314238104Sdes		ldns_dnssec_rrsets *rrsets,
315238104Sdes		bool follow)
316238104Sdes{
317238104Sdes	ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
318238104Sdes}
319238104Sdes
320238104Sdesvoid
321238104Sdesldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
322238104Sdes{
323238104Sdes	ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
324238104Sdes			rrsets, follow);
325238104Sdes}
326238104Sdes
327238104Sdesldns_dnssec_name *
328238104Sdesldns_dnssec_name_new()
329238104Sdes{
330238104Sdes	ldns_dnssec_name *new_name;
331238104Sdes
332238104Sdes	new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
333238104Sdes	if (!new_name) {
334238104Sdes		return NULL;
335238104Sdes	}
336238104Sdes	/*
337238104Sdes	 * not needed anymore because CALLOC initalizes everything to zero.
338238104Sdes
339238104Sdes	new_name->name = NULL;
340238104Sdes	new_name->rrsets = NULL;
341238104Sdes	new_name->name_alloced = false;
342238104Sdes	new_name->nsec = NULL;
343238104Sdes	new_name->nsec_signatures = NULL;
344238104Sdes
345238104Sdes	new_name->is_glue = false;
346238104Sdes	new_name->hashed_name = NULL;
347238104Sdes
348238104Sdes	 */
349238104Sdes	return new_name;
350238104Sdes}
351238104Sdes
352238104Sdesldns_dnssec_name *
353238104Sdesldns_dnssec_name_new_frm_rr(ldns_rr *rr)
354238104Sdes{
355238104Sdes	ldns_dnssec_name *new_name = ldns_dnssec_name_new();
356238104Sdes
357238104Sdes	new_name->name = ldns_rr_owner(rr);
358238104Sdes	if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
359238104Sdes		ldns_dnssec_name_free(new_name);
360238104Sdes		return NULL;
361238104Sdes	}
362238104Sdes
363238104Sdes	return new_name;
364238104Sdes}
365238104Sdes
366238104SdesINLINE void
367238104Sdesldns_dnssec_name_free_internal(ldns_dnssec_name *name,
368238104Sdes                               int deep)
369238104Sdes{
370238104Sdes	if (name) {
371238104Sdes		if (name->name_alloced) {
372238104Sdes			ldns_rdf_deep_free(name->name);
373238104Sdes		}
374238104Sdes		if (name->rrsets) {
375238104Sdes			ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
376238104Sdes		}
377238104Sdes		if (name->nsec && deep) {
378238104Sdes			ldns_rr_free(name->nsec);
379238104Sdes		}
380238104Sdes		if (name->nsec_signatures) {
381238104Sdes			ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
382238104Sdes		}
383238104Sdes		if (name->hashed_name) {
384238104Sdes			if (deep) {
385238104Sdes				ldns_rdf_deep_free(name->hashed_name);
386238104Sdes			}
387238104Sdes		}
388238104Sdes		LDNS_FREE(name);
389238104Sdes	}
390238104Sdes}
391238104Sdes
392238104Sdesvoid
393238104Sdesldns_dnssec_name_free(ldns_dnssec_name *name)
394238104Sdes{
395238104Sdes  ldns_dnssec_name_free_internal(name, 0);
396238104Sdes}
397238104Sdes
398238104Sdesvoid
399238104Sdesldns_dnssec_name_deep_free(ldns_dnssec_name *name)
400238104Sdes{
401238104Sdes  ldns_dnssec_name_free_internal(name, 1);
402238104Sdes}
403238104Sdes
404238104Sdesldns_rdf *
405238104Sdesldns_dnssec_name_name(ldns_dnssec_name *name)
406238104Sdes{
407238104Sdes	if (name) {
408238104Sdes		return name->name;
409238104Sdes	}
410238104Sdes	return NULL;
411238104Sdes}
412238104Sdes
413238104Sdesbool
414238104Sdesldns_dnssec_name_is_glue(ldns_dnssec_name *name)
415238104Sdes{
416238104Sdes	if (name) {
417238104Sdes		return name->is_glue;
418238104Sdes	}
419238104Sdes	return false;
420238104Sdes}
421238104Sdes
422238104Sdesvoid
423238104Sdesldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
424238104Sdes					 ldns_rdf *dname)
425238104Sdes{
426238104Sdes	if (rrset && dname) {
427238104Sdes		rrset->name = dname;
428238104Sdes	}
429238104Sdes}
430238104Sdes
431238104Sdesldns_rr *
432238104Sdesldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
433238104Sdes{
434238104Sdes	if (rrset) {
435238104Sdes		return rrset->nsec;
436238104Sdes	}
437238104Sdes	return NULL;
438238104Sdes}
439238104Sdes
440238104Sdesvoid
441238104Sdesldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
442238104Sdes{
443238104Sdes	if (rrset && nsec) {
444238104Sdes		rrset->nsec = nsec;
445238104Sdes	}
446238104Sdes}
447238104Sdes
448238104Sdesint
449238104Sdesldns_dnssec_name_cmp(const void *a, const void *b)
450238104Sdes{
451238104Sdes	ldns_dnssec_name *na = (ldns_dnssec_name *) a;
452238104Sdes	ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
453238104Sdes
454238104Sdes	if (na && nb) {
455238104Sdes		return ldns_dname_compare(ldns_dnssec_name_name(na),
456238104Sdes							 ldns_dnssec_name_name(nb));
457238104Sdes	} else if (na) {
458238104Sdes		return 1;
459238104Sdes	} else if (nb) {
460238104Sdes		return -1;
461238104Sdes	} else {
462238104Sdes		return 0;
463238104Sdes	}
464238104Sdes}
465238104Sdes
466238104Sdesldns_status
467238104Sdesldns_dnssec_name_add_rr(ldns_dnssec_name *name,
468238104Sdes				    ldns_rr *rr)
469238104Sdes{
470238104Sdes	ldns_status result = LDNS_STATUS_OK;
471238104Sdes	ldns_rdf *name_name;
472238104Sdes	bool hashed_name = false;
473238104Sdes	ldns_rr_type rr_type;
474238104Sdes	ldns_rr_type typecovered = 0;
475238104Sdes
476238104Sdes	/* special handling for NSEC3 and NSECX covering RRSIGS */
477238104Sdes
478238104Sdes	if (!name || !rr) {
479238104Sdes		return LDNS_STATUS_ERR;
480238104Sdes	}
481238104Sdes
482238104Sdes	rr_type = ldns_rr_get_type(rr);
483238104Sdes
484238104Sdes	if (rr_type == LDNS_RR_TYPE_RRSIG) {
485238104Sdes		typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
486238104Sdes	}
487238104Sdes
488238104Sdes#ifdef HAVE_SSL
489238104Sdes	if (rr_type == LDNS_RR_TYPE_NSEC3 ||
490238104Sdes	    typecovered == LDNS_RR_TYPE_NSEC3) {
491238104Sdes		name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
492238104Sdes										   ldns_dnssec_name_name(name));
493238104Sdes		hashed_name = true;
494238104Sdes	} else {
495238104Sdes		name_name = ldns_dnssec_name_name(name);
496238104Sdes	}
497238104Sdes#else
498238104Sdes	name_name = ldns_dnssec_name_name(name);
499238104Sdes#endif /* HAVE_SSL */
500238104Sdes
501238104Sdes	if (rr_type == LDNS_RR_TYPE_NSEC ||
502238104Sdes	    rr_type == LDNS_RR_TYPE_NSEC3) {
503238104Sdes		/* XX check if is already set (and error?) */
504238104Sdes		name->nsec = rr;
505238104Sdes	} else if (typecovered == LDNS_RR_TYPE_NSEC ||
506238104Sdes			 typecovered == LDNS_RR_TYPE_NSEC3) {
507238104Sdes		if (name->nsec_signatures) {
508238104Sdes			result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
509238104Sdes		} else {
510238104Sdes			name->nsec_signatures = ldns_dnssec_rrs_new();
511238104Sdes			name->nsec_signatures->rr = rr;
512238104Sdes		}
513238104Sdes	} else {
514238104Sdes		/* it's a 'normal' RR, add it to the right rrset */
515238104Sdes		if (name->rrsets) {
516238104Sdes			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
517238104Sdes		} else {
518238104Sdes			name->rrsets = ldns_dnssec_rrsets_new();
519238104Sdes			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
520238104Sdes		}
521238104Sdes	}
522238104Sdes
523238104Sdes	if (hashed_name) {
524238104Sdes		ldns_rdf_deep_free(name_name);
525238104Sdes	}
526238104Sdes
527238104Sdes	return result;
528238104Sdes}
529238104Sdes
530238104Sdesldns_dnssec_rrsets *
531238104Sdesldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
532238104Sdes					   ldns_rr_type type) {
533238104Sdes	ldns_dnssec_rrsets *result;
534238104Sdes
535238104Sdes	result = name->rrsets;
536238104Sdes	while (result) {
537238104Sdes		if (result->type == type) {
538238104Sdes			return result;
539238104Sdes		} else {
540238104Sdes			result = result->next;
541238104Sdes		}
542238104Sdes	}
543238104Sdes	return NULL;
544238104Sdes}
545238104Sdes
546238104Sdesldns_dnssec_rrsets *
547238104Sdesldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
548238104Sdes					   ldns_rdf *dname,
549238104Sdes					   ldns_rr_type type)
550238104Sdes{
551238104Sdes	ldns_rbnode_t *node;
552238104Sdes
553238104Sdes	if (!zone || !dname) {
554238104Sdes		return NULL;
555238104Sdes	}
556238104Sdes
557238104Sdes	node = ldns_rbtree_search(zone->names, dname);
558238104Sdes	if (node) {
559238104Sdes		return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
560238104Sdes									type);
561238104Sdes	} else {
562238104Sdes		return NULL;
563238104Sdes	}
564238104Sdes}
565238104Sdes
566238104Sdesvoid
567238104Sdesldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
568238104Sdes		ldns_dnssec_name *name,
569238104Sdes		bool show_soa)
570238104Sdes{
571238104Sdes	if (name) {
572238104Sdes		if(name->rrsets) {
573238104Sdes			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
574238104Sdes					name->rrsets, true, show_soa);
575238104Sdes		} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
576238104Sdes			fprintf(out, ";; Empty nonterminal: ");
577238104Sdes			ldns_rdf_print(out, name->name);
578238104Sdes			fprintf(out, "\n");
579238104Sdes		}
580238104Sdes		if(name->nsec) {
581238104Sdes			ldns_rr_print_fmt(out, fmt, name->nsec);
582238104Sdes		}
583238104Sdes		if (name->nsec_signatures) {
584238104Sdes			ldns_dnssec_rrs_print_fmt(out, fmt,
585238104Sdes					name->nsec_signatures);
586238104Sdes		}
587238104Sdes	} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
588238104Sdes		fprintf(out, "; <void>\n");
589238104Sdes	}
590238104Sdes}
591238104Sdes
592238104Sdesvoid
593238104Sdesldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
594238104Sdes{
595238104Sdes	ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default,
596238104Sdes		       name, show_soa);
597238104Sdes}
598238104Sdes
599238104Sdesvoid
600238104Sdesldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
601238104Sdes		ldns_dnssec_name *name)
602238104Sdes{
603238104Sdes	ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
604238104Sdes}
605238104Sdes
606238104Sdesvoid
607238104Sdesldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
608238104Sdes{
609238104Sdes	ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
610238104Sdes}
611238104Sdes
612238104Sdes
613238104Sdesldns_dnssec_zone *
614238104Sdesldns_dnssec_zone_new()
615238104Sdes{
616238104Sdes	ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
617238104Sdes        if(!zone) return NULL;
618238104Sdes	zone->soa = NULL;
619238104Sdes	zone->names = NULL;
620238104Sdes
621238104Sdes	return zone;
622238104Sdes}
623238104Sdes
624238104Sdesstatic bool
625238104Sdesrr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
626238104Sdes{
627238104Sdes	return     ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
628238104Sdes		&& ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
629238104Sdes}
630238104Sdes
631238104Sdes/* When the zone is first read into an list and then inserted into an
632238104Sdes * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
633238104Sdes * to each other. Because ldns-verify-zone (the only program that uses this
634238104Sdes * function) uses the rbtree mostly for sequentual walking, this results
635238104Sdes * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
636238104Sdes */
637238104Sdes#define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
638238104Sdes
639238104Sdesldns_status
640238104Sdesldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
641238104Sdes	       	uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
642238104Sdes{
643238104Sdes	ldns_rr* cur_rr;
644238104Sdes	size_t i;
645238104Sdes
646238104Sdes	ldns_rdf *my_origin = NULL;
647238104Sdes	ldns_rdf *my_prev = NULL;
648238104Sdes
649238104Sdes	ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
650238104Sdes	/* when reading NSEC3s, there is a chance that we encounter nsecs
651238104Sdes	   for empty nonterminals, whose nonterminals we cannot derive yet
652238104Sdes	   because the needed information is to be read later. in that case
653238104Sdes	   we keep a list of those nsec3's and retry to add them later */
654238104Sdes	ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
655238104Sdes	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
656238104Sdes
657238104Sdes	ldns_status status = LDNS_STATUS_MEM_ERR;
658238104Sdes
659238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
660238104Sdes	ldns_zone* zone = NULL;
661238104Sdes	if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
662238104Sdes			!= LDNS_STATUS_OK) goto error;
663238104Sdes#else
664238104Sdes	uint32_t  my_ttl = ttl;
665238104Sdes#endif
666238104Sdes
667238104Sdes	if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
668238104Sdes
669238104Sdes	if (origin) {
670238104Sdes		if (!(my_origin = ldns_rdf_clone(origin))) goto error;
671238104Sdes		if (!(my_prev   = ldns_rdf_clone(origin))) goto error;
672238104Sdes	}
673238104Sdes
674238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
675238104Sdes	if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
676238104Sdes			!= LDNS_STATUS_OK) goto error;
677238104Sdes
678238104Sdes	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
679238104Sdes		cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
680238104Sdes		status = LDNS_STATUS_OK;
681238104Sdes#else
682238104Sdes	while (!feof(fp)) {
683238104Sdes		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
684238104Sdes				&my_prev, line_nr);
685238104Sdes
686238104Sdes#endif
687238104Sdes		switch (status) {
688238104Sdes		case LDNS_STATUS_OK:
689238104Sdes
690238104Sdes			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
691238104Sdes			if (status ==
692238104Sdes				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
693238104Sdes
694238104Sdes				if (rr_is_rrsig_covering(cur_rr,
695238104Sdes							LDNS_RR_TYPE_NSEC3)){
696238104Sdes					ldns_rr_list_push_rr(todo_nsec3_rrsigs,
697238104Sdes							cur_rr);
698238104Sdes				} else {
699238104Sdes					ldns_rr_list_push_rr(todo_nsec3s,
700238104Sdes						       	cur_rr);
701238104Sdes				}
702238104Sdes			} else if (status != LDNS_STATUS_OK)
703238104Sdes				goto error;
704238104Sdes
705238104Sdes			break;
706238104Sdes
707238104Sdes
708238104Sdes		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
709238104Sdes		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
710238104Sdes		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
711238104Sdes			break;
712238104Sdes
713238104Sdes		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
714238104Sdes			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
715238104Sdes			break;
716238104Sdes
717238104Sdes		default:
718238104Sdes			goto error;
719238104Sdes		}
720238104Sdes	}
721238104Sdes
722238104Sdes	if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
723238104Sdes		(void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
724238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
725238104Sdes			cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
726238104Sdes			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
727238104Sdes		}
728238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++){
729238104Sdes			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
730238104Sdes			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
731238104Sdes		}
732238104Sdes	} else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
733238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++){
734238104Sdes			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
735238104Sdes			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
736238104Sdes		}
737238104Sdes	}
738238104Sdes
739238104Sdes	ldns_rr_list_free(todo_nsec3_rrsigs);
740238104Sdes	ldns_rr_list_free(todo_nsec3s);
741238104Sdes
742238104Sdes	if (z) {
743238104Sdes		*z = newzone;
744238104Sdes	} else {
745238104Sdes		ldns_dnssec_zone_free(newzone);
746238104Sdes	}
747238104Sdes
748238104Sdes	return LDNS_STATUS_OK;
749238104Sdes
750238104Sdeserror:
751238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
752238104Sdes	if (zone) {
753238104Sdes		ldns_zone_free(zone);
754238104Sdes	}
755238104Sdes#endif
756238104Sdes	if (my_origin) {
757238104Sdes		ldns_rdf_deep_free(my_origin);
758238104Sdes	}
759238104Sdes	if (my_prev) {
760238104Sdes		ldns_rdf_deep_free(my_prev);
761238104Sdes	}
762238104Sdes	if (newzone) {
763238104Sdes		ldns_dnssec_zone_free(newzone);
764238104Sdes	}
765238104Sdes	return status;
766238104Sdes}
767238104Sdes
768238104Sdesldns_status
769238104Sdesldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
770238104Sdes		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
771238104Sdes{
772238104Sdes	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
773238104Sdes}
774238104Sdes
775238104Sdesvoid
776238104Sdesldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
777238104Sdes	(void) arg;
778238104Sdes	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
779238104Sdes	LDNS_FREE(node);
780238104Sdes}
781238104Sdes
782238104Sdesvoid
783238104Sdesldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
784238104Sdes	(void) arg;
785238104Sdes	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
786238104Sdes	LDNS_FREE(node);
787238104Sdes}
788238104Sdes
789238104Sdesvoid
790238104Sdesldns_dnssec_zone_free(ldns_dnssec_zone *zone)
791238104Sdes{
792238104Sdes	if (zone) {
793238104Sdes		if (zone->names) {
794238104Sdes			/* destroy all name structures within the tree */
795238104Sdes			ldns_traverse_postorder(zone->names,
796238104Sdes						    ldns_dnssec_name_node_free,
797238104Sdes						    NULL);
798238104Sdes			LDNS_FREE(zone->names);
799238104Sdes		}
800238104Sdes		LDNS_FREE(zone);
801238104Sdes	}
802238104Sdes}
803238104Sdes
804238104Sdesvoid
805238104Sdesldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
806238104Sdes{
807238104Sdes	if (zone) {
808238104Sdes		if (zone->names) {
809238104Sdes			/* destroy all name structures within the tree */
810238104Sdes			ldns_traverse_postorder(zone->names,
811238104Sdes						    ldns_dnssec_name_node_deep_free,
812238104Sdes						    NULL);
813238104Sdes			LDNS_FREE(zone->names);
814238104Sdes		}
815238104Sdes		LDNS_FREE(zone);
816238104Sdes	}
817238104Sdes}
818238104Sdes
819238104Sdes/* use for dname comparison in tree */
820238104Sdesint
821238104Sdesldns_dname_compare_v(const void *a, const void *b) {
822238104Sdes	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
823238104Sdes}
824238104Sdes
825238104Sdes#ifdef HAVE_SSL
826238104Sdesldns_rbnode_t *
827238104Sdesldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
828238104Sdes                                     ldns_rr *rr) {
829238104Sdes	ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
830238104Sdes	ldns_dnssec_name *current_name;
831238104Sdes	ldns_rdf *hashed_name;
832238104Sdes
833238104Sdes	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
834238104Sdes
835238104Sdes	while (current_node != LDNS_RBTREE_NULL) {
836238104Sdes		current_name = (ldns_dnssec_name *) current_node->data;
837238104Sdes		if (!current_name->hashed_name) {
838238104Sdes			current_name->hashed_name =
839238104Sdes				ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
840238104Sdes		}
841238104Sdes		if (ldns_dname_compare(hashed_name,
842238104Sdes						   current_name->hashed_name)
843238104Sdes		    == 0) {
844238104Sdes			ldns_rdf_deep_free(hashed_name);
845238104Sdes			return current_node;
846238104Sdes		}
847238104Sdes		current_node = ldns_rbtree_next(current_node);
848238104Sdes	}
849238104Sdes	ldns_rdf_deep_free(hashed_name);
850238104Sdes	return NULL;
851238104Sdes}
852238104Sdes
853238104Sdesldns_status
854238104Sdesldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
855238104Sdes{
856238104Sdes	ldns_status result = LDNS_STATUS_OK;
857238104Sdes	ldns_dnssec_name *cur_name;
858238104Sdes	ldns_rbnode_t *cur_node;
859238104Sdes	ldns_rr_type type_covered = 0;
860238104Sdes
861238104Sdes	if (!zone || !rr) {
862238104Sdes		return LDNS_STATUS_ERR;
863238104Sdes	}
864238104Sdes
865238104Sdes	if (!zone->names) {
866238104Sdes		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
867238104Sdes                if(!zone->names) return LDNS_STATUS_MEM_ERR;
868238104Sdes	}
869238104Sdes
870238104Sdes	/* we need the original of the hashed name if this is
871238104Sdes	   an NSEC3, or an RRSIG that covers an NSEC3 */
872238104Sdes	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
873238104Sdes		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
874238104Sdes	}
875238104Sdes	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
876238104Sdes	    type_covered == LDNS_RR_TYPE_NSEC3) {
877238104Sdes		cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
878238104Sdes					 						   rr);
879238104Sdes		if (!cur_node) {
880238104Sdes			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
881238104Sdes		}
882238104Sdes	} else {
883238104Sdes		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
884238104Sdes	}
885238104Sdes
886238104Sdes	if (!cur_node) {
887238104Sdes		/* add */
888238104Sdes		cur_name = ldns_dnssec_name_new_frm_rr(rr);
889238104Sdes                if(!cur_name) return LDNS_STATUS_MEM_ERR;
890238104Sdes		cur_node = LDNS_MALLOC(ldns_rbnode_t);
891238104Sdes                if(!cur_node) {
892238104Sdes                        ldns_dnssec_name_free(cur_name);
893238104Sdes                        return LDNS_STATUS_MEM_ERR;
894238104Sdes                }
895238104Sdes		cur_node->key = ldns_rr_owner(rr);
896238104Sdes		cur_node->data = cur_name;
897238104Sdes		(void)ldns_rbtree_insert(zone->names, cur_node);
898238104Sdes	} else {
899238104Sdes		cur_name = (ldns_dnssec_name *) cur_node->data;
900238104Sdes		result = ldns_dnssec_name_add_rr(cur_name, rr);
901238104Sdes	}
902238104Sdes
903238104Sdes	if (result != LDNS_STATUS_OK) {
904238104Sdes		fprintf(stderr, "error adding rr: ");
905238104Sdes		ldns_rr_print(stderr, rr);
906238104Sdes	}
907238104Sdes
908238104Sdes	/*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
909238104Sdes	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
910238104Sdes		zone->soa = cur_name;
911238104Sdes	}
912238104Sdes
913238104Sdes	return result;
914238104Sdes}
915238104Sdes#endif /* HAVE_SSL */
916238104Sdes
917238104Sdesvoid
918238104Sdesldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
919238104Sdes		ldns_rbtree_t *tree,
920238104Sdes		bool print_soa)
921238104Sdes{
922238104Sdes	ldns_rbnode_t *node;
923238104Sdes	ldns_dnssec_name *name;
924238104Sdes
925238104Sdes	node = ldns_rbtree_first(tree);
926238104Sdes	while (node != LDNS_RBTREE_NULL) {
927238104Sdes		name = (ldns_dnssec_name *) node->data;
928238104Sdes		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
929238104Sdes		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
930238104Sdes			fprintf(out, ";\n");
931238104Sdes		node = ldns_rbtree_next(node);
932238104Sdes	}
933238104Sdes}
934238104Sdes
935238104Sdesvoid
936238104Sdesldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
937238104Sdes{
938238104Sdes	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
939238104Sdes		       tree, print_soa);
940238104Sdes}
941238104Sdes
942238104Sdesvoid
943238104Sdesldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
944238104Sdes	       ldns_dnssec_zone *zone)
945238104Sdes{
946238104Sdes	if (zone) {
947238104Sdes		if (zone->soa) {
948238104Sdes			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
949238104Sdes				fprintf(out, ";; Zone: ");
950238104Sdes				ldns_rdf_print(out, ldns_dnssec_name_name(
951238104Sdes							zone->soa));
952238104Sdes				fprintf(out, "\n;\n");
953238104Sdes			}
954238104Sdes			ldns_dnssec_rrsets_print_fmt(out, fmt,
955238104Sdes					ldns_dnssec_name_find_rrset(
956238104Sdes						zone->soa,
957238104Sdes						LDNS_RR_TYPE_SOA),
958238104Sdes					false);
959238104Sdes			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
960238104Sdes				fprintf(out, ";\n");
961238104Sdes		}
962238104Sdes
963238104Sdes		if (zone->names) {
964238104Sdes			ldns_dnssec_zone_names_print_fmt(out, fmt,
965238104Sdes					zone->names, false);
966238104Sdes		}
967238104Sdes	}
968238104Sdes}
969238104Sdes
970238104Sdesvoid
971238104Sdesldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
972238104Sdes{
973238104Sdes	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
974238104Sdes}
975238104Sdes
976238104Sdesldns_status
977238104Sdesldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
978238104Sdes{
979238104Sdes	ldns_dnssec_name *new_name;
980238104Sdes	ldns_rdf *cur_name;
981238104Sdes	ldns_rdf *next_name;
982238104Sdes	ldns_rbnode_t *cur_node, *next_node, *new_node;
983238104Sdes
984238104Sdes	/* for the detection */
985238104Sdes	uint16_t i, cur_label_count, next_label_count;
986238104Sdes	uint16_t soa_label_count = 0;
987238104Sdes	ldns_rdf *l1, *l2;
988238104Sdes	int lpos;
989238104Sdes
990238104Sdes	if (!zone) {
991238104Sdes		return LDNS_STATUS_ERR;
992238104Sdes	}
993238104Sdes	if (zone->soa && zone->soa->name) {
994238104Sdes		soa_label_count = ldns_dname_label_count(zone->soa->name);
995238104Sdes	}
996238104Sdes
997238104Sdes	cur_node = ldns_rbtree_first(zone->names);
998238104Sdes	while (cur_node != LDNS_RBTREE_NULL) {
999238104Sdes		next_node = ldns_rbtree_next(cur_node);
1000238104Sdes
1001238104Sdes		/* skip glue */
1002238104Sdes		while (next_node != LDNS_RBTREE_NULL &&
1003238104Sdes		       next_node->data &&
1004238104Sdes		       ((ldns_dnssec_name *)next_node->data)->is_glue
1005238104Sdes		) {
1006238104Sdes			next_node = ldns_rbtree_next(next_node);
1007238104Sdes		}
1008238104Sdes
1009238104Sdes		if (next_node == LDNS_RBTREE_NULL) {
1010238104Sdes			next_node = ldns_rbtree_first(zone->names);
1011238104Sdes		}
1012238104Sdes
1013238104Sdes		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1014238104Sdes		next_name = ((ldns_dnssec_name *)next_node->data)->name;
1015238104Sdes		cur_label_count = ldns_dname_label_count(cur_name);
1016238104Sdes		next_label_count = ldns_dname_label_count(next_name);
1017238104Sdes
1018238104Sdes		/* Since the names are in canonical order, we can
1019238104Sdes		 * recognize empty non-terminals by their labels;
1020238104Sdes		 * every label after the first one on the next owner
1021238104Sdes		 * name is a non-terminal if it either does not exist
1022238104Sdes		 * in the current name or is different from the same
1023238104Sdes		 * label in the current name (counting from the end)
1024238104Sdes		 */
1025238104Sdes		for (i = 1; i < next_label_count - soa_label_count; i++) {
1026238104Sdes			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1027238104Sdes			if (lpos >= 0) {
1028238104Sdes				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1029238104Sdes			} else {
1030238104Sdes				l1 = NULL;
1031238104Sdes			}
1032238104Sdes			l2 = ldns_dname_clone_from(next_name, i);
1033238104Sdes
1034238104Sdes			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1035238104Sdes				/* We have an empty nonterminal, add it to the
1036238104Sdes				 * tree
1037238104Sdes				 */
1038238104Sdes				new_name = ldns_dnssec_name_new();
1039238104Sdes				if (!new_name) {
1040238104Sdes					return LDNS_STATUS_MEM_ERR;
1041238104Sdes				}
1042238104Sdes				new_name->name = ldns_dname_clone_from(next_name,
1043238104Sdes				                                       i);
1044238104Sdes				if (!new_name->name) {
1045238104Sdes					ldns_dnssec_name_free(new_name);
1046238104Sdes					return LDNS_STATUS_MEM_ERR;
1047238104Sdes				}
1048238104Sdes				new_name->name_alloced = true;
1049238104Sdes				new_node = LDNS_MALLOC(ldns_rbnode_t);
1050238104Sdes				if (!new_node) {
1051238104Sdes					ldns_dnssec_name_free(new_name);
1052238104Sdes					return LDNS_STATUS_MEM_ERR;
1053238104Sdes				}
1054238104Sdes				new_node->key = new_name->name;
1055238104Sdes				new_node->data = new_name;
1056238104Sdes				(void)ldns_rbtree_insert(zone->names, new_node);
1057238104Sdes			}
1058238104Sdes			ldns_rdf_deep_free(l1);
1059238104Sdes			ldns_rdf_deep_free(l2);
1060238104Sdes		}
1061238104Sdes
1062238104Sdes		/* we might have inserted a new node after
1063238104Sdes		 * the current one so we can't just use next()
1064238104Sdes		 */
1065238104Sdes		if (next_node != ldns_rbtree_first(zone->names)) {
1066238104Sdes			cur_node = next_node;
1067238104Sdes		} else {
1068238104Sdes			cur_node = LDNS_RBTREE_NULL;
1069238104Sdes		}
1070238104Sdes	}
1071238104Sdes	return LDNS_STATUS_OK;
1072238104Sdes}
1073238104Sdes
1074238104Sdesbool
1075238104Sdesldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1076238104Sdes{
1077238104Sdes	ldns_rr* nsec3;
1078238104Sdes	ldns_rbnode_t* node;
1079238104Sdes
1080238104Sdes	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1081238104Sdes		node = ldns_rbtree_first(zone->names);
1082238104Sdes		while (node != LDNS_RBTREE_NULL) {
1083238104Sdes			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1084238104Sdes			if (nsec3 &&ldns_rr_get_type(nsec3)
1085238104Sdes					== LDNS_RR_TYPE_NSEC3 &&
1086238104Sdes					ldns_nsec3_optout(nsec3)) {
1087238104Sdes				return true;
1088238104Sdes			}
1089238104Sdes			node = ldns_rbtree_next(node);
1090238104Sdes		}
1091238104Sdes	}
1092238104Sdes	return false;
1093238104Sdes}
1094