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	       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, 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(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		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		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, 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(ldns_dnssec_name *name)
395{
396	if (name) {
397		return name->name;
398	}
399	return NULL;
400}
401
402bool
403ldns_dnssec_name_is_glue(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(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(ldns_dnssec_zone *zone,
509					   ldns_rdf *dname,
510					   ldns_rr_type type)
511{
512	ldns_rbnode_t *node;
513
514	if (!zone || !dname) {
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		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		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, 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
596ldns_status
597ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
598	       	uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
599{
600	ldns_rr* cur_rr;
601	size_t i;
602
603	ldns_rdf *my_origin = NULL;
604	ldns_rdf *my_prev = NULL;
605
606	ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
607	/* when reading NSEC3s, there is a chance that we encounter nsecs
608	   for empty nonterminals, whose nonterminals we cannot derive yet
609	   because the needed information is to be read later. in that case
610	   we keep a list of those nsec3's and retry to add them later */
611	ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
612	ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
613
614	ldns_status status = LDNS_STATUS_MEM_ERR;
615
616#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
617	ldns_zone* zone = NULL;
618	if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
619			!= LDNS_STATUS_OK) goto error;
620#else
621	uint32_t  my_ttl = ttl;
622#endif
623
624	if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
625
626	if (origin) {
627		if (!(my_origin = ldns_rdf_clone(origin))) goto error;
628		if (!(my_prev   = ldns_rdf_clone(origin))) goto error;
629	}
630
631#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
632	if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
633			!= LDNS_STATUS_OK) goto error;
634
635	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
636		cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
637		status = LDNS_STATUS_OK;
638#else
639	while (!feof(fp)) {
640		status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
641				&my_prev, line_nr);
642
643#endif
644		switch (status) {
645		case LDNS_STATUS_OK:
646
647			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
648			if (status ==
649				LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
650
651				if (rr_is_rrsig_covering(cur_rr,
652							LDNS_RR_TYPE_NSEC3)){
653					ldns_rr_list_push_rr(todo_nsec3_rrsigs,
654							cur_rr);
655				} else {
656					ldns_rr_list_push_rr(todo_nsec3s,
657						       	cur_rr);
658				}
659				status = LDNS_STATUS_OK;
660
661			} else if (status != LDNS_STATUS_OK)
662				goto error;
663
664			break;
665
666
667		case LDNS_STATUS_SYNTAX_EMPTY:	/* empty line was seen */
668		case LDNS_STATUS_SYNTAX_TTL:	/* the ttl was set*/
669		case LDNS_STATUS_SYNTAX_ORIGIN:	/* the origin was set*/
670			status = LDNS_STATUS_OK;
671			break;
672
673		case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
674			status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
675			break;
676
677		default:
678			goto error;
679		}
680	}
681
682	if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
683		(void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
684		for (i = 0; status == LDNS_STATUS_OK &&
685				i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
686			cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
687			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
688		}
689	}
690	if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
691		for (i = 0; status == LDNS_STATUS_OK &&
692				i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
693				i++){
694			cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
695			status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
696		}
697	}
698
699	if (z) {
700		*z = newzone;
701		newzone = NULL;
702	} else {
703		ldns_dnssec_zone_free(newzone);
704	}
705
706error:
707#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
708	if (zone) {
709		ldns_zone_free(zone);
710	}
711#endif
712	ldns_rr_list_free(todo_nsec3_rrsigs);
713	ldns_rr_list_free(todo_nsec3s);
714
715	if (my_origin) {
716		ldns_rdf_deep_free(my_origin);
717	}
718	if (my_prev) {
719		ldns_rdf_deep_free(my_prev);
720	}
721	if (newzone) {
722		ldns_dnssec_zone_free(newzone);
723	}
724	return status;
725}
726
727ldns_status
728ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
729		uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
730{
731	return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
732}
733
734static void
735ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
736	(void) arg;
737	ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
738	LDNS_FREE(node);
739}
740
741static void
742ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
743	(void) arg;
744	ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
745	LDNS_FREE(node);
746}
747
748void
749ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
750{
751	if (zone) {
752		if (zone->names) {
753			/* destroy all name structures within the tree */
754			ldns_traverse_postorder(zone->names,
755						    ldns_dnssec_name_node_free,
756						    NULL);
757			LDNS_FREE(zone->names);
758		}
759		LDNS_FREE(zone);
760	}
761}
762
763void
764ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
765{
766	if (zone) {
767		if (zone->names) {
768			/* destroy all name structures within the tree */
769			ldns_traverse_postorder(zone->names,
770						    ldns_dnssec_name_node_deep_free,
771						    NULL);
772			LDNS_FREE(zone->names);
773		}
774		LDNS_FREE(zone);
775	}
776}
777
778/* use for dname comparison in tree */
779int
780ldns_dname_compare_v(const void *a, const void *b) {
781	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
782}
783
784static void
785ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
786		ldns_dnssec_name* name, ldns_rr* nsec3rr);
787
788static void
789ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
790	(void) arg;
791	LDNS_FREE(node);
792}
793
794static void
795ldns_dnssec_zone_hashed_names_from_nsec3(
796		ldns_dnssec_zone* zone, ldns_rr* nsec3rr)
797{
798	ldns_rbnode_t* current_node;
799	ldns_dnssec_name* current_name;
800
801	assert(zone != NULL);
802	assert(nsec3rr != NULL);
803
804	if (zone->hashed_names) {
805		ldns_traverse_postorder(zone->hashed_names,
806				ldns_hashed_names_node_free, NULL);
807		LDNS_FREE(zone->hashed_names);
808	}
809	zone->_nsec3params = nsec3rr;
810
811	/* So this is a NSEC3 zone.
812	* Calculate hashes for all names already in the zone
813	*/
814	zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
815	if (zone->hashed_names == NULL) {
816		return;
817	}
818	for ( current_node  = ldns_rbtree_first(zone->names)
819	    ; current_node != LDNS_RBTREE_NULL
820	    ; current_node  = ldns_rbtree_next(current_node)
821	    ) {
822		current_name = (ldns_dnssec_name *) current_node->data;
823		ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr);
824
825	}
826}
827
828static void
829ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
830		ldns_dnssec_name* name, ldns_rr* nsec3rr)
831{
832	ldns_rbnode_t* new_node;
833
834	assert(name != NULL);
835	if (! zone->_nsec3params) {
836		if (! nsec3rr) {
837			return;
838		}
839		ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr);
840
841	} else if (! nsec3rr) {
842		nsec3rr = zone->_nsec3params;
843	}
844	name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name);
845
846	/* Also store in zone->hashed_names */
847	if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) {
848
849		new_node->key  = name->hashed_name;
850		new_node->data = name;
851
852		if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) {
853
854				LDNS_FREE(new_node);
855		}
856	}
857}
858
859
860static ldns_rbnode_t *
861ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) {
862	ldns_rdf *hashed_name;
863
864	hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
865	if (hashed_name == NULL) {
866		return NULL;
867	}
868	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){
869
870		ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr);
871	}
872	if (zone->hashed_names == NULL) {
873		ldns_rdf_deep_free(hashed_name);
874		return NULL;
875	}
876	return  ldns_rbtree_search(zone->hashed_names, hashed_name);
877}
878
879ldns_status
880ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
881{
882	ldns_status result = LDNS_STATUS_OK;
883	ldns_dnssec_name *cur_name;
884	ldns_rbnode_t *cur_node;
885	ldns_rr_type type_covered = 0;
886
887	if (!zone || !rr) {
888		return LDNS_STATUS_ERR;
889	}
890
891	if (!zone->names) {
892		zone->names = ldns_rbtree_create(ldns_dname_compare_v);
893                if(!zone->names) return LDNS_STATUS_MEM_ERR;
894	}
895
896	/* we need the original of the hashed name if this is
897	   an NSEC3, or an RRSIG that covers an NSEC3 */
898	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
899		type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
900	}
901	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
902	    type_covered == LDNS_RR_TYPE_NSEC3) {
903		cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr);
904		if (!cur_node) {
905			return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
906		}
907	} else {
908		cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
909	}
910	if (!cur_node) {
911		/* add */
912		cur_name = ldns_dnssec_name_new_frm_rr(rr);
913                if(!cur_name) return LDNS_STATUS_MEM_ERR;
914		cur_node = LDNS_MALLOC(ldns_rbnode_t);
915                if(!cur_node) {
916                        ldns_dnssec_name_free(cur_name);
917                        return LDNS_STATUS_MEM_ERR;
918                }
919		cur_node->key = ldns_rr_owner(rr);
920		cur_node->data = cur_name;
921		(void)ldns_rbtree_insert(zone->names, cur_node);
922		ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL);
923	} else {
924		cur_name = (ldns_dnssec_name *) cur_node->data;
925		result = ldns_dnssec_name_add_rr(cur_name, rr);
926	}
927	if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
928		zone->soa = cur_name;
929	}
930	return result;
931}
932
933void
934ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
935		ldns_rbtree_t *tree,
936		bool print_soa)
937{
938	ldns_rbnode_t *node;
939	ldns_dnssec_name *name;
940
941	node = ldns_rbtree_first(tree);
942	while (node != LDNS_RBTREE_NULL) {
943		name = (ldns_dnssec_name *) node->data;
944		ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
945		if ((fmt->flags & LDNS_COMMENT_LAYOUT))
946			fprintf(out, ";\n");
947		node = ldns_rbtree_next(node);
948	}
949}
950
951void
952ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
953{
954	ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
955		       tree, print_soa);
956}
957
958void
959ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
960	       ldns_dnssec_zone *zone)
961{
962	if (zone) {
963		if (zone->soa) {
964			if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
965				fprintf(out, ";; Zone: ");
966				ldns_rdf_print(out, ldns_dnssec_name_name(
967							zone->soa));
968				fprintf(out, "\n;\n");
969			}
970			ldns_dnssec_rrsets_print_fmt(out, fmt,
971					ldns_dnssec_name_find_rrset(
972						zone->soa,
973						LDNS_RR_TYPE_SOA),
974					false);
975			if ((fmt->flags & LDNS_COMMENT_LAYOUT))
976				fprintf(out, ";\n");
977		}
978
979		if (zone->names) {
980			ldns_dnssec_zone_names_print_fmt(out, fmt,
981					zone->names, false);
982		}
983	}
984}
985
986void
987ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
988{
989	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
990}
991
992ldns_status
993ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
994{
995	ldns_dnssec_name *new_name;
996	ldns_rdf *cur_name;
997	ldns_rdf *next_name;
998	ldns_rbnode_t *cur_node, *next_node, *new_node;
999
1000	/* for the detection */
1001	uint16_t i, cur_label_count, next_label_count;
1002	uint16_t soa_label_count = 0;
1003	ldns_rdf *l1, *l2;
1004	int lpos;
1005
1006	if (!zone) {
1007		return LDNS_STATUS_ERR;
1008	}
1009	if (zone->soa && zone->soa->name) {
1010		soa_label_count = ldns_dname_label_count(zone->soa->name);
1011	}
1012
1013	cur_node = ldns_rbtree_first(zone->names);
1014	while (cur_node != LDNS_RBTREE_NULL) {
1015		next_node = ldns_rbtree_next(cur_node);
1016
1017		/* skip glue */
1018		while (next_node != LDNS_RBTREE_NULL &&
1019		       next_node->data &&
1020		       ((ldns_dnssec_name *)next_node->data)->is_glue
1021		) {
1022			next_node = ldns_rbtree_next(next_node);
1023		}
1024
1025		if (next_node == LDNS_RBTREE_NULL) {
1026			next_node = ldns_rbtree_first(zone->names);
1027		}
1028		if (! cur_node->data || ! next_node->data) {
1029			return LDNS_STATUS_ERR;
1030		}
1031		cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1032		next_name = ((ldns_dnssec_name *)next_node->data)->name;
1033		cur_label_count = ldns_dname_label_count(cur_name);
1034		next_label_count = ldns_dname_label_count(next_name);
1035
1036		/* Since the names are in canonical order, we can
1037		 * recognize empty non-terminals by their labels;
1038		 * every label after the first one on the next owner
1039		 * name is a non-terminal if it either does not exist
1040		 * in the current name or is different from the same
1041		 * label in the current name (counting from the end)
1042		 */
1043		for (i = 1; i < next_label_count - soa_label_count; i++) {
1044			lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1045			if (lpos >= 0) {
1046				l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1047			} else {
1048				l1 = NULL;
1049			}
1050			l2 = ldns_dname_clone_from(next_name, i);
1051
1052			if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1053				/* We have an empty nonterminal, add it to the
1054				 * tree
1055				 */
1056				new_name = ldns_dnssec_name_new();
1057				if (!new_name) {
1058					return LDNS_STATUS_MEM_ERR;
1059				}
1060				new_name->name = ldns_dname_clone_from(next_name,
1061				                                       i);
1062				if (!new_name->name) {
1063					ldns_dnssec_name_free(new_name);
1064					return LDNS_STATUS_MEM_ERR;
1065				}
1066				new_name->name_alloced = true;
1067				new_node = LDNS_MALLOC(ldns_rbnode_t);
1068				if (!new_node) {
1069					ldns_dnssec_name_free(new_name);
1070					return LDNS_STATUS_MEM_ERR;
1071				}
1072				new_node->key = new_name->name;
1073				new_node->data = new_name;
1074				(void)ldns_rbtree_insert(zone->names, new_node);
1075				ldns_dnssec_name_make_hashed_name(
1076						zone, new_name, NULL);
1077			}
1078			ldns_rdf_deep_free(l1);
1079			ldns_rdf_deep_free(l2);
1080		}
1081
1082		/* we might have inserted a new node after
1083		 * the current one so we can't just use next()
1084		 */
1085		if (next_node != ldns_rbtree_first(zone->names)) {
1086			cur_node = next_node;
1087		} else {
1088			cur_node = LDNS_RBTREE_NULL;
1089		}
1090	}
1091	return LDNS_STATUS_OK;
1092}
1093
1094bool
1095ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1096{
1097	ldns_rr* nsec3;
1098	ldns_rbnode_t* node;
1099
1100	if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1101		node = ldns_rbtree_first(zone->names);
1102		while (node != LDNS_RBTREE_NULL) {
1103			nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1104			if (nsec3 &&ldns_rr_get_type(nsec3)
1105					== LDNS_RR_TYPE_NSEC3 &&
1106					ldns_nsec3_optout(nsec3)) {
1107				return true;
1108			}
1109			node = ldns_rbtree_next(node);
1110		}
1111	}
1112	return false;
1113}
1114