]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/iterator/iter_fwd.c
2 * iterator/iter_fwd.c - iterative resolver module forward zones.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * This file contains functions to assist the iterator module.
40 * Keep track of forward zones and config settings.
43 #include "iterator/iter_fwd.h"
44 #include "iterator/iter_delegpt.h"
46 #include "util/config_file.h"
47 #include "util/net_help.h"
48 #include "util/data/dname.h"
49 #include "ldns/rrdef.h"
50 #include "ldns/str2wire.h"
53 fwd_cmp(const void* k1
, const void* k2
)
56 struct iter_forward_zone
* n1
= (struct iter_forward_zone
*)k1
;
57 struct iter_forward_zone
* n2
= (struct iter_forward_zone
*)k2
;
58 if(n1
->dclass
!= n2
->dclass
) {
59 if(n1
->dclass
< n2
->dclass
)
63 return dname_lab_cmp(n1
->name
, n1
->namelabs
, n2
->name
, n2
->namelabs
,
70 struct iter_forwards
* fwd
= (struct iter_forwards
*)calloc(1,
71 sizeof(struct iter_forwards
));
77 static void fwd_zone_free(struct iter_forward_zone
* n
)
80 delegpt_free_mlc(n
->dp
);
85 static void delfwdnode(rbnode_t
* n
, void* ATTR_UNUSED(arg
))
87 struct iter_forward_zone
* node
= (struct iter_forward_zone
*)n
;
91 static void fwd_del_tree(struct iter_forwards
* fwd
)
94 traverse_postorder(fwd
->tree
, &delfwdnode
, NULL
);
99 forwards_delete(struct iter_forwards
* fwd
)
107 /** insert info into forward structure */
109 forwards_insert_data(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
,
110 size_t nmlen
, int nmlabs
, struct delegpt
* dp
)
112 struct iter_forward_zone
* node
= (struct iter_forward_zone
*)malloc(
113 sizeof(struct iter_forward_zone
));
115 delegpt_free_mlc(dp
);
118 node
->node
.key
= node
;
120 node
->name
= memdup(nm
, nmlen
);
122 delegpt_free_mlc(dp
);
126 node
->namelen
= nmlen
;
127 node
->namelabs
= nmlabs
;
129 if(!rbtree_insert(fwd
->tree
, &node
->node
)) {
132 log_err("duplicate forward zone %s ignored.", buf
);
133 delegpt_free_mlc(dp
);
140 /** insert new info into forward structure given dp */
142 forwards_insert(struct iter_forwards
* fwd
, uint16_t c
, struct delegpt
* dp
)
144 return forwards_insert_data(fwd
, c
, dp
->name
, dp
->namelen
,
148 /** initialise parent pointers in the tree */
150 fwd_init_parents(struct iter_forwards
* fwd
)
152 struct iter_forward_zone
* node
, *prev
= NULL
, *p
;
154 RBTREE_FOR(node
, struct iter_forward_zone
*, fwd
->tree
) {
156 if(!prev
|| prev
->dclass
!= node
->dclass
) {
160 (void)dname_lab_cmp(prev
->name
, prev
->namelabs
, node
->name
,
161 node
->namelabs
, &m
); /* we know prev is smaller */
162 /* sort order like: . com. bla.com. zwb.com. net. */
163 /* find the previous, or parent-parent-parent */
164 for(p
= prev
; p
; p
= p
->parent
)
165 /* looking for name with few labels, a parent */
166 if(p
->namelabs
<= m
) {
167 /* ==: since prev matched m, this is closest*/
168 /* <: prev matches more, but is not a parent,
169 * this one is a (grand)parent */
178 static struct delegpt
*
179 read_fwds_name(struct config_stub
* s
)
185 log_err("forward zone without a name (use name \".\" to forward everything)");
188 dname
= sldns_str2wire_dname(s
->name
, &dname_len
);
190 log_err("cannot parse forward zone name %s", s
->name
);
193 if(!(dp
=delegpt_create_mlc(dname
))) {
195 log_err("out of memory");
202 /** set fwd host names */
204 read_fwds_host(struct config_stub
* s
, struct delegpt
* dp
)
206 struct config_strlist
* p
;
209 for(p
= s
->hosts
; p
; p
= p
->next
) {
211 dname
= sldns_str2wire_dname(p
->str
, &dname_len
);
213 log_err("cannot parse forward %s server name: '%s'",
217 if(!delegpt_add_ns_mlc(dp
, dname
, 0)) {
219 log_err("out of memory");
227 /** set fwd server addresses */
229 read_fwds_addr(struct config_stub
* s
, struct delegpt
* dp
)
231 struct config_strlist
* p
;
232 struct sockaddr_storage addr
;
234 for(p
= s
->addrs
; p
; p
= p
->next
) {
236 if(!extstrtoaddr(p
->str
, &addr
, &addrlen
)) {
237 log_err("cannot parse forward %s ip address: '%s'",
241 if(!delegpt_add_addr_mlc(dp
, &addr
, addrlen
, 0, 0)) {
242 log_err("out of memory");
249 /** read forwards config */
251 read_forwards(struct iter_forwards
* fwd
, struct config_file
* cfg
)
253 struct config_stub
* s
;
254 for(s
= cfg
->forwards
; s
; s
= s
->next
) {
256 if(!(dp
=read_fwds_name(s
)))
258 if(!read_fwds_host(s
, dp
) || !read_fwds_addr(s
, dp
)) {
259 delegpt_free_mlc(dp
);
262 /* set flag that parent side NS information is included.
263 * Asking a (higher up) server on the internet is not useful */
264 /* the flag is turned off for 'forward-first' so that the
265 * last resort will ask for parent-side NS record and thus
266 * fallback to the internet name servers on a failure */
267 dp
->has_parent_side_NS
= (uint8_t)!s
->isfirst
;
268 verbose(VERB_QUERY
, "Forward zone server list:");
269 delegpt_log(VERB_QUERY
, dp
);
270 if(!forwards_insert(fwd
, LDNS_RR_CLASS_IN
, dp
))
276 /** insert a stub hole (if necessary) for stub name */
278 fwd_add_stub_hole(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
)
280 struct iter_forward_zone key
;
284 key
.namelabs
= dname_count_size_labels(key
.name
, &key
.namelen
);
285 return forwards_insert_data(fwd
, key
.dclass
, key
.name
,
286 key
.namelen
, key
.namelabs
, NULL
);
289 /** make NULL entries for stubs */
291 make_stub_holes(struct iter_forwards
* fwd
, struct config_file
* cfg
)
293 struct config_stub
* s
;
296 for(s
= cfg
->stubs
; s
; s
= s
->next
) {
297 dname
= sldns_str2wire_dname(s
->name
, &dname_len
);
299 log_err("cannot parse stub name '%s'", s
->name
);
302 if(!fwd_add_stub_hole(fwd
, LDNS_RR_CLASS_IN
, dname
)) {
304 log_err("out of memory");
313 forwards_apply_cfg(struct iter_forwards
* fwd
, struct config_file
* cfg
)
316 fwd
->tree
= rbtree_create(fwd_cmp
);
320 /* read forward zones */
321 if(!read_forwards(fwd
, cfg
))
323 if(!make_stub_holes(fwd
, cfg
))
325 fwd_init_parents(fwd
);
330 forwards_find(struct iter_forwards
* fwd
, uint8_t* qname
, uint16_t qclass
)
332 rbnode_t
* res
= NULL
;
333 struct iter_forward_zone key
;
337 key
.namelabs
= dname_count_size_labels(qname
, &key
.namelen
);
338 res
= rbtree_search(fwd
->tree
, &key
);
339 if(res
) return ((struct iter_forward_zone
*)res
)->dp
;
344 forwards_lookup(struct iter_forwards
* fwd
, uint8_t* qname
, uint16_t qclass
)
346 /* lookup the forward zone in the tree */
347 rbnode_t
* res
= NULL
;
348 struct iter_forward_zone
*result
;
349 struct iter_forward_zone key
;
353 key
.namelabs
= dname_count_size_labels(qname
, &key
.namelen
);
354 if(rbtree_find_less_equal(fwd
->tree
, &key
, &res
)) {
356 result
= (struct iter_forward_zone
*)res
;
358 /* smaller element (or no element) */
360 result
= (struct iter_forward_zone
*)res
;
361 if(!result
|| result
->dclass
!= qclass
)
363 /* count number of labels matched */
364 (void)dname_lab_cmp(result
->name
, result
->namelabs
, key
.name
,
366 while(result
) { /* go up until qname is subdomain of stub */
367 if(result
->namelabs
<= m
)
369 result
= result
->parent
;
378 forwards_lookup_root(struct iter_forwards
* fwd
, uint16_t qclass
)
381 return forwards_lookup(fwd
, &root
, qclass
);
385 forwards_next_root(struct iter_forwards
* fwd
, uint16_t* dclass
)
387 struct iter_forward_zone key
;
389 struct iter_forward_zone
* p
;
391 /* first root item is first item in tree */
392 n
= rbtree_first(fwd
->tree
);
395 p
= (struct iter_forward_zone
*)n
;
396 if(dname_is_root(p
->name
)) {
400 /* root not first item? search for higher items */
401 *dclass
= p
->dclass
+ 1;
402 return forwards_next_root(fwd
, dclass
);
404 /* find class n in tree, we may get a direct hit, or if we don't
405 * this is the last item of the previous class so rbtree_next() takes
406 * us to the next root (if any) */
408 key
.name
= (uint8_t*)"\000";
411 key
.dclass
= *dclass
;
413 if(rbtree_find_less_equal(fwd
->tree
, &key
, &n
)) {
417 /* smaller element */
418 if(!n
|| n
== RBTREE_NULL
)
419 return 0; /* nothing found */
422 return 0; /* no higher */
423 p
= (struct iter_forward_zone
*)n
;
424 if(dname_is_root(p
->name
)) {
428 /* not a root node, return next higher item */
429 *dclass
= p
->dclass
+1;
430 return forwards_next_root(fwd
, dclass
);
435 forwards_get_mem(struct iter_forwards
* fwd
)
437 struct iter_forward_zone
* p
;
441 s
= sizeof(*fwd
) + sizeof(*fwd
->tree
);
442 RBTREE_FOR(p
, struct iter_forward_zone
*, fwd
->tree
) {
443 s
+= sizeof(*p
) + p
->namelen
+ delegpt_get_mem(p
->dp
);
448 static struct iter_forward_zone
*
449 fwd_zone_find(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
)
451 struct iter_forward_zone key
;
455 key
.namelabs
= dname_count_size_labels(nm
, &key
.namelen
);
456 return (struct iter_forward_zone
*)rbtree_search(fwd
->tree
, &key
);
460 forwards_add_zone(struct iter_forwards
* fwd
, uint16_t c
, struct delegpt
* dp
)
462 struct iter_forward_zone
*z
;
463 if((z
=fwd_zone_find(fwd
, c
, dp
->name
)) != NULL
) {
464 (void)rbtree_delete(fwd
->tree
, &z
->node
);
467 if(!forwards_insert(fwd
, c
, dp
))
469 fwd_init_parents(fwd
);
474 forwards_delete_zone(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
)
476 struct iter_forward_zone
*z
;
477 if(!(z
=fwd_zone_find(fwd
, c
, nm
)))
478 return; /* nothing to do */
479 (void)rbtree_delete(fwd
->tree
, &z
->node
);
481 fwd_init_parents(fwd
);
485 forwards_add_stub_hole(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
)
487 if(!fwd_add_stub_hole(fwd
, c
, nm
)) {
490 fwd_init_parents(fwd
);
495 forwards_delete_stub_hole(struct iter_forwards
* fwd
, uint16_t c
, uint8_t* nm
)
497 struct iter_forward_zone
*z
;
498 if(!(z
=fwd_zone_find(fwd
, c
, nm
)))
499 return; /* nothing to do */
501 return; /* not a stub hole */
502 (void)rbtree_delete(fwd
->tree
, &z
->node
);
504 fwd_init_parents(fwd
);