dnssec_zone.c revision 246827
1/*
2 * special zone file structures and functions for better dnssec handling
3 */
4
5#include <ldns/config.h>
6
7#include <ldns/ldns.h>
8
9ldns_dnssec_rrs *
10ldns_dnssec_rrs_new(void)
11{
12	ldns_dnssec_rrs *new_rrs;
13	new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
14        if(!new_rrs) return NULL;
15	new_rrs->rr = NULL;
16	new_rrs->next = NULL;
17	return new_rrs;
18}
19
20INLINE void
21ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
22{
23	ldns_dnssec_rrs *next;
24	while (rrs) {
25		next = rrs->next;
26		if (deep) {
27			ldns_rr_free(rrs->rr);
28		}
29		LDNS_FREE(rrs);
30		rrs = next;
31	}
32}
33
34void
35ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
36{
37	ldns_dnssec_rrs_free_internal(rrs, 0);
38}
39
40void
41ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
42{
43	ldns_dnssec_rrs_free_internal(rrs, 1);
44}
45
46ldns_status
47ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
48{
49	int cmp;
50	ldns_dnssec_rrs *new_rrs;
51	if (!rrs || !rr) {
52		return LDNS_STATUS_ERR;
53	}
54
55	/* this could be done more efficiently; name and type should already
56	   be equal */
57	cmp = ldns_rr_compare(rrs->rr,
58					  rr);
59	/* should we error on equal? */
60	if (cmp <= 0) {
61		if (rrs->next) {
62			return ldns_dnssec_rrs_add_rr(rrs->next, rr);
63		} else {
64			new_rrs = ldns_dnssec_rrs_new();
65			new_rrs->rr = rr;
66			rrs->next = new_rrs;
67		}
68	} else if (cmp > 0) {
69		/* put the current old rr in the new next, put the new
70		   rr in the current container */
71		new_rrs = ldns_dnssec_rrs_new();
72		new_rrs->rr = rrs->rr;
73		new_rrs->next = rrs->next;
74		rrs->rr = rr;
75		rrs->next = new_rrs;
76	}
77	return LDNS_STATUS_OK;
78}
79
80void
81ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
82	       ldns_dnssec_rrs *rrs)
83{
84	if (!rrs) {
85		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
86			fprintf(out, "; <void>");
87	} else {
88		if (rrs->rr) {
89			ldns_rr_print_fmt(out, fmt, rrs->rr);
90		}
91		if (rrs->next) {
92			ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
93		}
94	}
95}
96
97void
98ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs)
99{
100	ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
101}
102
103
104ldns_dnssec_rrsets *
105ldns_dnssec_rrsets_new(void)
106{
107	ldns_dnssec_rrsets *new_rrsets;
108	new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
109        if(!new_rrsets) return NULL;
110	new_rrsets->rrs = NULL;
111	new_rrsets->type = 0;
112	new_rrsets->signatures = NULL;
113	new_rrsets->next = NULL;
114	return new_rrsets;
115}
116
117INLINE void
118ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
119{
120	if (rrsets) {
121		if (rrsets->rrs) {
122			ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
123		}
124		if (rrsets->next) {
125			ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
126		}
127		if (rrsets->signatures) {
128			ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
129		}
130		LDNS_FREE(rrsets);
131	}
132}
133
134void
135ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
136{
137	ldns_dnssec_rrsets_free_internal(rrsets, 0);
138}
139
140void
141ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
142{
143	ldns_dnssec_rrsets_free_internal(rrsets, 1);
144}
145
146ldns_rr_type
147ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets)
148{
149	if (rrsets) {
150		return rrsets->type;
151	} else {
152		return 0;
153	}
154}
155
156ldns_status
157ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
158					   ldns_rr_type type)
159{
160	if (rrsets) {
161		rrsets->type = type;
162		return LDNS_STATUS_OK;
163	}
164	return LDNS_STATUS_ERR;
165}
166
167static ldns_dnssec_rrsets *
168ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
169{
170	ldns_dnssec_rrsets *new_rrsets;
171	ldns_rr_type rr_type;
172	bool rrsig;
173
174	new_rrsets = ldns_dnssec_rrsets_new();
175	rr_type = ldns_rr_get_type(rr);
176	if (rr_type == LDNS_RR_TYPE_RRSIG) {
177		rrsig = true;
178		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
179	} else {
180		rrsig = false;
181	}
182	if (!rrsig) {
183		new_rrsets->rrs = ldns_dnssec_rrs_new();
184		new_rrsets->rrs->rr = rr;
185	} else {
186		new_rrsets->signatures = ldns_dnssec_rrs_new();
187		new_rrsets->signatures->rr = rr;
188	}
189	new_rrsets->type = rr_type;
190	return new_rrsets;
191}
192
193ldns_status
194ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
195{
196	ldns_dnssec_rrsets *new_rrsets;
197	ldns_rr_type rr_type;
198	bool rrsig = false;
199	ldns_status result = LDNS_STATUS_OK;
200
201	if (!rrsets || !rr) {
202		return LDNS_STATUS_ERR;
203	}
204
205	rr_type = ldns_rr_get_type(rr);
206
207	if (rr_type == LDNS_RR_TYPE_RRSIG) {
208		rrsig = true;
209		rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
210	}
211
212	if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
213		if (!rrsig) {
214			rrsets->rrs = ldns_dnssec_rrs_new();
215			rrsets->rrs->rr = rr;
216			rrsets->type = rr_type;
217		} else {
218			rrsets->signatures = ldns_dnssec_rrs_new();
219			rrsets->signatures->rr = rr;
220			rrsets->type = rr_type;
221		}
222		return LDNS_STATUS_OK;
223	}
224
225	if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
226		if (rrsets->next) {
227			result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
228		} else {
229			new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
230			rrsets->next = new_rrsets;
231		}
232	} else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
233		/* move the current one into the new next,
234		   replace field of current with data from new rr */
235		new_rrsets = ldns_dnssec_rrsets_new();
236		new_rrsets->rrs = rrsets->rrs;
237		new_rrsets->type = rrsets->type;
238		new_rrsets->signatures = rrsets->signatures;
239		new_rrsets->next = rrsets->next;
240		if (!rrsig) {
241			rrsets->rrs = ldns_dnssec_rrs_new();
242			rrsets->rrs->rr = rr;
243			rrsets->signatures = NULL;
244		} else {
245			rrsets->rrs = NULL;
246			rrsets->signatures = ldns_dnssec_rrs_new();
247			rrsets->signatures->rr = rr;
248		}
249		rrsets->type = rr_type;
250		rrsets->next = new_rrsets;
251	} else {
252		/* equal, add to current rrsets */
253		if (rrsig) {
254			if (rrsets->signatures) {
255				result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
256			} else {
257				rrsets->signatures = ldns_dnssec_rrs_new();
258				rrsets->signatures->rr = rr;
259			}
260		} else {
261			if (rrsets->rrs) {
262				result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
263			} else {
264				rrsets->rrs = ldns_dnssec_rrs_new();
265				rrsets->rrs->rr = rr;
266			}
267		}
268	}
269
270	return result;
271}
272
273static void
274ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
275		ldns_dnssec_rrsets *rrsets,
276		bool follow,
277		bool show_soa)
278{
279	if (!rrsets) {
280		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
281			fprintf(out, "; <void>\n");
282	} else {
283		if (rrsets->rrs &&
284		    (show_soa ||
285			ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
286		    )
287		   ) {
288			ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
289			if (rrsets->signatures) {
290				ldns_dnssec_rrs_print_fmt(out, fmt,
291						rrsets->signatures);
292			}
293		}
294		if (follow && rrsets->next) {
295			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
296					rrsets->next, follow, show_soa);
297		}
298	}
299}
300
301static void
302ldns_dnssec_rrsets_print_soa(FILE *out,
303		ldns_dnssec_rrsets *rrsets,
304		bool follow,
305		bool show_soa)
306{
307	ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default,
308		       	rrsets, follow, show_soa);
309}
310
311
312void
313ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
314		ldns_dnssec_rrsets *rrsets,
315		bool follow)
316{
317	ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
318}
319
320void
321ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
322{
323	ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
324			rrsets, follow);
325}
326
327ldns_dnssec_name *
328ldns_dnssec_name_new(void)
329{
330	ldns_dnssec_name *new_name;
331
332	new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
333	if (!new_name) {
334		return NULL;
335	}
336	/*
337	 * not needed anymore because CALLOC initalizes everything to zero.
338
339	new_name->name = NULL;
340	new_name->rrsets = NULL;
341	new_name->name_alloced = false;
342	new_name->nsec = NULL;
343	new_name->nsec_signatures = NULL;
344
345	new_name->is_glue = false;
346	new_name->hashed_name = NULL;
347
348	 */
349	return new_name;
350}
351
352ldns_dnssec_name *
353ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
354{
355	ldns_dnssec_name *new_name = ldns_dnssec_name_new();
356
357	new_name->name = ldns_rr_owner(rr);
358	if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
359		ldns_dnssec_name_free(new_name);
360		return NULL;
361	}
362
363	return new_name;
364}
365
366INLINE void
367ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
368                               int deep)
369{
370	if (name) {
371		if (name->name_alloced) {
372			ldns_rdf_deep_free(name->name);
373		}
374		if (name->rrsets) {
375			ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
376		}
377		if (name->nsec && deep) {
378			ldns_rr_free(name->nsec);
379		}
380		if (name->nsec_signatures) {
381			ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
382		}
383		if (name->hashed_name) {
384			if (deep) {
385				ldns_rdf_deep_free(name->hashed_name);
386			}
387		}
388		LDNS_FREE(name);
389	}
390}
391
392void
393ldns_dnssec_name_free(ldns_dnssec_name *name)
394{
395  ldns_dnssec_name_free_internal(name, 0);
396}
397
398void
399ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
400{
401  ldns_dnssec_name_free_internal(name, 1);
402}
403
404ldns_rdf *
405ldns_dnssec_name_name(ldns_dnssec_name *name)
406{
407	if (name) {
408		return name->name;
409	}
410	return NULL;
411}
412
413bool
414ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
415{
416	if (name) {
417		return name->is_glue;
418	}
419	return false;
420}
421
422void
423ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
424					 ldns_rdf *dname)
425{
426	if (rrset && dname) {
427		rrset->name = dname;
428	}
429}
430
431static ldns_rr *
432ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
433{
434	if (rrset) {
435		return rrset->nsec;
436	}
437	return NULL;
438}
439
440void
441ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
442{
443	if (rrset && nsec) {
444		rrset->nsec = nsec;
445	}
446}
447
448int
449ldns_dnssec_name_cmp(const void *a, const void *b)
450{
451	ldns_dnssec_name *na = (ldns_dnssec_name *) a;
452	ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
453
454	if (na && nb) {
455		return ldns_dname_compare(ldns_dnssec_name_name(na),
456							 ldns_dnssec_name_name(nb));
457	} else if (na) {
458		return 1;
459	} else if (nb) {
460		return -1;
461	} else {
462		return 0;
463	}
464}
465
466ldns_status
467ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
468				    ldns_rr *rr)
469{
470	ldns_status result = LDNS_STATUS_OK;
471	ldns_rdf *name_name;
472	bool hashed_name = false;
473	ldns_rr_type rr_type;
474	ldns_rr_type typecovered = 0;
475
476	/* special handling for NSEC3 and NSECX covering RRSIGS */
477
478	if (!name || !rr) {
479		return LDNS_STATUS_ERR;
480	}
481
482	rr_type = ldns_rr_get_type(rr);
483
484	if (rr_type == LDNS_RR_TYPE_RRSIG) {
485		typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
486	}
487
488#ifdef HAVE_SSL
489	if (rr_type == LDNS_RR_TYPE_NSEC3 ||
490	    typecovered == LDNS_RR_TYPE_NSEC3) {
491		name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
492										   ldns_dnssec_name_name(name));
493		hashed_name = true;
494	} else {
495		name_name = ldns_dnssec_name_name(name);
496	}
497#else
498	name_name = ldns_dnssec_name_name(name);
499#endif /* HAVE_SSL */
500
501	if (rr_type == LDNS_RR_TYPE_NSEC ||
502	    rr_type == LDNS_RR_TYPE_NSEC3) {
503		/* XX check if is already set (and error?) */
504		name->nsec = rr;
505	} else if (typecovered == LDNS_RR_TYPE_NSEC ||
506			 typecovered == LDNS_RR_TYPE_NSEC3) {
507		if (name->nsec_signatures) {
508			result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
509		} else {
510			name->nsec_signatures = ldns_dnssec_rrs_new();
511			name->nsec_signatures->rr = rr;
512		}
513	} else {
514		/* it's a 'normal' RR, add it to the right rrset */
515		if (name->rrsets) {
516			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
517		} else {
518			name->rrsets = ldns_dnssec_rrsets_new();
519			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
520		}
521	}
522
523	if (hashed_name) {
524		ldns_rdf_deep_free(name_name);
525	}
526
527	return result;
528}
529
530ldns_dnssec_rrsets *
531ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
532					   ldns_rr_type type) {
533	ldns_dnssec_rrsets *result;
534
535	result = name->rrsets;
536	while (result) {
537		if (result->type == type) {
538			return result;
539		} else {
540			result = result->next;
541		}
542	}
543	return NULL;
544}
545
546ldns_dnssec_rrsets *
547ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
548					   ldns_rdf *dname,
549					   ldns_rr_type type)
550{
551	ldns_rbnode_t *node;
552
553	if (!zone || !dname) {
554		return NULL;
555	}
556
557	node = ldns_rbtree_search(zone->names, dname);
558	if (node) {
559		return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
560									type);
561	} else {
562		return NULL;
563	}
564}
565
566static void
567ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
568		ldns_dnssec_name *name,
569		bool show_soa)
570{
571	if (name) {
572		if(name->rrsets) {
573			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
574					name->rrsets, true, show_soa);
575		} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
576			fprintf(out, ";; Empty nonterminal: ");
577			ldns_rdf_print(out, name->name);
578			fprintf(out, "\n");
579		}
580		if(name->nsec) {
581			ldns_rr_print_fmt(out, fmt, name->nsec);
582		}
583		if (name->nsec_signatures) {
584			ldns_dnssec_rrs_print_fmt(out, fmt,
585					name->nsec_signatures);
586		}
587	} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
588		fprintf(out, "; <void>\n");
589	}
590}
591
592static void
593ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
594{
595	ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default,
596		       name, show_soa);
597}
598
599void
600ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
601		ldns_dnssec_name *name)
602{
603	ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
604}
605
606void
607ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
608{
609	ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
610}
611
612
613ldns_dnssec_zone *
614ldns_dnssec_zone_new(void)
615{
616	ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
617        if(!zone) return NULL;
618	zone->soa = NULL;
619	zone->names = NULL;
620
621	return zone;
622}
623
624static bool
625rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
626{
627	return     ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
628		&& ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
629}
630
631/* When the zone is first read into an list and then inserted into an
632 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
633 * to each other. Because ldns-verify-zone (the only program that uses this
634 * function) uses the rbtree mostly for sequentual walking, this results
635 * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
636 */
637#define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
638
639ldns_status
640ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
641	       	uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
642{
643	ldns_rr* cur_rr;
644	size_t i;
645
646	ldns_rdf *my_origin = NULL;
647	ldns_rdf *my_prev = NULL;
648
649	ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
650	/* when reading NSEC3s, there is a chance that we encounter nsecs
651	   for empty nonterminals, whose nonterminals we cannot derive yet
652	   because the needed information is to be read later. in that case
653	   we keep a list of those nsec3's and retry to add them later */
654	ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
655	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
656
657	ldns_status status = LDNS_STATUS_MEM_ERR;
658
659#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
660	ldns_zone* zone = NULL;
661	if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
662			!= LDNS_STATUS_OK) goto error;
663#else
664	uint32_t  my_ttl = ttl;
665#endif
666
667	if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
668
669	if (origin) {
670		if (!(my_origin = ldns_rdf_clone(origin))) goto error;
671		if (!(my_prev   = ldns_rdf_clone(origin))) goto error;
672	}
673
674#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
675	if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
676			!= LDNS_STATUS_OK) goto error;
677
678	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
679		cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
680		status = LDNS_STATUS_OK;
681#else
682	while (!feof(fp)) {
683		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
684				&my_prev, line_nr);
685
686#endif
687		switch (status) {
688		case LDNS_STATUS_OK:
689
690			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
691			if (status ==
692				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
693
694				if (rr_is_rrsig_covering(cur_rr,
695							LDNS_RR_TYPE_NSEC3)){
696					ldns_rr_list_push_rr(todo_nsec3_rrsigs,
697							cur_rr);
698				} else {
699					ldns_rr_list_push_rr(todo_nsec3s,
700						       	cur_rr);
701				}
702			} else if (status != LDNS_STATUS_OK)
703				goto error;
704
705			break;
706
707
708		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
709		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
710		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
711			break;
712
713		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
714			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
715			break;
716
717		default:
718			goto error;
719		}
720	}
721
722	if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
723		(void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
724		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
725			cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
726			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
727		}
728		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++){
729			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
730			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
731		}
732	} else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
733		for (i = 0; i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++){
734			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
735			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
736		}
737	}
738
739	ldns_rr_list_free(todo_nsec3_rrsigs);
740	ldns_rr_list_free(todo_nsec3s);
741
742	if (z) {
743		*z = newzone;
744	} else {
745		ldns_dnssec_zone_free(newzone);
746	}
747
748	return LDNS_STATUS_OK;
749
750error:
751#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
752	if (zone) {
753		ldns_zone_free(zone);
754	}
755#endif
756	if (my_origin) {
757		ldns_rdf_deep_free(my_origin);
758	}
759	if (my_prev) {
760		ldns_rdf_deep_free(my_prev);
761	}
762	if (newzone) {
763		ldns_dnssec_zone_free(newzone);
764	}
765	return status;
766}
767
768ldns_status
769ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
770		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
771{
772	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
773}
774
775static void
776ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
777	(void) arg;
778	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
779	LDNS_FREE(node);
780}
781
782static void
783ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
784	(void) arg;
785	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
786	LDNS_FREE(node);
787}
788
789void
790ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
791{
792	if (zone) {
793		if (zone->names) {
794			/* destroy all name structures within the tree */
795			ldns_traverse_postorder(zone->names,
796						    ldns_dnssec_name_node_free,
797						    NULL);
798			LDNS_FREE(zone->names);
799		}
800		LDNS_FREE(zone);
801	}
802}
803
804void
805ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
806{
807	if (zone) {
808		if (zone->names) {
809			/* destroy all name structures within the tree */
810			ldns_traverse_postorder(zone->names,
811						    ldns_dnssec_name_node_deep_free,
812						    NULL);
813			LDNS_FREE(zone->names);
814		}
815		LDNS_FREE(zone);
816	}
817}
818
819/* use for dname comparison in tree */
820static int
821ldns_dname_compare_v(const void *a, const void *b) {
822	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
823}
824
825#ifdef HAVE_SSL
826static ldns_rbnode_t *
827ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
828                                     ldns_rr *rr) {
829	ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
830	ldns_dnssec_name *current_name;
831	ldns_rdf *hashed_name;
832
833	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
834
835	while (current_node != LDNS_RBTREE_NULL) {
836		current_name = (ldns_dnssec_name *) current_node->data;
837		if (!current_name->hashed_name) {
838			current_name->hashed_name =
839				ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
840		}
841		if (ldns_dname_compare(hashed_name,
842						   current_name->hashed_name)
843		    == 0) {
844			ldns_rdf_deep_free(hashed_name);
845			return current_node;
846		}
847		current_node = ldns_rbtree_next(current_node);
848	}
849	ldns_rdf_deep_free(hashed_name);
850	return NULL;
851}
852
853ldns_status
854ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
855{
856	ldns_status result = LDNS_STATUS_OK;
857	ldns_dnssec_name *cur_name;
858	ldns_rbnode_t *cur_node;
859	ldns_rr_type type_covered = 0;
860
861	if (!zone || !rr) {
862		return LDNS_STATUS_ERR;
863	}
864
865	if (!zone->names) {
866		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
867                if(!zone->names) return LDNS_STATUS_MEM_ERR;
868	}
869
870	/* we need the original of the hashed name if this is
871	   an NSEC3, or an RRSIG that covers an NSEC3 */
872	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
873		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
874	}
875	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
876	    type_covered == LDNS_RR_TYPE_NSEC3) {
877		cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
878					 						   rr);
879		if (!cur_node) {
880			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
881		}
882	} else {
883		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
884	}
885
886	if (!cur_node) {
887		/* add */
888		cur_name = ldns_dnssec_name_new_frm_rr(rr);
889                if(!cur_name) return LDNS_STATUS_MEM_ERR;
890		cur_node = LDNS_MALLOC(ldns_rbnode_t);
891                if(!cur_node) {
892                        ldns_dnssec_name_free(cur_name);
893                        return LDNS_STATUS_MEM_ERR;
894                }
895		cur_node->key = ldns_rr_owner(rr);
896		cur_node->data = cur_name;
897		(void)ldns_rbtree_insert(zone->names, cur_node);
898	} else {
899		cur_name = (ldns_dnssec_name *) cur_node->data;
900		result = ldns_dnssec_name_add_rr(cur_name, rr);
901	}
902
903	if (result != LDNS_STATUS_OK) {
904		fprintf(stderr, "error adding rr: ");
905		ldns_rr_print(stderr, rr);
906	}
907
908	/*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
909	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
910		zone->soa = cur_name;
911	}
912
913	return result;
914}
915#endif /* HAVE_SSL */
916
917void
918ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
919		ldns_rbtree_t *tree,
920		bool print_soa)
921{
922	ldns_rbnode_t *node;
923	ldns_dnssec_name *name;
924
925	node = ldns_rbtree_first(tree);
926	while (node != LDNS_RBTREE_NULL) {
927		name = (ldns_dnssec_name *) node->data;
928		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
929		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
930			fprintf(out, ";\n");
931		node = ldns_rbtree_next(node);
932	}
933}
934
935void
936ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
937{
938	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
939		       tree, print_soa);
940}
941
942void
943ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
944	       ldns_dnssec_zone *zone)
945{
946	if (zone) {
947		if (zone->soa) {
948			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
949				fprintf(out, ";; Zone: ");
950				ldns_rdf_print(out, ldns_dnssec_name_name(
951							zone->soa));
952				fprintf(out, "\n;\n");
953			}
954			ldns_dnssec_rrsets_print_fmt(out, fmt,
955					ldns_dnssec_name_find_rrset(
956						zone->soa,
957						LDNS_RR_TYPE_SOA),
958					false);
959			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
960				fprintf(out, ";\n");
961		}
962
963		if (zone->names) {
964			ldns_dnssec_zone_names_print_fmt(out, fmt,
965					zone->names, false);
966		}
967	}
968}
969
970void
971ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
972{
973	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
974}
975
976ldns_status
977ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
978{
979	ldns_dnssec_name *new_name;
980	ldns_rdf *cur_name;
981	ldns_rdf *next_name;
982	ldns_rbnode_t *cur_node, *next_node, *new_node;
983
984	/* for the detection */
985	uint16_t i, cur_label_count, next_label_count;
986	uint16_t soa_label_count = 0;
987	ldns_rdf *l1, *l2;
988	int lpos;
989
990	if (!zone) {
991		return LDNS_STATUS_ERR;
992	}
993	if (zone->soa && zone->soa->name) {
994		soa_label_count = ldns_dname_label_count(zone->soa->name);
995	}
996
997	cur_node = ldns_rbtree_first(zone->names);
998	while (cur_node != LDNS_RBTREE_NULL) {
999		next_node = ldns_rbtree_next(cur_node);
1000
1001		/* skip glue */
1002		while (next_node != LDNS_RBTREE_NULL &&
1003		       next_node->data &&
1004		       ((ldns_dnssec_name *)next_node->data)->is_glue
1005		) {
1006			next_node = ldns_rbtree_next(next_node);
1007		}
1008
1009		if (next_node == LDNS_RBTREE_NULL) {
1010			next_node = ldns_rbtree_first(zone->names);
1011		}
1012
1013		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1014		next_name = ((ldns_dnssec_name *)next_node->data)->name;
1015		cur_label_count = ldns_dname_label_count(cur_name);
1016		next_label_count = ldns_dname_label_count(next_name);
1017
1018		/* Since the names are in canonical order, we can
1019		 * recognize empty non-terminals by their labels;
1020		 * every label after the first one on the next owner
1021		 * name is a non-terminal if it either does not exist
1022		 * in the current name or is different from the same
1023		 * label in the current name (counting from the end)
1024		 */
1025		for (i = 1; i < next_label_count - soa_label_count; i++) {
1026			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1027			if (lpos >= 0) {
1028				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1029			} else {
1030				l1 = NULL;
1031			}
1032			l2 = ldns_dname_clone_from(next_name, i);
1033
1034			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1035				/* We have an empty nonterminal, add it to the
1036				 * tree
1037				 */
1038				new_name = ldns_dnssec_name_new();
1039				if (!new_name) {
1040					return LDNS_STATUS_MEM_ERR;
1041				}
1042				new_name->name = ldns_dname_clone_from(next_name,
1043				                                       i);
1044				if (!new_name->name) {
1045					ldns_dnssec_name_free(new_name);
1046					return LDNS_STATUS_MEM_ERR;
1047				}
1048				new_name->name_alloced = true;
1049				new_node = LDNS_MALLOC(ldns_rbnode_t);
1050				if (!new_node) {
1051					ldns_dnssec_name_free(new_name);
1052					return LDNS_STATUS_MEM_ERR;
1053				}
1054				new_node->key = new_name->name;
1055				new_node->data = new_name;
1056				(void)ldns_rbtree_insert(zone->names, new_node);
1057			}
1058			ldns_rdf_deep_free(l1);
1059			ldns_rdf_deep_free(l2);
1060		}
1061
1062		/* we might have inserted a new node after
1063		 * the current one so we can't just use next()
1064		 */
1065		if (next_node != ldns_rbtree_first(zone->names)) {
1066			cur_node = next_node;
1067		} else {
1068			cur_node = LDNS_RBTREE_NULL;
1069		}
1070	}
1071	return LDNS_STATUS_OK;
1072}
1073
1074bool
1075ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1076{
1077	ldns_rr* nsec3;
1078	ldns_rbnode_t* node;
1079
1080	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1081		node = ldns_rbtree_first(zone->names);
1082		while (node != LDNS_RBTREE_NULL) {
1083			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1084			if (nsec3 &&ldns_rr_get_type(nsec3)
1085					== LDNS_RR_TYPE_NSEC3 &&
1086					ldns_nsec3_optout(nsec3)) {
1087				return true;
1088			}
1089			node = ldns_rbtree_next(node);
1090		}
1091	}
1092	return false;
1093}
1094