dnssec_zone.c revision 246854
173252Simp/*
273252Simp * special zone file structures and functions for better dnssec handling
373252Simp */
473252Simp
573252Simp#include <ldns/config.h>
673252Simp
773252Simp#include <ldns/ldns.h>
873252Simp
973252Simpldns_dnssec_rrs *
1073252Simpldns_dnssec_rrs_new(void)
1173252Simp{
1273252Simp	ldns_dnssec_rrs *new_rrs;
1373252Simp	new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
1473252Simp        if(!new_rrs) return NULL;
1573252Simp	new_rrs->rr = NULL;
1673252Simp	new_rrs->next = NULL;
1773252Simp	return new_rrs;
1873252Simp}
1973252Simp
2073252SimpINLINE void
2173252Simpldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
2273252Simp{
2373252Simp	ldns_dnssec_rrs *next;
2473252Simp	while (rrs) {
2573252Simp		next = rrs->next;
2673252Simp		if (deep) {
2773252Simp			ldns_rr_free(rrs->rr);
2873252Simp		}
2973252Simp		LDNS_FREE(rrs);
3073252Simp		rrs = next;
3173252Simp	}
3273252Simp}
3379538Sru
3473252Simpvoid
3573270Sruldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
3673268Sasmodai{
3773252Simp	ldns_dnssec_rrs_free_internal(rrs, 0);
3888509Sdavidc}
3984306Sru
4073252Simpvoid
4173252Simpldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
4273252Simp{
4373252Simp	ldns_dnssec_rrs_free_internal(rrs, 1);
4473252Simp}
4588509Sdavidc
4673252Simpldns_status
4773270Sruldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
4873270Sru{
4973270Sru	int cmp;
5073252Simp	ldns_dnssec_rrs *new_rrs;
5173271Sasmodai	if (!rrs || !rr) {
5273270Sru		return LDNS_STATUS_ERR;
5373270Sru	}
5473271Sasmodai
5573270Sru	/* this could be done more efficiently; name and type should already
5673271Sasmodai	   be equal */
5773270Sru	cmp = ldns_rr_compare(rrs->rr,
5873270Sru					  rr);
5973271Sasmodai	/* should we error on equal? */
6073270Sru	if (cmp <= 0) {
6173271Sasmodai		if (rrs->next) {
6273270Sru			return ldns_dnssec_rrs_add_rr(rrs->next, rr);
6373252Simp		} else {
6473271Sasmodai			new_rrs = ldns_dnssec_rrs_new();
6573270Sru			new_rrs->rr = rr;
6673270Sru			rrs->next = new_rrs;
6773271Sasmodai		}
6873270Sru	} else if (cmp > 0) {
6973270Sru		/* put the current old rr in the new next, put the new
7073270Sru		   rr in the current container */
7173270Sru		new_rrs = ldns_dnssec_rrs_new();
7273270Sru		new_rrs->rr = rrs->rr;
7373270Sru		new_rrs->next = rrs->next;
7473252Simp		rrs->rr = rr;
7573252Simp		rrs->next = new_rrs;
7673270Sru	}
7773252Simp	return LDNS_STATUS_OK;
7873270Sru}
79267936Sbapt
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			status = LDNS_STATUS_OK;
712			break;
713
714		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
715			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
716			break;
717
718		default:
719			goto error;
720		}
721	}
722
723	if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
724		(void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
725		for (i = 0; status == LDNS_STATUS_OK &&
726				i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
727			cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
728			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
729		}
730		for (i = 0; status == LDNS_STATUS_OK &&
731				i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
732			       	i++){
733			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
734			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
735		}
736	} else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
737		for (i = 0; status == LDNS_STATUS_OK &&
738				i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
739				i++){
740			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
741			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
742		}
743	}
744
745	if (z) {
746		*z = newzone;
747		newzone = NULL;
748	} else {
749		ldns_dnssec_zone_free(newzone);
750	}
751
752error:
753#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
754	if (zone) {
755		ldns_zone_free(zone);
756	}
757#endif
758	ldns_rr_list_free(todo_nsec3_rrsigs);
759	ldns_rr_list_free(todo_nsec3s);
760
761	if (my_origin) {
762		ldns_rdf_deep_free(my_origin);
763	}
764	if (my_prev) {
765		ldns_rdf_deep_free(my_prev);
766	}
767	if (newzone) {
768		ldns_dnssec_zone_free(newzone);
769	}
770	return status;
771}
772
773ldns_status
774ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
775		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
776{
777	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
778}
779
780static void
781ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
782	(void) arg;
783	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
784	LDNS_FREE(node);
785}
786
787static void
788ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
789	(void) arg;
790	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
791	LDNS_FREE(node);
792}
793
794void
795ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
796{
797	if (zone) {
798		if (zone->names) {
799			/* destroy all name structures within the tree */
800			ldns_traverse_postorder(zone->names,
801						    ldns_dnssec_name_node_free,
802						    NULL);
803			LDNS_FREE(zone->names);
804		}
805		LDNS_FREE(zone);
806	}
807}
808
809void
810ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
811{
812	if (zone) {
813		if (zone->names) {
814			/* destroy all name structures within the tree */
815			ldns_traverse_postorder(zone->names,
816						    ldns_dnssec_name_node_deep_free,
817						    NULL);
818			LDNS_FREE(zone->names);
819		}
820		LDNS_FREE(zone);
821	}
822}
823
824/* use for dname comparison in tree */
825static int
826ldns_dname_compare_v(const void *a, const void *b) {
827	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
828}
829
830static ldns_rbnode_t *
831ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
832                                     ldns_rr *rr) {
833	ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
834	ldns_dnssec_name *current_name;
835	ldns_rdf *hashed_name;
836
837	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
838
839	while (current_node != LDNS_RBTREE_NULL) {
840		current_name = (ldns_dnssec_name *) current_node->data;
841		if (!current_name->hashed_name) {
842			current_name->hashed_name =
843				ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
844		}
845		if (ldns_dname_compare(hashed_name,
846						   current_name->hashed_name)
847		    == 0) {
848			ldns_rdf_deep_free(hashed_name);
849			return current_node;
850		}
851		current_node = ldns_rbtree_next(current_node);
852	}
853	ldns_rdf_deep_free(hashed_name);
854	return NULL;
855}
856
857ldns_status
858ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
859{
860	ldns_status result = LDNS_STATUS_OK;
861	ldns_dnssec_name *cur_name;
862	ldns_rbnode_t *cur_node;
863	ldns_rr_type type_covered = 0;
864
865	if (!zone || !rr) {
866		return LDNS_STATUS_ERR;
867	}
868
869	if (!zone->names) {
870		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
871                if(!zone->names) return LDNS_STATUS_MEM_ERR;
872	}
873
874	/* we need the original of the hashed name if this is
875	   an NSEC3, or an RRSIG that covers an NSEC3 */
876	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
877		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
878	}
879	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
880	    type_covered == LDNS_RR_TYPE_NSEC3) {
881		cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
882					 						   rr);
883		if (!cur_node) {
884			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
885		}
886	} else {
887		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
888	}
889
890	if (!cur_node) {
891		/* add */
892		cur_name = ldns_dnssec_name_new_frm_rr(rr);
893                if(!cur_name) return LDNS_STATUS_MEM_ERR;
894		cur_node = LDNS_MALLOC(ldns_rbnode_t);
895                if(!cur_node) {
896                        ldns_dnssec_name_free(cur_name);
897                        return LDNS_STATUS_MEM_ERR;
898                }
899		cur_node->key = ldns_rr_owner(rr);
900		cur_node->data = cur_name;
901		(void)ldns_rbtree_insert(zone->names, cur_node);
902	} else {
903		cur_name = (ldns_dnssec_name *) cur_node->data;
904		result = ldns_dnssec_name_add_rr(cur_name, rr);
905	}
906
907	if (result != LDNS_STATUS_OK) {
908		fprintf(stderr, "error adding rr: ");
909		ldns_rr_print(stderr, rr);
910	}
911
912	/*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
913	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
914		zone->soa = cur_name;
915	}
916
917	return result;
918}
919
920void
921ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
922		ldns_rbtree_t *tree,
923		bool print_soa)
924{
925	ldns_rbnode_t *node;
926	ldns_dnssec_name *name;
927
928	node = ldns_rbtree_first(tree);
929	while (node != LDNS_RBTREE_NULL) {
930		name = (ldns_dnssec_name *) node->data;
931		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
932		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
933			fprintf(out, ";\n");
934		node = ldns_rbtree_next(node);
935	}
936}
937
938void
939ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
940{
941	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
942		       tree, print_soa);
943}
944
945void
946ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
947	       ldns_dnssec_zone *zone)
948{
949	if (zone) {
950		if (zone->soa) {
951			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
952				fprintf(out, ";; Zone: ");
953				ldns_rdf_print(out, ldns_dnssec_name_name(
954							zone->soa));
955				fprintf(out, "\n;\n");
956			}
957			ldns_dnssec_rrsets_print_fmt(out, fmt,
958					ldns_dnssec_name_find_rrset(
959						zone->soa,
960						LDNS_RR_TYPE_SOA),
961					false);
962			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
963				fprintf(out, ";\n");
964		}
965
966		if (zone->names) {
967			ldns_dnssec_zone_names_print_fmt(out, fmt,
968					zone->names, false);
969		}
970	}
971}
972
973void
974ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
975{
976	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
977}
978
979ldns_status
980ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
981{
982	ldns_dnssec_name *new_name;
983	ldns_rdf *cur_name;
984	ldns_rdf *next_name;
985	ldns_rbnode_t *cur_node, *next_node, *new_node;
986
987	/* for the detection */
988	uint16_t i, cur_label_count, next_label_count;
989	uint16_t soa_label_count = 0;
990	ldns_rdf *l1, *l2;
991	int lpos;
992
993	if (!zone) {
994		return LDNS_STATUS_ERR;
995	}
996	if (zone->soa && zone->soa->name) {
997		soa_label_count = ldns_dname_label_count(zone->soa->name);
998	}
999
1000	cur_node = ldns_rbtree_first(zone->names);
1001	while (cur_node != LDNS_RBTREE_NULL) {
1002		next_node = ldns_rbtree_next(cur_node);
1003
1004		/* skip glue */
1005		while (next_node != LDNS_RBTREE_NULL &&
1006		       next_node->data &&
1007		       ((ldns_dnssec_name *)next_node->data)->is_glue
1008		) {
1009			next_node = ldns_rbtree_next(next_node);
1010		}
1011
1012		if (next_node == LDNS_RBTREE_NULL) {
1013			next_node = ldns_rbtree_first(zone->names);
1014		}
1015		if (! cur_node->data || ! next_node->data) {
1016			return LDNS_STATUS_ERR;
1017		}
1018		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1019		next_name = ((ldns_dnssec_name *)next_node->data)->name;
1020		cur_label_count = ldns_dname_label_count(cur_name);
1021		next_label_count = ldns_dname_label_count(next_name);
1022
1023		/* Since the names are in canonical order, we can
1024		 * recognize empty non-terminals by their labels;
1025		 * every label after the first one on the next owner
1026		 * name is a non-terminal if it either does not exist
1027		 * in the current name or is different from the same
1028		 * label in the current name (counting from the end)
1029		 */
1030		for (i = 1; i < next_label_count - soa_label_count; i++) {
1031			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1032			if (lpos >= 0) {
1033				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1034			} else {
1035				l1 = NULL;
1036			}
1037			l2 = ldns_dname_clone_from(next_name, i);
1038
1039			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1040				/* We have an empty nonterminal, add it to the
1041				 * tree
1042				 */
1043				new_name = ldns_dnssec_name_new();
1044				if (!new_name) {
1045					return LDNS_STATUS_MEM_ERR;
1046				}
1047				new_name->name = ldns_dname_clone_from(next_name,
1048				                                       i);
1049				if (!new_name->name) {
1050					ldns_dnssec_name_free(new_name);
1051					return LDNS_STATUS_MEM_ERR;
1052				}
1053				new_name->name_alloced = true;
1054				new_node = LDNS_MALLOC(ldns_rbnode_t);
1055				if (!new_node) {
1056					ldns_dnssec_name_free(new_name);
1057					return LDNS_STATUS_MEM_ERR;
1058				}
1059				new_node->key = new_name->name;
1060				new_node->data = new_name;
1061				(void)ldns_rbtree_insert(zone->names, new_node);
1062			}
1063			ldns_rdf_deep_free(l1);
1064			ldns_rdf_deep_free(l2);
1065		}
1066
1067		/* we might have inserted a new node after
1068		 * the current one so we can't just use next()
1069		 */
1070		if (next_node != ldns_rbtree_first(zone->names)) {
1071			cur_node = next_node;
1072		} else {
1073			cur_node = LDNS_RBTREE_NULL;
1074		}
1075	}
1076	return LDNS_STATUS_OK;
1077}
1078
1079bool
1080ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1081{
1082	ldns_rr* nsec3;
1083	ldns_rbnode_t* node;
1084
1085	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1086		node = ldns_rbtree_first(zone->names);
1087		while (node != LDNS_RBTREE_NULL) {
1088			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1089			if (nsec3 &&ldns_rr_get_type(nsec3)
1090					== LDNS_RR_TYPE_NSEC3 &&
1091					ldns_nsec3_optout(nsec3)) {
1092				return true;
1093			}
1094			node = ldns_rbtree_next(node);
1095		}
1096	}
1097	return false;
1098}
1099