2 * iterator/iter_hints.c - iterative resolver module stub and root hints.
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 stub and root hints, and read those from config.
43 #include "iterator/iter_hints.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"
51 #include "ldns/wire2str.h"
56 struct iter_hints
* hints
= (struct iter_hints
*)calloc(1,
57 sizeof(struct iter_hints
));
63 static void hints_stub_free(struct iter_hints_stub
* s
)
66 delegpt_free_mlc(s
->dp
);
70 static void delhintnode(rbnode_t
* n
, void* ATTR_UNUSED(arg
))
72 struct iter_hints_stub
* node
= (struct iter_hints_stub
*)n
;
73 hints_stub_free(node
);
76 static void hints_del_tree(struct iter_hints
* hints
)
78 traverse_postorder(&hints
->tree
, &delhintnode
, NULL
);
82 hints_delete(struct iter_hints
* hints
)
86 hints_del_tree(hints
);
90 /** add hint to delegation hints */
92 ah(struct delegpt
* dp
, const char* sv
, const char* ip
)
94 struct sockaddr_storage addr
;
97 uint8_t* dname
= sldns_str2wire_dname(sv
, &dname_len
);
99 log_err("could not parse %s", sv
);
102 if(!delegpt_add_ns_mlc(dp
, dname
, 0) ||
103 !extstrtoaddr(ip
, &addr
, &addrlen
) ||
104 !delegpt_add_target_mlc(dp
, dname
, dname_len
,
105 &addr
, addrlen
, 0, 0)) {
113 /** obtain compiletime provided root hints */
114 static struct delegpt
*
115 compile_time_root_prime(int do_ip4
, int do_ip6
)
118 ; This file is made available by InterNIC
119 ; under anonymous FTP as
120 ; file /domain/named.cache
121 ; on server FTP.INTERNIC.NET
122 ; -OR- RS.INTERNIC.NET
124 ; related version of root zone: changes-on-20120103
126 struct delegpt
* dp
= delegpt_create_mlc((uint8_t*)"\000");
129 dp
->has_parent_side_NS
= 1;
131 if(!ah(dp
, "A.ROOT-SERVERS.NET.", "198.41.0.4")) goto failed
;
132 if(!ah(dp
, "B.ROOT-SERVERS.NET.", "192.228.79.201")) goto failed
;
133 if(!ah(dp
, "C.ROOT-SERVERS.NET.", "192.33.4.12")) goto failed
;
134 if(!ah(dp
, "D.ROOT-SERVERS.NET.", "199.7.91.13")) goto failed
;
135 if(!ah(dp
, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed
;
136 if(!ah(dp
, "F.ROOT-SERVERS.NET.", "192.5.5.241")) goto failed
;
137 if(!ah(dp
, "G.ROOT-SERVERS.NET.", "192.112.36.4")) goto failed
;
138 if(!ah(dp
, "H.ROOT-SERVERS.NET.", "128.63.2.53")) goto failed
;
139 if(!ah(dp
, "I.ROOT-SERVERS.NET.", "192.36.148.17")) goto failed
;
140 if(!ah(dp
, "J.ROOT-SERVERS.NET.", "192.58.128.30")) goto failed
;
141 if(!ah(dp
, "K.ROOT-SERVERS.NET.", "193.0.14.129")) goto failed
;
142 if(!ah(dp
, "L.ROOT-SERVERS.NET.", "199.7.83.42")) goto failed
;
143 if(!ah(dp
, "M.ROOT-SERVERS.NET.", "202.12.27.33")) goto failed
;
146 if(!ah(dp
, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) goto failed
;
147 if(!ah(dp
, "B.ROOT-SERVERS.NET.", "2001:500:84::b")) goto failed
;
148 if(!ah(dp
, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed
;
149 if(!ah(dp
, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed
;
150 if(!ah(dp
, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed
;
151 if(!ah(dp
, "H.ROOT-SERVERS.NET.", "2001:500:1::803f:235")) goto failed
;
152 if(!ah(dp
, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed
;
153 if(!ah(dp
, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed
;
154 if(!ah(dp
, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) goto failed
;
155 if(!ah(dp
, "L.ROOT-SERVERS.NET.", "2001:500:3::42")) goto failed
;
156 if(!ah(dp
, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) goto failed
;
160 delegpt_free_mlc(dp
);
164 /** insert new hint info into hint structure */
166 hints_insert(struct iter_hints
* hints
, uint16_t c
, struct delegpt
* dp
,
169 struct iter_hints_stub
* node
= (struct iter_hints_stub
*)malloc(
170 sizeof(struct iter_hints_stub
));
172 delegpt_free_mlc(dp
);
176 node
->noprime
= (uint8_t)noprime
;
177 if(!name_tree_insert(&hints
->tree
, &node
->node
, dp
->name
, dp
->namelen
,
180 dname_str(dp
->name
, buf
);
181 log_err("second hints for zone %s ignored.", buf
);
182 delegpt_free_mlc(dp
);
189 static struct delegpt
*
190 read_stubs_name(struct config_stub
* s
)
196 log_err("stub zone without a name");
199 dname
= sldns_str2wire_dname(s
->name
, &dname_len
);
201 log_err("cannot parse stub zone name %s", s
->name
);
204 if(!(dp
=delegpt_create_mlc(dname
))) {
206 log_err("out of memory");
213 /** set stub host names */
215 read_stubs_host(struct config_stub
* s
, struct delegpt
* dp
)
217 struct config_strlist
* p
;
220 for(p
= s
->hosts
; p
; p
= p
->next
) {
222 dname
= sldns_str2wire_dname(p
->str
, &dname_len
);
224 log_err("cannot parse stub %s nameserver name: '%s'",
228 if(!delegpt_add_ns_mlc(dp
, dname
, 0)) {
230 log_err("out of memory");
238 /** set stub server addresses */
240 read_stubs_addr(struct config_stub
* s
, struct delegpt
* dp
)
242 struct config_strlist
* p
;
243 struct sockaddr_storage addr
;
245 for(p
= s
->addrs
; p
; p
= p
->next
) {
247 if(!extstrtoaddr(p
->str
, &addr
, &addrlen
)) {
248 log_err("cannot parse stub %s ip address: '%s'",
252 if(!delegpt_add_addr_mlc(dp
, &addr
, addrlen
, 0, 0)) {
253 log_err("out of memory");
260 /** read stubs config */
262 read_stubs(struct iter_hints
* hints
, struct config_file
* cfg
)
264 struct config_stub
* s
;
266 for(s
= cfg
->stubs
; s
; s
= s
->next
) {
267 if(!(dp
=read_stubs_name(s
)))
269 if(!read_stubs_host(s
, dp
) || !read_stubs_addr(s
, dp
)) {
270 delegpt_free_mlc(dp
);
273 /* the flag is turned off for 'stub-first' so that the
274 * last resort will ask for parent-side NS record and thus
275 * fallback to the internet name servers on a failure */
276 dp
->has_parent_side_NS
= (uint8_t)!s
->isfirst
;
277 delegpt_log(VERB_QUERY
, dp
);
278 if(!hints_insert(hints
, LDNS_RR_CLASS_IN
, dp
, !s
->isprime
))
284 /** read root hints from file */
286 read_root_hints(struct iter_hints
* hints
, char* fname
)
288 struct sldns_file_parse_state pstate
;
290 uint8_t rr
[LDNS_RR_BUF_SIZE
];
291 size_t rr_len
, dname_len
;
293 uint16_t c
= LDNS_RR_CLASS_IN
;
294 FILE* f
= fopen(fname
, "r");
296 log_err("could not read root hints %s: %s",
297 fname
, strerror(errno
));
300 dp
= delegpt_create_mlc(NULL
);
302 log_err("out of memory reading root hints");
306 verbose(VERB_QUERY
, "Reading root hints from %s", fname
);
307 memset(&pstate
, 0, sizeof(pstate
));
309 dp
->has_parent_side_NS
= 1;
313 status
= sldns_fp2wire_rr_buf(f
, rr
, &rr_len
, &dname_len
,
316 log_err("reading root hints %s %d:%d: %s", fname
,
317 pstate
.lineno
, LDNS_WIREPARSE_OFFSET(status
),
318 sldns_get_errorstr_parse(status
));
322 continue; /* EMPTY line, TTL or ORIGIN */
323 if(sldns_wirerr_get_type(rr
, rr_len
, dname_len
)
324 == LDNS_RR_TYPE_NS
) {
325 if(!delegpt_add_ns_mlc(dp
, sldns_wirerr_get_rdata(rr
,
326 rr_len
, dname_len
), 0)) {
327 log_err("out of memory reading root hints");
330 c
= sldns_wirerr_get_class(rr
, rr_len
, dname_len
);
332 if(!delegpt_set_name_mlc(dp
, rr
)) {
333 log_err("out of memory.");
337 } else if(sldns_wirerr_get_type(rr
, rr_len
, dname_len
)
338 == LDNS_RR_TYPE_A
&& sldns_wirerr_get_rdatalen(rr
,
339 rr_len
, dname_len
) == INET_SIZE
) {
340 struct sockaddr_in sa
;
341 socklen_t len
= (socklen_t
)sizeof(sa
);
343 sa
.sin_family
= AF_INET
;
344 sa
.sin_port
= (in_port_t
)htons(UNBOUND_DNS_PORT
);
345 memmove(&sa
.sin_addr
,
346 sldns_wirerr_get_rdata(rr
, rr_len
, dname_len
),
348 if(!delegpt_add_target_mlc(dp
, rr
, dname_len
,
349 (struct sockaddr_storage
*)&sa
, len
,
351 log_err("out of memory reading root hints");
354 } else if(sldns_wirerr_get_type(rr
, rr_len
, dname_len
)
355 == LDNS_RR_TYPE_AAAA
&& sldns_wirerr_get_rdatalen(rr
,
356 rr_len
, dname_len
) == INET6_SIZE
) {
357 struct sockaddr_in6 sa
;
358 socklen_t len
= (socklen_t
)sizeof(sa
);
360 sa
.sin6_family
= AF_INET6
;
361 sa
.sin6_port
= (in_port_t
)htons(UNBOUND_DNS_PORT
);
362 memmove(&sa
.sin6_addr
,
363 sldns_wirerr_get_rdata(rr
, rr_len
, dname_len
),
365 if(!delegpt_add_target_mlc(dp
, rr
, dname_len
,
366 (struct sockaddr_storage
*)&sa
, len
,
368 log_err("out of memory reading root hints");
373 sldns_wire2str_type_buf(sldns_wirerr_get_type(rr
,
374 rr_len
, dname_len
), buf
, sizeof(buf
));
375 log_warn("root hints %s:%d skipping type %s",
376 fname
, pstate
.lineno
, buf
);
381 log_warn("root hints %s: no NS content", fname
);
382 delegpt_free_mlc(dp
);
385 if(!hints_insert(hints
, c
, dp
, 0)) {
388 delegpt_log(VERB_QUERY
, dp
);
392 delegpt_free_mlc(dp
);
397 /** read root hints list */
399 read_root_hints_list(struct iter_hints
* hints
, struct config_file
* cfg
)
401 struct config_strlist
* p
;
402 for(p
= cfg
->root_hints
; p
; p
= p
->next
) {
404 if(p
->str
&& p
->str
[0]) {
406 if(cfg
->chrootdir
&& cfg
->chrootdir
[0] &&
407 strncmp(p
->str
, cfg
->chrootdir
,
408 strlen(cfg
->chrootdir
)) == 0)
409 f
+= strlen(cfg
->chrootdir
);
410 if(!read_root_hints(hints
, f
))
418 hints_apply_cfg(struct iter_hints
* hints
, struct config_file
* cfg
)
420 hints_del_tree(hints
);
421 name_tree_init(&hints
->tree
);
423 /* read root hints */
424 if(!read_root_hints_list(hints
, cfg
))
427 /* read stub hints */
428 if(!read_stubs(hints
, cfg
))
431 /* use fallback compiletime root hints */
432 if(!hints_lookup_root(hints
, LDNS_RR_CLASS_IN
)) {
433 struct delegpt
* dp
= compile_time_root_prime(cfg
->do_ip4
,
435 verbose(VERB_ALGO
, "no config, using builtin root hints.");
438 if(!hints_insert(hints
, LDNS_RR_CLASS_IN
, dp
, 0))
442 name_tree_init_parents(&hints
->tree
);
447 hints_lookup_root(struct iter_hints
* hints
, uint16_t qclass
)
450 struct iter_hints_stub
*stub
;
451 stub
= (struct iter_hints_stub
*)name_tree_find(&hints
->tree
,
452 &rootlab
, 1, 1, qclass
);
458 struct iter_hints_stub
*
459 hints_lookup_stub(struct iter_hints
* hints
, uint8_t* qname
,
460 uint16_t qclass
, struct delegpt
* cache_dp
)
464 struct iter_hints_stub
*r
;
466 /* first lookup the stub */
467 labs
= dname_count_size_labels(qname
, &len
);
468 r
= (struct iter_hints_stub
*)name_tree_lookup(&hints
->tree
, qname
,
472 /* If there is no cache (root prime situation) */
473 if(cache_dp
== NULL
) {
474 if(r
->dp
->namelabs
!= 1)
475 return r
; /* no cache dp, use any non-root stub */
480 * If the stub is same as the delegation we got
481 * And has noprime set, we need to 'prime' to use this stub instead.
483 if(r
->noprime
&& query_dname_compare(cache_dp
->name
, r
->dp
->name
)==0)
484 return r
; /* use this stub instead of cached dp */
487 * If our cached delegation point is above the hint, we need to prime.
489 if(dname_strict_subdomain(r
->dp
->name
, r
->dp
->namelabs
,
490 cache_dp
->name
, cache_dp
->namelabs
))
491 return r
; /* need to prime this stub */
495 int hints_next_root(struct iter_hints
* hints
, uint16_t* qclass
)
497 return name_tree_next_root(&hints
->tree
, qclass
);
501 hints_get_mem(struct iter_hints
* hints
)
504 struct iter_hints_stub
* p
;
507 RBTREE_FOR(p
, struct iter_hints_stub
*, &hints
->tree
) {
508 s
+= sizeof(*p
) + delegpt_get_mem(p
->dp
);
514 hints_add_stub(struct iter_hints
* hints
, uint16_t c
, struct delegpt
* dp
,
517 struct iter_hints_stub
*z
;
518 if((z
=(struct iter_hints_stub
*)name_tree_find(&hints
->tree
,
519 dp
->name
, dp
->namelen
, dp
->namelabs
, c
)) != NULL
) {
520 (void)rbtree_delete(&hints
->tree
, &z
->node
);
523 if(!hints_insert(hints
, c
, dp
, noprime
))
525 name_tree_init_parents(&hints
->tree
);
530 hints_delete_stub(struct iter_hints
* hints
, uint16_t c
, uint8_t* nm
)
532 struct iter_hints_stub
*z
;
534 int labs
= dname_count_size_labels(nm
, &len
);
535 if(!(z
=(struct iter_hints_stub
*)name_tree_find(&hints
->tree
,
537 return; /* nothing to do */
538 (void)rbtree_delete(&hints
->tree
, &z
->node
);
540 name_tree_init_parents(&hints
->tree
);