1933707f3Ssthen /*
2933707f3Ssthen * iterator/iter_hints.c - iterative resolver module stub and root hints.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
240b68ff31Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
250b68ff31Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
260b68ff31Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
270b68ff31Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
280b68ff31Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
290b68ff31Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
300b68ff31Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
310b68ff31Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
320b68ff31Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
330b68ff31Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen */
35933707f3Ssthen
36933707f3Ssthen /**
37933707f3Ssthen * \file
38933707f3Ssthen *
39933707f3Ssthen * This file contains functions to assist the iterator module.
40933707f3Ssthen * Keep track of stub and root hints, and read those from config.
41933707f3Ssthen */
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "iterator/iter_hints.h"
44933707f3Ssthen #include "iterator/iter_delegpt.h"
45933707f3Ssthen #include "util/log.h"
46933707f3Ssthen #include "util/config_file.h"
47933707f3Ssthen #include "util/net_help.h"
48933707f3Ssthen #include "util/data/dname.h"
49a58bff56Ssthen #include "sldns/rrdef.h"
50a58bff56Ssthen #include "sldns/str2wire.h"
51a58bff56Ssthen #include "sldns/wire2str.h"
52933707f3Ssthen
53933707f3Ssthen struct iter_hints*
hints_create(void)54933707f3Ssthen hints_create(void)
55933707f3Ssthen {
56933707f3Ssthen struct iter_hints* hints = (struct iter_hints*)calloc(1,
57933707f3Ssthen sizeof(struct iter_hints));
58933707f3Ssthen if(!hints)
59933707f3Ssthen return NULL;
60*2bdc0ed1Ssthen lock_rw_init(&hints->lock);
61*2bdc0ed1Ssthen lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree));
62933707f3Ssthen return hints;
63933707f3Ssthen }
64933707f3Ssthen
hints_stub_free(struct iter_hints_stub * s)65d8d14d0cSsthen static void hints_stub_free(struct iter_hints_stub* s)
66d8d14d0cSsthen {
67d8d14d0cSsthen if(!s) return;
68d8d14d0cSsthen delegpt_free_mlc(s->dp);
69d8d14d0cSsthen free(s);
70d8d14d0cSsthen }
71d8d14d0cSsthen
delhintnode(rbnode_type * n,void * ATTR_UNUSED (arg))7277079be7Ssthen static void delhintnode(rbnode_type* n, void* ATTR_UNUSED(arg))
73d8d14d0cSsthen {
74d8d14d0cSsthen struct iter_hints_stub* node = (struct iter_hints_stub*)n;
75d8d14d0cSsthen hints_stub_free(node);
76d8d14d0cSsthen }
77d8d14d0cSsthen
hints_del_tree(struct iter_hints * hints)78d8d14d0cSsthen static void hints_del_tree(struct iter_hints* hints)
79d8d14d0cSsthen {
80d8d14d0cSsthen traverse_postorder(&hints->tree, &delhintnode, NULL);
81d8d14d0cSsthen }
82d8d14d0cSsthen
83933707f3Ssthen void
hints_delete(struct iter_hints * hints)84933707f3Ssthen hints_delete(struct iter_hints* hints)
85933707f3Ssthen {
86933707f3Ssthen if(!hints)
87933707f3Ssthen return;
88*2bdc0ed1Ssthen lock_rw_destroy(&hints->lock);
89d8d14d0cSsthen hints_del_tree(hints);
90933707f3Ssthen free(hints);
91933707f3Ssthen }
92933707f3Ssthen
93933707f3Ssthen /** add hint to delegation hints */
94933707f3Ssthen static int
ah(struct delegpt * dp,const char * sv,const char * ip)95d8d14d0cSsthen ah(struct delegpt* dp, const char* sv, const char* ip)
96933707f3Ssthen {
97933707f3Ssthen struct sockaddr_storage addr;
98933707f3Ssthen socklen_t addrlen;
990b68ff31Ssthen size_t dname_len;
1000b68ff31Ssthen uint8_t* dname = sldns_str2wire_dname(sv, &dname_len);
1010b68ff31Ssthen if(!dname) {
102933707f3Ssthen log_err("could not parse %s", sv);
103933707f3Ssthen return 0;
104933707f3Ssthen }
105e21c60efSsthen if(!delegpt_add_ns_mlc(dp, dname, 0, NULL, UNBOUND_DNS_PORT) ||
10645872187Ssthen !extstrtoaddr(ip, &addr, &addrlen, UNBOUND_DNS_PORT) ||
1070b68ff31Ssthen !delegpt_add_target_mlc(dp, dname, dname_len,
108933707f3Ssthen &addr, addrlen, 0, 0)) {
1090b68ff31Ssthen free(dname);
110933707f3Ssthen return 0;
111933707f3Ssthen }
1120b68ff31Ssthen free(dname);
113933707f3Ssthen return 1;
114933707f3Ssthen }
115933707f3Ssthen
116933707f3Ssthen /** obtain compiletime provided root hints */
117933707f3Ssthen static struct delegpt*
compile_time_root_prime(int do_ip4,int do_ip6)118d8d14d0cSsthen compile_time_root_prime(int do_ip4, int do_ip6)
119933707f3Ssthen {
120933707f3Ssthen /* from:
121933707f3Ssthen ; This file is made available by InterNIC
122933707f3Ssthen ; under anonymous FTP as
123933707f3Ssthen ; file /domain/named.cache
124933707f3Ssthen ; on server FTP.INTERNIC.NET
125933707f3Ssthen ; -OR- RS.INTERNIC.NET
126933707f3Ssthen ;
127e9c7b4efSsthen ; related version of root zone: changes-on-20120103
128933707f3Ssthen */
129d8d14d0cSsthen struct delegpt* dp = delegpt_create_mlc((uint8_t*)"\000");
130933707f3Ssthen if(!dp)
131933707f3Ssthen return NULL;
132933707f3Ssthen dp->has_parent_side_NS = 1;
133933707f3Ssthen if(do_ip4) {
1343dcb24b8Ssthen if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4")) goto failed;
135f46c52bfSsthen if(!ah(dp, "B.ROOT-SERVERS.NET.", "170.247.170.2")) goto failed;
1363dcb24b8Ssthen if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12")) goto failed;
13755cae749Sjakob if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13")) goto failed;
1383dcb24b8Ssthen if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed;
1393dcb24b8Ssthen if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241")) goto failed;
1403dcb24b8Ssthen if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4")) goto failed;
141a961b961Ssthen if(!ah(dp, "H.ROOT-SERVERS.NET.", "198.97.190.53")) goto failed;
1423dcb24b8Ssthen if(!ah(dp, "I.ROOT-SERVERS.NET.", "192.36.148.17")) goto failed;
1433dcb24b8Ssthen if(!ah(dp, "J.ROOT-SERVERS.NET.", "192.58.128.30")) goto failed;
1443dcb24b8Ssthen if(!ah(dp, "K.ROOT-SERVERS.NET.", "193.0.14.129")) goto failed;
1453dcb24b8Ssthen if(!ah(dp, "L.ROOT-SERVERS.NET.", "199.7.83.42")) goto failed;
1463dcb24b8Ssthen if(!ah(dp, "M.ROOT-SERVERS.NET.", "202.12.27.33")) goto failed;
147933707f3Ssthen }
148933707f3Ssthen if(do_ip6) {
1493dcb24b8Ssthen if(!ah(dp, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) goto failed;
150f46c52bfSsthen if(!ah(dp, "B.ROOT-SERVERS.NET.", "2801:1b8:10::b")) goto failed;
151e10d3884Sbrad if(!ah(dp, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed;
1523dcb24b8Ssthen if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed;
15377079be7Ssthen if(!ah(dp, "E.ROOT-SERVERS.NET.", "2001:500:a8::e")) goto failed;
1543dcb24b8Ssthen if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed;
15577079be7Ssthen if(!ah(dp, "G.ROOT-SERVERS.NET.", "2001:500:12::d0d")) goto failed;
156a961b961Ssthen if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::53")) goto failed;
1573dcb24b8Ssthen if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed;
1583dcb24b8Ssthen if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed;
1593dcb24b8Ssthen if(!ah(dp, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) goto failed;
1602ee382b6Ssthen if(!ah(dp, "L.ROOT-SERVERS.NET.", "2001:500:9f::42")) goto failed;
1613dcb24b8Ssthen if(!ah(dp, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) goto failed;
162933707f3Ssthen }
163933707f3Ssthen return dp;
1643dcb24b8Ssthen failed:
1653dcb24b8Ssthen delegpt_free_mlc(dp);
1663dcb24b8Ssthen return 0;
167933707f3Ssthen }
168933707f3Ssthen
169933707f3Ssthen /** insert new hint info into hint structure */
170933707f3Ssthen static int
hints_insert(struct iter_hints * hints,uint16_t c,struct delegpt * dp,int noprime)171933707f3Ssthen hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
172933707f3Ssthen int noprime)
173933707f3Ssthen {
174d8d14d0cSsthen struct iter_hints_stub* node = (struct iter_hints_stub*)malloc(
175933707f3Ssthen sizeof(struct iter_hints_stub));
176d8d14d0cSsthen if(!node) {
177d8d14d0cSsthen delegpt_free_mlc(dp);
178933707f3Ssthen return 0;
179d8d14d0cSsthen }
180933707f3Ssthen node->dp = dp;
181933707f3Ssthen node->noprime = (uint8_t)noprime;
182d8d14d0cSsthen if(!name_tree_insert(&hints->tree, &node->node, dp->name, dp->namelen,
183933707f3Ssthen dp->namelabs, c)) {
184e9c7b4efSsthen char buf[257];
185e9c7b4efSsthen dname_str(dp->name, buf);
186e9c7b4efSsthen log_err("second hints for zone %s ignored.", buf);
187d8d14d0cSsthen delegpt_free_mlc(dp);
188d8d14d0cSsthen free(node);
189933707f3Ssthen }
190933707f3Ssthen return 1;
191933707f3Ssthen }
192933707f3Ssthen
193933707f3Ssthen /** set stub name */
194d8d14d0cSsthen static struct delegpt*
read_stubs_name(struct config_stub * s)195d8d14d0cSsthen read_stubs_name(struct config_stub* s)
196933707f3Ssthen {
197d8d14d0cSsthen struct delegpt* dp;
1980b68ff31Ssthen size_t dname_len;
1990b68ff31Ssthen uint8_t* dname;
200933707f3Ssthen if(!s->name) {
201933707f3Ssthen log_err("stub zone without a name");
202d8d14d0cSsthen return NULL;
203933707f3Ssthen }
2040b68ff31Ssthen dname = sldns_str2wire_dname(s->name, &dname_len);
2050b68ff31Ssthen if(!dname) {
206933707f3Ssthen log_err("cannot parse stub zone name %s", s->name);
207d8d14d0cSsthen return NULL;
208933707f3Ssthen }
2090b68ff31Ssthen if(!(dp=delegpt_create_mlc(dname))) {
2100b68ff31Ssthen free(dname);
211933707f3Ssthen log_err("out of memory");
212d8d14d0cSsthen return NULL;
213933707f3Ssthen }
2140b68ff31Ssthen free(dname);
215d8d14d0cSsthen return dp;
216933707f3Ssthen }
217933707f3Ssthen
218933707f3Ssthen /** set stub host names */
219933707f3Ssthen static int
read_stubs_host(struct config_stub * s,struct delegpt * dp)220d8d14d0cSsthen read_stubs_host(struct config_stub* s, struct delegpt* dp)
221933707f3Ssthen {
222933707f3Ssthen struct config_strlist* p;
2230b68ff31Ssthen uint8_t* dname;
224e21c60efSsthen char* tls_auth_name;
225e21c60efSsthen int port;
226933707f3Ssthen for(p = s->hosts; p; p = p->next) {
227933707f3Ssthen log_assert(p->str);
228e21c60efSsthen dname = authextstrtodname(p->str, &port, &tls_auth_name);
2290b68ff31Ssthen if(!dname) {
230933707f3Ssthen log_err("cannot parse stub %s nameserver name: '%s'",
231933707f3Ssthen s->name, p->str);
232933707f3Ssthen return 0;
233933707f3Ssthen }
234e21c60efSsthen #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
235e21c60efSsthen if(tls_auth_name)
236e21c60efSsthen log_err("no name verification functionality in "
237e21c60efSsthen "ssl library, ignored name for %s", p->str);
238e21c60efSsthen #endif
239e21c60efSsthen if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) {
2400b68ff31Ssthen free(dname);
241933707f3Ssthen log_err("out of memory");
242933707f3Ssthen return 0;
243933707f3Ssthen }
2440b68ff31Ssthen free(dname);
245933707f3Ssthen }
246933707f3Ssthen return 1;
247933707f3Ssthen }
248933707f3Ssthen
249933707f3Ssthen /** set stub server addresses */
250933707f3Ssthen static int
read_stubs_addr(struct config_stub * s,struct delegpt * dp)251d8d14d0cSsthen read_stubs_addr(struct config_stub* s, struct delegpt* dp)
252933707f3Ssthen {
253933707f3Ssthen struct config_strlist* p;
254933707f3Ssthen struct sockaddr_storage addr;
255933707f3Ssthen socklen_t addrlen;
25620237c55Ssthen char* auth_name;
257933707f3Ssthen for(p = s->addrs; p; p = p->next) {
258933707f3Ssthen log_assert(p->str);
25920237c55Ssthen if(!authextstrtoaddr(p->str, &addr, &addrlen, &auth_name)) {
260933707f3Ssthen log_err("cannot parse stub %s ip address: '%s'",
261933707f3Ssthen s->name, p->str);
262933707f3Ssthen return 0;
263933707f3Ssthen }
264c3b38330Ssthen #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
2652308e98cSsthen if(auth_name)
2662308e98cSsthen log_err("no name verification functionality in "
2672308e98cSsthen "ssl library, ignored name for %s", p->str);
2682308e98cSsthen #endif
26920237c55Ssthen if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
270e21c60efSsthen auth_name, -1)) {
271933707f3Ssthen log_err("out of memory");
272933707f3Ssthen return 0;
273933707f3Ssthen }
274933707f3Ssthen }
275933707f3Ssthen return 1;
276933707f3Ssthen }
277933707f3Ssthen
278933707f3Ssthen /** read stubs config */
279933707f3Ssthen static int
read_stubs(struct iter_hints * hints,struct config_file * cfg)280933707f3Ssthen read_stubs(struct iter_hints* hints, struct config_file* cfg)
281933707f3Ssthen {
282933707f3Ssthen struct config_stub* s;
283d8d14d0cSsthen struct delegpt* dp;
284933707f3Ssthen for(s = cfg->stubs; s; s = s->next) {
2853dcb24b8Ssthen if(!(dp=read_stubs_name(s)))
286933707f3Ssthen return 0;
2873dcb24b8Ssthen if(!read_stubs_host(s, dp) || !read_stubs_addr(s, dp)) {
2883dcb24b8Ssthen delegpt_free_mlc(dp);
2893dcb24b8Ssthen return 0;
2903dcb24b8Ssthen }
291d8d14d0cSsthen /* the flag is turned off for 'stub-first' so that the
292d8d14d0cSsthen * last resort will ask for parent-side NS record and thus
293d8d14d0cSsthen * fallback to the internet name servers on a failure */
294d8d14d0cSsthen dp->has_parent_side_NS = (uint8_t)!s->isfirst;
2952308e98cSsthen /* Do not cache if set. */
2962308e98cSsthen dp->no_cache = s->no_cache;
29777079be7Ssthen /* ssl_upstream */
29877079be7Ssthen dp->ssl_upstream = (uint8_t)s->ssl_upstream;
299e21c60efSsthen /* tcp_upstream */
300e21c60efSsthen dp->tcp_upstream = (uint8_t)s->tcp_upstream;
3013dcb24b8Ssthen delegpt_log(VERB_QUERY, dp);
302933707f3Ssthen if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
303933707f3Ssthen return 0;
304933707f3Ssthen }
305933707f3Ssthen return 1;
306933707f3Ssthen }
307933707f3Ssthen
308933707f3Ssthen /** read root hints from file */
309933707f3Ssthen static int
read_root_hints(struct iter_hints * hints,char * fname)310933707f3Ssthen read_root_hints(struct iter_hints* hints, char* fname)
311933707f3Ssthen {
3120b68ff31Ssthen struct sldns_file_parse_state pstate;
313933707f3Ssthen struct delegpt* dp;
3140b68ff31Ssthen uint8_t rr[LDNS_RR_BUF_SIZE];
3150b68ff31Ssthen size_t rr_len, dname_len;
3160b68ff31Ssthen int status;
317933707f3Ssthen uint16_t c = LDNS_RR_CLASS_IN;
318933707f3Ssthen FILE* f = fopen(fname, "r");
319933707f3Ssthen if(!f) {
320933707f3Ssthen log_err("could not read root hints %s: %s",
321933707f3Ssthen fname, strerror(errno));
322933707f3Ssthen return 0;
323933707f3Ssthen }
324d8d14d0cSsthen dp = delegpt_create_mlc(NULL);
325933707f3Ssthen if(!dp) {
326933707f3Ssthen log_err("out of memory reading root hints");
327933707f3Ssthen fclose(f);
328933707f3Ssthen return 0;
329933707f3Ssthen }
330933707f3Ssthen verbose(VERB_QUERY, "Reading root hints from %s", fname);
3310b68ff31Ssthen memset(&pstate, 0, sizeof(pstate));
3320b68ff31Ssthen pstate.lineno = 1;
333933707f3Ssthen dp->has_parent_side_NS = 1;
334933707f3Ssthen while(!feof(f)) {
3350b68ff31Ssthen rr_len = sizeof(rr);
3360b68ff31Ssthen dname_len = 0;
3370b68ff31Ssthen status = sldns_fp2wire_rr_buf(f, rr, &rr_len, &dname_len,
3380b68ff31Ssthen &pstate);
3390b68ff31Ssthen if(status != 0) {
3400b68ff31Ssthen log_err("reading root hints %s %d:%d: %s", fname,
3410b68ff31Ssthen pstate.lineno, LDNS_WIREPARSE_OFFSET(status),
3420b68ff31Ssthen sldns_get_errorstr_parse(status));
343933707f3Ssthen goto stop_read;
344933707f3Ssthen }
3450b68ff31Ssthen if(rr_len == 0)
3460b68ff31Ssthen continue; /* EMPTY line, TTL or ORIGIN */
3470b68ff31Ssthen if(sldns_wirerr_get_type(rr, rr_len, dname_len)
3480b68ff31Ssthen == LDNS_RR_TYPE_NS) {
3490b68ff31Ssthen if(!delegpt_add_ns_mlc(dp, sldns_wirerr_get_rdata(rr,
350e21c60efSsthen rr_len, dname_len), 0, NULL, UNBOUND_DNS_PORT)) {
351933707f3Ssthen log_err("out of memory reading root hints");
352933707f3Ssthen goto stop_read;
353933707f3Ssthen }
3540b68ff31Ssthen c = sldns_wirerr_get_class(rr, rr_len, dname_len);
355933707f3Ssthen if(!dp->name) {
3560b68ff31Ssthen if(!delegpt_set_name_mlc(dp, rr)) {
357933707f3Ssthen log_err("out of memory.");
358933707f3Ssthen goto stop_read;
359933707f3Ssthen }
360933707f3Ssthen }
3610b68ff31Ssthen } else if(sldns_wirerr_get_type(rr, rr_len, dname_len)
3620b68ff31Ssthen == LDNS_RR_TYPE_A && sldns_wirerr_get_rdatalen(rr,
3630b68ff31Ssthen rr_len, dname_len) == INET_SIZE) {
364933707f3Ssthen struct sockaddr_in sa;
365933707f3Ssthen socklen_t len = (socklen_t)sizeof(sa);
366933707f3Ssthen memset(&sa, 0, len);
367933707f3Ssthen sa.sin_family = AF_INET;
368933707f3Ssthen sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
369933707f3Ssthen memmove(&sa.sin_addr,
3700b68ff31Ssthen sldns_wirerr_get_rdata(rr, rr_len, dname_len),
3710b68ff31Ssthen INET_SIZE);
3720b68ff31Ssthen if(!delegpt_add_target_mlc(dp, rr, dname_len,
373933707f3Ssthen (struct sockaddr_storage*)&sa, len,
374933707f3Ssthen 0, 0)) {
375933707f3Ssthen log_err("out of memory reading root hints");
376933707f3Ssthen goto stop_read;
377933707f3Ssthen }
3780b68ff31Ssthen } else if(sldns_wirerr_get_type(rr, rr_len, dname_len)
3790b68ff31Ssthen == LDNS_RR_TYPE_AAAA && sldns_wirerr_get_rdatalen(rr,
3800b68ff31Ssthen rr_len, dname_len) == INET6_SIZE) {
381933707f3Ssthen struct sockaddr_in6 sa;
382933707f3Ssthen socklen_t len = (socklen_t)sizeof(sa);
383933707f3Ssthen memset(&sa, 0, len);
384933707f3Ssthen sa.sin6_family = AF_INET6;
385933707f3Ssthen sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
386933707f3Ssthen memmove(&sa.sin6_addr,
3870b68ff31Ssthen sldns_wirerr_get_rdata(rr, rr_len, dname_len),
3880b68ff31Ssthen INET6_SIZE);
3890b68ff31Ssthen if(!delegpt_add_target_mlc(dp, rr, dname_len,
390933707f3Ssthen (struct sockaddr_storage*)&sa, len,
391933707f3Ssthen 0, 0)) {
392933707f3Ssthen log_err("out of memory reading root hints");
393933707f3Ssthen goto stop_read;
394933707f3Ssthen }
395933707f3Ssthen } else {
3960b68ff31Ssthen char buf[17];
3970b68ff31Ssthen sldns_wire2str_type_buf(sldns_wirerr_get_type(rr,
3980b68ff31Ssthen rr_len, dname_len), buf, sizeof(buf));
3990b68ff31Ssthen log_warn("root hints %s:%d skipping type %s",
4000b68ff31Ssthen fname, pstate.lineno, buf);
401933707f3Ssthen }
402933707f3Ssthen }
403933707f3Ssthen fclose(f);
404933707f3Ssthen if(!dp->name) {
405933707f3Ssthen log_warn("root hints %s: no NS content", fname);
406d8d14d0cSsthen delegpt_free_mlc(dp);
407933707f3Ssthen return 1;
408933707f3Ssthen }
409e21c60efSsthen delegpt_log(VERB_QUERY, dp);
410933707f3Ssthen if(!hints_insert(hints, c, dp, 0)) {
411933707f3Ssthen return 0;
412933707f3Ssthen }
413933707f3Ssthen return 1;
414933707f3Ssthen
415933707f3Ssthen stop_read:
416d8d14d0cSsthen delegpt_free_mlc(dp);
417933707f3Ssthen fclose(f);
418933707f3Ssthen return 0;
419933707f3Ssthen }
420933707f3Ssthen
421933707f3Ssthen /** read root hints list */
422933707f3Ssthen static int
read_root_hints_list(struct iter_hints * hints,struct config_file * cfg)423933707f3Ssthen read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
424933707f3Ssthen {
425933707f3Ssthen struct config_strlist* p;
426933707f3Ssthen for(p = cfg->root_hints; p; p = p->next) {
427933707f3Ssthen log_assert(p->str);
428933707f3Ssthen if(p->str && p->str[0]) {
429933707f3Ssthen char* f = p->str;
430933707f3Ssthen if(cfg->chrootdir && cfg->chrootdir[0] &&
431933707f3Ssthen strncmp(p->str, cfg->chrootdir,
432933707f3Ssthen strlen(cfg->chrootdir)) == 0)
433933707f3Ssthen f += strlen(cfg->chrootdir);
434933707f3Ssthen if(!read_root_hints(hints, f))
435933707f3Ssthen return 0;
436933707f3Ssthen }
437933707f3Ssthen }
438933707f3Ssthen return 1;
439933707f3Ssthen }
440933707f3Ssthen
441933707f3Ssthen int
hints_apply_cfg(struct iter_hints * hints,struct config_file * cfg)442933707f3Ssthen hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
443933707f3Ssthen {
444*2bdc0ed1Ssthen int nolock = 1;
445*2bdc0ed1Ssthen lock_rw_wrlock(&hints->lock);
446d8d14d0cSsthen hints_del_tree(hints);
447933707f3Ssthen name_tree_init(&hints->tree);
448933707f3Ssthen
449933707f3Ssthen /* read root hints */
450*2bdc0ed1Ssthen if(!read_root_hints_list(hints, cfg)) {
451*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
452933707f3Ssthen return 0;
453933707f3Ssthen }
454933707f3Ssthen
455*2bdc0ed1Ssthen /* read stub hints */
456*2bdc0ed1Ssthen if(!read_stubs(hints, cfg)) {
457*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
458*2bdc0ed1Ssthen return 0;
459*2bdc0ed1Ssthen }
460*2bdc0ed1Ssthen
461*2bdc0ed1Ssthen /* use fallback compiletime root hints */
462*2bdc0ed1Ssthen if(!hints_find_root(hints, LDNS_RR_CLASS_IN, nolock)) {
463*2bdc0ed1Ssthen struct delegpt* dp = compile_time_root_prime(cfg->do_ip4,
464*2bdc0ed1Ssthen cfg->do_ip6);
465*2bdc0ed1Ssthen verbose(VERB_ALGO, "no config, using builtin root hints.");
466*2bdc0ed1Ssthen if(!dp) {
467*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
468*2bdc0ed1Ssthen return 0;
469*2bdc0ed1Ssthen }
470*2bdc0ed1Ssthen if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) {
471*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
472*2bdc0ed1Ssthen return 0;
473*2bdc0ed1Ssthen }
474*2bdc0ed1Ssthen }
475*2bdc0ed1Ssthen
476933707f3Ssthen name_tree_init_parents(&hints->tree);
477*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
478933707f3Ssthen return 1;
479933707f3Ssthen }
480933707f3Ssthen
481933707f3Ssthen struct delegpt*
hints_find(struct iter_hints * hints,uint8_t * qname,uint16_t qclass,int nolock)482*2bdc0ed1Ssthen hints_find(struct iter_hints* hints, uint8_t* qname, uint16_t qclass,
483*2bdc0ed1Ssthen int nolock)
484*2bdc0ed1Ssthen {
485*2bdc0ed1Ssthen struct iter_hints_stub *stub;
486*2bdc0ed1Ssthen size_t len;
487*2bdc0ed1Ssthen int has_dp;
488*2bdc0ed1Ssthen int labs = dname_count_size_labels(qname, &len);
489*2bdc0ed1Ssthen /* lock_() calls are macros that could be nothing, surround in {} */
490*2bdc0ed1Ssthen if(!nolock) { lock_rw_rdlock(&hints->lock); }
491*2bdc0ed1Ssthen stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
492*2bdc0ed1Ssthen qname, len, labs, qclass);
493*2bdc0ed1Ssthen has_dp = stub && stub->dp;
494*2bdc0ed1Ssthen if(!has_dp && !nolock) { lock_rw_unlock(&hints->lock); }
495*2bdc0ed1Ssthen return has_dp?stub->dp:NULL;
496*2bdc0ed1Ssthen }
497*2bdc0ed1Ssthen
498*2bdc0ed1Ssthen struct delegpt*
hints_find_root(struct iter_hints * hints,uint16_t qclass,int nolock)499*2bdc0ed1Ssthen hints_find_root(struct iter_hints* hints, uint16_t qclass, int nolock)
500933707f3Ssthen {
501933707f3Ssthen uint8_t rootlab = 0;
502*2bdc0ed1Ssthen return hints_find(hints, &rootlab, qclass, nolock);
503933707f3Ssthen }
504933707f3Ssthen
505933707f3Ssthen struct iter_hints_stub*
hints_lookup_stub(struct iter_hints * hints,uint8_t * qname,uint16_t qclass,struct delegpt * cache_dp,int nolock)506933707f3Ssthen hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
507*2bdc0ed1Ssthen uint16_t qclass, struct delegpt* cache_dp, int nolock)
508933707f3Ssthen {
509933707f3Ssthen size_t len;
510933707f3Ssthen int labs;
511933707f3Ssthen struct iter_hints_stub *r;
512933707f3Ssthen
513933707f3Ssthen /* first lookup the stub */
514933707f3Ssthen labs = dname_count_size_labels(qname, &len);
515*2bdc0ed1Ssthen /* lock_() calls are macros that could be nothing, surround in {} */
516*2bdc0ed1Ssthen if(!nolock) { lock_rw_rdlock(&hints->lock); }
517933707f3Ssthen r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
518933707f3Ssthen len, labs, qclass);
519*2bdc0ed1Ssthen if(!r) {
520*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
521*2bdc0ed1Ssthen return NULL;
522*2bdc0ed1Ssthen }
523933707f3Ssthen
524933707f3Ssthen /* If there is no cache (root prime situation) */
525933707f3Ssthen if(cache_dp == NULL) {
526933707f3Ssthen if(r->dp->namelabs != 1)
527933707f3Ssthen return r; /* no cache dp, use any non-root stub */
528*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
529933707f3Ssthen return NULL;
530933707f3Ssthen }
531933707f3Ssthen
532933707f3Ssthen /*
533933707f3Ssthen * If the stub is same as the delegation we got
534933707f3Ssthen * And has noprime set, we need to 'prime' to use this stub instead.
535933707f3Ssthen */
536933707f3Ssthen if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0)
537933707f3Ssthen return r; /* use this stub instead of cached dp */
538933707f3Ssthen
539933707f3Ssthen /*
540933707f3Ssthen * If our cached delegation point is above the hint, we need to prime.
541933707f3Ssthen */
542933707f3Ssthen if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
543933707f3Ssthen cache_dp->name, cache_dp->namelabs))
544933707f3Ssthen return r; /* need to prime this stub */
545*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
546933707f3Ssthen return NULL;
547933707f3Ssthen }
548933707f3Ssthen
hints_next_root(struct iter_hints * hints,uint16_t * qclass,int nolock)549*2bdc0ed1Ssthen int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock)
550933707f3Ssthen {
551*2bdc0ed1Ssthen int ret;
552*2bdc0ed1Ssthen /* lock_() calls are macros that could be nothing, surround in {} */
553*2bdc0ed1Ssthen if(!nolock) { lock_rw_rdlock(&hints->lock); }
554*2bdc0ed1Ssthen ret = name_tree_next_root(&hints->tree, qclass);
555*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
556*2bdc0ed1Ssthen return ret;
557933707f3Ssthen }
558933707f3Ssthen
559933707f3Ssthen size_t
hints_get_mem(struct iter_hints * hints)560933707f3Ssthen hints_get_mem(struct iter_hints* hints)
561933707f3Ssthen {
562d8d14d0cSsthen size_t s;
563d8d14d0cSsthen struct iter_hints_stub* p;
564933707f3Ssthen if(!hints) return 0;
565*2bdc0ed1Ssthen lock_rw_rdlock(&hints->lock);
566d8d14d0cSsthen s = sizeof(*hints);
567d8d14d0cSsthen RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
568d8d14d0cSsthen s += sizeof(*p) + delegpt_get_mem(p->dp);
569933707f3Ssthen }
570*2bdc0ed1Ssthen lock_rw_unlock(&hints->lock);
571d8d14d0cSsthen return s;
572d8d14d0cSsthen }
573d8d14d0cSsthen
574d8d14d0cSsthen int
hints_add_stub(struct iter_hints * hints,uint16_t c,struct delegpt * dp,int noprime,int nolock)575d8d14d0cSsthen hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
576*2bdc0ed1Ssthen int noprime, int nolock)
577d8d14d0cSsthen {
578d8d14d0cSsthen struct iter_hints_stub *z;
579*2bdc0ed1Ssthen /* lock_() calls are macros that could be nothing, surround in {} */
580*2bdc0ed1Ssthen if(!nolock) { lock_rw_wrlock(&hints->lock); }
581d8d14d0cSsthen if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
582d8d14d0cSsthen dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
583d8d14d0cSsthen (void)rbtree_delete(&hints->tree, &z->node);
584d8d14d0cSsthen hints_stub_free(z);
585d8d14d0cSsthen }
586*2bdc0ed1Ssthen if(!hints_insert(hints, c, dp, noprime)) {
587*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
588d8d14d0cSsthen return 0;
589*2bdc0ed1Ssthen }
590d8d14d0cSsthen name_tree_init_parents(&hints->tree);
591*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
592d8d14d0cSsthen return 1;
593d8d14d0cSsthen }
594d8d14d0cSsthen
595d8d14d0cSsthen void
hints_delete_stub(struct iter_hints * hints,uint16_t c,uint8_t * nm,int nolock)596*2bdc0ed1Ssthen hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm,
597*2bdc0ed1Ssthen int nolock)
598d8d14d0cSsthen {
599d8d14d0cSsthen struct iter_hints_stub *z;
600d8d14d0cSsthen size_t len;
601d8d14d0cSsthen int labs = dname_count_size_labels(nm, &len);
602*2bdc0ed1Ssthen /* lock_() calls are macros that could be nothing, surround in {} */
603*2bdc0ed1Ssthen if(!nolock) { lock_rw_wrlock(&hints->lock); }
604d8d14d0cSsthen if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
605*2bdc0ed1Ssthen nm, len, labs, c))) {
606*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
607d8d14d0cSsthen return; /* nothing to do */
608*2bdc0ed1Ssthen }
609d8d14d0cSsthen (void)rbtree_delete(&hints->tree, &z->node);
610d8d14d0cSsthen hints_stub_free(z);
611d8d14d0cSsthen name_tree_init_parents(&hints->tree);
612*2bdc0ed1Ssthen if(!nolock) { lock_rw_unlock(&hints->lock); }
613d8d14d0cSsthen }
614