xref: /freebsd/contrib/unbound/util/storage/dnstree.c (revision b7579f77d18196a58ff700756c84dc9a302a7f67)
1*b7579f77SDag-Erling Smørgrav /*
2*b7579f77SDag-Erling Smørgrav  * util/storage/dnstree.c - support for rbtree types suitable for DNS code.
3*b7579f77SDag-Erling Smørgrav  *
4*b7579f77SDag-Erling Smørgrav  * Copyright (c) 2008, NLnet Labs. All rights reserved.
5*b7579f77SDag-Erling Smørgrav  *
6*b7579f77SDag-Erling Smørgrav  * This software is open source.
7*b7579f77SDag-Erling Smørgrav  *
8*b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9*b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10*b7579f77SDag-Erling Smørgrav  * are met:
11*b7579f77SDag-Erling Smørgrav  *
12*b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14*b7579f77SDag-Erling Smørgrav  *
15*b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16*b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17*b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18*b7579f77SDag-Erling Smørgrav  *
19*b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20*b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21*b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22*b7579f77SDag-Erling Smørgrav  *
23*b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*b7579f77SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25*b7579f77SDag-Erling Smørgrav  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26*b7579f77SDag-Erling Smørgrav  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27*b7579f77SDag-Erling Smørgrav  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*b7579f77SDag-Erling Smørgrav  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*b7579f77SDag-Erling Smørgrav  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30*b7579f77SDag-Erling Smørgrav  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31*b7579f77SDag-Erling Smørgrav  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32*b7579f77SDag-Erling Smørgrav  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*b7579f77SDag-Erling Smørgrav  * POSSIBILITY OF SUCH DAMAGE.
34*b7579f77SDag-Erling Smørgrav  */
35*b7579f77SDag-Erling Smørgrav 
36*b7579f77SDag-Erling Smørgrav /**
37*b7579f77SDag-Erling Smørgrav  * \file
38*b7579f77SDag-Erling Smørgrav  *
39*b7579f77SDag-Erling Smørgrav  * This file contains structures combining types and functions to
40*b7579f77SDag-Erling Smørgrav  * manipulate those structures that help building DNS lookup trees.
41*b7579f77SDag-Erling Smørgrav  */
42*b7579f77SDag-Erling Smørgrav #include "config.h"
43*b7579f77SDag-Erling Smørgrav #include "util/storage/dnstree.h"
44*b7579f77SDag-Erling Smørgrav #include "util/data/dname.h"
45*b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
46*b7579f77SDag-Erling Smørgrav 
47*b7579f77SDag-Erling Smørgrav int name_tree_compare(const void* k1, const void* k2)
48*b7579f77SDag-Erling Smørgrav {
49*b7579f77SDag-Erling Smørgrav         struct name_tree_node* x = (struct name_tree_node*)k1;
50*b7579f77SDag-Erling Smørgrav         struct name_tree_node* y = (struct name_tree_node*)k2;
51*b7579f77SDag-Erling Smørgrav         int m;
52*b7579f77SDag-Erling Smørgrav         if(x->dclass != y->dclass) {
53*b7579f77SDag-Erling Smørgrav                 if(x->dclass < y->dclass)
54*b7579f77SDag-Erling Smørgrav                         return -1;
55*b7579f77SDag-Erling Smørgrav                 return 1;
56*b7579f77SDag-Erling Smørgrav         }
57*b7579f77SDag-Erling Smørgrav         return dname_lab_cmp(x->name, x->labs, y->name, y->labs, &m);
58*b7579f77SDag-Erling Smørgrav }
59*b7579f77SDag-Erling Smørgrav 
60*b7579f77SDag-Erling Smørgrav int addr_tree_compare(const void* k1, const void* k2)
61*b7579f77SDag-Erling Smørgrav {
62*b7579f77SDag-Erling Smørgrav         struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
63*b7579f77SDag-Erling Smørgrav         struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
64*b7579f77SDag-Erling Smørgrav         int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
65*b7579f77SDag-Erling Smørgrav                 n2->addrlen);
66*b7579f77SDag-Erling Smørgrav         if(r != 0) return r;
67*b7579f77SDag-Erling Smørgrav         if(n1->net < n2->net)
68*b7579f77SDag-Erling Smørgrav                 return -1;
69*b7579f77SDag-Erling Smørgrav         if(n1->net > n2->net)
70*b7579f77SDag-Erling Smørgrav                 return 1;
71*b7579f77SDag-Erling Smørgrav         return 0;
72*b7579f77SDag-Erling Smørgrav }
73*b7579f77SDag-Erling Smørgrav 
74*b7579f77SDag-Erling Smørgrav void name_tree_init(rbtree_t* tree)
75*b7579f77SDag-Erling Smørgrav {
76*b7579f77SDag-Erling Smørgrav 	rbtree_init(tree, &name_tree_compare);
77*b7579f77SDag-Erling Smørgrav }
78*b7579f77SDag-Erling Smørgrav 
79*b7579f77SDag-Erling Smørgrav void addr_tree_init(rbtree_t* tree)
80*b7579f77SDag-Erling Smørgrav {
81*b7579f77SDag-Erling Smørgrav 	rbtree_init(tree, &addr_tree_compare);
82*b7579f77SDag-Erling Smørgrav }
83*b7579f77SDag-Erling Smørgrav 
84*b7579f77SDag-Erling Smørgrav int name_tree_insert(rbtree_t* tree, struct name_tree_node* node,
85*b7579f77SDag-Erling Smørgrav         uint8_t* name, size_t len, int labs, uint16_t dclass)
86*b7579f77SDag-Erling Smørgrav {
87*b7579f77SDag-Erling Smørgrav 	node->node.key = node;
88*b7579f77SDag-Erling Smørgrav 	node->name = name;
89*b7579f77SDag-Erling Smørgrav 	node->len = len;
90*b7579f77SDag-Erling Smørgrav 	node->labs = labs;
91*b7579f77SDag-Erling Smørgrav 	node->dclass = dclass;
92*b7579f77SDag-Erling Smørgrav 	node->parent = NULL;
93*b7579f77SDag-Erling Smørgrav 	return rbtree_insert(tree, &node->node) != NULL;
94*b7579f77SDag-Erling Smørgrav }
95*b7579f77SDag-Erling Smørgrav 
96*b7579f77SDag-Erling Smørgrav int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node,
97*b7579f77SDag-Erling Smørgrav         struct sockaddr_storage* addr, socklen_t addrlen, int net)
98*b7579f77SDag-Erling Smørgrav {
99*b7579f77SDag-Erling Smørgrav 	node->node.key = node;
100*b7579f77SDag-Erling Smørgrav 	memcpy(&node->addr, addr, addrlen);
101*b7579f77SDag-Erling Smørgrav 	node->addrlen = addrlen;
102*b7579f77SDag-Erling Smørgrav 	node->net = net;
103*b7579f77SDag-Erling Smørgrav 	node->parent = NULL;
104*b7579f77SDag-Erling Smørgrav 	return rbtree_insert(tree, &node->node) != NULL;
105*b7579f77SDag-Erling Smørgrav }
106*b7579f77SDag-Erling Smørgrav 
107*b7579f77SDag-Erling Smørgrav void addr_tree_init_parents(rbtree_t* tree)
108*b7579f77SDag-Erling Smørgrav {
109*b7579f77SDag-Erling Smørgrav         struct addr_tree_node* node, *prev = NULL, *p;
110*b7579f77SDag-Erling Smørgrav         int m;
111*b7579f77SDag-Erling Smørgrav         RBTREE_FOR(node, struct addr_tree_node*, tree) {
112*b7579f77SDag-Erling Smørgrav                 node->parent = NULL;
113*b7579f77SDag-Erling Smørgrav                 if(!prev || prev->addrlen != node->addrlen) {
114*b7579f77SDag-Erling Smørgrav                         prev = node;
115*b7579f77SDag-Erling Smørgrav                         continue;
116*b7579f77SDag-Erling Smørgrav                 }
117*b7579f77SDag-Erling Smørgrav                 m = addr_in_common(&prev->addr, prev->net, &node->addr,
118*b7579f77SDag-Erling Smørgrav                         node->net, node->addrlen);
119*b7579f77SDag-Erling Smørgrav                 /* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
120*b7579f77SDag-Erling Smørgrav                 /* find the previous, or parent-parent-parent */
121*b7579f77SDag-Erling Smørgrav                 for(p = prev; p; p = p->parent)
122*b7579f77SDag-Erling Smørgrav                         if(p->net <= m) {
123*b7579f77SDag-Erling Smørgrav                                 /* ==: since prev matched m, this is closest*/
124*b7579f77SDag-Erling Smørgrav                                 /* <: prev matches more, but is not a parent,
125*b7579f77SDag-Erling Smørgrav 				 * this one is a (grand)parent */
126*b7579f77SDag-Erling Smørgrav                                 node->parent = p;
127*b7579f77SDag-Erling Smørgrav                                 break;
128*b7579f77SDag-Erling Smørgrav                         }
129*b7579f77SDag-Erling Smørgrav                 prev = node;
130*b7579f77SDag-Erling Smørgrav         }
131*b7579f77SDag-Erling Smørgrav }
132*b7579f77SDag-Erling Smørgrav 
133*b7579f77SDag-Erling Smørgrav void name_tree_init_parents(rbtree_t* tree)
134*b7579f77SDag-Erling Smørgrav {
135*b7579f77SDag-Erling Smørgrav         struct name_tree_node* node, *prev = NULL, *p;
136*b7579f77SDag-Erling Smørgrav         int m;
137*b7579f77SDag-Erling Smørgrav         RBTREE_FOR(node, struct name_tree_node*, tree) {
138*b7579f77SDag-Erling Smørgrav                 node->parent = NULL;
139*b7579f77SDag-Erling Smørgrav                 if(!prev || prev->dclass != node->dclass) {
140*b7579f77SDag-Erling Smørgrav                         prev = node;
141*b7579f77SDag-Erling Smørgrav                         continue;
142*b7579f77SDag-Erling Smørgrav                 }
143*b7579f77SDag-Erling Smørgrav                 (void)dname_lab_cmp(prev->name, prev->labs, node->name,
144*b7579f77SDag-Erling Smørgrav                         node->labs, &m); /* we know prev is smaller */
145*b7579f77SDag-Erling Smørgrav 		/* sort order like: . com. bla.com. zwb.com. net. */
146*b7579f77SDag-Erling Smørgrav                 /* find the previous, or parent-parent-parent */
147*b7579f77SDag-Erling Smørgrav                 for(p = prev; p; p = p->parent)
148*b7579f77SDag-Erling Smørgrav                         if(p->labs <= m) {
149*b7579f77SDag-Erling Smørgrav                                 /* ==: since prev matched m, this is closest*/
150*b7579f77SDag-Erling Smørgrav                                 /* <: prev matches more, but is not a parent,
151*b7579f77SDag-Erling Smørgrav 				 * this one is a (grand)parent */
152*b7579f77SDag-Erling Smørgrav                                 node->parent = p;
153*b7579f77SDag-Erling Smørgrav                                 break;
154*b7579f77SDag-Erling Smørgrav                         }
155*b7579f77SDag-Erling Smørgrav                 prev = node;
156*b7579f77SDag-Erling Smørgrav         }
157*b7579f77SDag-Erling Smørgrav }
158*b7579f77SDag-Erling Smørgrav 
159*b7579f77SDag-Erling Smørgrav struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
160*b7579f77SDag-Erling Smørgrav         size_t len, int labs, uint16_t dclass)
161*b7579f77SDag-Erling Smørgrav {
162*b7579f77SDag-Erling Smørgrav 	struct name_tree_node key;
163*b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
164*b7579f77SDag-Erling Smørgrav 	key.name = name;
165*b7579f77SDag-Erling Smørgrav 	key.len = len;
166*b7579f77SDag-Erling Smørgrav 	key.labs = labs;
167*b7579f77SDag-Erling Smørgrav 	key.dclass = dclass;
168*b7579f77SDag-Erling Smørgrav 	return (struct name_tree_node*)rbtree_search(tree, &key);
169*b7579f77SDag-Erling Smørgrav }
170*b7579f77SDag-Erling Smørgrav 
171*b7579f77SDag-Erling Smørgrav struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
172*b7579f77SDag-Erling Smørgrav         size_t len, int labs, uint16_t dclass)
173*b7579f77SDag-Erling Smørgrav {
174*b7579f77SDag-Erling Smørgrav         rbnode_t* res = NULL;
175*b7579f77SDag-Erling Smørgrav         struct name_tree_node *result;
176*b7579f77SDag-Erling Smørgrav         struct name_tree_node key;
177*b7579f77SDag-Erling Smørgrav         key.node.key = &key;
178*b7579f77SDag-Erling Smørgrav         key.name = name;
179*b7579f77SDag-Erling Smørgrav         key.len = len;
180*b7579f77SDag-Erling Smørgrav         key.labs = labs;
181*b7579f77SDag-Erling Smørgrav         key.dclass = dclass;
182*b7579f77SDag-Erling Smørgrav         if(rbtree_find_less_equal(tree, &key, &res)) {
183*b7579f77SDag-Erling Smørgrav                 /* exact */
184*b7579f77SDag-Erling Smørgrav                 result = (struct name_tree_node*)res;
185*b7579f77SDag-Erling Smørgrav         } else {
186*b7579f77SDag-Erling Smørgrav                 /* smaller element (or no element) */
187*b7579f77SDag-Erling Smørgrav                 int m;
188*b7579f77SDag-Erling Smørgrav                 result = (struct name_tree_node*)res;
189*b7579f77SDag-Erling Smørgrav                 if(!result || result->dclass != dclass)
190*b7579f77SDag-Erling Smørgrav                         return NULL;
191*b7579f77SDag-Erling Smørgrav                 /* count number of labels matched */
192*b7579f77SDag-Erling Smørgrav                 (void)dname_lab_cmp(result->name, result->labs, key.name,
193*b7579f77SDag-Erling Smørgrav                         key.labs, &m);
194*b7579f77SDag-Erling Smørgrav                 while(result) { /* go up until qname is subdomain of stub */
195*b7579f77SDag-Erling Smørgrav                         if(result->labs <= m)
196*b7579f77SDag-Erling Smørgrav                                 break;
197*b7579f77SDag-Erling Smørgrav                         result = result->parent;
198*b7579f77SDag-Erling Smørgrav                 }
199*b7579f77SDag-Erling Smørgrav         }
200*b7579f77SDag-Erling Smørgrav 	return result;
201*b7579f77SDag-Erling Smørgrav }
202*b7579f77SDag-Erling Smørgrav 
203*b7579f77SDag-Erling Smørgrav struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
204*b7579f77SDag-Erling Smørgrav         struct sockaddr_storage* addr, socklen_t addrlen)
205*b7579f77SDag-Erling Smørgrav {
206*b7579f77SDag-Erling Smørgrav         rbnode_t* res = NULL;
207*b7579f77SDag-Erling Smørgrav         struct addr_tree_node* result;
208*b7579f77SDag-Erling Smørgrav         struct addr_tree_node key;
209*b7579f77SDag-Erling Smørgrav         key.node.key = &key;
210*b7579f77SDag-Erling Smørgrav         memcpy(&key.addr, addr, addrlen);
211*b7579f77SDag-Erling Smørgrav         key.addrlen = addrlen;
212*b7579f77SDag-Erling Smørgrav         key.net = (addr_is_ip6(addr, addrlen)?128:32);
213*b7579f77SDag-Erling Smørgrav         if(rbtree_find_less_equal(tree, &key, &res)) {
214*b7579f77SDag-Erling Smørgrav                 /* exact */
215*b7579f77SDag-Erling Smørgrav                 return (struct addr_tree_node*)res;
216*b7579f77SDag-Erling Smørgrav         } else {
217*b7579f77SDag-Erling Smørgrav                 /* smaller element (or no element) */
218*b7579f77SDag-Erling Smørgrav                 int m;
219*b7579f77SDag-Erling Smørgrav                 result = (struct addr_tree_node*)res;
220*b7579f77SDag-Erling Smørgrav                 if(!result || result->addrlen != addrlen)
221*b7579f77SDag-Erling Smørgrav                         return 0;
222*b7579f77SDag-Erling Smørgrav                 /* count number of bits matched */
223*b7579f77SDag-Erling Smørgrav                 m = addr_in_common(&result->addr, result->net, addr,
224*b7579f77SDag-Erling Smørgrav                         key.net, addrlen);
225*b7579f77SDag-Erling Smørgrav                 while(result) { /* go up until addr is inside netblock */
226*b7579f77SDag-Erling Smørgrav                         if(result->net <= m)
227*b7579f77SDag-Erling Smørgrav                                 break;
228*b7579f77SDag-Erling Smørgrav                         result = result->parent;
229*b7579f77SDag-Erling Smørgrav                 }
230*b7579f77SDag-Erling Smørgrav         }
231*b7579f77SDag-Erling Smørgrav         return result;
232*b7579f77SDag-Erling Smørgrav }
233*b7579f77SDag-Erling Smørgrav 
234*b7579f77SDag-Erling Smørgrav int
235*b7579f77SDag-Erling Smørgrav name_tree_next_root(rbtree_t* tree, uint16_t* dclass)
236*b7579f77SDag-Erling Smørgrav {
237*b7579f77SDag-Erling Smørgrav 	struct name_tree_node key;
238*b7579f77SDag-Erling Smørgrav 	rbnode_t* n;
239*b7579f77SDag-Erling Smørgrav 	struct name_tree_node* p;
240*b7579f77SDag-Erling Smørgrav 	if(*dclass == 0) {
241*b7579f77SDag-Erling Smørgrav 		/* first root item is first item in tree */
242*b7579f77SDag-Erling Smørgrav 		n = rbtree_first(tree);
243*b7579f77SDag-Erling Smørgrav 		if(n == RBTREE_NULL)
244*b7579f77SDag-Erling Smørgrav 			return 0;
245*b7579f77SDag-Erling Smørgrav 		p = (struct name_tree_node*)n;
246*b7579f77SDag-Erling Smørgrav 		if(dname_is_root(p->name)) {
247*b7579f77SDag-Erling Smørgrav 			*dclass = p->dclass;
248*b7579f77SDag-Erling Smørgrav 			return 1;
249*b7579f77SDag-Erling Smørgrav 		}
250*b7579f77SDag-Erling Smørgrav 		/* root not first item? search for higher items */
251*b7579f77SDag-Erling Smørgrav 		*dclass = p->dclass + 1;
252*b7579f77SDag-Erling Smørgrav 		return name_tree_next_root(tree, dclass);
253*b7579f77SDag-Erling Smørgrav 	}
254*b7579f77SDag-Erling Smørgrav 	/* find class n in tree, we may get a direct hit, or if we don't
255*b7579f77SDag-Erling Smørgrav 	 * this is the last item of the previous class so rbtree_next() takes
256*b7579f77SDag-Erling Smørgrav 	 * us to the next root (if any) */
257*b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
258*b7579f77SDag-Erling Smørgrav 	key.name = (uint8_t*)"\000";
259*b7579f77SDag-Erling Smørgrav 	key.len = 1;
260*b7579f77SDag-Erling Smørgrav 	key.labs = 0;
261*b7579f77SDag-Erling Smørgrav 	key.dclass = *dclass;
262*b7579f77SDag-Erling Smørgrav 	n = NULL;
263*b7579f77SDag-Erling Smørgrav 	if(rbtree_find_less_equal(tree, &key, &n)) {
264*b7579f77SDag-Erling Smørgrav 		/* exact */
265*b7579f77SDag-Erling Smørgrav 		return 1;
266*b7579f77SDag-Erling Smørgrav 	} else {
267*b7579f77SDag-Erling Smørgrav 		/* smaller element */
268*b7579f77SDag-Erling Smørgrav 		if(!n || n == RBTREE_NULL)
269*b7579f77SDag-Erling Smørgrav 			return 0; /* nothing found */
270*b7579f77SDag-Erling Smørgrav 		n = rbtree_next(n);
271*b7579f77SDag-Erling Smørgrav 		if(n == RBTREE_NULL)
272*b7579f77SDag-Erling Smørgrav 			return 0; /* no higher */
273*b7579f77SDag-Erling Smørgrav 		p = (struct name_tree_node*)n;
274*b7579f77SDag-Erling Smørgrav 		if(dname_is_root(p->name)) {
275*b7579f77SDag-Erling Smørgrav 			*dclass = p->dclass;
276*b7579f77SDag-Erling Smørgrav 			return 1;
277*b7579f77SDag-Erling Smørgrav 		}
278*b7579f77SDag-Erling Smørgrav 		/* not a root node, return next higher item */
279*b7579f77SDag-Erling Smørgrav 		*dclass = p->dclass+1;
280*b7579f77SDag-Erling Smørgrav 		return name_tree_next_root(tree, dclass);
281*b7579f77SDag-Erling Smørgrav 	}
282*b7579f77SDag-Erling Smørgrav }
283