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