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