xref: /freebsd/contrib/ldns/dnssec_zone.c (revision f1f890804985a1043da42a5def13c79dc005f5e9)
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 #if 0
302 static void
303 ldns_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 
313 void
314 ldns_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 
321 void
322 ldns_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 
328 ldns_dnssec_name *
329 ldns_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 
353 ldns_dnssec_name *
354 ldns_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 
367 INLINE void
368 ldns_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 
393 void
394 ldns_dnssec_name_free(ldns_dnssec_name *name)
395 {
396   ldns_dnssec_name_free_internal(name, 0);
397 }
398 
399 void
400 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
401 {
402   ldns_dnssec_name_free_internal(name, 1);
403 }
404 
405 ldns_rdf *
406 ldns_dnssec_name_name(ldns_dnssec_name *name)
407 {
408 	if (name) {
409 		return name->name;
410 	}
411 	return NULL;
412 }
413 
414 bool
415 ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
416 {
417 	if (name) {
418 		return name->is_glue;
419 	}
420 	return false;
421 }
422 
423 void
424 ldns_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
433 static ldns_rr *
434 ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
435 {
436 	if (rrset) {
437 		return rrset->nsec;
438 	}
439 	return NULL;
440 }
441 #endif
442 
443 void
444 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
445 {
446 	if (rrset && nsec) {
447 		rrset->nsec = nsec;
448 	}
449 }
450 
451 int
452 ldns_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 
469 ldns_status
470 ldns_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 
533 ldns_dnssec_rrsets *
534 ldns_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 
549 ldns_dnssec_rrsets *
550 ldns_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 
569 static void
570 ldns_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
596 static void
597 ldns_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 
604 void
605 ldns_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 
611 void
612 ldns_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 
618 ldns_dnssec_zone *
619 ldns_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 
629 static bool
630 rr_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 
644 ldns_status
645 ldns_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 
757 error:
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 
778 ldns_status
779 ldns_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 
785 static void
786 ldns_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 
792 static void
793 ldns_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 
799 void
800 ldns_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 
814 void
815 ldns_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 */
830 static int
831 ldns_dname_compare_v(const void *a, const void *b) {
832 	return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
833 }
834 
835 static ldns_rbnode_t *
836 ldns_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 
862 ldns_status
863 ldns_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 
925 void
926 ldns_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 
943 void
944 ldns_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 
950 void
951 ldns_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 
978 void
979 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
980 {
981 	ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
982 }
983 
984 ldns_status
985 ldns_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 
1084 bool
1085 ldns_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