xref: /openbsd/usr.sbin/nsd/namedb.c (revision a904e103)
1 /*
2  * namedb.c -- common namedb operations.
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <sys/types.h>
13 
14 #include <assert.h>
15 #include <ctype.h>
16 #include <limits.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "namedb.h"
21 #include "nsec3.h"
22 
23 static domain_type *
allocate_domain_info(domain_table_type * table,const dname_type * dname,domain_type * parent)24 allocate_domain_info(domain_table_type* table,
25 		     const dname_type* dname,
26 		     domain_type* parent)
27 {
28 	domain_type *result;
29 
30 	assert(table);
31 	assert(dname);
32 	assert(parent);
33 
34 	result = (domain_type *) region_alloc(table->region,
35 					      sizeof(domain_type));
36 #ifdef USE_RADIX_TREE
37 	result->dname
38 #else
39 	result->node.key
40 #endif
41 		= dname_partial_copy(
42 		table->region, dname, domain_dname(parent)->label_count + 1);
43 	result->parent = parent;
44 	result->wildcard_child_closest_match = result;
45 	result->rrsets = NULL;
46 	result->usage = 0;
47 #ifdef NSEC3
48 	result->nsec3 = NULL;
49 #endif
50 	result->is_existing = 0;
51 	result->is_apex = 0;
52 	assert(table->numlist_last); /* it exists because root exists */
53 	/* push this domain at the end of the numlist */
54 	result->number = table->numlist_last->number+1;
55 	result->numlist_next = NULL;
56 	result->numlist_prev = table->numlist_last;
57 	table->numlist_last->numlist_next = result;
58 	table->numlist_last = result;
59 
60 	return result;
61 }
62 
63 #ifdef NSEC3
64 void
allocate_domain_nsec3(domain_table_type * table,domain_type * result)65 allocate_domain_nsec3(domain_table_type* table, domain_type* result)
66 {
67 	if(result->nsec3)
68 		return;
69 	result->nsec3 = (struct nsec3_domain_data*) region_alloc(table->region,
70 		sizeof(struct nsec3_domain_data));
71 	result->nsec3->nsec3_cover = NULL;
72 	result->nsec3->nsec3_wcard_child_cover = NULL;
73 	result->nsec3->nsec3_ds_parent_cover = NULL;
74 	result->nsec3->nsec3_is_exact = 0;
75 	result->nsec3->nsec3_ds_parent_is_exact = 0;
76 	result->nsec3->hash_wc = NULL;
77 	result->nsec3->ds_parent_hash = NULL;
78 	result->nsec3->prehash_prev = NULL;
79 	result->nsec3->prehash_next = NULL;
80 	result->nsec3->nsec3_node.key = NULL;
81 }
82 #endif /* NSEC3 */
83 
84 /** make the domain last in the numlist, changes numbers of domains */
85 static void
numlist_make_last(domain_table_type * table,domain_type * domain)86 numlist_make_last(domain_table_type* table, domain_type* domain)
87 {
88 	uint32_t sw;
89 	domain_type* last = table->numlist_last;
90 	if(domain == last)
91 		return;
92 	/* swap numbers with the last element */
93 	sw = domain->number;
94 	domain->number = last->number;
95 	last->number = sw;
96 	/* swap list position with the last element */
97 	assert(domain->numlist_next);
98 	assert(last->numlist_prev);
99 	if(domain->numlist_next != last) {
100 		/* case 1: there are nodes between domain .. last */
101 		domain_type* span_start = domain->numlist_next;
102 		domain_type* span_end = last->numlist_prev;
103 		/* these assignments walk the new list from start to end */
104 		if(domain->numlist_prev)
105 			domain->numlist_prev->numlist_next = last;
106 		last->numlist_prev = domain->numlist_prev;
107 		last->numlist_next = span_start;
108 		span_start->numlist_prev = last;
109 		span_end->numlist_next = domain;
110 		domain->numlist_prev = span_end;
111 		domain->numlist_next = NULL;
112 	} else {
113 		/* case 2: domain and last are neighbors */
114 		/* these assignments walk the new list from start to end */
115 		if(domain->numlist_prev)
116 			domain->numlist_prev->numlist_next = last;
117 		last->numlist_prev = domain->numlist_prev;
118 		last->numlist_next = domain;
119 		domain->numlist_prev = last;
120 		domain->numlist_next = NULL;
121 	}
122 	table->numlist_last = domain;
123 }
124 
125 /** pop the biggest domain off the numlist */
126 static domain_type*
numlist_pop_last(domain_table_type * table)127 numlist_pop_last(domain_table_type* table)
128 {
129 	domain_type* d = table->numlist_last;
130 	table->numlist_last = table->numlist_last->numlist_prev;
131 	if(table->numlist_last)
132 		table->numlist_last->numlist_next = NULL;
133 	return d;
134 }
135 
136 /** see if a domain is eligible to be deleted, and thus is not used */
137 static int
domain_can_be_deleted(domain_type * domain)138 domain_can_be_deleted(domain_type* domain)
139 {
140 	domain_type* n;
141 	/* it has data or it has usage, do not delete it */
142 	if(domain->rrsets) return 0;
143 	if(domain->usage) return 0;
144 	n = domain_next(domain);
145 	/* it has children domains, do not delete it */
146 	if(n && domain_is_subdomain(n, domain))
147 		return 0;
148 	return 1;
149 }
150 
151 #ifdef NSEC3
152 /** see if domain is on the prehash list */
domain_is_prehash(domain_table_type * table,domain_type * domain)153 int domain_is_prehash(domain_table_type* table, domain_type* domain)
154 {
155 	if(domain->nsec3
156 		&& (domain->nsec3->prehash_prev || domain->nsec3->prehash_next))
157 		return 1;
158 	return (table->prehash_list == domain);
159 }
160 
161 /** remove domain node from NSEC3 tree in hash space */
162 void
zone_del_domain_in_hash_tree(rbtree_type * tree,rbnode_type * node)163 zone_del_domain_in_hash_tree(rbtree_type* tree, rbnode_type* node)
164 {
165 	if(!node->key)
166 		return;
167 	rbtree_delete(tree, node->key);
168 	/* note that domain is no longer in the tree */
169 	node->key = NULL;
170 }
171 
172 /** clear the prehash list */
prehash_clear(domain_table_type * table)173 void prehash_clear(domain_table_type* table)
174 {
175 	domain_type* d = table->prehash_list, *n;
176 	while(d) {
177 		n = d->nsec3->prehash_next;
178 		d->nsec3->prehash_prev = NULL;
179 		d->nsec3->prehash_next = NULL;
180 		d = n;
181 	}
182 	table->prehash_list = NULL;
183 }
184 
185 /** add domain to prehash list */
186 void
prehash_add(domain_table_type * table,domain_type * domain)187 prehash_add(domain_table_type* table, domain_type* domain)
188 {
189 	if(domain_is_prehash(table, domain))
190 		return;
191 	allocate_domain_nsec3(table, domain);
192 	domain->nsec3->prehash_next = table->prehash_list;
193 	if(table->prehash_list)
194 		table->prehash_list->nsec3->prehash_prev = domain;
195 	table->prehash_list = domain;
196 }
197 
198 /** remove domain from prehash list */
199 void
prehash_del(domain_table_type * table,domain_type * domain)200 prehash_del(domain_table_type* table, domain_type* domain)
201 {
202 	if(domain->nsec3->prehash_next)
203 		domain->nsec3->prehash_next->nsec3->prehash_prev =
204 			domain->nsec3->prehash_prev;
205 	if(domain->nsec3->prehash_prev)
206 		domain->nsec3->prehash_prev->nsec3->prehash_next =
207 			domain->nsec3->prehash_next;
208 	else	table->prehash_list = domain->nsec3->prehash_next;
209 	domain->nsec3->prehash_next = NULL;
210 	domain->nsec3->prehash_prev = NULL;
211 }
212 #endif /* NSEC3 */
213 
214 /** perform domain name deletion */
215 static void
do_deldomain(namedb_type * db,domain_type * domain)216 do_deldomain(namedb_type* db, domain_type* domain)
217 {
218 	assert(domain && domain->parent); /* exists and not root */
219 	/* first adjust the number list so that domain is the last one */
220 	numlist_make_last(db->domains, domain);
221 	/* pop off the domain from the number list */
222 	(void)numlist_pop_last(db->domains);
223 
224 #ifdef NSEC3
225 	/* if on prehash list, remove from prehash */
226 	if(domain_is_prehash(db->domains, domain))
227 		prehash_del(db->domains, domain);
228 
229 	/* see if nsec3-nodes are used */
230 	if(domain->nsec3) {
231 		if(domain->nsec3->nsec3_node.key)
232 			zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
233 				->nsec3tree, &domain->nsec3->nsec3_node);
234 		if(domain->nsec3->hash_wc) {
235 			if(domain->nsec3->hash_wc->hash.node.key)
236 				zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
237 					->hashtree, &domain->nsec3->hash_wc->hash.node);
238 			if(domain->nsec3->hash_wc->wc.node.key)
239 				zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
240 					->wchashtree, &domain->nsec3->hash_wc->wc.node);
241 		}
242 		if(domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key)
243 			zone_del_domain_in_hash_tree(nsec3_tree_dszone(db, domain)
244 				->dshashtree, &domain->nsec3->ds_parent_hash->node);
245 		if(domain->nsec3->hash_wc) {
246 			region_recycle(db->domains->region,
247 				domain->nsec3->hash_wc,
248 				sizeof(nsec3_hash_wc_node_type));
249 		}
250 		if(domain->nsec3->ds_parent_hash) {
251 			region_recycle(db->domains->region,
252 				domain->nsec3->ds_parent_hash,
253 				sizeof(nsec3_hash_node_type));
254 		}
255 		region_recycle(db->domains->region, domain->nsec3,
256 			sizeof(struct nsec3_domain_data));
257 	}
258 #endif /* NSEC3 */
259 
260 	/* see if this domain is someones wildcard-child-closest-match,
261 	 * which can only be the parent, and then it should use the
262 	 * one-smaller than this domain as closest-match. */
263 	if(domain->parent->wildcard_child_closest_match == domain)
264 		domain->parent->wildcard_child_closest_match =
265 			domain_previous_existing_child(domain);
266 
267 	/* actual removal */
268 #ifdef USE_RADIX_TREE
269 	radix_delete(db->domains->nametree, domain->rnode);
270 #else
271 	rbtree_delete(db->domains->names_to_domains, domain->node.key);
272 #endif
273 	region_recycle(db->domains->region, domain_dname(domain),
274 		dname_total_size(domain_dname(domain)));
275 	region_recycle(db->domains->region, domain, sizeof(domain_type));
276 }
277 
278 void
domain_table_deldomain(namedb_type * db,domain_type * domain)279 domain_table_deldomain(namedb_type* db, domain_type* domain)
280 {
281 	domain_type* parent;
282 
283 	while(domain_can_be_deleted(domain)) {
284 		parent = domain->parent;
285 		/* delete it */
286 		do_deldomain(db, domain);
287 		/* test parent */
288 		domain = parent;
289 	}
290 }
291 
hash_tree_delete(region_type * region,rbtree_type * tree)292 void hash_tree_delete(region_type* region, rbtree_type* tree)
293 {
294 	region_recycle(region, tree, sizeof(rbtree_type));
295 }
296 
297 /** add domain nsec3 node to hashedspace tree */
zone_add_domain_in_hash_tree(region_type * region,rbtree_type ** tree,int (* cmpf)(const void *,const void *),domain_type * domain,rbnode_type * node)298 void zone_add_domain_in_hash_tree(region_type* region, rbtree_type** tree,
299 	int (*cmpf)(const void*, const void*),
300 	domain_type* domain, rbnode_type* node)
301 {
302 	if(!*tree)
303 		*tree = rbtree_create(region, cmpf);
304 	if(node->key && node->key == domain
305 	&& rbtree_search(*tree, domain) == node)
306 		return;
307 	memset(node, 0, sizeof(rbnode_type));
308 	node->key = domain;
309 	rbtree_insert(*tree, node);
310 }
311 
312 domain_table_type *
domain_table_create(region_type * region)313 domain_table_create(region_type* region)
314 {
315 	const dname_type* origin;
316 	domain_table_type* result;
317 	domain_type* root;
318 
319 	assert(region);
320 
321 	origin = dname_make(region, (uint8_t *) "", 0);
322 
323 	root = (domain_type *) region_alloc(region, sizeof(domain_type));
324 #ifdef USE_RADIX_TREE
325 	root->dname
326 #else
327 	root->node.key
328 #endif
329 		= origin;
330 	root->parent = NULL;
331 	root->wildcard_child_closest_match = root;
332 	root->rrsets = NULL;
333 	root->number = 1; /* 0 is used for after header */
334 	root->usage = 1; /* do not delete root, ever */
335 	root->is_existing = 0;
336 	root->is_apex = 0;
337 	root->numlist_prev = NULL;
338 	root->numlist_next = NULL;
339 #ifdef NSEC3
340 	root->nsec3 = NULL;
341 #endif
342 
343 	result = (domain_table_type *) region_alloc(region,
344 						    sizeof(domain_table_type));
345 	result->region = region;
346 #ifdef USE_RADIX_TREE
347 	result->nametree = radix_tree_create(region);
348 	root->rnode = radname_insert(result->nametree, dname_name(root->dname),
349 		root->dname->name_size, root);
350 #else
351 	result->names_to_domains = rbtree_create(
352 		region, (int (*)(const void *, const void *)) dname_compare);
353 	rbtree_insert(result->names_to_domains, (rbnode_type *) root);
354 #endif
355 
356 	result->root = root;
357 	result->numlist_last = root;
358 #ifdef NSEC3
359 	result->prehash_list = NULL;
360 #endif
361 
362 	return result;
363 }
364 
365 int
domain_table_search(domain_table_type * table,const dname_type * dname,domain_type ** closest_match,domain_type ** closest_encloser)366 domain_table_search(domain_table_type *table,
367 		   const dname_type   *dname,
368 		   domain_type       **closest_match,
369 		   domain_type       **closest_encloser)
370 {
371 	int exact;
372 	uint8_t label_match_count;
373 
374 	assert(table);
375 	assert(dname);
376 	assert(closest_match);
377 	assert(closest_encloser);
378 
379 #ifdef USE_RADIX_TREE
380 	exact = radname_find_less_equal(table->nametree, dname_name(dname),
381 		dname->name_size, (struct radnode**)closest_match);
382 	*closest_match = (domain_type*)((*(struct radnode**)closest_match)->elem);
383 #else
384 	exact = rbtree_find_less_equal(table->names_to_domains, dname, (rbnode_type **) closest_match);
385 #endif
386 	assert(*closest_match);
387 
388 	*closest_encloser = *closest_match;
389 
390 	if (!exact) {
391 		label_match_count = dname_label_match_count(
392 			domain_dname(*closest_encloser),
393 			dname);
394 		assert(label_match_count < dname->label_count);
395 		while (label_match_count < domain_dname(*closest_encloser)->label_count) {
396 			(*closest_encloser) = (*closest_encloser)->parent;
397 			assert(*closest_encloser);
398 		}
399 	}
400 
401 	return exact;
402 }
403 
404 domain_type *
domain_table_find(domain_table_type * table,const dname_type * dname)405 domain_table_find(domain_table_type* table,
406 		  const dname_type* dname)
407 {
408 	domain_type* closest_match;
409 	domain_type* closest_encloser;
410 	int exact;
411 
412 	exact = domain_table_search(
413 		table, dname, &closest_match, &closest_encloser);
414 	return exact ? closest_encloser : NULL;
415 }
416 
417 
418 domain_type *
domain_table_insert(domain_table_type * table,const dname_type * dname)419 domain_table_insert(domain_table_type* table,
420 		    const dname_type* dname)
421 {
422 	domain_type* closest_match;
423 	domain_type* closest_encloser;
424 	domain_type* result;
425 	int exact;
426 
427 	assert(table);
428 	assert(dname);
429 
430 	exact = domain_table_search(
431 		table, dname, &closest_match, &closest_encloser);
432 	if (exact) {
433 		result = closest_encloser;
434 	} else {
435 		assert(domain_dname(closest_encloser)->label_count < dname->label_count);
436 
437 		/* Insert new node(s).  */
438 		do {
439 			result = allocate_domain_info(table,
440 						      dname,
441 						      closest_encloser);
442 #ifdef USE_RADIX_TREE
443 			result->rnode = radname_insert(table->nametree,
444 				dname_name(result->dname),
445 				result->dname->name_size, result);
446 #else
447 			rbtree_insert(table->names_to_domains, (rbnode_type *) result);
448 #endif
449 
450 			/*
451 			 * If the newly added domain name is larger
452 			 * than the parent's current
453 			 * wildcard_child_closest_match but smaller or
454 			 * equal to the wildcard domain name, update
455 			 * the parent's wildcard_child_closest_match
456 			 * field.
457 			 */
458 			if (label_compare(dname_name(domain_dname(result)),
459 					  (const uint8_t *) "\001*") <= 0
460 			    && dname_compare(domain_dname(result),
461 					     domain_dname(closest_encloser->wildcard_child_closest_match)) > 0)
462 			{
463 				closest_encloser->wildcard_child_closest_match
464 					= result;
465 			}
466 			closest_encloser = result;
467 		} while (domain_dname(closest_encloser)->label_count < dname->label_count);
468 	}
469 
470 	return result;
471 }
472 
domain_previous_existing_child(domain_type * domain)473 domain_type *domain_previous_existing_child(domain_type* domain)
474 {
475 	domain_type* parent = domain->parent;
476 	domain = domain_previous(domain);
477 	while(domain && !domain->is_existing) {
478 		if(domain == parent) /* do not walk back above parent */
479 			return parent;
480 		domain = domain_previous(domain);
481 	}
482 	return domain;
483 }
484 
485 void
domain_add_rrset(domain_type * domain,rrset_type * rrset)486 domain_add_rrset(domain_type* domain, rrset_type* rrset)
487 {
488 #if 0 	/* fast */
489 	rrset->next = domain->rrsets;
490 	domain->rrsets = rrset;
491 #else
492 	/* preserve ordering, add at end */
493 	rrset_type** p = &domain->rrsets;
494 	while(*p)
495 		p = &((*p)->next);
496 	*p = rrset;
497 	rrset->next = 0;
498 #endif
499 
500 	while (domain && !domain->is_existing) {
501 		domain->is_existing = 1;
502 		/* does this name in existance update the parent's
503 		 * wildcard closest match? */
504 		if(domain->parent
505 		   && label_compare(dname_name(domain_dname(domain)),
506 			(const uint8_t *) "\001*") <= 0
507 		   && dname_compare(domain_dname(domain),
508 		   	domain_dname(domain->parent->wildcard_child_closest_match)) > 0) {
509 			domain->parent->wildcard_child_closest_match = domain;
510 		}
511 		domain = domain->parent;
512 	}
513 }
514 
515 
516 rrset_type *
domain_find_rrset(domain_type * domain,zone_type * zone,uint16_t type)517 domain_find_rrset(domain_type* domain, zone_type* zone, uint16_t type)
518 {
519 	rrset_type* result = domain->rrsets;
520 
521 	while (result) {
522 		if (result->zone == zone && rrset_rrtype(result) == type) {
523 			return result;
524 		}
525 		result = result->next;
526 	}
527 	return NULL;
528 }
529 
530 rrset_type *
domain_find_any_rrset(domain_type * domain,zone_type * zone)531 domain_find_any_rrset(domain_type* domain, zone_type* zone)
532 {
533 	rrset_type* result = domain->rrsets;
534 
535 	while (result) {
536 		if (result->zone == zone) {
537 			return result;
538 		}
539 		result = result->next;
540 	}
541 	return NULL;
542 }
543 
544 zone_type *
domain_find_zone(namedb_type * db,domain_type * domain)545 domain_find_zone(namedb_type* db, domain_type* domain)
546 {
547 	rrset_type* rrset;
548 	while (domain) {
549 		if(domain->is_apex) {
550 			for (rrset = domain->rrsets; rrset; rrset = rrset->next) {
551 				if (rrset_rrtype(rrset) == TYPE_SOA) {
552 					return rrset->zone;
553 				}
554 			}
555 			return namedb_find_zone(db, domain_dname(domain));
556 		}
557 		domain = domain->parent;
558 	}
559 	return NULL;
560 }
561 
562 zone_type *
domain_find_parent_zone(namedb_type * db,zone_type * zone)563 domain_find_parent_zone(namedb_type* db, zone_type* zone)
564 {
565 	rrset_type* rrset;
566 
567 	assert(zone);
568 
569 	for (rrset = zone->apex->rrsets; rrset; rrset = rrset->next) {
570 		if (rrset->zone != zone && rrset_rrtype(rrset) == TYPE_NS) {
571 			return rrset->zone;
572 		}
573 	}
574 	/* the NS record in the parent zone above this zone is not present,
575 	 * workaround to find that parent zone anyway */
576 	if(zone->apex->parent)
577 		return domain_find_zone(db, zone->apex->parent);
578 	return NULL;
579 }
580 
581 domain_type *
domain_find_ns_rrsets(domain_type * domain,zone_type * zone,rrset_type ** ns)582 domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns)
583 {
584 	/* return highest NS RRset in the zone that is a delegation above */
585 	domain_type* result = NULL;
586 	rrset_type* rrset = NULL;
587 	while (domain && domain != zone->apex) {
588 		rrset = domain_find_rrset(domain, zone, TYPE_NS);
589 		if (rrset) {
590 			*ns = rrset;
591 			result = domain;
592 		}
593 		domain = domain->parent;
594 	}
595 
596 	if(result)
597 		return result;
598 
599 	*ns = NULL;
600 	return NULL;
601 }
602 
603 domain_type *
find_dname_above(domain_type * domain,zone_type * zone)604 find_dname_above(domain_type* domain, zone_type* zone)
605 {
606 	domain_type* d = domain->parent;
607 	while(d && d != zone->apex) {
608 		if(domain_find_rrset(d, zone, TYPE_DNAME))
609 			return d;
610 		d = d->parent;
611 	}
612 	return NULL;
613 }
614 
615 int
domain_is_glue(domain_type * domain,zone_type * zone)616 domain_is_glue(domain_type* domain, zone_type* zone)
617 {
618 	rrset_type* unused;
619 	domain_type* ns_domain = domain_find_ns_rrsets(domain, zone, &unused);
620 	return (ns_domain != NULL &&
621 		domain_find_rrset(ns_domain, zone, TYPE_SOA) == NULL);
622 }
623 
624 domain_type *
domain_wildcard_child(domain_type * domain)625 domain_wildcard_child(domain_type* domain)
626 {
627 	domain_type* wildcard_child;
628 
629 	assert(domain);
630 	assert(domain->wildcard_child_closest_match);
631 
632 	wildcard_child = domain->wildcard_child_closest_match;
633 	if (wildcard_child != domain
634 	    && label_is_wildcard(dname_name(domain_dname(wildcard_child))))
635 	{
636 		return wildcard_child;
637 	} else {
638 		return NULL;
639 	}
640 }
641 
642 int
zone_is_secure(zone_type * zone)643 zone_is_secure(zone_type* zone)
644 {
645 	assert(zone);
646 	return zone->is_secure;
647 }
648 
649 uint16_t
rr_rrsig_type_covered(rr_type * rr)650 rr_rrsig_type_covered(rr_type* rr)
651 {
652 	assert(rr->type == TYPE_RRSIG);
653 	assert(rr->rdata_count > 0);
654 	assert(rdata_atom_size(rr->rdatas[0]) == sizeof(uint16_t));
655 
656 	return ntohs(* (uint16_t *) rdata_atom_data(rr->rdatas[0]));
657 }
658 
659 zone_type *
namedb_find_zone(namedb_type * db,const dname_type * dname)660 namedb_find_zone(namedb_type* db, const dname_type* dname)
661 {
662 	struct radnode* n = radname_search(db->zonetree, dname_name(dname),
663 		dname->name_size);
664 	if(n) return (zone_type*)n->elem;
665 	return NULL;
666 }
667 
668 rrset_type *
domain_find_non_cname_rrset(domain_type * domain,zone_type * zone)669 domain_find_non_cname_rrset(domain_type* domain, zone_type* zone)
670 {
671 	/* find any rrset type that is not allowed next to a CNAME */
672 	/* nothing is allowed next to a CNAME, except RRSIG, NSEC, NSEC3 */
673 	rrset_type *result = domain->rrsets;
674 
675 	while (result) {
676 		if (result->zone == zone && /* here is the list of exceptions*/
677 			rrset_rrtype(result) != TYPE_CNAME &&
678 			rrset_rrtype(result) != TYPE_RRSIG &&
679 			rrset_rrtype(result) != TYPE_NXT &&
680 			rrset_rrtype(result) != TYPE_SIG &&
681 			rrset_rrtype(result) != TYPE_NSEC &&
682 			rrset_rrtype(result) != TYPE_NSEC3 ) {
683 			return result;
684 		}
685 		result = result->next;
686 	}
687 	return NULL;
688 }
689 
690 int
namedb_lookup(struct namedb * db,const dname_type * dname,domain_type ** closest_match,domain_type ** closest_encloser)691 namedb_lookup(struct namedb* db,
692 	      const dname_type* dname,
693 	      domain_type     **closest_match,
694 	      domain_type     **closest_encloser)
695 {
696 	return domain_table_search(
697 		db->domains, dname, closest_match, closest_encloser);
698 }
699 
zone_rr_iter_init(struct zone_rr_iter * iter,struct zone * zone)700 void zone_rr_iter_init(struct zone_rr_iter *iter, struct zone *zone)
701 {
702 	assert(iter != NULL);
703 	assert(zone != NULL);
704 	memset(iter, 0, sizeof(*iter));
705 	iter->zone = zone;
706 }
707 
zone_rr_iter_next(struct zone_rr_iter * iter)708 rr_type *zone_rr_iter_next(struct zone_rr_iter *iter)
709 {
710 	assert(iter != NULL);
711 	assert(iter->zone != NULL);
712 
713 	if(iter->index == -1) {
714 		assert(iter->domain == NULL);
715 		assert(iter->rrset == NULL);
716 		return NULL;
717 	} else if(iter->rrset == NULL) {
718 		/* ensure SOA RR is returned first */
719 		assert(iter->domain == NULL);
720 		assert(iter->index == 0);
721 		iter->rrset = iter->zone->soa_rrset;
722 	}
723 
724 	while(iter->rrset != NULL) {
725 		if(iter->index < iter->rrset->rr_count) {
726 			return &iter->rrset->rrs[iter->index++];
727 		}
728 		iter->index = 0;
729 		if(iter->domain == NULL) {
730 			assert(iter->rrset == iter->zone->soa_rrset);
731 			iter->domain = iter->zone->apex;
732 			iter->rrset = iter->domain->rrsets;
733 		} else {
734 			iter->rrset = iter->rrset->next;
735 		}
736 		/* ensure SOA RR is not returned again and RR belongs to zone */
737 		while((iter->rrset == NULL && iter->domain != NULL) ||
738 		      (iter->rrset != NULL && (iter->rrset == iter->zone->soa_rrset ||
739 		                               iter->rrset->zone != iter->zone)))
740 		{
741 			if(iter->rrset != NULL) {
742 				iter->rrset = iter->rrset->next;
743 			} else {
744 				iter->domain = domain_next(iter->domain);
745 				if(iter->domain != NULL &&
746 				   dname_is_subdomain(domain_dname(iter->domain),
747 				                      domain_dname(iter->zone->apex)))
748 				{
749 					iter->rrset = iter->domain->rrsets;
750 				}
751 			}
752 		}
753 	}
754 
755 	assert(iter->rrset == NULL);
756 	assert(iter->domain == NULL);
757 	iter->index = -1;
758 
759 	return NULL;
760 }
761