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