1 /* 2 * iterator/iter_fwd.c - iterative resolver module forward zones. 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 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. 34 */ 35 36 /** 37 * \file 38 * 39 * This file contains functions to assist the iterator module. 40 * Keep track of forward zones and config settings. 41 */ 42 #include "config.h" 43 #include "iterator/iter_fwd.h" 44 #include "iterator/iter_delegpt.h" 45 #include "util/log.h" 46 #include "util/config_file.h" 47 #include "util/net_help.h" 48 #include "util/data/dname.h" 49 #include "sldns/rrdef.h" 50 #include "sldns/str2wire.h" 51 52 int 53 fwd_cmp(const void* k1, const void* k2) 54 { 55 int m; 56 struct iter_forward_zone* n1 = (struct iter_forward_zone*)k1; 57 struct iter_forward_zone* n2 = (struct iter_forward_zone*)k2; 58 if(n1->dclass != n2->dclass) { 59 if(n1->dclass < n2->dclass) 60 return -1; 61 return 1; 62 } 63 return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs, 64 &m); 65 } 66 67 struct iter_forwards* 68 forwards_create(void) 69 { 70 struct iter_forwards* fwd = (struct iter_forwards*)calloc(1, 71 sizeof(struct iter_forwards)); 72 if(!fwd) 73 return NULL; 74 lock_rw_init(&fwd->lock); 75 return fwd; 76 } 77 78 static void fwd_zone_free(struct iter_forward_zone* n) 79 { 80 if(!n) return; 81 delegpt_free_mlc(n->dp); 82 free(n->name); 83 free(n); 84 } 85 86 static void delfwdnode(rbnode_type* n, void* ATTR_UNUSED(arg)) 87 { 88 struct iter_forward_zone* node = (struct iter_forward_zone*)n; 89 fwd_zone_free(node); 90 } 91 92 static void fwd_del_tree(struct iter_forwards* fwd) 93 { 94 if(fwd->tree) 95 traverse_postorder(fwd->tree, &delfwdnode, NULL); 96 free(fwd->tree); 97 } 98 99 void 100 forwards_delete(struct iter_forwards* fwd) 101 { 102 if(!fwd) 103 return; 104 lock_rw_destroy(&fwd->lock); 105 fwd_del_tree(fwd); 106 free(fwd); 107 } 108 109 /** insert info into forward structure */ 110 static int 111 forwards_insert_data(struct iter_forwards* fwd, uint16_t c, uint8_t* nm, 112 size_t nmlen, int nmlabs, struct delegpt* dp) 113 { 114 struct iter_forward_zone* node = (struct iter_forward_zone*)malloc( 115 sizeof(struct iter_forward_zone)); 116 if(!node) { 117 delegpt_free_mlc(dp); 118 return 0; 119 } 120 node->node.key = node; 121 node->dclass = c; 122 node->name = memdup(nm, nmlen); 123 if(!node->name) { 124 delegpt_free_mlc(dp); 125 free(node); 126 return 0; 127 } 128 node->namelen = nmlen; 129 node->namelabs = nmlabs; 130 node->dp = dp; 131 if(!rbtree_insert(fwd->tree, &node->node)) { 132 char buf[LDNS_MAX_DOMAINLEN]; 133 dname_str(nm, buf); 134 log_err("duplicate forward zone %s ignored.", buf); 135 delegpt_free_mlc(dp); 136 free(node->name); 137 free(node); 138 } 139 return 1; 140 } 141 142 static struct iter_forward_zone* 143 fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) 144 { 145 struct iter_forward_zone key; 146 key.node.key = &key; 147 key.dclass = c; 148 key.name = nm; 149 key.namelabs = dname_count_size_labels(nm, &key.namelen); 150 return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key); 151 } 152 153 /** insert new info into forward structure given dp */ 154 static int 155 forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp) 156 { 157 return forwards_insert_data(fwd, c, dp->name, dp->namelen, 158 dp->namelabs, dp); 159 } 160 161 /** initialise parent pointers in the tree */ 162 static void 163 fwd_init_parents(struct iter_forwards* fwd) 164 { 165 struct iter_forward_zone* node, *prev = NULL, *p; 166 int m; 167 RBTREE_FOR(node, struct iter_forward_zone*, fwd->tree) { 168 node->parent = NULL; 169 if(!prev || prev->dclass != node->dclass) { 170 prev = node; 171 continue; 172 } 173 (void)dname_lab_cmp(prev->name, prev->namelabs, node->name, 174 node->namelabs, &m); /* we know prev is smaller */ 175 /* sort order like: . com. bla.com. zwb.com. net. */ 176 /* find the previous, or parent-parent-parent */ 177 for(p = prev; p; p = p->parent) 178 /* looking for name with few labels, a parent */ 179 if(p->namelabs <= m) { 180 /* ==: since prev matched m, this is closest*/ 181 /* <: prev matches more, but is not a parent, 182 * this one is a (grand)parent */ 183 node->parent = p; 184 break; 185 } 186 prev = node; 187 } 188 } 189 190 /** set zone name */ 191 static struct delegpt* 192 read_fwds_name(struct config_stub* s) 193 { 194 struct delegpt* dp; 195 uint8_t* dname; 196 size_t dname_len; 197 if(!s->name) { 198 log_err("forward zone without a name (use name \".\" to forward everything)"); 199 return NULL; 200 } 201 dname = sldns_str2wire_dname(s->name, &dname_len); 202 if(!dname) { 203 log_err("cannot parse forward zone name %s", s->name); 204 return NULL; 205 } 206 if(!(dp=delegpt_create_mlc(dname))) { 207 free(dname); 208 log_err("out of memory"); 209 return NULL; 210 } 211 free(dname); 212 return dp; 213 } 214 215 /** set fwd host names */ 216 static int 217 read_fwds_host(struct config_stub* s, struct delegpt* dp) 218 { 219 struct config_strlist* p; 220 uint8_t* dname; 221 char* tls_auth_name; 222 int port; 223 for(p = s->hosts; p; p = p->next) { 224 log_assert(p->str); 225 dname = authextstrtodname(p->str, &port, &tls_auth_name); 226 if(!dname) { 227 log_err("cannot parse forward %s server name: '%s'", 228 s->name, p->str); 229 return 0; 230 } 231 if(dname_subdomain_c(dname, dp->name)) { 232 log_warn("forward-host '%s' may have a circular " 233 "dependency on forward-zone '%s'", 234 p->str, s->name); 235 } 236 #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) 237 if(tls_auth_name) 238 log_err("no name verification functionality in " 239 "ssl library, ignored name for %s", p->str); 240 #endif 241 if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) { 242 free(dname); 243 log_err("out of memory"); 244 return 0; 245 } 246 free(dname); 247 } 248 return 1; 249 } 250 251 /** set fwd server addresses */ 252 static int 253 read_fwds_addr(struct config_stub* s, struct delegpt* dp) 254 { 255 struct config_strlist* p; 256 struct sockaddr_storage addr; 257 socklen_t addrlen; 258 char* tls_auth_name; 259 for(p = s->addrs; p; p = p->next) { 260 log_assert(p->str); 261 if(!authextstrtoaddr(p->str, &addr, &addrlen, &tls_auth_name)) { 262 log_err("cannot parse forward %s ip address: '%s'", 263 s->name, p->str); 264 return 0; 265 } 266 #if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) 267 if(tls_auth_name) 268 log_err("no name verification functionality in " 269 "ssl library, ignored name for %s", p->str); 270 #endif 271 if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0, 272 tls_auth_name, -1)) { 273 log_err("out of memory"); 274 return 0; 275 } 276 } 277 return 1; 278 } 279 280 /** read forwards config */ 281 static int 282 read_forwards(struct iter_forwards* fwd, struct config_file* cfg) 283 { 284 struct config_stub* s; 285 for(s = cfg->forwards; s; s = s->next) { 286 struct delegpt* dp; 287 if(!(dp=read_fwds_name(s))) 288 return 0; 289 if(!read_fwds_host(s, dp) || !read_fwds_addr(s, dp)) { 290 delegpt_free_mlc(dp); 291 return 0; 292 } 293 /* set flag that parent side NS information is included. 294 * Asking a (higher up) server on the internet is not useful */ 295 /* the flag is turned off for 'forward-first' so that the 296 * last resort will ask for parent-side NS record and thus 297 * fallback to the internet name servers on a failure */ 298 dp->has_parent_side_NS = (uint8_t)!s->isfirst; 299 /* Do not cache if set. */ 300 dp->no_cache = s->no_cache; 301 /* use SSL for queries to this forwarder */ 302 dp->ssl_upstream = (uint8_t)s->ssl_upstream; 303 /* use TCP for queries to this forwarder */ 304 dp->tcp_upstream = (uint8_t)s->tcp_upstream; 305 verbose(VERB_QUERY, "Forward zone server list:"); 306 delegpt_log(VERB_QUERY, dp); 307 if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp)) 308 return 0; 309 } 310 return 1; 311 } 312 313 /** insert a stub hole (if necessary) for stub name */ 314 static int 315 fwd_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) 316 { 317 struct iter_forward_zone key; 318 key.node.key = &key; 319 key.dclass = c; 320 key.name = nm; 321 key.namelabs = dname_count_size_labels(key.name, &key.namelen); 322 return forwards_insert_data(fwd, key.dclass, key.name, 323 key.namelen, key.namelabs, NULL); 324 } 325 326 /** make NULL entries for stubs */ 327 static int 328 make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg) 329 { 330 struct config_stub* s; 331 uint8_t* dname; 332 size_t dname_len; 333 for(s = cfg->stubs; s; s = s->next) { 334 if(!s->name) continue; 335 dname = sldns_str2wire_dname(s->name, &dname_len); 336 if(!dname) { 337 log_err("cannot parse stub name '%s'", s->name); 338 return 0; 339 } 340 if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) { 341 /* Already a forward zone there. */ 342 free(dname); 343 continue; 344 } 345 if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) { 346 free(dname); 347 log_err("out of memory"); 348 return 0; 349 } 350 free(dname); 351 } 352 return 1; 353 } 354 355 /** make NULL entries for auths */ 356 static int 357 make_auth_holes(struct iter_forwards* fwd, struct config_file* cfg) 358 { 359 struct config_auth* a; 360 uint8_t* dname; 361 size_t dname_len; 362 for(a = cfg->auths; a; a = a->next) { 363 if(!a->name) continue; 364 dname = sldns_str2wire_dname(a->name, &dname_len); 365 if(!dname) { 366 log_err("cannot parse auth name '%s'", a->name); 367 return 0; 368 } 369 if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) { 370 /* Already a forward zone there. */ 371 free(dname); 372 continue; 373 } 374 if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) { 375 free(dname); 376 log_err("out of memory"); 377 return 0; 378 } 379 free(dname); 380 } 381 return 1; 382 } 383 384 int 385 forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg) 386 { 387 if(fwd->tree) { 388 lock_unprotect(&fwd->lock, fwd->tree); 389 } 390 fwd_del_tree(fwd); 391 fwd->tree = rbtree_create(fwd_cmp); 392 if(!fwd->tree) 393 return 0; 394 lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree)); 395 396 lock_rw_wrlock(&fwd->lock); 397 /* read forward zones */ 398 if(!read_forwards(fwd, cfg)) { 399 lock_rw_unlock(&fwd->lock); 400 return 0; 401 } 402 if(!make_stub_holes(fwd, cfg)) { 403 lock_rw_unlock(&fwd->lock); 404 return 0; 405 } 406 /* TODO: Now we punch holes for auth zones as well so that in 407 * iterator:forward_request() we see the configured 408 * delegation point, but code flow/naming is hard to follow. 409 * Consider having a single tree with configured 410 * delegation points for all categories 411 * (stubs, forwards, auths). */ 412 if(!make_auth_holes(fwd, cfg)) { 413 lock_rw_unlock(&fwd->lock); 414 return 0; 415 } 416 fwd_init_parents(fwd); 417 lock_rw_unlock(&fwd->lock); 418 return 1; 419 } 420 421 struct delegpt* 422 forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass, 423 int nolock) 424 { 425 struct iter_forward_zone* res; 426 struct iter_forward_zone key; 427 int has_dp; 428 key.node.key = &key; 429 key.dclass = qclass; 430 key.name = qname; 431 key.namelabs = dname_count_size_labels(qname, &key.namelen); 432 /* lock_() calls are macros that could be nothing, surround in {} */ 433 if(!nolock) { lock_rw_rdlock(&fwd->lock); } 434 res = (struct iter_forward_zone*)rbtree_search(fwd->tree, &key); 435 has_dp = res && res->dp; 436 if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); } 437 return has_dp?res->dp:NULL; 438 } 439 440 struct delegpt* 441 forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass, 442 int nolock) 443 { 444 /* lookup the forward zone in the tree */ 445 rbnode_type* res = NULL; 446 struct iter_forward_zone *result; 447 struct iter_forward_zone key; 448 int has_dp; 449 key.node.key = &key; 450 key.dclass = qclass; 451 key.name = qname; 452 key.namelabs = dname_count_size_labels(qname, &key.namelen); 453 /* lock_() calls are macros that could be nothing, surround in {} */ 454 if(!nolock) { lock_rw_rdlock(&fwd->lock); } 455 if(rbtree_find_less_equal(fwd->tree, &key, &res)) { 456 /* exact */ 457 result = (struct iter_forward_zone*)res; 458 } else { 459 /* smaller element (or no element) */ 460 int m; 461 result = (struct iter_forward_zone*)res; 462 if(!result || result->dclass != qclass) { 463 if(!nolock) { lock_rw_unlock(&fwd->lock); } 464 return NULL; 465 } 466 /* count number of labels matched */ 467 (void)dname_lab_cmp(result->name, result->namelabs, key.name, 468 key.namelabs, &m); 469 while(result) { /* go up until qname is subdomain of stub */ 470 if(result->namelabs <= m) 471 break; 472 result = result->parent; 473 } 474 } 475 has_dp = result && result->dp; 476 if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); } 477 return has_dp?result->dp:NULL; 478 } 479 480 struct delegpt* 481 forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass, int nolock) 482 { 483 uint8_t root = 0; 484 return forwards_lookup(fwd, &root, qclass, nolock); 485 } 486 487 /* Finds next root item in forwards lookup tree. 488 * Caller needs to handle locking of the forwards structure. */ 489 static int 490 next_root_locked(struct iter_forwards* fwd, uint16_t* dclass) 491 { 492 struct iter_forward_zone key; 493 rbnode_type* n; 494 struct iter_forward_zone* p; 495 if(*dclass == 0) { 496 /* first root item is first item in tree */ 497 n = rbtree_first(fwd->tree); 498 if(n == RBTREE_NULL) 499 return 0; 500 p = (struct iter_forward_zone*)n; 501 if(dname_is_root(p->name)) { 502 *dclass = p->dclass; 503 return 1; 504 } 505 /* root not first item? search for higher items */ 506 *dclass = p->dclass + 1; 507 return next_root_locked(fwd, dclass); 508 } 509 /* find class n in tree, we may get a direct hit, or if we don't 510 * this is the last item of the previous class so rbtree_next() takes 511 * us to the next root (if any) */ 512 key.node.key = &key; 513 key.name = (uint8_t*)"\000"; 514 key.namelen = 1; 515 key.namelabs = 0; 516 key.dclass = *dclass; 517 n = NULL; 518 if(rbtree_find_less_equal(fwd->tree, &key, &n)) { 519 /* exact */ 520 return 1; 521 } else { 522 /* smaller element */ 523 if(!n || n == RBTREE_NULL) 524 return 0; /* nothing found */ 525 n = rbtree_next(n); 526 if(n == RBTREE_NULL) 527 return 0; /* no higher */ 528 p = (struct iter_forward_zone*)n; 529 if(dname_is_root(p->name)) { 530 *dclass = p->dclass; 531 return 1; 532 } 533 /* not a root node, return next higher item */ 534 *dclass = p->dclass+1; 535 return next_root_locked(fwd, dclass); 536 } 537 } 538 539 int 540 forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass, int nolock) 541 { 542 int ret; 543 /* lock_() calls are macros that could be nothing, surround in {} */ 544 if(!nolock) { lock_rw_rdlock(&fwd->lock); } 545 ret = next_root_locked(fwd, dclass); 546 if(!nolock) { lock_rw_unlock(&fwd->lock); } 547 return ret; 548 } 549 550 size_t 551 forwards_get_mem(struct iter_forwards* fwd) 552 { 553 struct iter_forward_zone* p; 554 size_t s; 555 if(!fwd) 556 return 0; 557 lock_rw_rdlock(&fwd->lock); 558 s = sizeof(*fwd) + sizeof(*fwd->tree); 559 RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) { 560 s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp); 561 } 562 lock_rw_unlock(&fwd->lock); 563 return s; 564 } 565 566 int 567 forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp, 568 int nolock) 569 { 570 struct iter_forward_zone *z; 571 /* lock_() calls are macros that could be nothing, surround in {} */ 572 if(!nolock) { lock_rw_wrlock(&fwd->lock); } 573 if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) { 574 (void)rbtree_delete(fwd->tree, &z->node); 575 fwd_zone_free(z); 576 } 577 if(!forwards_insert(fwd, c, dp)) { 578 if(!nolock) { lock_rw_unlock(&fwd->lock); } 579 return 0; 580 } 581 fwd_init_parents(fwd); 582 if(!nolock) { lock_rw_unlock(&fwd->lock); } 583 return 1; 584 } 585 586 void 587 forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm, 588 int nolock) 589 { 590 struct iter_forward_zone *z; 591 /* lock_() calls are macros that could be nothing, surround in {} */ 592 if(!nolock) { lock_rw_wrlock(&fwd->lock); } 593 if(!(z=fwd_zone_find(fwd, c, nm))) { 594 if(!nolock) { lock_rw_unlock(&fwd->lock); } 595 return; /* nothing to do */ 596 } 597 (void)rbtree_delete(fwd->tree, &z->node); 598 fwd_zone_free(z); 599 fwd_init_parents(fwd); 600 if(!nolock) { lock_rw_unlock(&fwd->lock); } 601 } 602 603 int 604 forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm, 605 int nolock) 606 { 607 /* lock_() calls are macros that could be nothing, surround in {} */ 608 if(!nolock) { lock_rw_wrlock(&fwd->lock); } 609 if(fwd_zone_find(fwd, c, nm) != NULL) { 610 if(!nolock) { lock_rw_unlock(&fwd->lock); } 611 return 1; /* already a stub zone there */ 612 } 613 if(!fwd_add_stub_hole(fwd, c, nm)) { 614 if(!nolock) { lock_rw_unlock(&fwd->lock); } 615 return 0; 616 } 617 fwd_init_parents(fwd); 618 if(!nolock) { lock_rw_unlock(&fwd->lock); } 619 return 1; 620 } 621 622 void 623 forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, 624 uint8_t* nm, int nolock) 625 { 626 struct iter_forward_zone *z; 627 /* lock_() calls are macros that could be nothing, surround in {} */ 628 if(!nolock) { lock_rw_wrlock(&fwd->lock); } 629 if(!(z=fwd_zone_find(fwd, c, nm))) { 630 if(!nolock) { lock_rw_unlock(&fwd->lock); } 631 return; /* nothing to do */ 632 } 633 if(z->dp != NULL) { 634 if(!nolock) { lock_rw_unlock(&fwd->lock); } 635 return; /* not a stub hole */ 636 } 637 (void)rbtree_delete(fwd->tree, &z->node); 638 fwd_zone_free(z); 639 fwd_init_parents(fwd); 640 if(!nolock) { lock_rw_unlock(&fwd->lock); } 641 } 642 643 void 644 forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data) 645 { 646 rbtree_type* oldtree = fwd->tree; 647 if(oldtree) { 648 lock_unprotect(&fwd->lock, oldtree); 649 } 650 if(data->tree) { 651 lock_unprotect(&data->lock, data->tree); 652 } 653 fwd->tree = data->tree; 654 data->tree = oldtree; 655 lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree)); 656 lock_protect(&data->lock, data->tree, sizeof(*data->tree)); 657 } 658