xref: /freebsd/contrib/unbound/iterator/iter_hints.c (revision 5ae59dec60e3815b621ae87f74a377cf3449ca55)
1 /*
2  * iterator/iter_hints.c - iterative resolver module stub and root hints.
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
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.
18  *
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.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This file contains functions to assist the iterator module.
40  * Keep track of stub and root hints, and read those from config.
41  */
42 #include "config.h"
43 #include <ldns/dname.h>
44 #include <ldns/rr.h>
45 #include "iterator/iter_hints.h"
46 #include "iterator/iter_delegpt.h"
47 #include "util/log.h"
48 #include "util/config_file.h"
49 #include "util/net_help.h"
50 #include "util/data/dname.h"
51 
52 struct iter_hints*
53 hints_create(void)
54 {
55 	struct iter_hints* hints = (struct iter_hints*)calloc(1,
56 		sizeof(struct iter_hints));
57 	if(!hints)
58 		return NULL;
59 	return hints;
60 }
61 
62 static void hints_stub_free(struct iter_hints_stub* s)
63 {
64 	if(!s) return;
65 	delegpt_free_mlc(s->dp);
66 	free(s);
67 }
68 
69 static void delhintnode(rbnode_t* n, void* ATTR_UNUSED(arg))
70 {
71 	struct iter_hints_stub* node = (struct iter_hints_stub*)n;
72 	hints_stub_free(node);
73 }
74 
75 static void hints_del_tree(struct iter_hints* hints)
76 {
77 	traverse_postorder(&hints->tree, &delhintnode, NULL);
78 }
79 
80 void
81 hints_delete(struct iter_hints* hints)
82 {
83 	if(!hints)
84 		return;
85 	hints_del_tree(hints);
86 	free(hints);
87 }
88 
89 /** add hint to delegation hints */
90 static int
91 ah(struct delegpt* dp, const char* sv, const char* ip)
92 {
93 	struct sockaddr_storage addr;
94 	socklen_t addrlen;
95 	ldns_rdf* rdf = ldns_dname_new_frm_str(sv);
96 	if(!rdf) {
97 		log_err("could not parse %s", sv);
98 		return 0;
99 	}
100 	if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(rdf), 0) ||
101 	   !extstrtoaddr(ip, &addr, &addrlen) ||
102 	   !delegpt_add_target_mlc(dp, ldns_rdf_data(rdf), ldns_rdf_size(rdf),
103 		&addr, addrlen, 0, 0)) {
104 		ldns_rdf_deep_free(rdf);
105 		return 0;
106 	}
107 	ldns_rdf_deep_free(rdf);
108 	return 1;
109 }
110 
111 /** obtain compiletime provided root hints */
112 static struct delegpt*
113 compile_time_root_prime(int do_ip4, int do_ip6)
114 {
115 	/* from:
116 	 ;       This file is made available by InterNIC
117 	 ;       under anonymous FTP as
118 	 ;           file                /domain/named.cache
119 	 ;           on server           FTP.INTERNIC.NET
120 	 ;       -OR-                    RS.INTERNIC.NET
121 	 ;
122 	 ;       related version of root zone:   changes-on-20120103
123 	 */
124 	struct delegpt* dp = delegpt_create_mlc((uint8_t*)"\000");
125 	if(!dp)
126 		return NULL;
127 	dp->has_parent_side_NS = 1;
128       if(do_ip4) {
129 	if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4"))	goto failed;
130 	if(!ah(dp, "B.ROOT-SERVERS.NET.", "192.228.79.201")) goto failed;
131 	if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12"))	goto failed;
132 	if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13"))	goto failed;
133 	if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed;
134 	if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241"))	goto failed;
135 	if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4"))	goto failed;
136 	if(!ah(dp, "H.ROOT-SERVERS.NET.", "128.63.2.53"))	goto failed;
137 	if(!ah(dp, "I.ROOT-SERVERS.NET.", "192.36.148.17"))	goto failed;
138 	if(!ah(dp, "J.ROOT-SERVERS.NET.", "192.58.128.30"))	goto failed;
139 	if(!ah(dp, "K.ROOT-SERVERS.NET.", "193.0.14.129"))	goto failed;
140 	if(!ah(dp, "L.ROOT-SERVERS.NET.", "199.7.83.42"))	goto failed;
141 	if(!ah(dp, "M.ROOT-SERVERS.NET.", "202.12.27.33"))	goto failed;
142       }
143       if(do_ip6) {
144 	if(!ah(dp, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) goto failed;
145 	if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed;
146 	if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed;
147 	if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::803f:235")) goto failed;
148 	if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed;
149 	if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed;
150 	if(!ah(dp, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) goto failed;
151 	if(!ah(dp, "L.ROOT-SERVERS.NET.", "2001:500:3::42")) goto failed;
152 	if(!ah(dp, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) goto failed;
153       }
154 	return dp;
155 failed:
156 	delegpt_free_mlc(dp);
157 	return 0;
158 }
159 
160 /** insert new hint info into hint structure */
161 static int
162 hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
163 	int noprime)
164 {
165 	struct iter_hints_stub* node = (struct iter_hints_stub*)malloc(
166 		sizeof(struct iter_hints_stub));
167 	if(!node) {
168 		delegpt_free_mlc(dp);
169 		return 0;
170 	}
171 	node->dp = dp;
172 	node->noprime = (uint8_t)noprime;
173 	if(!name_tree_insert(&hints->tree, &node->node, dp->name, dp->namelen,
174 		dp->namelabs, c)) {
175 		char buf[257];
176 		dname_str(dp->name, buf);
177 		log_err("second hints for zone %s ignored.", buf);
178 		delegpt_free_mlc(dp);
179 		free(node);
180 	}
181 	return 1;
182 }
183 
184 /** set stub name */
185 static struct delegpt*
186 read_stubs_name(struct config_stub* s)
187 {
188 	struct delegpt* dp;
189 	ldns_rdf* rdf;
190 	if(!s->name) {
191 		log_err("stub zone without a name");
192 		return NULL;
193 	}
194 	rdf = ldns_dname_new_frm_str(s->name);
195 	if(!rdf) {
196 		log_err("cannot parse stub zone name %s", s->name);
197 		return NULL;
198 	}
199 	if(!(dp=delegpt_create_mlc(ldns_rdf_data(rdf)))) {
200 		ldns_rdf_deep_free(rdf);
201 		log_err("out of memory");
202 		return NULL;
203 	}
204 	ldns_rdf_deep_free(rdf);
205 	return dp;
206 }
207 
208 /** set stub host names */
209 static int
210 read_stubs_host(struct config_stub* s, struct delegpt* dp)
211 {
212 	struct config_strlist* p;
213 	ldns_rdf* rdf;
214 	for(p = s->hosts; p; p = p->next) {
215 		log_assert(p->str);
216 		rdf = ldns_dname_new_frm_str(p->str);
217 		if(!rdf) {
218 			log_err("cannot parse stub %s nameserver name: '%s'",
219 				s->name, p->str);
220 			return 0;
221 		}
222 		if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(rdf), 0)) {
223 			ldns_rdf_deep_free(rdf);
224 			log_err("out of memory");
225 			return 0;
226 		}
227 		ldns_rdf_deep_free(rdf);
228 	}
229 	return 1;
230 }
231 
232 /** set stub server addresses */
233 static int
234 read_stubs_addr(struct config_stub* s, struct delegpt* dp)
235 {
236 	struct config_strlist* p;
237 	struct sockaddr_storage addr;
238 	socklen_t addrlen;
239 	for(p = s->addrs; p; p = p->next) {
240 		log_assert(p->str);
241 		if(!extstrtoaddr(p->str, &addr, &addrlen)) {
242 			log_err("cannot parse stub %s ip address: '%s'",
243 				s->name, p->str);
244 			return 0;
245 		}
246 		if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) {
247 			log_err("out of memory");
248 			return 0;
249 		}
250 	}
251 	return 1;
252 }
253 
254 /** read stubs config */
255 static int
256 read_stubs(struct iter_hints* hints, struct config_file* cfg)
257 {
258 	struct config_stub* s;
259 	struct delegpt* dp;
260 	for(s = cfg->stubs; s; s = s->next) {
261 		if(!(dp=read_stubs_name(s)))
262 			return 0;
263 		if(!read_stubs_host(s, dp) || !read_stubs_addr(s, dp)) {
264 			delegpt_free_mlc(dp);
265 			return 0;
266 		}
267 		/* the flag is turned off for 'stub-first' so that the
268 		 * last resort will ask for parent-side NS record and thus
269 		 * fallback to the internet name servers on a failure */
270 		dp->has_parent_side_NS = (uint8_t)!s->isfirst;
271 		delegpt_log(VERB_QUERY, dp);
272 		if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
273 			return 0;
274 	}
275 	return 1;
276 }
277 
278 /** read root hints from file */
279 static int
280 read_root_hints(struct iter_hints* hints, char* fname)
281 {
282 	int lineno = 0;
283 	uint32_t default_ttl = 0;
284 	ldns_rdf* origin = NULL;
285 	ldns_rdf* prev_rr = NULL;
286 	struct delegpt* dp;
287 	ldns_rr* rr = NULL;
288 	ldns_status status;
289 	uint16_t c = LDNS_RR_CLASS_IN;
290 	FILE* f = fopen(fname, "r");
291 	if(!f) {
292 		log_err("could not read root hints %s: %s",
293 			fname, strerror(errno));
294 		return 0;
295 	}
296 	dp = delegpt_create_mlc(NULL);
297 	if(!dp) {
298 		log_err("out of memory reading root hints");
299 		fclose(f);
300 		return 0;
301 	}
302 	verbose(VERB_QUERY, "Reading root hints from %s", fname);
303 	dp->has_parent_side_NS = 1;
304 	while(!feof(f)) {
305 		status = ldns_rr_new_frm_fp_l(&rr, f,
306 			&default_ttl, &origin, &prev_rr, &lineno);
307 		if(status == LDNS_STATUS_SYNTAX_EMPTY ||
308 			status == LDNS_STATUS_SYNTAX_TTL ||
309 			status == LDNS_STATUS_SYNTAX_ORIGIN)
310 			continue;
311 		if(status != LDNS_STATUS_OK) {
312 			log_err("reading root hints %s %d: %s", fname,
313 				lineno, ldns_get_errorstr_by_id(status));
314 			goto stop_read;
315 		}
316 		if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
317 			if(!delegpt_add_ns_mlc(dp,
318 				ldns_rdf_data(ldns_rr_rdf(rr, 0)), 0)) {
319 				log_err("out of memory reading root hints");
320 				goto stop_read;
321 			}
322 			c = ldns_rr_get_class(rr);
323 			if(!dp->name) {
324 				if(!delegpt_set_name_mlc(dp,
325 					ldns_rdf_data(ldns_rr_owner(rr)))){
326 					log_err("out of memory.");
327 					goto stop_read;
328 				}
329 			}
330 		} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A) {
331 			struct sockaddr_in sa;
332 			socklen_t len = (socklen_t)sizeof(sa);
333 			memset(&sa, 0, len);
334 			sa.sin_family = AF_INET;
335 			sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
336 			memmove(&sa.sin_addr,
337 				ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET_SIZE);
338 			if(!delegpt_add_target_mlc(dp,
339 					ldns_rdf_data(ldns_rr_owner(rr)),
340 					ldns_rdf_size(ldns_rr_owner(rr)),
341 					(struct sockaddr_storage*)&sa, len,
342 					0, 0)) {
343 				log_err("out of memory reading root hints");
344 				goto stop_read;
345 			}
346 		} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
347 			struct sockaddr_in6 sa;
348 			socklen_t len = (socklen_t)sizeof(sa);
349 			memset(&sa, 0, len);
350 			sa.sin6_family = AF_INET6;
351 			sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
352 			memmove(&sa.sin6_addr,
353 				ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET6_SIZE);
354 			if(!delegpt_add_target_mlc(dp,
355 					ldns_rdf_data(ldns_rr_owner(rr)),
356 					ldns_rdf_size(ldns_rr_owner(rr)),
357 					(struct sockaddr_storage*)&sa, len,
358 					0, 0)) {
359 				log_err("out of memory reading root hints");
360 				goto stop_read;
361 			}
362 		} else {
363 			log_warn("root hints %s:%d skipping type %d",
364 				fname, lineno, ldns_rr_get_type(rr));
365 		}
366 
367 		ldns_rr_free(rr);
368 	}
369 
370 	if (origin)
371 		ldns_rdf_deep_free(origin);
372 	if (prev_rr)
373 		ldns_rdf_deep_free(prev_rr);
374 	fclose(f);
375 	if(!dp->name) {
376 		log_warn("root hints %s: no NS content", fname);
377 		delegpt_free_mlc(dp);
378 		return 1;
379 	}
380 	if(!hints_insert(hints, c, dp, 0)) {
381 		return 0;
382 	}
383 	delegpt_log(VERB_QUERY, dp);
384 	return 1;
385 
386 stop_read:
387 	if (origin)
388 		ldns_rdf_deep_free(origin);
389 	if (prev_rr)
390 		ldns_rdf_deep_free(prev_rr);
391 	delegpt_free_mlc(dp);
392 	fclose(f);
393 	return 0;
394 }
395 
396 /** read root hints list */
397 static int
398 read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
399 {
400 	struct config_strlist* p;
401 	for(p = cfg->root_hints; p; p = p->next) {
402 		log_assert(p->str);
403 		if(p->str && p->str[0]) {
404 			char* f = p->str;
405 			if(cfg->chrootdir && cfg->chrootdir[0] &&
406 				strncmp(p->str, cfg->chrootdir,
407 				strlen(cfg->chrootdir)) == 0)
408 				f += strlen(cfg->chrootdir);
409 			if(!read_root_hints(hints, f))
410 				return 0;
411 		}
412 	}
413 	return 1;
414 }
415 
416 int
417 hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
418 {
419 	hints_del_tree(hints);
420 	name_tree_init(&hints->tree);
421 
422 	/* read root hints */
423 	if(!read_root_hints_list(hints, cfg))
424 		return 0;
425 
426 	/* read stub hints */
427 	if(!read_stubs(hints, cfg))
428 		return 0;
429 
430 	/* use fallback compiletime root hints */
431 	if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) {
432 		struct delegpt* dp = compile_time_root_prime(cfg->do_ip4,
433 			cfg->do_ip6);
434 		verbose(VERB_ALGO, "no config, using builtin root hints.");
435 		if(!dp)
436 			return 0;
437 		if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0))
438 			return 0;
439 	}
440 
441 	name_tree_init_parents(&hints->tree);
442 	return 1;
443 }
444 
445 struct delegpt*
446 hints_lookup_root(struct iter_hints* hints, uint16_t qclass)
447 {
448 	uint8_t rootlab = 0;
449 	struct iter_hints_stub *stub;
450 	stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
451 		&rootlab, 1, 1, qclass);
452 	if(!stub)
453 		return NULL;
454 	return stub->dp;
455 }
456 
457 struct iter_hints_stub*
458 hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
459 	uint16_t qclass, struct delegpt* cache_dp)
460 {
461 	size_t len;
462 	int labs;
463 	struct iter_hints_stub *r;
464 
465 	/* first lookup the stub */
466 	labs = dname_count_size_labels(qname, &len);
467 	r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
468 		len, labs, qclass);
469 	if(!r) return NULL;
470 
471 	/* If there is no cache (root prime situation) */
472 	if(cache_dp == NULL) {
473 		if(r->dp->namelabs != 1)
474 			return r; /* no cache dp, use any non-root stub */
475 		return NULL;
476 	}
477 
478 	/*
479 	 * If the stub is same as the delegation we got
480 	 * And has noprime set, we need to 'prime' to use this stub instead.
481 	 */
482 	if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0)
483 		return r; /* use this stub instead of cached dp */
484 
485 	/*
486 	 * If our cached delegation point is above the hint, we need to prime.
487 	 */
488 	if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
489 		cache_dp->name, cache_dp->namelabs))
490 		return r; /* need to prime this stub */
491 	return NULL;
492 }
493 
494 int hints_next_root(struct iter_hints* hints, uint16_t* qclass)
495 {
496 	return name_tree_next_root(&hints->tree, qclass);
497 }
498 
499 size_t
500 hints_get_mem(struct iter_hints* hints)
501 {
502 	size_t s;
503 	struct iter_hints_stub* p;
504 	if(!hints) return 0;
505 	s = sizeof(*hints);
506 	RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
507 		s += sizeof(*p) + delegpt_get_mem(p->dp);
508 	}
509 	return s;
510 }
511 
512 int
513 hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
514 	int noprime)
515 {
516 	struct iter_hints_stub *z;
517 	if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
518 		dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
519 		(void)rbtree_delete(&hints->tree, &z->node);
520 		hints_stub_free(z);
521 	}
522 	if(!hints_insert(hints, c, dp, noprime))
523 		return 0;
524 	name_tree_init_parents(&hints->tree);
525 	return 1;
526 }
527 
528 void
529 hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm)
530 {
531 	struct iter_hints_stub *z;
532 	size_t len;
533 	int labs = dname_count_size_labels(nm, &len);
534 	if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
535 		nm, len, labs, c)))
536 		return; /* nothing to do */
537 	(void)rbtree_delete(&hints->tree, &z->node);
538 	hints_stub_free(z);
539 	name_tree_init_parents(&hints->tree);
540 }
541 
542