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