xref: /openbsd/usr.sbin/nsd/namedb.c (revision aee1b7aa)
162ac0c33Sjakob /*
262ac0c33Sjakob  * namedb.c -- common namedb operations.
362ac0c33Sjakob  *
4217deabeSjakob  * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
10*aee1b7aaSsthen #include "config.h"
1162ac0c33Sjakob 
1262ac0c33Sjakob #include <sys/types.h>
1362ac0c33Sjakob 
1462ac0c33Sjakob #include <assert.h>
1562ac0c33Sjakob #include <ctype.h>
1662ac0c33Sjakob #include <limits.h>
1762ac0c33Sjakob #include <stdio.h>
1862ac0c33Sjakob #include <string.h>
190c2b6c02Sjakob #include <errno.h>
2062ac0c33Sjakob 
2162ac0c33Sjakob #include "namedb.h"
2262ac0c33Sjakob 
2362ac0c33Sjakob 
2462ac0c33Sjakob static domain_type *
2562ac0c33Sjakob allocate_domain_info(domain_table_type *table,
2662ac0c33Sjakob 		     const dname_type *dname,
2762ac0c33Sjakob 		     domain_type *parent)
2862ac0c33Sjakob {
2962ac0c33Sjakob 	domain_type *result;
3062ac0c33Sjakob 
3162ac0c33Sjakob 	assert(table);
3262ac0c33Sjakob 	assert(dname);
3362ac0c33Sjakob 	assert(parent);
3462ac0c33Sjakob 
3562ac0c33Sjakob 	result = (domain_type *) region_alloc(table->region,
3662ac0c33Sjakob 					      sizeof(domain_type));
3762ac0c33Sjakob 	result->node.key = dname_partial_copy(
3862ac0c33Sjakob 		table->region, dname, domain_dname(parent)->label_count + 1);
3962ac0c33Sjakob 	result->parent = parent;
40044f85deSsthen 	result->nextdiff = NULL;
4162ac0c33Sjakob 	result->wildcard_child_closest_match = result;
4262ac0c33Sjakob 	result->rrsets = NULL;
4362ac0c33Sjakob 	result->number = 0;
4462ac0c33Sjakob #ifdef NSEC3
4562ac0c33Sjakob 	result->nsec3_cover = NULL;
460c2b6c02Sjakob #ifdef FULL_PREHASH
4762ac0c33Sjakob 	result->nsec3_wcard_child_cover = NULL;
4862ac0c33Sjakob 	result->nsec3_ds_parent_cover = NULL;
4962ac0c33Sjakob 	result->nsec3_lookup = NULL;
5062ac0c33Sjakob 	result->nsec3_is_exact = 0;
5162ac0c33Sjakob 	result->nsec3_ds_parent_is_exact = 0;
520c2b6c02Sjakob #endif /* FULL_PREHASH */
530c2b6c02Sjakob #endif /* NSEC3 */
5462ac0c33Sjakob 	result->is_existing = 0;
5562ac0c33Sjakob 	result->is_apex = 0;
560c2b6c02Sjakob 	result->has_SOA = 0;
5762ac0c33Sjakob 
5862ac0c33Sjakob 	return result;
5962ac0c33Sjakob }
6062ac0c33Sjakob 
6162ac0c33Sjakob domain_table_type *
6262ac0c33Sjakob domain_table_create(region_type *region)
6362ac0c33Sjakob {
6462ac0c33Sjakob 	const dname_type *origin;
6562ac0c33Sjakob 	domain_table_type *result;
6662ac0c33Sjakob 	domain_type *root;
6762ac0c33Sjakob 
6862ac0c33Sjakob 	assert(region);
6962ac0c33Sjakob 
7062ac0c33Sjakob 	origin = dname_make(region, (uint8_t *) "", 0);
7162ac0c33Sjakob 
7262ac0c33Sjakob 	root = (domain_type *) region_alloc(region, sizeof(domain_type));
7362ac0c33Sjakob 	root->node.key = origin;
7462ac0c33Sjakob 	root->parent = NULL;
75044f85deSsthen 	root->nextdiff = NULL;
7662ac0c33Sjakob 	root->wildcard_child_closest_match = root;
7762ac0c33Sjakob 	root->rrsets = NULL;
7862ac0c33Sjakob 	root->number = 1; /* 0 is used for after header */
7962ac0c33Sjakob 	root->is_existing = 0;
8062ac0c33Sjakob 	root->is_apex = 0;
810c2b6c02Sjakob 	root->has_SOA = 0;
8262ac0c33Sjakob #ifdef NSEC3
830c2b6c02Sjakob 	root->nsec3_cover = NULL;
840c2b6c02Sjakob #ifdef FULL_PREHASH
8562ac0c33Sjakob 	root->nsec3_is_exact = 0;
8662ac0c33Sjakob 	root->nsec3_ds_parent_is_exact = 0;
8762ac0c33Sjakob 	root->nsec3_wcard_child_cover = NULL;
8862ac0c33Sjakob 	root->nsec3_ds_parent_cover = NULL;
8962ac0c33Sjakob 	root->nsec3_lookup = NULL;
900c2b6c02Sjakob #endif /* FULL_PREHASH */
910c2b6c02Sjakob #endif /* NSEC3 */
9262ac0c33Sjakob 
9362ac0c33Sjakob 	result = (domain_table_type *) region_alloc(region,
9462ac0c33Sjakob 						    sizeof(domain_table_type));
9562ac0c33Sjakob 	result->region = region;
9662ac0c33Sjakob 	result->names_to_domains = rbtree_create(
9762ac0c33Sjakob 		region, (int (*)(const void *, const void *)) dname_compare);
9862ac0c33Sjakob 	rbtree_insert(result->names_to_domains, (rbnode_t *) root);
9962ac0c33Sjakob 
10062ac0c33Sjakob 	result->root = root;
10162ac0c33Sjakob 
10262ac0c33Sjakob 	return result;
10362ac0c33Sjakob }
10462ac0c33Sjakob 
10562ac0c33Sjakob int
10662ac0c33Sjakob domain_table_search(domain_table_type *table,
10762ac0c33Sjakob 		   const dname_type   *dname,
10862ac0c33Sjakob 		   domain_type       **closest_match,
10962ac0c33Sjakob 		   domain_type       **closest_encloser)
11062ac0c33Sjakob {
11162ac0c33Sjakob 	int exact;
11262ac0c33Sjakob 	uint8_t label_match_count;
11362ac0c33Sjakob 
11462ac0c33Sjakob 	assert(table);
11562ac0c33Sjakob 	assert(dname);
11662ac0c33Sjakob 	assert(closest_match);
11762ac0c33Sjakob 	assert(closest_encloser);
11862ac0c33Sjakob 
11962ac0c33Sjakob 	exact = rbtree_find_less_equal(table->names_to_domains, dname, (rbnode_t **) closest_match);
12062ac0c33Sjakob 	assert(*closest_match);
12162ac0c33Sjakob 
12262ac0c33Sjakob 	*closest_encloser = *closest_match;
12362ac0c33Sjakob 
12462ac0c33Sjakob 	if (!exact) {
12562ac0c33Sjakob 		label_match_count = dname_label_match_count(
12662ac0c33Sjakob 			domain_dname(*closest_encloser),
12762ac0c33Sjakob 			dname);
12862ac0c33Sjakob 		assert(label_match_count < dname->label_count);
12962ac0c33Sjakob 		while (label_match_count < domain_dname(*closest_encloser)->label_count) {
13062ac0c33Sjakob 			(*closest_encloser) = (*closest_encloser)->parent;
13162ac0c33Sjakob 			assert(*closest_encloser);
13262ac0c33Sjakob 		}
13362ac0c33Sjakob 	}
13462ac0c33Sjakob 
13562ac0c33Sjakob 	return exact;
13662ac0c33Sjakob }
13762ac0c33Sjakob 
13862ac0c33Sjakob domain_type *
13962ac0c33Sjakob domain_table_find(domain_table_type *table,
14062ac0c33Sjakob 		  const dname_type *dname)
14162ac0c33Sjakob {
14262ac0c33Sjakob 	domain_type *closest_match;
14362ac0c33Sjakob 	domain_type *closest_encloser;
14462ac0c33Sjakob 	int exact;
14562ac0c33Sjakob 
14662ac0c33Sjakob 	exact = domain_table_search(
14762ac0c33Sjakob 		table, dname, &closest_match, &closest_encloser);
14862ac0c33Sjakob 	return exact ? closest_encloser : NULL;
14962ac0c33Sjakob }
15062ac0c33Sjakob 
15162ac0c33Sjakob 
15262ac0c33Sjakob domain_type *
15362ac0c33Sjakob domain_table_insert(domain_table_type *table,
15462ac0c33Sjakob 		    const dname_type  *dname)
15562ac0c33Sjakob {
15662ac0c33Sjakob 	domain_type *closest_match;
15762ac0c33Sjakob 	domain_type *closest_encloser;
15862ac0c33Sjakob 	domain_type *result;
15962ac0c33Sjakob 	int exact;
16062ac0c33Sjakob 
16162ac0c33Sjakob 	assert(table);
16262ac0c33Sjakob 	assert(dname);
16362ac0c33Sjakob 
16462ac0c33Sjakob 	exact = domain_table_search(
16562ac0c33Sjakob 		table, dname, &closest_match, &closest_encloser);
16662ac0c33Sjakob 	if (exact) {
16762ac0c33Sjakob 		result = closest_encloser;
16862ac0c33Sjakob 	} else {
16962ac0c33Sjakob 		assert(domain_dname(closest_encloser)->label_count < dname->label_count);
17062ac0c33Sjakob 
17162ac0c33Sjakob 		/* Insert new node(s).  */
17262ac0c33Sjakob 		do {
17362ac0c33Sjakob 			result = allocate_domain_info(table,
17462ac0c33Sjakob 						      dname,
17562ac0c33Sjakob 						      closest_encloser);
17662ac0c33Sjakob 			rbtree_insert(table->names_to_domains, (rbnode_t *) result);
17762ac0c33Sjakob 			result->number = table->names_to_domains->count;
17862ac0c33Sjakob 
17962ac0c33Sjakob 			/*
18062ac0c33Sjakob 			 * If the newly added domain name is larger
18162ac0c33Sjakob 			 * than the parent's current
18262ac0c33Sjakob 			 * wildcard_child_closest_match but smaller or
18362ac0c33Sjakob 			 * equal to the wildcard domain name, update
18462ac0c33Sjakob 			 * the parent's wildcard_child_closest_match
18562ac0c33Sjakob 			 * field.
18662ac0c33Sjakob 			 */
18762ac0c33Sjakob 			if (label_compare(dname_name(domain_dname(result)),
18862ac0c33Sjakob 					  (const uint8_t *) "\001*") <= 0
18962ac0c33Sjakob 			    && dname_compare(domain_dname(result),
19062ac0c33Sjakob 					     domain_dname(closest_encloser->wildcard_child_closest_match)) > 0)
19162ac0c33Sjakob 			{
19262ac0c33Sjakob 				closest_encloser->wildcard_child_closest_match
19362ac0c33Sjakob 					= result;
19462ac0c33Sjakob 			}
19562ac0c33Sjakob 			closest_encloser = result;
19662ac0c33Sjakob 		} while (domain_dname(closest_encloser)->label_count < dname->label_count);
19762ac0c33Sjakob 	}
19862ac0c33Sjakob 
19962ac0c33Sjakob 	return result;
20062ac0c33Sjakob }
20162ac0c33Sjakob 
20262ac0c33Sjakob int
20362ac0c33Sjakob domain_table_iterate(domain_table_type *table,
20462ac0c33Sjakob 		    domain_table_iterator_type iterator,
20562ac0c33Sjakob 		    void *user_data)
20662ac0c33Sjakob {
20762ac0c33Sjakob 	const void *dname;
20862ac0c33Sjakob 	void *node;
20962ac0c33Sjakob 	int error = 0;
21062ac0c33Sjakob 
21162ac0c33Sjakob 	assert(table);
21262ac0c33Sjakob 
21362ac0c33Sjakob 	RBTREE_WALK(table->names_to_domains, dname, node) {
21462ac0c33Sjakob 		error += iterator((domain_type *) node, user_data);
21562ac0c33Sjakob 	}
21662ac0c33Sjakob 
21762ac0c33Sjakob 	return error;
21862ac0c33Sjakob }
21962ac0c33Sjakob 
22062ac0c33Sjakob 
22162ac0c33Sjakob void
22262ac0c33Sjakob domain_add_rrset(domain_type *domain, rrset_type *rrset)
22362ac0c33Sjakob {
22462ac0c33Sjakob #if 0 	/* fast */
22562ac0c33Sjakob 	rrset->next = domain->rrsets;
22662ac0c33Sjakob 	domain->rrsets = rrset;
22762ac0c33Sjakob #else
22862ac0c33Sjakob 	/* preserve ordering, add at end */
22962ac0c33Sjakob 	rrset_type** p = &domain->rrsets;
23062ac0c33Sjakob 	while(*p)
23162ac0c33Sjakob 		p = &((*p)->next);
23262ac0c33Sjakob 	*p = rrset;
23362ac0c33Sjakob 	rrset->next = 0;
23462ac0c33Sjakob #endif
23562ac0c33Sjakob 
23662ac0c33Sjakob 	while (domain && !domain->is_existing) {
23762ac0c33Sjakob 		domain->is_existing = 1;
23862ac0c33Sjakob 		domain = domain->parent;
23962ac0c33Sjakob 	}
24062ac0c33Sjakob }
24162ac0c33Sjakob 
24262ac0c33Sjakob 
24362ac0c33Sjakob rrset_type *
24462ac0c33Sjakob domain_find_rrset(domain_type *domain, zone_type *zone, uint16_t type)
24562ac0c33Sjakob {
24662ac0c33Sjakob 	rrset_type *result = domain->rrsets;
24762ac0c33Sjakob 
24862ac0c33Sjakob 	while (result) {
24962ac0c33Sjakob 		if (result->zone == zone && rrset_rrtype(result) == type) {
25062ac0c33Sjakob 			return result;
25162ac0c33Sjakob 		}
25262ac0c33Sjakob 		result = result->next;
25362ac0c33Sjakob 	}
25462ac0c33Sjakob 	return NULL;
25562ac0c33Sjakob }
25662ac0c33Sjakob 
25762ac0c33Sjakob rrset_type *
25862ac0c33Sjakob domain_find_any_rrset(domain_type *domain, zone_type *zone)
25962ac0c33Sjakob {
26062ac0c33Sjakob 	rrset_type *result = domain->rrsets;
26162ac0c33Sjakob 
26262ac0c33Sjakob 	while (result) {
26362ac0c33Sjakob 		if (result->zone == zone) {
26462ac0c33Sjakob 			return result;
26562ac0c33Sjakob 		}
26662ac0c33Sjakob 		result = result->next;
26762ac0c33Sjakob 	}
26862ac0c33Sjakob 	return NULL;
26962ac0c33Sjakob }
27062ac0c33Sjakob 
27162ac0c33Sjakob zone_type *
27262ac0c33Sjakob domain_find_zone(domain_type *domain)
27362ac0c33Sjakob {
27462ac0c33Sjakob 	rrset_type *rrset;
27562ac0c33Sjakob 	while (domain) {
27662ac0c33Sjakob 		for (rrset = domain->rrsets; rrset; rrset = rrset->next) {
27762ac0c33Sjakob 			if (rrset_rrtype(rrset) == TYPE_SOA) {
27862ac0c33Sjakob 				return rrset->zone;
27962ac0c33Sjakob 			}
28062ac0c33Sjakob 		}
28162ac0c33Sjakob 		domain = domain->parent;
28262ac0c33Sjakob 	}
28362ac0c33Sjakob 	return NULL;
28462ac0c33Sjakob }
28562ac0c33Sjakob 
2860c2b6c02Sjakob #ifndef FULL_PREHASH
2870c2b6c02Sjakob domain_type *
2880c2b6c02Sjakob domain_find_zone_apex(domain_type *domain) {
2890c2b6c02Sjakob 	while (domain != NULL) {
2900c2b6c02Sjakob 		if (domain->has_SOA != 0)
2910c2b6c02Sjakob 			return domain;
2920c2b6c02Sjakob 		domain = domain->parent;
2930c2b6c02Sjakob 	}
2940c2b6c02Sjakob 	return NULL;
2950c2b6c02Sjakob }
2960c2b6c02Sjakob #endif /* !FULL_PREHASH */
2970c2b6c02Sjakob 
29862ac0c33Sjakob zone_type *
29962ac0c33Sjakob domain_find_parent_zone(zone_type *zone)
30062ac0c33Sjakob {
30162ac0c33Sjakob 	rrset_type *rrset;
30262ac0c33Sjakob 
30362ac0c33Sjakob 	assert(zone);
30462ac0c33Sjakob 
30562ac0c33Sjakob 	for (rrset = zone->apex->rrsets; rrset; rrset = rrset->next) {
30662ac0c33Sjakob 		if (rrset->zone != zone && rrset_rrtype(rrset) == TYPE_NS) {
30762ac0c33Sjakob 			return rrset->zone;
30862ac0c33Sjakob 		}
30962ac0c33Sjakob 	}
31062ac0c33Sjakob 	return NULL;
31162ac0c33Sjakob }
31262ac0c33Sjakob 
31362ac0c33Sjakob domain_type *
31462ac0c33Sjakob domain_find_ns_rrsets(domain_type *domain, zone_type *zone, rrset_type **ns)
31562ac0c33Sjakob {
31662ac0c33Sjakob 	while (domain && domain != zone->apex) {
31762ac0c33Sjakob 		*ns = domain_find_rrset(domain, zone, TYPE_NS);
31862ac0c33Sjakob 		if (*ns)
31962ac0c33Sjakob 			return domain;
32062ac0c33Sjakob 		domain = domain->parent;
32162ac0c33Sjakob 	}
32262ac0c33Sjakob 
32362ac0c33Sjakob 	*ns = NULL;
32462ac0c33Sjakob 	return NULL;
32562ac0c33Sjakob }
32662ac0c33Sjakob 
32762ac0c33Sjakob int
32862ac0c33Sjakob domain_is_glue(domain_type *domain, zone_type *zone)
32962ac0c33Sjakob {
33062ac0c33Sjakob 	rrset_type *unused;
33162ac0c33Sjakob 	domain_type *ns_domain = domain_find_ns_rrsets(domain, zone, &unused);
33262ac0c33Sjakob 	return (ns_domain != NULL &&
33362ac0c33Sjakob 		domain_find_rrset(ns_domain, zone, TYPE_SOA) == NULL);
33462ac0c33Sjakob }
33562ac0c33Sjakob 
33662ac0c33Sjakob domain_type *
33762ac0c33Sjakob domain_wildcard_child(domain_type *domain)
33862ac0c33Sjakob {
33962ac0c33Sjakob 	domain_type *wildcard_child;
34062ac0c33Sjakob 
34162ac0c33Sjakob 	assert(domain);
34262ac0c33Sjakob 	assert(domain->wildcard_child_closest_match);
34362ac0c33Sjakob 
34462ac0c33Sjakob 	wildcard_child = domain->wildcard_child_closest_match;
34562ac0c33Sjakob 	if (wildcard_child != domain
34662ac0c33Sjakob 	    && label_is_wildcard(dname_name(domain_dname(wildcard_child))))
34762ac0c33Sjakob 	{
34862ac0c33Sjakob 		return wildcard_child;
34962ac0c33Sjakob 	} else {
35062ac0c33Sjakob 		return NULL;
35162ac0c33Sjakob 	}
35262ac0c33Sjakob }
35362ac0c33Sjakob 
35462ac0c33Sjakob int
35562ac0c33Sjakob zone_is_secure(zone_type *zone)
35662ac0c33Sjakob {
35762ac0c33Sjakob 	assert(zone);
35862ac0c33Sjakob 	return zone->is_secure;
35962ac0c33Sjakob }
36062ac0c33Sjakob 
36162ac0c33Sjakob uint16_t
36262ac0c33Sjakob rr_rrsig_type_covered(rr_type *rr)
36362ac0c33Sjakob {
36462ac0c33Sjakob 	assert(rr->type == TYPE_RRSIG);
36562ac0c33Sjakob 	assert(rr->rdata_count > 0);
36662ac0c33Sjakob 	assert(rdata_atom_size(rr->rdatas[0]) == sizeof(uint16_t));
36762ac0c33Sjakob 
36862ac0c33Sjakob 	return ntohs(* (uint16_t *) rdata_atom_data(rr->rdatas[0]));
36962ac0c33Sjakob }
37062ac0c33Sjakob 
37162ac0c33Sjakob zone_type *
37262ac0c33Sjakob namedb_find_zone(namedb_type *db, domain_type *domain)
37362ac0c33Sjakob {
37462ac0c33Sjakob 	zone_type *zone;
37562ac0c33Sjakob 
37662ac0c33Sjakob 	for (zone = db->zones; zone; zone = zone->next) {
37762ac0c33Sjakob 		if (zone->apex == domain)
37862ac0c33Sjakob 			break;
37962ac0c33Sjakob 	}
38062ac0c33Sjakob 
38162ac0c33Sjakob 	return zone;
38262ac0c33Sjakob }
38362ac0c33Sjakob 
38462ac0c33Sjakob rrset_type *
38562ac0c33Sjakob domain_find_non_cname_rrset(domain_type *domain, zone_type *zone)
38662ac0c33Sjakob {
38762ac0c33Sjakob 	/* find any rrset type that is not allowed next to a CNAME */
38862ac0c33Sjakob 	/* nothing is allowed next to a CNAME, except RRSIG, NSEC, NSEC3 */
38962ac0c33Sjakob 	rrset_type *result = domain->rrsets;
39062ac0c33Sjakob 
39162ac0c33Sjakob 	while (result) {
39262ac0c33Sjakob 		if (result->zone == zone && /* here is the list of exceptions*/
39362ac0c33Sjakob 			rrset_rrtype(result) != TYPE_CNAME &&
39462ac0c33Sjakob 			rrset_rrtype(result) != TYPE_RRSIG &&
39562ac0c33Sjakob 			rrset_rrtype(result) != TYPE_NXT &&
39662ac0c33Sjakob 			rrset_rrtype(result) != TYPE_SIG &&
39762ac0c33Sjakob 			rrset_rrtype(result) != TYPE_NSEC &&
39862ac0c33Sjakob 			rrset_rrtype(result) != TYPE_NSEC3 ) {
39962ac0c33Sjakob 			return result;
40062ac0c33Sjakob 		}
40162ac0c33Sjakob 		result = result->next;
40262ac0c33Sjakob 	}
40362ac0c33Sjakob 	return NULL;
40462ac0c33Sjakob }
4050c2b6c02Sjakob 
4060c2b6c02Sjakob /**
4070c2b6c02Sjakob  * Create namedb.
4080c2b6c02Sjakob  *
4090c2b6c02Sjakob  */
4100c2b6c02Sjakob struct namedb *
4110c2b6c02Sjakob namedb_create(void)
4120c2b6c02Sjakob {
4130c2b6c02Sjakob 	struct namedb *db = NULL;
4140c2b6c02Sjakob 	region_type *region = NULL;
4150c2b6c02Sjakob #ifdef NSEC3
4160c2b6c02Sjakob #ifndef FULL_PREHASH
4170c2b6c02Sjakob 	region_type *nsec3_region = NULL;
4180c2b6c02Sjakob 	region_type *nsec3_mod_region = NULL;
4190c2b6c02Sjakob #endif /* !FULL_PREHASH */
4200c2b6c02Sjakob #endif /* NSEC3 */
4210c2b6c02Sjakob 
4220c2b6c02Sjakob #ifdef USE_MMAP_ALLOC
4230c2b6c02Sjakob 	region = region_create_custom(mmap_alloc, mmap_free,
4240c2b6c02Sjakob 		MMAP_ALLOC_CHUNK_SIZE, MMAP_ALLOC_LARGE_OBJECT_SIZE,
4250c2b6c02Sjakob 		MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
4260c2b6c02Sjakob #else /* !USE_MMAP_ALLOC */
4270c2b6c02Sjakob 	region = region_create_custom(xalloc, free,
4280c2b6c02Sjakob 		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
4290c2b6c02Sjakob 		DEFAULT_INITIAL_CLEANUP_SIZE, 1);
4300c2b6c02Sjakob #endif /* !USE_MMAP_ALLOC */
4310c2b6c02Sjakob 	if (region == NULL)
4320c2b6c02Sjakob 		return NULL;
4330c2b6c02Sjakob 
4340c2b6c02Sjakob #ifdef NSEC3
4350c2b6c02Sjakob #ifndef FULL_PREHASH
4360c2b6c02Sjakob #ifdef USE_MMAP_ALLOC
4370c2b6c02Sjakob 	nsec3_region = region_create_custom(mmap_alloc, mmap_free,
4380c2b6c02Sjakob 		MMAP_ALLOC_CHUNK_SIZE, MMAP_ALLOC_LARGE_OBJECT_SIZE,
4390c2b6c02Sjakob 		MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
4400c2b6c02Sjakob #else /* !USE_MMAP_ALLOC */
4410c2b6c02Sjakob 	nsec3_region = region_create_custom(xalloc, free,
4420c2b6c02Sjakob 		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
4430c2b6c02Sjakob 		DEFAULT_INITIAL_CLEANUP_SIZE, 1);
4440c2b6c02Sjakob #endif /* !USE_MMAP_ALLOC */
4450c2b6c02Sjakob 	if (nsec3_region == NULL) {
4460c2b6c02Sjakob 		region_destroy(region);
4470c2b6c02Sjakob 		return NULL;
4480c2b6c02Sjakob 	}
4490c2b6c02Sjakob #ifdef USE_MMAP_ALLOC
4500c2b6c02Sjakob 	nsec3_mod_region = region_create_custom(mmap_alloc, mmap_free,
4510c2b6c02Sjakob 		MMAP_ALLOC_CHUNK_SIZE, MMAP_ALLOC_LARGE_OBJECT_SIZE,
4520c2b6c02Sjakob 		MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
4530c2b6c02Sjakob #else /* !USE_MMAP_ALLOC */
4540c2b6c02Sjakob 	nsec3_mod_region = region_create_custom(xalloc, free,
4550c2b6c02Sjakob 		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
4560c2b6c02Sjakob 		DEFAULT_INITIAL_CLEANUP_SIZE, 1);
4570c2b6c02Sjakob #endif /* !USE_MMAP_ALLOC */
4580c2b6c02Sjakob 	if (nsec3_mod_region == NULL) {
4590c2b6c02Sjakob 		region_destroy(region);
4600c2b6c02Sjakob 		region_destroy(nsec3_region);
4610c2b6c02Sjakob 		return NULL;
4620c2b6c02Sjakob 	}
4630c2b6c02Sjakob #endif /* !FULL_PREHASH */
4640c2b6c02Sjakob #endif /* NSEC3 */
4650c2b6c02Sjakob 
4660c2b6c02Sjakob 	/* Make a new structure... */
4670c2b6c02Sjakob 	db = (namedb_type *) region_alloc(region, sizeof(namedb_type));
4680c2b6c02Sjakob 	db->region = region;
4690c2b6c02Sjakob #ifdef NSEC3
4700c2b6c02Sjakob #ifndef FULL_PREHASH
4710c2b6c02Sjakob 	db->nsec3_region = nsec3_region;
4720c2b6c02Sjakob 	db->nsec3_mod_region = nsec3_mod_region;
4730c2b6c02Sjakob 	db->nsec3_mod_domains = NULL;
4740c2b6c02Sjakob #endif /* !FULL_PREHASH */
4750c2b6c02Sjakob #endif /* NSEC3 */
4760c2b6c02Sjakob 	db->domains = domain_table_create(region);
4770c2b6c02Sjakob 	db->zones = NULL;
4780c2b6c02Sjakob 	db->zone_count = 0;
4790c2b6c02Sjakob 	db->filename = NULL;
4800c2b6c02Sjakob 	db->fd = NULL;
4810c2b6c02Sjakob 	db->crc = ~0;
4820c2b6c02Sjakob 	db->crc_pos = 0;
4830c2b6c02Sjakob 	db->diff_skip = 0;
4840c2b6c02Sjakob 	db->diff_pos = 0;
4850c2b6c02Sjakob 	return db;
4860c2b6c02Sjakob }
4870c2b6c02Sjakob 
4880c2b6c02Sjakob /**
4890c2b6c02Sjakob  * Destroy namedb.
4900c2b6c02Sjakob  *
4910c2b6c02Sjakob  */
4920c2b6c02Sjakob void
4930c2b6c02Sjakob namedb_destroy(struct namedb *db)
4940c2b6c02Sjakob {
4950c2b6c02Sjakob #ifdef NSEC3
4960c2b6c02Sjakob #ifndef FULL_PREHASH
4970c2b6c02Sjakob 	region_destroy(db->nsec3_mod_region);
4980c2b6c02Sjakob 	db->nsec3_mod_region = NULL;
4990c2b6c02Sjakob 	db->nsec3_mod_domains = NULL;
5000c2b6c02Sjakob 	region_destroy(db->nsec3_region);
5010c2b6c02Sjakob 	db->nsec3_region = NULL;
5020c2b6c02Sjakob #endif /* !FULL_PREHASH */
5030c2b6c02Sjakob #endif /* NSEC3 */
5040c2b6c02Sjakob 	region_destroy(db->region);
5050c2b6c02Sjakob }
5060c2b6c02Sjakob 
5070c2b6c02Sjakob 
5080c2b6c02Sjakob #ifdef NSEC3
5090c2b6c02Sjakob #ifndef FULL_PREHASH
5100c2b6c02Sjakob int
5110c2b6c02Sjakob zone_nsec3_domains_create(struct namedb *db, struct zone *zone)
5120c2b6c02Sjakob {
5130c2b6c02Sjakob 	if ((db == NULL) || (zone == NULL))
5140c2b6c02Sjakob 		return EINVAL;
5150c2b6c02Sjakob 	if (zone->nsec3_domains != NULL)
5160c2b6c02Sjakob 		return 0;
5170c2b6c02Sjakob 	zone->nsec3_domains = rbtree_create(db->nsec3_region,
5180c2b6c02Sjakob 					    dname_compare);
5190c2b6c02Sjakob 	if (zone->nsec3_domains == NULL)
5200c2b6c02Sjakob 		return ENOMEM;
5210c2b6c02Sjakob 	return 0;
5220c2b6c02Sjakob }
5230c2b6c02Sjakob 
5240c2b6c02Sjakob int
5250c2b6c02Sjakob zone_nsec3_domains_destroy(struct namedb *db, struct zone *zone)
5260c2b6c02Sjakob {
5270c2b6c02Sjakob 	rbnode_t *node;
5280c2b6c02Sjakob 	if ((db == NULL) || (zone == NULL))
5290c2b6c02Sjakob 		return EINVAL;
5300c2b6c02Sjakob 	if (zone->nsec3_domains == NULL)
5310c2b6c02Sjakob 		return 0;
5320c2b6c02Sjakob 
5330c2b6c02Sjakob 	node = rbtree_postorder_first(zone->nsec3_domains->root);
5340c2b6c02Sjakob 	while (node != RBTREE_NULL) {
5350c2b6c02Sjakob 		struct nsec3_domain *nsec3_domain =
5360c2b6c02Sjakob 			(struct nsec3_domain *) node;
5370c2b6c02Sjakob 		node = rbtree_postorder_next(node);
5380c2b6c02Sjakob 
5390c2b6c02Sjakob 		if (nsec3_domain->covers != NULL) {
5400c2b6c02Sjakob 			nsec3_domain->covers->nsec3_cover = NULL;
5410c2b6c02Sjakob 		}
5420c2b6c02Sjakob 		region_recycle(db->nsec3_region, nsec3_domain,
5430c2b6c02Sjakob 			sizeof(*nsec3_domain));
5440c2b6c02Sjakob 	}
5450c2b6c02Sjakob 	region_recycle(db->nsec3_region, zone->nsec3_domains,
5460c2b6c02Sjakob 		sizeof(*(zone->nsec3_domains)));
5470c2b6c02Sjakob 	zone->nsec3_domains = NULL;
5480c2b6c02Sjakob 	return 0;
5490c2b6c02Sjakob }
5500c2b6c02Sjakob 
5510c2b6c02Sjakob 
5520c2b6c02Sjakob int
5530c2b6c02Sjakob namedb_add_nsec3_domain(struct namedb *db, struct domain *domain,
5540c2b6c02Sjakob 	struct zone *zone)
5550c2b6c02Sjakob {
5560c2b6c02Sjakob 	struct nsec3_domain *nsec3_domain;
5570c2b6c02Sjakob 	if (zone->nsec3_domains == NULL)
5580c2b6c02Sjakob 		return 0;
5590c2b6c02Sjakob 	nsec3_domain = (struct nsec3_domain *) region_alloc(db->nsec3_region,
5600c2b6c02Sjakob 		sizeof(*nsec3_domain));
5610c2b6c02Sjakob 	if (nsec3_domain == NULL)
5620c2b6c02Sjakob 		return ENOMEM;
5630c2b6c02Sjakob 	nsec3_domain->node.key = domain_dname(domain);
5640c2b6c02Sjakob 	nsec3_domain->nsec3_domain = domain;
5650c2b6c02Sjakob 	nsec3_domain->covers = NULL;
5660c2b6c02Sjakob 	if (rbtree_insert(zone->nsec3_domains, (rbnode_t *) nsec3_domain) == NULL) {
5670c2b6c02Sjakob 		region_recycle(db->nsec3_region, nsec3_domain, sizeof(*nsec3_domain));
5680c2b6c02Sjakob 	}
5690c2b6c02Sjakob 	return 0;
5700c2b6c02Sjakob }
5710c2b6c02Sjakob 
5720c2b6c02Sjakob 
5730c2b6c02Sjakob int
5740c2b6c02Sjakob namedb_del_nsec3_domain(struct namedb *db, struct domain *domain,
5750c2b6c02Sjakob 	struct zone *zone)
5760c2b6c02Sjakob {
5770c2b6c02Sjakob 	rbnode_t *node;
5780c2b6c02Sjakob 	struct nsec3_domain *nsec3_domain;
5790c2b6c02Sjakob 	int error = 0;
5800c2b6c02Sjakob 
5810c2b6c02Sjakob 	if (zone->nsec3_domains == NULL)
5820c2b6c02Sjakob 		return 0;
5830c2b6c02Sjakob 
5840c2b6c02Sjakob 	node = rbtree_delete(zone->nsec3_domains, domain_dname(domain));
5850c2b6c02Sjakob 	if (node == NULL)
5860c2b6c02Sjakob 		return 0;
5870c2b6c02Sjakob 
5880c2b6c02Sjakob 	nsec3_domain = (struct nsec3_domain *) node;
5890c2b6c02Sjakob 	if (nsec3_domain->covers != NULL) {
5900c2b6c02Sjakob 		/*
5910c2b6c02Sjakob 		 * It is possible that this NSEC3 domain was modified
5920c2b6c02Sjakob 		 * due to the addition/deletion of another NSEC3 domain.
5930c2b6c02Sjakob 		 * Make sure it gets added to the NSEC3 list later by
5940c2b6c02Sjakob 		 * making sure it's covered domain is added to the
5950c2b6c02Sjakob 		 * NSEC3 mod list. S64#3441
5960c2b6c02Sjakob 		 */
5970c2b6c02Sjakob 		error = namedb_add_nsec3_mod_domain(db, nsec3_domain->covers);
5980c2b6c02Sjakob 		nsec3_domain->covers->nsec3_cover = NULL;
5990c2b6c02Sjakob 		nsec3_domain->covers = NULL;
6000c2b6c02Sjakob 	}
6010c2b6c02Sjakob 	region_recycle(db->nsec3_region, nsec3_domain, sizeof(*nsec3_domain));
6020c2b6c02Sjakob 	return error;
6030c2b6c02Sjakob }
6040c2b6c02Sjakob 
6050c2b6c02Sjakob 
6060c2b6c02Sjakob int
6070c2b6c02Sjakob namedb_nsec3_mod_domains_create(struct namedb *db)
6080c2b6c02Sjakob {
6090c2b6c02Sjakob 	if (db == NULL)
6100c2b6c02Sjakob 		return EINVAL;
6110c2b6c02Sjakob 	namedb_nsec3_mod_domains_destroy(db);
6120c2b6c02Sjakob 
6130c2b6c02Sjakob 	db->nsec3_mod_domains = rbtree_create(db->nsec3_mod_region, dname_compare);
6140c2b6c02Sjakob 	if (db->nsec3_mod_domains == NULL)
6150c2b6c02Sjakob 		return ENOMEM;
6160c2b6c02Sjakob 	return 0;
6170c2b6c02Sjakob }
6180c2b6c02Sjakob 
6190c2b6c02Sjakob 
6200c2b6c02Sjakob int
6210c2b6c02Sjakob namedb_nsec3_mod_domains_destroy(struct namedb *db)
6220c2b6c02Sjakob {
6230c2b6c02Sjakob 	if (db == NULL)
6240c2b6c02Sjakob 		return EINVAL;
6250c2b6c02Sjakob 	if (db->nsec3_mod_domains == NULL)
6260c2b6c02Sjakob 		return 0;
6270c2b6c02Sjakob 	region_free_all(db->nsec3_mod_region);
6280c2b6c02Sjakob 	db->nsec3_mod_domains = NULL;
6290c2b6c02Sjakob 	return 0;
6300c2b6c02Sjakob }
6310c2b6c02Sjakob 
6320c2b6c02Sjakob int
6330c2b6c02Sjakob namedb_add_nsec3_mod_domain(struct namedb *db, struct domain *domain)
6340c2b6c02Sjakob {
6350c2b6c02Sjakob 	struct nsec3_mod_domain *nsec3_mod_domain;
6360c2b6c02Sjakob 	nsec3_mod_domain = (struct nsec3_mod_domain *)
6370c2b6c02Sjakob 		region_alloc(db->nsec3_mod_region, sizeof(*nsec3_mod_domain));
6380c2b6c02Sjakob 	if (nsec3_mod_domain == NULL) {
6390c2b6c02Sjakob 		log_msg(LOG_ERR,
6400c2b6c02Sjakob 			"memory allocation failure on modified domain");
6410c2b6c02Sjakob 		return ENOMEM;
6420c2b6c02Sjakob 	}
6430c2b6c02Sjakob 	nsec3_mod_domain->node.key = domain_dname(domain);
6440c2b6c02Sjakob 	nsec3_mod_domain->domain = domain;
6450c2b6c02Sjakob 
6460c2b6c02Sjakob 	if (rbtree_insert(db->nsec3_mod_domains, (rbnode_t *) nsec3_mod_domain) == NULL) {
6470c2b6c02Sjakob 		region_recycle(db->nsec3_mod_region, nsec3_mod_domain,
6480c2b6c02Sjakob 			sizeof(*nsec3_mod_domain));
6490c2b6c02Sjakob 	}
6500c2b6c02Sjakob 	return 0;
6510c2b6c02Sjakob }
6520c2b6c02Sjakob #endif /* !FULL_PREHASH */
6530c2b6c02Sjakob #endif /* NSEC3 */
654