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