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
301
302void
303ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
304		ldns_dnssec_rrsets *rrsets,
305		bool follow)
306{
307	ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
308}
309
310void
311ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
312{
313	ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
314			rrsets, follow);
315}
316
317ldns_dnssec_name *
318ldns_dnssec_name_new(void)
319{
320	ldns_dnssec_name *new_name;
321
322	new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
323	if (!new_name) {
324		return NULL;
325	}
326	/*
327	 * not needed anymore because CALLOC initalizes everything to zero.
328
329	new_name->name = NULL;
330	new_name->rrsets = NULL;
331	new_name->name_alloced = false;
332	new_name->nsec = NULL;
333	new_name->nsec_signatures = NULL;
334
335	new_name->is_glue = false;
336	new_name->hashed_name = NULL;
337
338	 */
339	return new_name;
340}
341
342ldns_dnssec_name *
343ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
344{
345	ldns_dnssec_name *new_name = ldns_dnssec_name_new();
346
347	new_name->name = ldns_rr_owner(rr);
348	if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
349		ldns_dnssec_name_free(new_name);
350		return NULL;
351	}
352
353	return new_name;
354}
355
356INLINE void
357ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
358                               int deep)
359{
360	if (name) {
361		if (name->name_alloced) {
362			ldns_rdf_deep_free(name->name);
363		}
364		if (name->rrsets) {
365			ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
366		}
367		if (name->nsec && deep) {
368			ldns_rr_free(name->nsec);
369		}
370		if (name->nsec_signatures) {
371			ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
372		}
373		if (name->hashed_name) {
374			if (deep) {
375				ldns_rdf_deep_free(name->hashed_name);
376			}
377		}
378		LDNS_FREE(name);
379	}
380}
381
382void
383ldns_dnssec_name_free(ldns_dnssec_name *name)
384{
385  ldns_dnssec_name_free_internal(name, 0);
386}
387
388void
389ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
390{
391  ldns_dnssec_name_free_internal(name, 1);
392}
393
394ldns_rdf *
395ldns_dnssec_name_name(ldns_dnssec_name *name)
396{
397	if (name) {
398		return name->name;
399	}
400	return NULL;
401}
402
403bool
404ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
405{
406	if (name) {
407		return name->is_glue;
408	}
409	return false;
410}
411
412void
413ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
414					 ldns_rdf *dname)
415{
416	if (rrset && dname) {
417		rrset->name = dname;
418	}
419}
420
421
422void
423ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
424{
425	if (rrset && nsec) {
426		rrset->nsec = nsec;
427	}
428}
429
430int
431ldns_dnssec_name_cmp(const void *a, const void *b)
432{
433	ldns_dnssec_name *na = (ldns_dnssec_name *) a;
434	ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
435
436	if (na && nb) {
437		return ldns_dname_compare(ldns_dnssec_name_name(na),
438							 ldns_dnssec_name_name(nb));
439	} else if (na) {
440		return 1;
441	} else if (nb) {
442		return -1;
443	} else {
444		return 0;
445	}
446}
447
448ldns_status
449ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
450				    ldns_rr *rr)
451{
452	ldns_status result = LDNS_STATUS_OK;
453	ldns_rdf *name_name;
454	bool hashed_name = false;
455	ldns_rr_type rr_type;
456	ldns_rr_type typecovered = 0;
457
458	/* special handling for NSEC3 and NSECX covering RRSIGS */
459
460	if (!name || !rr) {
461		return LDNS_STATUS_ERR;
462	}
463
464	rr_type = ldns_rr_get_type(rr);
465
466	if (rr_type == LDNS_RR_TYPE_RRSIG) {
467		typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
468	}
469
470#ifdef HAVE_SSL
471	if (rr_type == LDNS_RR_TYPE_NSEC3 ||
472	    typecovered == LDNS_RR_TYPE_NSEC3) {
473		name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
474										   ldns_dnssec_name_name(name));
475		hashed_name = true;
476	} else {
477		name_name = ldns_dnssec_name_name(name);
478	}
479#else
480	name_name = ldns_dnssec_name_name(name);
481#endif /* HAVE_SSL */
482
483	if (rr_type == LDNS_RR_TYPE_NSEC ||
484	    rr_type == LDNS_RR_TYPE_NSEC3) {
485		/* XX check if is already set (and error?) */
486		name->nsec = rr;
487	} else if (typecovered == LDNS_RR_TYPE_NSEC ||
488			 typecovered == LDNS_RR_TYPE_NSEC3) {
489		if (name->nsec_signatures) {
490			result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
491		} else {
492			name->nsec_signatures = ldns_dnssec_rrs_new();
493			name->nsec_signatures->rr = rr;
494		}
495	} else {
496		/* it's a 'normal' RR, add it to the right rrset */
497		if (name->rrsets) {
498			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
499		} else {
500			name->rrsets = ldns_dnssec_rrsets_new();
501			result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
502		}
503	}
504
505	if (hashed_name) {
506		ldns_rdf_deep_free(name_name);
507	}
508
509	return result;
510}
511
512ldns_dnssec_rrsets *
513ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
514					   ldns_rr_type type) {
515	ldns_dnssec_rrsets *result;
516
517	result = name->rrsets;
518	while (result) {
519		if (result->type == type) {
520			return result;
521		} else {
522			result = result->next;
523		}
524	}
525	return NULL;
526}
527
528ldns_dnssec_rrsets *
529ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
530					   ldns_rdf *dname,
531					   ldns_rr_type type)
532{
533	ldns_rbnode_t *node;
534
535	if (!zone || !dname) {
536		return NULL;
537	}
538
539	node = ldns_rbtree_search(zone->names, dname);
540	if (node) {
541		return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
542									type);
543	} else {
544		return NULL;
545	}
546}
547
548static void
549ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
550		ldns_dnssec_name *name,
551		bool show_soa)
552{
553	if (name) {
554		if(name->rrsets) {
555			ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
556					name->rrsets, true, show_soa);
557		} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
558			fprintf(out, ";; Empty nonterminal: ");
559			ldns_rdf_print(out, name->name);
560			fprintf(out, "\n");
561		}
562		if(name->nsec) {
563			ldns_rr_print_fmt(out, fmt, name->nsec);
564		}
565		if (name->nsec_signatures) {
566			ldns_dnssec_rrs_print_fmt(out, fmt,
567					name->nsec_signatures);
568		}
569	} else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
570		fprintf(out, "; <void>\n");
571	}
572}
573
574
575void
576ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
577		ldns_dnssec_name *name)
578{
579	ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
580}
581
582void
583ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
584{
585	ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
586}
587
588
589ldns_dnssec_zone *
590ldns_dnssec_zone_new(void)
591{
592	ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
593        if(!zone) return NULL;
594	zone->soa = NULL;
595	zone->names = NULL;
596
597	return zone;
598}
599
600static bool
601rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
602{
603	return     ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
604		&& ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
605}
606
607/* When the zone is first read into an list and then inserted into an
608 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
609 * to each other. Because ldns-verify-zone (the only program that uses this
610 * function) uses the rbtree mostly for sequentual walking, this results
611 * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
612 */
613#define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
614
615ldns_status
616ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
617	       	uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
618{
619	ldns_rr* cur_rr;
620	size_t i;
621
622	ldns_rdf *my_origin = NULL;
623	ldns_rdf *my_prev = NULL;
624
625	ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
626	/* when reading NSEC3s, there is a chance that we encounter nsecs
627	   for empty nonterminals, whose nonterminals we cannot derive yet
628	   because the needed information is to be read later. in that case
629	   we keep a list of those nsec3's and retry to add them later */
630	ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
631	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
632
633	ldns_status status = LDNS_STATUS_MEM_ERR;
634
635#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
636	ldns_zone* zone = NULL;
637	if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
638			!= LDNS_STATUS_OK) goto error;
639#else
640	uint32_t  my_ttl = ttl;
641#endif
642
643	if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
644
645	if (origin) {
646		if (!(my_origin = ldns_rdf_clone(origin))) goto error;
647		if (!(my_prev   = ldns_rdf_clone(origin))) goto error;
648	}
649
650#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
651	if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
652			!= LDNS_STATUS_OK) goto error;
653
654	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
655		cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
656		status = LDNS_STATUS_OK;
657#else
658	while (!feof(fp)) {
659		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
660				&my_prev, line_nr);
661
662#endif
663		switch (status) {
664		case LDNS_STATUS_OK:
665
666			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
667			if (status ==
668				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
669
670				if (rr_is_rrsig_covering(cur_rr,
671							LDNS_RR_TYPE_NSEC3)){
672					ldns_rr_list_push_rr(todo_nsec3_rrsigs,
673							cur_rr);
674				} else {
675					ldns_rr_list_push_rr(todo_nsec3s,
676						       	cur_rr);
677				}
678			} else if (status != LDNS_STATUS_OK)
679				goto error;
680
681			break;
682
683
684		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
685		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
686		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
687			status = LDNS_STATUS_OK;
688			break;
689
690		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
691			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
692			break;
693
694		default:
695			goto error;
696		}
697	}
698
699	if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
700		(void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
701		for (i = 0; status == LDNS_STATUS_OK &&
702				i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
703			cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
704			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
705		}
706		for (i = 0; status == LDNS_STATUS_OK &&
707				i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
708			       	i++){
709			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
710			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
711		}
712	} else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
713		for (i = 0; status == LDNS_STATUS_OK &&
714				i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
715				i++){
716			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
717			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
718		}
719	}
720
721	if (z) {
722		*z = newzone;
723		newzone = NULL;
724	} else {
725		ldns_dnssec_zone_free(newzone);
726	}
727
728error:
729#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
730	if (zone) {
731		ldns_zone_free(zone);
732	}
733#endif
734	ldns_rr_list_free(todo_nsec3_rrsigs);
735	ldns_rr_list_free(todo_nsec3s);
736
737	if (my_origin) {
738		ldns_rdf_deep_free(my_origin);
739	}
740	if (my_prev) {
741		ldns_rdf_deep_free(my_prev);
742	}
743	if (newzone) {
744		ldns_dnssec_zone_free(newzone);
745	}
746	return status;
747}
748
749ldns_status
750ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
751		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
752{
753	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
754}
755
756static void
757ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
758	(void) arg;
759	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
760	LDNS_FREE(node);
761}
762
763static void
764ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
765	(void) arg;
766	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
767	LDNS_FREE(node);
768}
769
770void
771ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
772{
773	if (zone) {
774		if (zone->names) {
775			/* destroy all name structures within the tree */
776			ldns_traverse_postorder(zone->names,
777						    ldns_dnssec_name_node_free,
778						    NULL);
779			LDNS_FREE(zone->names);
780		}
781		LDNS_FREE(zone);
782	}
783}
784
785void
786ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
787{
788	if (zone) {
789		if (zone->names) {
790			/* destroy all name structures within the tree */
791			ldns_traverse_postorder(zone->names,
792						    ldns_dnssec_name_node_deep_free,
793						    NULL);
794			LDNS_FREE(zone->names);
795		}
796		LDNS_FREE(zone);
797	}
798}
799
800/* use for dname comparison in tree */
801int
802ldns_dname_compare_v(const void *a, const void *b) {
803	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
804}
805
806static ldns_rbnode_t *
807ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
808                                     ldns_rr *rr) {
809	ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
810	ldns_dnssec_name *current_name;
811	ldns_rdf *hashed_name;
812
813	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
814
815	while (current_node != LDNS_RBTREE_NULL) {
816		current_name = (ldns_dnssec_name *) current_node->data;
817		if (!current_name->hashed_name) {
818			current_name->hashed_name =
819				ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
820		}
821		if (ldns_dname_compare(hashed_name,
822						   current_name->hashed_name)
823		    == 0) {
824			ldns_rdf_deep_free(hashed_name);
825			return current_node;
826		}
827		current_node = ldns_rbtree_next(current_node);
828	}
829	ldns_rdf_deep_free(hashed_name);
830	return NULL;
831}
832
833ldns_status
834ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
835{
836	ldns_status result = LDNS_STATUS_OK;
837	ldns_dnssec_name *cur_name;
838	ldns_rbnode_t *cur_node;
839	ldns_rr_type type_covered = 0;
840
841	if (!zone || !rr) {
842		return LDNS_STATUS_ERR;
843	}
844
845	if (!zone->names) {
846		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
847                if(!zone->names) return LDNS_STATUS_MEM_ERR;
848	}
849
850	/* we need the original of the hashed name if this is
851	   an NSEC3, or an RRSIG that covers an NSEC3 */
852	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
853		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
854	}
855	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
856	    type_covered == LDNS_RR_TYPE_NSEC3) {
857		cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
858					 						   rr);
859		if (!cur_node) {
860			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
861		}
862	} else {
863		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
864	}
865
866	if (!cur_node) {
867		/* add */
868		cur_name = ldns_dnssec_name_new_frm_rr(rr);
869                if(!cur_name) return LDNS_STATUS_MEM_ERR;
870		cur_node = LDNS_MALLOC(ldns_rbnode_t);
871                if(!cur_node) {
872                        ldns_dnssec_name_free(cur_name);
873                        return LDNS_STATUS_MEM_ERR;
874                }
875		cur_node->key = ldns_rr_owner(rr);
876		cur_node->data = cur_name;
877		(void)ldns_rbtree_insert(zone->names, cur_node);
878	} else {
879		cur_name = (ldns_dnssec_name *) cur_node->data;
880		result = ldns_dnssec_name_add_rr(cur_name, rr);
881	}
882
883	if (result != LDNS_STATUS_OK) {
884		fprintf(stderr, "error adding rr: ");
885		ldns_rr_print(stderr, rr);
886	}
887
888	/*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
889	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
890		zone->soa = cur_name;
891	}
892
893	return result;
894}
895
896void
897ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
898		ldns_rbtree_t *tree,
899		bool print_soa)
900{
901	ldns_rbnode_t *node;
902	ldns_dnssec_name *name;
903
904	node = ldns_rbtree_first(tree);
905	while (node != LDNS_RBTREE_NULL) {
906		name = (ldns_dnssec_name *) node->data;
907		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
908		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
909			fprintf(out, ";\n");
910		node = ldns_rbtree_next(node);
911	}
912}
913
914void
915ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
916{
917	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
918		       tree, print_soa);
919}
920
921void
922ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
923	       ldns_dnssec_zone *zone)
924{
925	if (zone) {
926		if (zone->soa) {
927			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
928				fprintf(out, ";; Zone: ");
929				ldns_rdf_print(out, ldns_dnssec_name_name(
930							zone->soa));
931				fprintf(out, "\n;\n");
932			}
933			ldns_dnssec_rrsets_print_fmt(out, fmt,
934					ldns_dnssec_name_find_rrset(
935						zone->soa,
936						LDNS_RR_TYPE_SOA),
937					false);
938			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
939				fprintf(out, ";\n");
940		}
941
942		if (zone->names) {
943			ldns_dnssec_zone_names_print_fmt(out, fmt,
944					zone->names, false);
945		}
946	}
947}
948
949void
950ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
951{
952	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
953}
954
955ldns_status
956ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
957{
958	ldns_dnssec_name *new_name;
959	ldns_rdf *cur_name;
960	ldns_rdf *next_name;
961	ldns_rbnode_t *cur_node, *next_node, *new_node;
962
963	/* for the detection */
964	uint16_t i, cur_label_count, next_label_count;
965	uint16_t soa_label_count = 0;
966	ldns_rdf *l1, *l2;
967	int lpos;
968
969	if (!zone) {
970		return LDNS_STATUS_ERR;
971	}
972	if (zone->soa && zone->soa->name) {
973		soa_label_count = ldns_dname_label_count(zone->soa->name);
974	}
975
976	cur_node = ldns_rbtree_first(zone->names);
977	while (cur_node != LDNS_RBTREE_NULL) {
978		next_node = ldns_rbtree_next(cur_node);
979
980		/* skip glue */
981		while (next_node != LDNS_RBTREE_NULL &&
982		       next_node->data &&
983		       ((ldns_dnssec_name *)next_node->data)->is_glue
984		) {
985			next_node = ldns_rbtree_next(next_node);
986		}
987
988		if (next_node == LDNS_RBTREE_NULL) {
989			next_node = ldns_rbtree_first(zone->names);
990		}
991		if (! cur_node->data || ! next_node->data) {
992			return LDNS_STATUS_ERR;
993		}
994		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
995		next_name = ((ldns_dnssec_name *)next_node->data)->name;
996		cur_label_count = ldns_dname_label_count(cur_name);
997		next_label_count = ldns_dname_label_count(next_name);
998
999		/* Since the names are in canonical order, we can
1000		 * recognize empty non-terminals by their labels;
1001		 * every label after the first one on the next owner
1002		 * name is a non-terminal if it either does not exist
1003		 * in the current name or is different from the same
1004		 * label in the current name (counting from the end)
1005		 */
1006		for (i = 1; i < next_label_count - soa_label_count; i++) {
1007			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1008			if (lpos >= 0) {
1009				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1010			} else {
1011				l1 = NULL;
1012			}
1013			l2 = ldns_dname_clone_from(next_name, i);
1014
1015			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1016				/* We have an empty nonterminal, add it to the
1017				 * tree
1018				 */
1019				new_name = ldns_dnssec_name_new();
1020				if (!new_name) {
1021					return LDNS_STATUS_MEM_ERR;
1022				}
1023				new_name->name = ldns_dname_clone_from(next_name,
1024				                                       i);
1025				if (!new_name->name) {
1026					ldns_dnssec_name_free(new_name);
1027					return LDNS_STATUS_MEM_ERR;
1028				}
1029				new_name->name_alloced = true;
1030				new_node = LDNS_MALLOC(ldns_rbnode_t);
1031				if (!new_node) {
1032					ldns_dnssec_name_free(new_name);
1033					return LDNS_STATUS_MEM_ERR;
1034				}
1035				new_node->key = new_name->name;
1036				new_node->data = new_name;
1037				(void)ldns_rbtree_insert(zone->names, new_node);
1038			}
1039			ldns_rdf_deep_free(l1);
1040			ldns_rdf_deep_free(l2);
1041		}
1042
1043		/* we might have inserted a new node after
1044		 * the current one so we can't just use next()
1045		 */
1046		if (next_node != ldns_rbtree_first(zone->names)) {
1047			cur_node = next_node;
1048		} else {
1049			cur_node = LDNS_RBTREE_NULL;
1050		}
1051	}
1052	return LDNS_STATUS_OK;
1053}
1054
1055bool
1056ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1057{
1058	ldns_rr* nsec3;
1059	ldns_rbnode_t* node;
1060
1061	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1062		node = ldns_rbtree_first(zone->names);
1063		while (node != LDNS_RBTREE_NULL) {
1064			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1065			if (nsec3 &&ldns_rr_get_type(nsec3)
1066					== LDNS_RR_TYPE_NSEC3 &&
1067					ldns_nsec3_optout(nsec3)) {
1068				return true;
1069			}
1070			node = ldns_rbtree_next(node);
1071		}
1072	}
1073	return false;
1074}
1075