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/regional.h" 48 #include "util/log.h" 49 #include "util/config_file.h" 50 #include "util/net_help.h" 51 #include "util/data/dname.h" 52 53 struct iter_hints* 54 hints_create(void) 55 { 56 struct iter_hints* hints = (struct iter_hints*)calloc(1, 57 sizeof(struct iter_hints)); 58 if(!hints) 59 return NULL; 60 hints->region = regional_create(); 61 if(!hints->region) { 62 hints_delete(hints); 63 return NULL; 64 } 65 return hints; 66 } 67 68 void 69 hints_delete(struct iter_hints* hints) 70 { 71 if(!hints) 72 return; 73 regional_destroy(hints->region); 74 free(hints); 75 } 76 77 /** add hint to delegation hints */ 78 static int 79 ah(struct delegpt* dp, struct regional* r, const char* sv, const char* ip) 80 { 81 struct sockaddr_storage addr; 82 socklen_t addrlen; 83 ldns_rdf* rdf = ldns_dname_new_frm_str(sv); 84 if(!rdf) { 85 log_err("could not parse %s", sv); 86 return 0; 87 } 88 if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf), 0) || 89 !extstrtoaddr(ip, &addr, &addrlen) || 90 !delegpt_add_target(dp, r, ldns_rdf_data(rdf), ldns_rdf_size(rdf), 91 &addr, addrlen, 0, 0)) { 92 ldns_rdf_deep_free(rdf); 93 return 0; 94 } 95 ldns_rdf_deep_free(rdf); 96 return 1; 97 } 98 99 /** obtain compiletime provided root hints */ 100 static struct delegpt* 101 compile_time_root_prime(struct regional* r, int do_ip4, int do_ip6) 102 { 103 /* from: 104 ; This file is made available by InterNIC 105 ; under anonymous FTP as 106 ; file /domain/named.cache 107 ; on server FTP.INTERNIC.NET 108 ; -OR- RS.INTERNIC.NET 109 ; 110 ; related version of root zone: 2010061700 111 */ 112 struct delegpt* dp = delegpt_create(r); 113 if(!dp) 114 return NULL; 115 dp->has_parent_side_NS = 1; 116 if(!delegpt_set_name(dp, r, (uint8_t*)"\000")) 117 return NULL; 118 if(do_ip4) { 119 if(!ah(dp, r, "A.ROOT-SERVERS.NET.", "198.41.0.4")) return 0; 120 if(!ah(dp, r, "B.ROOT-SERVERS.NET.", "192.228.79.201")) return 0; 121 if(!ah(dp, r, "C.ROOT-SERVERS.NET.", "192.33.4.12")) return 0; 122 if(!ah(dp, r, "D.ROOT-SERVERS.NET.", "128.8.10.90")) return 0; 123 if(!ah(dp, r, "E.ROOT-SERVERS.NET.", "192.203.230.10")) return 0; 124 if(!ah(dp, r, "F.ROOT-SERVERS.NET.", "192.5.5.241")) return 0; 125 if(!ah(dp, r, "G.ROOT-SERVERS.NET.", "192.112.36.4")) return 0; 126 if(!ah(dp, r, "H.ROOT-SERVERS.NET.", "128.63.2.53")) return 0; 127 if(!ah(dp, r, "I.ROOT-SERVERS.NET.", "192.36.148.17")) return 0; 128 if(!ah(dp, r, "J.ROOT-SERVERS.NET.", "192.58.128.30")) return 0; 129 if(!ah(dp, r, "K.ROOT-SERVERS.NET.", "193.0.14.129")) return 0; 130 if(!ah(dp, r, "L.ROOT-SERVERS.NET.", "199.7.83.42")) return 0; 131 if(!ah(dp, r, "M.ROOT-SERVERS.NET.", "202.12.27.33")) return 0; 132 } 133 if(do_ip6) { 134 if(!ah(dp, r, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) return 0; 135 if(!ah(dp, r, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) return 0; 136 if(!ah(dp, r, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) return 0; 137 if(!ah(dp, r, "H.ROOT-SERVERS.NET.", "2001:500:1::803f:235")) return 0; 138 if(!ah(dp, r, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) return 0; 139 if(!ah(dp, r, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) return 0; 140 if(!ah(dp, r, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) return 0; 141 if(!ah(dp, r, "L.ROOT-SERVERS.NET.", "2001:500:3::42")) return 0; 142 if(!ah(dp, r, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) return 0; 143 } 144 return dp; 145 } 146 147 /** insert new hint info into hint structure */ 148 static int 149 hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp, 150 int noprime) 151 { 152 struct iter_hints_stub* node = regional_alloc(hints->region, 153 sizeof(struct iter_hints_stub)); 154 uint8_t* nm; 155 if(!node) 156 return 0; 157 nm = regional_alloc_init(hints->region, dp->name, dp->namelen); 158 if(!nm) 159 return 0; 160 node->dp = dp; 161 node->noprime = (uint8_t)noprime; 162 if(!name_tree_insert(&hints->tree, &node->node, nm, dp->namelen, 163 dp->namelabs, c)) { 164 log_err("second hints ignored."); 165 } 166 return 1; 167 } 168 169 /** set stub name */ 170 static int 171 read_stubs_name(struct iter_hints* hints, struct config_stub* s, 172 struct delegpt* dp) 173 { 174 ldns_rdf* rdf; 175 if(!s->name) { 176 log_err("stub zone without a name"); 177 return 0; 178 } 179 rdf = ldns_dname_new_frm_str(s->name); 180 if(!rdf) { 181 log_err("cannot parse stub zone name %s", s->name); 182 return 0; 183 } 184 if(!delegpt_set_name(dp, hints->region, ldns_rdf_data(rdf))) { 185 ldns_rdf_deep_free(rdf); 186 log_err("out of memory"); 187 return 0; 188 } 189 ldns_rdf_deep_free(rdf); 190 return 1; 191 } 192 193 /** set stub host names */ 194 static int 195 read_stubs_host(struct iter_hints* hints, struct config_stub* s, 196 struct delegpt* dp) 197 { 198 struct config_strlist* p; 199 ldns_rdf* rdf; 200 for(p = s->hosts; p; p = p->next) { 201 log_assert(p->str); 202 rdf = ldns_dname_new_frm_str(p->str); 203 if(!rdf) { 204 log_err("cannot parse stub %s nameserver name: '%s'", 205 s->name, p->str); 206 return 0; 207 } 208 if(!delegpt_add_ns(dp, hints->region, ldns_rdf_data(rdf), 0)) { 209 ldns_rdf_deep_free(rdf); 210 log_err("out of memory"); 211 return 0; 212 } 213 ldns_rdf_deep_free(rdf); 214 } 215 return 1; 216 } 217 218 /** set stub server addresses */ 219 static int 220 read_stubs_addr(struct iter_hints* hints, struct config_stub* s, 221 struct delegpt* dp) 222 { 223 struct config_strlist* p; 224 struct sockaddr_storage addr; 225 socklen_t addrlen; 226 for(p = s->addrs; p; p = p->next) { 227 log_assert(p->str); 228 if(!extstrtoaddr(p->str, &addr, &addrlen)) { 229 log_err("cannot parse stub %s ip address: '%s'", 230 s->name, p->str); 231 return 0; 232 } 233 if(!delegpt_add_addr(dp, hints->region, &addr, addrlen, 0, 0)) { 234 log_err("out of memory"); 235 return 0; 236 } 237 } 238 return 1; 239 } 240 241 /** read stubs config */ 242 static int 243 read_stubs(struct iter_hints* hints, struct config_file* cfg) 244 { 245 struct config_stub* s; 246 for(s = cfg->stubs; s; s = s->next) { 247 struct delegpt* dp = delegpt_create(hints->region); 248 if(!dp) { 249 log_err("out of memory"); 250 return 0; 251 } 252 dp->has_parent_side_NS = 1; 253 if(!read_stubs_name(hints, s, dp) || 254 !read_stubs_host(hints, s, dp) || 255 !read_stubs_addr(hints, s, dp)) 256 return 0; 257 if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime)) 258 return 0; 259 delegpt_log(VERB_QUERY, dp); 260 } 261 return 1; 262 } 263 264 /** read root hints from file */ 265 static int 266 read_root_hints(struct iter_hints* hints, char* fname) 267 { 268 int lineno = 0; 269 uint32_t default_ttl = 0; 270 ldns_rdf* origin = NULL; 271 ldns_rdf* prev_rr = NULL; 272 struct delegpt* dp; 273 ldns_rr* rr = NULL; 274 ldns_status status; 275 uint16_t c = LDNS_RR_CLASS_IN; 276 FILE* f = fopen(fname, "r"); 277 if(!f) { 278 log_err("could not read root hints %s: %s", 279 fname, strerror(errno)); 280 return 0; 281 } 282 dp = delegpt_create(hints->region); 283 if(!dp) { 284 log_err("out of memory reading root hints"); 285 fclose(f); 286 return 0; 287 } 288 verbose(VERB_QUERY, "Reading root hints from %s", fname); 289 dp->has_parent_side_NS = 1; 290 while(!feof(f)) { 291 status = ldns_rr_new_frm_fp_l(&rr, f, 292 &default_ttl, &origin, &prev_rr, &lineno); 293 if(status == LDNS_STATUS_SYNTAX_EMPTY || 294 status == LDNS_STATUS_SYNTAX_TTL || 295 status == LDNS_STATUS_SYNTAX_ORIGIN) 296 continue; 297 if(status != LDNS_STATUS_OK) { 298 log_err("reading root hints %s %d: %s", fname, 299 lineno, ldns_get_errorstr_by_id(status)); 300 goto stop_read; 301 } 302 if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) { 303 if(!delegpt_add_ns(dp, hints->region, 304 ldns_rdf_data(ldns_rr_rdf(rr, 0)), 0)) { 305 log_err("out of memory reading root hints"); 306 goto stop_read; 307 } 308 c = ldns_rr_get_class(rr); 309 if(!dp->name) { 310 if(!delegpt_set_name(dp, hints->region, 311 ldns_rdf_data(ldns_rr_owner(rr)))){ 312 log_err("out of memory."); 313 goto stop_read; 314 } 315 } 316 } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A) { 317 struct sockaddr_in sa; 318 socklen_t len = (socklen_t)sizeof(sa); 319 memset(&sa, 0, len); 320 sa.sin_family = AF_INET; 321 sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); 322 memmove(&sa.sin_addr, 323 ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET_SIZE); 324 if(!delegpt_add_target(dp, hints->region, 325 ldns_rdf_data(ldns_rr_owner(rr)), 326 ldns_rdf_size(ldns_rr_owner(rr)), 327 (struct sockaddr_storage*)&sa, len, 328 0, 0)) { 329 log_err("out of memory reading root hints"); 330 goto stop_read; 331 } 332 } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) { 333 struct sockaddr_in6 sa; 334 socklen_t len = (socklen_t)sizeof(sa); 335 memset(&sa, 0, len); 336 sa.sin6_family = AF_INET6; 337 sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); 338 memmove(&sa.sin6_addr, 339 ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET6_SIZE); 340 if(!delegpt_add_target(dp, hints->region, 341 ldns_rdf_data(ldns_rr_owner(rr)), 342 ldns_rdf_size(ldns_rr_owner(rr)), 343 (struct sockaddr_storage*)&sa, len, 344 0, 0)) { 345 log_err("out of memory reading root hints"); 346 goto stop_read; 347 } 348 } else { 349 log_warn("root hints %s:%d skipping type %d", 350 fname, lineno, ldns_rr_get_type(rr)); 351 } 352 353 ldns_rr_free(rr); 354 } 355 356 if (origin) 357 ldns_rdf_deep_free(origin); 358 if (prev_rr) 359 ldns_rdf_deep_free(prev_rr); 360 fclose(f); 361 if(!dp->name) { 362 log_warn("root hints %s: no NS content", fname); 363 return 1; 364 } 365 if(!hints_insert(hints, c, dp, 0)) { 366 return 0; 367 } 368 delegpt_log(VERB_QUERY, dp); 369 return 1; 370 371 stop_read: 372 if (origin) 373 ldns_rdf_deep_free(origin); 374 if (prev_rr) 375 ldns_rdf_deep_free(prev_rr); 376 fclose(f); 377 return 0; 378 } 379 380 /** read root hints list */ 381 static int 382 read_root_hints_list(struct iter_hints* hints, struct config_file* cfg) 383 { 384 struct config_strlist* p; 385 for(p = cfg->root_hints; p; p = p->next) { 386 log_assert(p->str); 387 if(p->str && p->str[0]) { 388 char* f = p->str; 389 if(cfg->chrootdir && cfg->chrootdir[0] && 390 strncmp(p->str, cfg->chrootdir, 391 strlen(cfg->chrootdir)) == 0) 392 f += strlen(cfg->chrootdir); 393 if(!read_root_hints(hints, f)) 394 return 0; 395 } 396 } 397 return 1; 398 } 399 400 int 401 hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg) 402 { 403 regional_free_all(hints->region); 404 name_tree_init(&hints->tree); 405 406 /* read root hints */ 407 if(!read_root_hints_list(hints, cfg)) 408 return 0; 409 410 /* read stub hints */ 411 if(!read_stubs(hints, cfg)) 412 return 0; 413 414 /* use fallback compiletime root hints */ 415 if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) { 416 struct delegpt* dp = compile_time_root_prime(hints->region, 417 cfg->do_ip4, cfg->do_ip6); 418 verbose(VERB_ALGO, "no config, using builtin root hints."); 419 if(!dp) 420 return 0; 421 if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) 422 return 0; 423 } 424 425 name_tree_init_parents(&hints->tree); 426 return 1; 427 } 428 429 struct delegpt* 430 hints_lookup_root(struct iter_hints* hints, uint16_t qclass) 431 { 432 uint8_t rootlab = 0; 433 struct iter_hints_stub *stub; 434 stub = (struct iter_hints_stub*)name_tree_find(&hints->tree, 435 &rootlab, 1, 1, qclass); 436 if(!stub) 437 return NULL; 438 return stub->dp; 439 } 440 441 struct iter_hints_stub* 442 hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, 443 uint16_t qclass, struct delegpt* cache_dp) 444 { 445 size_t len; 446 int labs; 447 struct iter_hints_stub *r; 448 449 /* first lookup the stub */ 450 labs = dname_count_size_labels(qname, &len); 451 r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname, 452 len, labs, qclass); 453 if(!r) return NULL; 454 455 /* If there is no cache (root prime situation) */ 456 if(cache_dp == NULL) { 457 if(r->dp->namelabs != 1) 458 return r; /* no cache dp, use any non-root stub */ 459 return NULL; 460 } 461 462 /* 463 * If the stub is same as the delegation we got 464 * And has noprime set, we need to 'prime' to use this stub instead. 465 */ 466 if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0) 467 return r; /* use this stub instead of cached dp */ 468 469 /* 470 * If our cached delegation point is above the hint, we need to prime. 471 */ 472 if(dname_strict_subdomain(r->dp->name, r->dp->namelabs, 473 cache_dp->name, cache_dp->namelabs)) 474 return r; /* need to prime this stub */ 475 return NULL; 476 } 477 478 int hints_next_root(struct iter_hints* hints, uint16_t* qclass) 479 { 480 return name_tree_next_root(&hints->tree, qclass); 481 } 482 483 size_t 484 hints_get_mem(struct iter_hints* hints) 485 { 486 if(!hints) return 0; 487 return sizeof(*hints) + regional_get_mem(hints->region); 488 } 489