server.c revision 165071
1/* 2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: server.c,v 1.339.2.15.2.70 2006/05/24 04:30:24 marka Exp $ */ 19 20#include <config.h> 21 22#include <stdlib.h> 23 24#include <isc/app.h> 25#include <isc/base64.h> 26#include <isc/dir.h> 27#include <isc/entropy.h> 28#include <isc/file.h> 29#include <isc/hash.h> 30#include <isc/lex.h> 31#include <isc/parseint.h> 32#include <isc/print.h> 33#include <isc/resource.h> 34#include <isc/stdio.h> 35#include <isc/string.h> 36#include <isc/task.h> 37#include <isc/timer.h> 38#include <isc/util.h> 39 40#include <isccfg/namedconf.h> 41 42#include <bind9/check.h> 43 44#include <dns/adb.h> 45#include <dns/cache.h> 46#include <dns/db.h> 47#include <dns/dispatch.h> 48#include <dns/forward.h> 49#include <dns/journal.h> 50#include <dns/keytable.h> 51#include <dns/master.h> 52#include <dns/masterdump.h> 53#include <dns/order.h> 54#include <dns/peer.h> 55#include <dns/portlist.h> 56#include <dns/rdataclass.h> 57#include <dns/rdataset.h> 58#include <dns/rdatastruct.h> 59#include <dns/resolver.h> 60#include <dns/rootns.h> 61#include <dns/secalg.h> 62#include <dns/stats.h> 63#include <dns/tkey.h> 64#include <dns/view.h> 65#include <dns/zone.h> 66#include <dns/zt.h> 67 68#include <dst/dst.h> 69#include <dst/result.h> 70 71#include <named/client.h> 72#include <named/config.h> 73#include <named/control.h> 74#include <named/interfacemgr.h> 75#include <named/log.h> 76#include <named/logconf.h> 77#include <named/lwresd.h> 78#include <named/main.h> 79#include <named/os.h> 80#include <named/server.h> 81#include <named/tkeyconf.h> 82#include <named/tsigconf.h> 83#include <named/zoneconf.h> 84#ifdef HAVE_LIBSCF 85#include <named/ns_smf_globals.h> 86#include <stdlib.h> 87#endif 88 89/* 90 * Check an operation for failure. Assumes that the function 91 * using it has a 'result' variable and a 'cleanup' label. 92 */ 93#define CHECK(op) \ 94 do { result = (op); \ 95 if (result != ISC_R_SUCCESS) goto cleanup; \ 96 } while (0) 97 98#define CHECKM(op, msg) \ 99 do { result = (op); \ 100 if (result != ISC_R_SUCCESS) { \ 101 isc_log_write(ns_g_lctx, \ 102 NS_LOGCATEGORY_GENERAL, \ 103 NS_LOGMODULE_SERVER, \ 104 ISC_LOG_ERROR, \ 105 "%s: %s", msg, \ 106 isc_result_totext(result)); \ 107 goto cleanup; \ 108 } \ 109 } while (0) \ 110 111#define CHECKMF(op, msg, file) \ 112 do { result = (op); \ 113 if (result != ISC_R_SUCCESS) { \ 114 isc_log_write(ns_g_lctx, \ 115 NS_LOGCATEGORY_GENERAL, \ 116 NS_LOGMODULE_SERVER, \ 117 ISC_LOG_ERROR, \ 118 "%s '%s': %s", msg, file, \ 119 isc_result_totext(result)); \ 120 goto cleanup; \ 121 } \ 122 } while (0) \ 123 124#define CHECKFATAL(op, msg) \ 125 do { result = (op); \ 126 if (result != ISC_R_SUCCESS) \ 127 fatal(msg, result); \ 128 } while (0) \ 129 130struct ns_dispatch { 131 isc_sockaddr_t addr; 132 unsigned int dispatchgen; 133 dns_dispatch_t *dispatch; 134 ISC_LINK(struct ns_dispatch) link; 135}; 136 137struct dumpcontext { 138 isc_mem_t *mctx; 139 isc_boolean_t dumpcache; 140 isc_boolean_t dumpzones; 141 FILE *fp; 142 ISC_LIST(struct viewlistentry) viewlist; 143 struct viewlistentry *view; 144 struct zonelistentry *zone; 145 dns_dumpctx_t *mdctx; 146 dns_db_t *db; 147 dns_db_t *cache; 148 isc_task_t *task; 149 dns_dbversion_t *version; 150}; 151 152struct viewlistentry { 153 dns_view_t *view; 154 ISC_LINK(struct viewlistentry) link; 155 ISC_LIST(struct zonelistentry) zonelist; 156}; 157 158struct zonelistentry { 159 dns_zone_t *zone; 160 ISC_LINK(struct zonelistentry) link; 161}; 162 163static void 164fatal(const char *msg, isc_result_t result); 165 166static void 167ns_server_reload(isc_task_t *task, isc_event_t *event); 168 169static isc_result_t 170ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 171 ns_aclconfctx_t *actx, 172 isc_mem_t *mctx, ns_listenelt_t **target); 173static isc_result_t 174ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 175 ns_aclconfctx_t *actx, 176 isc_mem_t *mctx, ns_listenlist_t **target); 177 178static isc_result_t 179configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 180 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype); 181 182static isc_result_t 183configure_alternates(const cfg_obj_t *config, dns_view_t *view, 184 const cfg_obj_t *alternates); 185 186static isc_result_t 187configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 188 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 189 ns_aclconfctx_t *aclconf); 190 191static void 192end_reserved_dispatches(ns_server_t *server, isc_boolean_t all); 193 194/* 195 * Configure a single view ACL at '*aclp'. Get its configuration by 196 * calling 'getvcacl' (for per-view configuration) and maybe 'getscacl' 197 * (for a global default). 198 */ 199static isc_result_t 200configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config, 201 const char *aclname, ns_aclconfctx_t *actx, 202 isc_mem_t *mctx, dns_acl_t **aclp) 203{ 204 isc_result_t result; 205 const cfg_obj_t *maps[3]; 206 const cfg_obj_t *aclobj = NULL; 207 int i = 0; 208 209 if (*aclp != NULL) 210 dns_acl_detach(aclp); 211 if (vconfig != NULL) 212 maps[i++] = cfg_tuple_get(vconfig, "options"); 213 if (config != NULL) { 214 const cfg_obj_t *options = NULL; 215 (void)cfg_map_get(config, "options", &options); 216 if (options != NULL) 217 maps[i++] = options; 218 } 219 maps[i] = NULL; 220 221 (void)ns_config_get(maps, aclname, &aclobj); 222 if (aclobj == NULL) 223 /* 224 * No value available. *aclp == NULL. 225 */ 226 return (ISC_R_SUCCESS); 227 228 result = ns_acl_fromconfig(aclobj, config, actx, mctx, aclp); 229 230 return (result); 231} 232 233static isc_result_t 234configure_view_dnsseckey(const cfg_obj_t *vconfig, const cfg_obj_t *key, 235 dns_keytable_t *keytable, isc_mem_t *mctx) 236{ 237 dns_rdataclass_t viewclass; 238 dns_rdata_dnskey_t keystruct; 239 isc_uint32_t flags, proto, alg; 240 const char *keystr, *keynamestr; 241 unsigned char keydata[4096]; 242 isc_buffer_t keydatabuf; 243 unsigned char rrdata[4096]; 244 isc_buffer_t rrdatabuf; 245 isc_region_t r; 246 dns_fixedname_t fkeyname; 247 dns_name_t *keyname; 248 isc_buffer_t namebuf; 249 isc_result_t result; 250 dst_key_t *dstkey = NULL; 251 252 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); 253 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); 254 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); 255 keyname = dns_fixedname_name(&fkeyname); 256 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 257 258 if (vconfig == NULL) 259 viewclass = dns_rdataclass_in; 260 else { 261 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class"); 262 CHECK(ns_config_getclass(classobj, dns_rdataclass_in, 263 &viewclass)); 264 } 265 keystruct.common.rdclass = viewclass; 266 keystruct.common.rdtype = dns_rdatatype_dnskey; 267 /* 268 * The key data in keystruct is not dynamically allocated. 269 */ 270 keystruct.mctx = NULL; 271 272 ISC_LINK_INIT(&keystruct.common, link); 273 274 if (flags > 0xffff) 275 CHECKM(ISC_R_RANGE, "key flags"); 276 if (proto > 0xff) 277 CHECKM(ISC_R_RANGE, "key protocol"); 278 if (alg > 0xff) 279 CHECKM(ISC_R_RANGE, "key algorithm"); 280 keystruct.flags = (isc_uint16_t)flags; 281 keystruct.protocol = (isc_uint8_t)proto; 282 keystruct.algorithm = (isc_uint8_t)alg; 283 284 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); 285 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 286 287 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); 288 CHECK(isc_base64_decodestring(keystr, &keydatabuf)); 289 isc_buffer_usedregion(&keydatabuf, &r); 290 keystruct.datalen = r.length; 291 keystruct.data = r.base; 292 293 CHECK(dns_rdata_fromstruct(NULL, 294 keystruct.common.rdclass, 295 keystruct.common.rdtype, 296 &keystruct, &rrdatabuf)); 297 dns_fixedname_init(&fkeyname); 298 isc_buffer_init(&namebuf, keynamestr, strlen(keynamestr)); 299 isc_buffer_add(&namebuf, strlen(keynamestr)); 300 CHECK(dns_name_fromtext(keyname, &namebuf, 301 dns_rootname, ISC_FALSE, 302 NULL)); 303 CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf, 304 mctx, &dstkey)); 305 306 CHECK(dns_keytable_add(keytable, &dstkey)); 307 INSIST(dstkey == NULL); 308 return (ISC_R_SUCCESS); 309 310 cleanup: 311 if (result == DST_R_NOCRYPTO) { 312 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 313 "ignoring trusted key for '%s': no crypto support", 314 keynamestr); 315 result = ISC_R_SUCCESS; 316 } else { 317 cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, 318 "configuring trusted key for '%s': %s", 319 keynamestr, isc_result_totext(result)); 320 result = ISC_R_FAILURE; 321 } 322 323 if (dstkey != NULL) 324 dst_key_free(&dstkey); 325 326 return (result); 327} 328 329/* 330 * Configure DNSSEC keys for a view. Currently used only for 331 * the security roots. 332 * 333 * The per-view configuration values and the server-global defaults are read 334 * from 'vconfig' and 'config'. The variable to be configured is '*target'. 335 */ 336static isc_result_t 337configure_view_dnsseckeys(const cfg_obj_t *vconfig, const cfg_obj_t *config, 338 isc_mem_t *mctx, dns_keytable_t **target) 339{ 340 isc_result_t result; 341 const cfg_obj_t *keys = NULL; 342 const cfg_obj_t *voptions = NULL; 343 const cfg_listelt_t *element, *element2; 344 const cfg_obj_t *keylist; 345 const cfg_obj_t *key; 346 dns_keytable_t *keytable = NULL; 347 348 CHECK(dns_keytable_create(mctx, &keytable)); 349 350 if (vconfig != NULL) 351 voptions = cfg_tuple_get(vconfig, "options"); 352 353 keys = NULL; 354 if (voptions != NULL) 355 (void)cfg_map_get(voptions, "trusted-keys", &keys); 356 if (keys == NULL) 357 (void)cfg_map_get(config, "trusted-keys", &keys); 358 359 for (element = cfg_list_first(keys); 360 element != NULL; 361 element = cfg_list_next(element)) 362 { 363 keylist = cfg_listelt_value(element); 364 for (element2 = cfg_list_first(keylist); 365 element2 != NULL; 366 element2 = cfg_list_next(element2)) 367 { 368 key = cfg_listelt_value(element2); 369 CHECK(configure_view_dnsseckey(vconfig, key, 370 keytable, mctx)); 371 } 372 } 373 374 dns_keytable_detach(target); 375 *target = keytable; /* Transfer ownership. */ 376 keytable = NULL; 377 result = ISC_R_SUCCESS; 378 379 cleanup: 380 return (result); 381} 382 383static isc_result_t 384mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) 385{ 386 const cfg_listelt_t *element; 387 const cfg_obj_t *obj; 388 const char *str; 389 dns_fixedname_t fixed; 390 dns_name_t *name; 391 isc_boolean_t value; 392 isc_result_t result; 393 isc_buffer_t b; 394 395 dns_fixedname_init(&fixed); 396 name = dns_fixedname_name(&fixed); 397 for (element = cfg_list_first(mbs); 398 element != NULL; 399 element = cfg_list_next(element)) 400 { 401 obj = cfg_listelt_value(element); 402 str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 403 isc_buffer_init(&b, str, strlen(str)); 404 isc_buffer_add(&b, strlen(str)); 405 CHECK(dns_name_fromtext(name, &b, dns_rootname, 406 ISC_FALSE, NULL)); 407 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value")); 408 CHECK(dns_resolver_setmustbesecure(resolver, name, value)); 409 } 410 411 result = ISC_R_SUCCESS; 412 413 cleanup: 414 return (result); 415} 416 417/* 418 * Get a dispatch appropriate for the resolver of a given view. 419 */ 420static isc_result_t 421get_view_querysource_dispatch(const cfg_obj_t **maps, 422 int af, dns_dispatch_t **dispatchp) 423{ 424 isc_result_t result; 425 dns_dispatch_t *disp; 426 isc_sockaddr_t sa; 427 unsigned int attrs, attrmask; 428 const cfg_obj_t *obj = NULL; 429 430 /* 431 * Make compiler happy. 432 */ 433 result = ISC_R_FAILURE; 434 435 switch (af) { 436 case AF_INET: 437 result = ns_config_get(maps, "query-source", &obj); 438 INSIST(result == ISC_R_SUCCESS); 439 break; 440 case AF_INET6: 441 result = ns_config_get(maps, "query-source-v6", &obj); 442 INSIST(result == ISC_R_SUCCESS); 443 break; 444 default: 445 INSIST(0); 446 } 447 448 sa = *(cfg_obj_assockaddr(obj)); 449 INSIST(isc_sockaddr_pf(&sa) == af); 450 451 /* 452 * If we don't support this address family, we're done! 453 */ 454 switch (af) { 455 case AF_INET: 456 result = isc_net_probeipv4(); 457 break; 458 case AF_INET6: 459 result = isc_net_probeipv6(); 460 break; 461 default: 462 INSIST(0); 463 } 464 if (result != ISC_R_SUCCESS) 465 return (ISC_R_SUCCESS); 466 467 /* 468 * Try to find a dispatcher that we can share. 469 */ 470 attrs = 0; 471 attrs |= DNS_DISPATCHATTR_UDP; 472 switch (af) { 473 case AF_INET: 474 attrs |= DNS_DISPATCHATTR_IPV4; 475 break; 476 case AF_INET6: 477 attrs |= DNS_DISPATCHATTR_IPV6; 478 break; 479 } 480 attrmask = 0; 481 attrmask |= DNS_DISPATCHATTR_UDP; 482 attrmask |= DNS_DISPATCHATTR_TCP; 483 attrmask |= DNS_DISPATCHATTR_IPV4; 484 attrmask |= DNS_DISPATCHATTR_IPV6; 485 486 disp = NULL; 487 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 488 ns_g_taskmgr, &sa, 4096, 489 1000, 32768, 16411, 16433, 490 attrs, attrmask, &disp); 491 if (result != ISC_R_SUCCESS) { 492 isc_sockaddr_t any; 493 char buf[ISC_SOCKADDR_FORMATSIZE]; 494 495 switch (af) { 496 case AF_INET: 497 isc_sockaddr_any(&any); 498 break; 499 case AF_INET6: 500 isc_sockaddr_any6(&any); 501 break; 502 } 503 if (isc_sockaddr_equal(&sa, &any)) 504 return (ISC_R_SUCCESS); 505 isc_sockaddr_format(&sa, buf, sizeof(buf)); 506 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 507 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 508 "could not get query source dispatcher (%s)", 509 buf); 510 return (result); 511 } 512 513 *dispatchp = disp; 514 515 return (ISC_R_SUCCESS); 516} 517 518static isc_result_t 519configure_order(dns_order_t *order, const cfg_obj_t *ent) { 520 dns_rdataclass_t rdclass; 521 dns_rdatatype_t rdtype; 522 const cfg_obj_t *obj; 523 dns_fixedname_t fixed; 524 unsigned int mode = 0; 525 const char *str; 526 isc_buffer_t b; 527 isc_result_t result; 528 isc_boolean_t addroot; 529 530 result = ns_config_getclass(cfg_tuple_get(ent, "class"), 531 dns_rdataclass_any, &rdclass); 532 if (result != ISC_R_SUCCESS) 533 return (result); 534 535 result = ns_config_gettype(cfg_tuple_get(ent, "type"), 536 dns_rdatatype_any, &rdtype); 537 if (result != ISC_R_SUCCESS) 538 return (result); 539 540 obj = cfg_tuple_get(ent, "name"); 541 if (cfg_obj_isstring(obj)) 542 str = cfg_obj_asstring(obj); 543 else 544 str = "*"; 545 addroot = ISC_TF(strcmp(str, "*") == 0); 546 isc_buffer_init(&b, str, strlen(str)); 547 isc_buffer_add(&b, strlen(str)); 548 dns_fixedname_init(&fixed); 549 result = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 550 dns_rootname, ISC_FALSE, NULL); 551 if (result != ISC_R_SUCCESS) 552 return (result); 553 554 obj = cfg_tuple_get(ent, "ordering"); 555 INSIST(cfg_obj_isstring(obj)); 556 str = cfg_obj_asstring(obj); 557 if (!strcasecmp(str, "fixed")) 558 mode = DNS_RDATASETATTR_FIXEDORDER; 559 else if (!strcasecmp(str, "random")) 560 mode = DNS_RDATASETATTR_RANDOMIZE; 561 else if (!strcasecmp(str, "cyclic")) 562 mode = 0; 563 else 564 INSIST(0); 565 566 /* 567 * "*" should match everything including the root (BIND 8 compat). 568 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a 569 * explicit entry for "." when the name is "*". 570 */ 571 if (addroot) { 572 result = dns_order_add(order, dns_rootname, 573 rdtype, rdclass, mode); 574 if (result != ISC_R_SUCCESS) 575 return (result); 576 } 577 578 return (dns_order_add(order, dns_fixedname_name(&fixed), 579 rdtype, rdclass, mode)); 580} 581 582static isc_result_t 583configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { 584 const isc_sockaddr_t *sa; 585 isc_netaddr_t na; 586 dns_peer_t *peer; 587 const cfg_obj_t *obj; 588 const char *str; 589 isc_result_t result; 590 591 sa = cfg_obj_assockaddr(cfg_map_getname(cpeer)); 592 isc_netaddr_fromsockaddr(&na, sa); 593 594 peer = NULL; 595 result = dns_peer_new(mctx, &na, &peer); 596 if (result != ISC_R_SUCCESS) 597 return (result); 598 599 obj = NULL; 600 (void)cfg_map_get(cpeer, "bogus", &obj); 601 if (obj != NULL) 602 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj))); 603 604 obj = NULL; 605 (void)cfg_map_get(cpeer, "provide-ixfr", &obj); 606 if (obj != NULL) 607 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj))); 608 609 obj = NULL; 610 (void)cfg_map_get(cpeer, "request-ixfr", &obj); 611 if (obj != NULL) 612 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj))); 613 614 obj = NULL; 615 (void)cfg_map_get(cpeer, "edns", &obj); 616 if (obj != NULL) 617 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj))); 618 619 obj = NULL; 620 (void)cfg_map_get(cpeer, "transfers", &obj); 621 if (obj != NULL) 622 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj))); 623 624 obj = NULL; 625 (void)cfg_map_get(cpeer, "transfer-format", &obj); 626 if (obj != NULL) { 627 str = cfg_obj_asstring(obj); 628 if (strcasecmp(str, "many-answers") == 0) 629 CHECK(dns_peer_settransferformat(peer, 630 dns_many_answers)); 631 else if (strcasecmp(str, "one-answer") == 0) 632 CHECK(dns_peer_settransferformat(peer, 633 dns_one_answer)); 634 else 635 INSIST(0); 636 } 637 638 obj = NULL; 639 (void)cfg_map_get(cpeer, "keys", &obj); 640 if (obj != NULL) { 641 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj)); 642 if (result != ISC_R_SUCCESS) 643 goto cleanup; 644 } 645 646 obj = NULL; 647 if (isc_sockaddr_pf(sa) == AF_INET) 648 (void)cfg_map_get(cpeer, "transfer-source", &obj); 649 else 650 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj); 651 if (obj != NULL) { 652 result = dns_peer_settransfersource(peer, 653 cfg_obj_assockaddr(obj)); 654 if (result != ISC_R_SUCCESS) 655 goto cleanup; 656 } 657 *peerp = peer; 658 return (ISC_R_SUCCESS); 659 660 cleanup: 661 dns_peer_detach(&peer); 662 return (result); 663} 664 665static isc_result_t 666disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { 667 isc_result_t result; 668 const cfg_obj_t *algorithms; 669 const cfg_listelt_t *element; 670 const char *str; 671 dns_fixedname_t fixed; 672 dns_name_t *name; 673 isc_buffer_t b; 674 675 dns_fixedname_init(&fixed); 676 name = dns_fixedname_name(&fixed); 677 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name")); 678 isc_buffer_init(&b, str, strlen(str)); 679 isc_buffer_add(&b, strlen(str)); 680 CHECK(dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL)); 681 682 algorithms = cfg_tuple_get(disabled, "algorithms"); 683 for (element = cfg_list_first(algorithms); 684 element != NULL; 685 element = cfg_list_next(element)) 686 { 687 isc_textregion_t r; 688 dns_secalg_t alg; 689 690 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base); 691 r.length = strlen(r.base); 692 693 result = dns_secalg_fromtext(&alg, &r); 694 if (result != ISC_R_SUCCESS) { 695 isc_uint8_t ui; 696 result = isc_parse_uint8(&ui, r.base, 10); 697 alg = ui; 698 } 699 if (result != ISC_R_SUCCESS) { 700 cfg_obj_log(cfg_listelt_value(element), 701 ns_g_lctx, ISC_LOG_ERROR, 702 "invalid algorithm"); 703 CHECK(result); 704 } 705 CHECK(dns_resolver_disable_algorithm(resolver, name, alg)); 706 } 707 cleanup: 708 return (result); 709} 710 711/* 712 * Configure 'view' according to 'vconfig', taking defaults from 'config' 713 * where values are missing in 'vconfig'. 714 * 715 * When configuring the default view, 'vconfig' will be NULL and the 716 * global defaults in 'config' used exclusively. 717 */ 718static isc_result_t 719configure_view(dns_view_t *view, const cfg_obj_t *config, 720 const cfg_obj_t *vconfig, isc_mem_t *mctx, ns_aclconfctx_t *actx, 721 isc_boolean_t need_hints) 722{ 723 const cfg_obj_t *maps[4]; 724 const cfg_obj_t *cfgmaps[3]; 725 const cfg_obj_t *options = NULL; 726 const cfg_obj_t *voptions = NULL; 727 const cfg_obj_t *forwardtype; 728 const cfg_obj_t *forwarders; 729 const cfg_obj_t *alternates; 730 const cfg_obj_t *zonelist; 731 const cfg_obj_t *disabled; 732 const cfg_obj_t *obj; 733 const cfg_listelt_t *element; 734 in_port_t port; 735 dns_cache_t *cache = NULL; 736 isc_result_t result; 737 isc_uint32_t max_adb_size; 738 isc_uint32_t max_cache_size; 739 isc_uint32_t lame_ttl; 740 dns_tsig_keyring_t *ring; 741 dns_view_t *pview = NULL; /* Production view */ 742 isc_mem_t *cmctx; 743 dns_dispatch_t *dispatch4 = NULL; 744 dns_dispatch_t *dispatch6 = NULL; 745 isc_boolean_t reused_cache = ISC_FALSE; 746 int i; 747 const char *str; 748 dns_order_t *order = NULL; 749 isc_uint32_t udpsize; 750 unsigned int check = 0; 751 752 REQUIRE(DNS_VIEW_VALID(view)); 753 754 cmctx = NULL; 755 756 if (config != NULL) 757 (void)cfg_map_get(config, "options", &options); 758 759 i = 0; 760 if (vconfig != NULL) { 761 voptions = cfg_tuple_get(vconfig, "options"); 762 maps[i++] = voptions; 763 } 764 if (options != NULL) 765 maps[i++] = options; 766 maps[i++] = ns_g_defaults; 767 maps[i] = NULL; 768 769 i = 0; 770 if (voptions != NULL) 771 cfgmaps[i++] = voptions; 772 if (config != NULL) 773 cfgmaps[i++] = config; 774 cfgmaps[i] = NULL; 775 776 /* 777 * Set the view's port number for outgoing queries. 778 */ 779 CHECKM(ns_config_getport(config, &port), "port"); 780 dns_view_setdstport(view, port); 781 782 /* 783 * Configure the zones. 784 */ 785 zonelist = NULL; 786 if (voptions != NULL) 787 (void)cfg_map_get(voptions, "zone", &zonelist); 788 else 789 (void)cfg_map_get(config, "zone", &zonelist); 790 for (element = cfg_list_first(zonelist); 791 element != NULL; 792 element = cfg_list_next(element)) 793 { 794 const cfg_obj_t *zconfig = cfg_listelt_value(element); 795 CHECK(configure_zone(config, zconfig, vconfig, mctx, view, 796 actx)); 797 } 798 799 /* 800 * Configure the view's cache. Try to reuse an existing 801 * cache if possible, otherwise create a new cache. 802 * Note that the ADB is not preserved in either case. 803 * 804 * XXX Determining when it is safe to reuse a cache is 805 * tricky. When the view's configuration changes, the cached 806 * data may become invalid because it reflects our old 807 * view of the world. As more view attributes become 808 * configurable, we will have to add code here to check 809 * whether they have changed in ways that could 810 * invalidate the cache. 811 */ 812 result = dns_viewlist_find(&ns_g_server->viewlist, 813 view->name, view->rdclass, 814 &pview); 815 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 816 goto cleanup; 817 if (pview != NULL) { 818 INSIST(pview->cache != NULL); 819 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 820 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3), 821 "reusing existing cache"); 822 reused_cache = ISC_TRUE; 823 dns_cache_attach(pview->cache, &cache); 824 dns_view_detach(&pview); 825 } else { 826 CHECK(isc_mem_create(0, 0, &cmctx)); 827 CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr, 828 view->rdclass, "rbt", 0, NULL, &cache)); 829 } 830 dns_view_setcache(view, cache); 831 832 /* 833 * cache-file cannot be inherited if views are present, but this 834 * should be caught by the configuration checking stage. 835 */ 836 obj = NULL; 837 result = ns_config_get(maps, "cache-file", &obj); 838 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) { 839 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj))); 840 if (!reused_cache) 841 CHECK(dns_cache_load(cache)); 842 } 843 844 obj = NULL; 845 result = ns_config_get(maps, "cleaning-interval", &obj); 846 INSIST(result == ISC_R_SUCCESS); 847 dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60); 848 849 obj = NULL; 850 result = ns_config_get(maps, "max-cache-size", &obj); 851 INSIST(result == ISC_R_SUCCESS); 852 if (cfg_obj_isstring(obj)) { 853 str = cfg_obj_asstring(obj); 854 INSIST(strcasecmp(str, "unlimited") == 0); 855 max_cache_size = ISC_UINT32_MAX; 856 } else { 857 isc_resourcevalue_t value; 858 value = cfg_obj_asuint64(obj); 859 if (value > ISC_UINT32_MAX) { 860 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 861 "'max-cache-size " 862 "%" ISC_PRINT_QUADFORMAT "d' is too large", 863 value); 864 result = ISC_R_RANGE; 865 goto cleanup; 866 } 867 max_cache_size = (isc_uint32_t)value; 868 } 869 dns_cache_setcachesize(cache, max_cache_size); 870 871 dns_cache_detach(&cache); 872 873 /* 874 * Check-names. 875 */ 876 obj = NULL; 877 result = ns_checknames_get(maps, "response", &obj); 878 INSIST(result == ISC_R_SUCCESS); 879 880 str = cfg_obj_asstring(obj); 881 if (strcasecmp(str, "fail") == 0) { 882 check = DNS_RESOLVER_CHECKNAMES | 883 DNS_RESOLVER_CHECKNAMESFAIL; 884 view->checknames = ISC_TRUE; 885 } else if (strcasecmp(str, "warn") == 0) { 886 check = DNS_RESOLVER_CHECKNAMES; 887 view->checknames = ISC_FALSE; 888 } else if (strcasecmp(str, "ignore") == 0) { 889 check = 0; 890 view->checknames = ISC_FALSE; 891 } else 892 INSIST(0); 893 894 /* 895 * Resolver. 896 * 897 * XXXRTH Hardwired number of tasks. 898 */ 899 CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4)); 900 CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6)); 901 if (dispatch4 == NULL && dispatch6 == NULL) { 902 UNEXPECTED_ERROR(__FILE__, __LINE__, 903 "unable to obtain neither an IPv4 nor" 904 " an IPv6 dispatch"); 905 result = ISC_R_UNEXPECTED; 906 goto cleanup; 907 } 908 CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, 909 ns_g_socketmgr, ns_g_timermgr, 910 check, ns_g_dispatchmgr, 911 dispatch4, dispatch6)); 912 913 /* 914 * Set the ADB cache size to 1/8th of the max-cache-size. 915 */ 916 max_adb_size = 0; 917 if (max_cache_size != 0) { 918 max_adb_size = max_cache_size / 8; 919 if (max_adb_size == 0) 920 max_adb_size = 1; /* Force minimum. */ 921 } 922 dns_adb_setadbsize(view->adb, max_adb_size); 923 924 /* 925 * Set resolver's lame-ttl. 926 */ 927 obj = NULL; 928 result = ns_config_get(maps, "lame-ttl", &obj); 929 INSIST(result == ISC_R_SUCCESS); 930 lame_ttl = cfg_obj_asuint32(obj); 931 if (lame_ttl > 1800) 932 lame_ttl = 1800; 933 dns_resolver_setlamettl(view->resolver, lame_ttl); 934 935 /* 936 * Set the resolver's EDNS UDP size. 937 */ 938 obj = NULL; 939 result = ns_config_get(maps, "edns-udp-size", &obj); 940 INSIST(result == ISC_R_SUCCESS); 941 udpsize = cfg_obj_asuint32(obj); 942 if (udpsize < 512) 943 udpsize = 512; 944 if (udpsize > 4096) 945 udpsize = 4096; 946 dns_resolver_setudpsize(view->resolver, (isc_uint16_t)udpsize); 947 948 /* 949 * Set supported DNSSEC algorithms. 950 */ 951 dns_resolver_reset_algorithms(view->resolver); 952 disabled = NULL; 953 (void)ns_config_get(maps, "disable-algorithms", &disabled); 954 if (disabled != NULL) { 955 for (element = cfg_list_first(disabled); 956 element != NULL; 957 element = cfg_list_next(element)) 958 CHECK(disable_algorithms(cfg_listelt_value(element), 959 view->resolver)); 960 } 961 962 /* 963 * A global or view "forwarders" option, if present, 964 * creates an entry for "." in the forwarding table. 965 */ 966 forwardtype = NULL; 967 forwarders = NULL; 968 (void)ns_config_get(maps, "forward", &forwardtype); 969 (void)ns_config_get(maps, "forwarders", &forwarders); 970 if (forwarders != NULL) 971 CHECK(configure_forward(config, view, dns_rootname, 972 forwarders, forwardtype)); 973 974 /* 975 * Dual Stack Servers. 976 */ 977 alternates = NULL; 978 (void)ns_config_get(maps, "dual-stack-servers", &alternates); 979 if (alternates != NULL) 980 CHECK(configure_alternates(config, view, alternates)); 981 982 /* 983 * We have default hints for class IN if we need them. 984 */ 985 if (view->rdclass == dns_rdataclass_in && view->hints == NULL) 986 dns_view_sethints(view, ns_g_server->in_roothints); 987 988 /* 989 * If we still have no hints, this is a non-IN view with no 990 * "hints zone" configured. Issue a warning, except if this 991 * is a root server. Root servers never need to consult 992 * their hints, so it's no point requiring users to configure 993 * them. 994 */ 995 if (view->hints == NULL) { 996 dns_zone_t *rootzone = NULL; 997 (void)dns_view_findzone(view, dns_rootname, &rootzone); 998 if (rootzone != NULL) { 999 dns_zone_detach(&rootzone); 1000 need_hints = ISC_FALSE; 1001 } 1002 if (need_hints) 1003 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1004 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1005 "no root hints for view '%s'", 1006 view->name); 1007 } 1008 1009 /* 1010 * Configure the view's TSIG keys. 1011 */ 1012 ring = NULL; 1013 CHECK(ns_tsigkeyring_fromconfig(config, vconfig, view->mctx, &ring)); 1014 dns_view_setkeyring(view, ring); 1015 1016 /* 1017 * Configure the view's peer list. 1018 */ 1019 { 1020 const cfg_obj_t *peers = NULL; 1021 const cfg_listelt_t *element; 1022 dns_peerlist_t *newpeers = NULL; 1023 1024 (void)ns_config_get(cfgmaps, "server", &peers); 1025 CHECK(dns_peerlist_new(mctx, &newpeers)); 1026 for (element = cfg_list_first(peers); 1027 element != NULL; 1028 element = cfg_list_next(element)) 1029 { 1030 const cfg_obj_t *cpeer = cfg_listelt_value(element); 1031 dns_peer_t *peer; 1032 1033 CHECK(configure_peer(cpeer, mctx, &peer)); 1034 dns_peerlist_addpeer(newpeers, peer); 1035 dns_peer_detach(&peer); 1036 } 1037 dns_peerlist_detach(&view->peers); 1038 view->peers = newpeers; /* Transfer ownership. */ 1039 } 1040 1041 /* 1042 * Configure the views rrset-order. 1043 */ 1044 { 1045 const cfg_obj_t *rrsetorder = NULL; 1046 const cfg_listelt_t *element; 1047 1048 (void)ns_config_get(maps, "rrset-order", &rrsetorder); 1049 CHECK(dns_order_create(mctx, &order)); 1050 for (element = cfg_list_first(rrsetorder); 1051 element != NULL; 1052 element = cfg_list_next(element)) 1053 { 1054 const cfg_obj_t *ent = cfg_listelt_value(element); 1055 1056 CHECK(configure_order(order, ent)); 1057 } 1058 if (view->order != NULL) 1059 dns_order_detach(&view->order); 1060 dns_order_attach(order, &view->order); 1061 dns_order_detach(&order); 1062 } 1063 /* 1064 * Copy the aclenv object. 1065 */ 1066 dns_aclenv_copy(&view->aclenv, &ns_g_server->aclenv); 1067 1068 /* 1069 * Configure the "match-clients" and "match-destinations" ACL. 1070 */ 1071 CHECK(configure_view_acl(vconfig, config, "match-clients", actx, 1072 ns_g_mctx, &view->matchclients)); 1073 CHECK(configure_view_acl(vconfig, config, "match-destinations", actx, 1074 ns_g_mctx, &view->matchdestinations)); 1075 1076 /* 1077 * Configure the "match-recursive-only" option. 1078 */ 1079 obj = NULL; 1080 (void)ns_config_get(maps, "match-recursive-only", &obj); 1081 if (obj != NULL && cfg_obj_asboolean(obj)) 1082 view->matchrecursiveonly = ISC_TRUE; 1083 else 1084 view->matchrecursiveonly = ISC_FALSE; 1085 1086 /* 1087 * Configure other configurable data. 1088 */ 1089 obj = NULL; 1090 result = ns_config_get(maps, "recursion", &obj); 1091 INSIST(result == ISC_R_SUCCESS); 1092 view->recursion = cfg_obj_asboolean(obj); 1093 1094 obj = NULL; 1095 result = ns_config_get(maps, "auth-nxdomain", &obj); 1096 INSIST(result == ISC_R_SUCCESS); 1097 view->auth_nxdomain = cfg_obj_asboolean(obj); 1098 1099 obj = NULL; 1100 result = ns_config_get(maps, "minimal-responses", &obj); 1101 INSIST(result == ISC_R_SUCCESS); 1102 view->minimalresponses = cfg_obj_asboolean(obj); 1103 1104 obj = NULL; 1105 result = ns_config_get(maps, "transfer-format", &obj); 1106 INSIST(result == ISC_R_SUCCESS); 1107 str = cfg_obj_asstring(obj); 1108 if (strcasecmp(str, "many-answers") == 0) 1109 view->transfer_format = dns_many_answers; 1110 else if (strcasecmp(str, "one-answer") == 0) 1111 view->transfer_format = dns_one_answer; 1112 else 1113 INSIST(0); 1114 1115 /* 1116 * Set sources where additional data and CNAME/DNAME 1117 * targets for authoritative answers may be found. 1118 */ 1119 obj = NULL; 1120 result = ns_config_get(maps, "additional-from-auth", &obj); 1121 INSIST(result == ISC_R_SUCCESS); 1122 view->additionalfromauth = cfg_obj_asboolean(obj); 1123 if (view->recursion && ! view->additionalfromauth) { 1124 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1125 "'additional-from-auth no' is only supported " 1126 "with 'recursion no'"); 1127 view->additionalfromauth = ISC_TRUE; 1128 } 1129 1130 obj = NULL; 1131 result = ns_config_get(maps, "additional-from-cache", &obj); 1132 INSIST(result == ISC_R_SUCCESS); 1133 view->additionalfromcache = cfg_obj_asboolean(obj); 1134 if (view->recursion && ! view->additionalfromcache) { 1135 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1136 "'additional-from-cache no' is only supported " 1137 "with 'recursion no'"); 1138 view->additionalfromcache = ISC_TRUE; 1139 } 1140 1141 CHECK(configure_view_acl(vconfig, config, "allow-query", 1142 actx, ns_g_mctx, &view->queryacl)); 1143 1144 if (strcmp(view->name, "_bind") != 0) 1145 CHECK(configure_view_acl(vconfig, config, "allow-recursion", 1146 actx, ns_g_mctx, &view->recursionacl)); 1147 1148 /* 1149 * Warning if both "recursion no;" and allow-recursion are active 1150 * except for "allow-recursion { none; };". 1151 */ 1152 if (!view->recursion && view->recursionacl != NULL && 1153 (view->recursionacl->length != 1 || 1154 view->recursionacl->elements[0].type != dns_aclelementtype_any || 1155 view->recursionacl->elements[0].negative != ISC_TRUE)) { 1156 const char *forview = " for view "; 1157 const char *viewname = view->name; 1158 1159 if (!strcmp(view->name, "_bind") || 1160 !strcmp(view->name, "_default")) { 1161 forview = ""; 1162 viewname = ""; 1163 } 1164 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1165 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1166 "both \"recursion no;\" and \"allow-recursion\" " 1167 "active%s%s", forview, viewname); 1168 } 1169 1170 CHECK(configure_view_acl(vconfig, config, "sortlist", 1171 actx, ns_g_mctx, &view->sortlist)); 1172 1173 obj = NULL; 1174 result = ns_config_get(maps, "request-ixfr", &obj); 1175 INSIST(result == ISC_R_SUCCESS); 1176 view->requestixfr = cfg_obj_asboolean(obj); 1177 1178 obj = NULL; 1179 result = ns_config_get(maps, "provide-ixfr", &obj); 1180 INSIST(result == ISC_R_SUCCESS); 1181 view->provideixfr = cfg_obj_asboolean(obj); 1182 1183 obj = NULL; 1184 result = ns_config_get(maps, "dnssec-enable", &obj); 1185 INSIST(result == ISC_R_SUCCESS); 1186 view->enablednssec = cfg_obj_asboolean(obj); 1187 1188 obj = NULL; 1189 result = ns_config_get(maps, "dnssec-lookaside", &obj); 1190 if (result == ISC_R_SUCCESS) { 1191 for (element = cfg_list_first(obj); 1192 element != NULL; 1193 element = cfg_list_next(element)) 1194 { 1195 const char *str; 1196 isc_buffer_t b; 1197 dns_name_t *dlv; 1198 1199 obj = cfg_listelt_value(element); 1200#if 0 1201 dns_fixedname_t fixed; 1202 dns_name_t *name; 1203 1204 /* 1205 * When we support multiple dnssec-lookaside 1206 * entries this is how to find the domain to be 1207 * checked. XXXMPA 1208 */ 1209 dns_fixedname_init(&fixed); 1210 name = dns_fixedname_name(&fixed); 1211 str = cfg_obj_asstring(cfg_tuple_get(obj, 1212 "domain")); 1213 isc_buffer_init(&b, str, strlen(str)); 1214 isc_buffer_add(&b, strlen(str)); 1215 CHECK(dns_name_fromtext(name, &b, dns_rootname, 1216 ISC_TRUE, NULL)); 1217#endif 1218 str = cfg_obj_asstring(cfg_tuple_get(obj, 1219 "trust-anchor")); 1220 isc_buffer_init(&b, str, strlen(str)); 1221 isc_buffer_add(&b, strlen(str)); 1222 dlv = dns_fixedname_name(&view->dlv_fixed); 1223 CHECK(dns_name_fromtext(dlv, &b, dns_rootname, 1224 ISC_TRUE, NULL)); 1225 view->dlv = dns_fixedname_name(&view->dlv_fixed); 1226 } 1227 } else 1228 view->dlv = NULL; 1229 1230 /* 1231 * For now, there is only one kind of trusted keys, the 1232 * "security roots". 1233 */ 1234 if (view->enablednssec) { 1235 CHECK(configure_view_dnsseckeys(vconfig, config, mctx, 1236 &view->secroots)); 1237 dns_resolver_resetmustbesecure(view->resolver); 1238 obj = NULL; 1239 result = ns_config_get(maps, "dnssec-must-be-secure", &obj); 1240 if (result == ISC_R_SUCCESS) 1241 CHECK(mustbesecure(obj, view->resolver)); 1242 } 1243 1244 obj = NULL; 1245 result = ns_config_get(maps, "max-cache-ttl", &obj); 1246 INSIST(result == ISC_R_SUCCESS); 1247 view->maxcachettl = cfg_obj_asuint32(obj); 1248 1249 obj = NULL; 1250 result = ns_config_get(maps, "max-ncache-ttl", &obj); 1251 INSIST(result == ISC_R_SUCCESS); 1252 view->maxncachettl = cfg_obj_asuint32(obj); 1253 if (view->maxncachettl > 7 * 24 * 3600) 1254 view->maxncachettl = 7 * 24 * 3600; 1255 1256 obj = NULL; 1257 result = ns_config_get(maps, "preferred-glue", &obj); 1258 if (result == ISC_R_SUCCESS) { 1259 str = cfg_obj_asstring(obj); 1260 if (strcasecmp(str, "a") == 0) 1261 view->preferred_glue = dns_rdatatype_a; 1262 else if (strcasecmp(str, "aaaa") == 0) 1263 view->preferred_glue = dns_rdatatype_aaaa; 1264 else 1265 view->preferred_glue = 0; 1266 } else 1267 view->preferred_glue = 0; 1268 1269 obj = NULL; 1270 result = ns_config_get(maps, "root-delegation-only", &obj); 1271 if (result == ISC_R_SUCCESS) { 1272 dns_view_setrootdelonly(view, ISC_TRUE); 1273 if (!cfg_obj_isvoid(obj)) { 1274 dns_fixedname_t fixed; 1275 dns_name_t *name; 1276 isc_buffer_t b; 1277 const char *str; 1278 const cfg_obj_t *exclude; 1279 1280 dns_fixedname_init(&fixed); 1281 name = dns_fixedname_name(&fixed); 1282 for (element = cfg_list_first(obj); 1283 element != NULL; 1284 element = cfg_list_next(element)) { 1285 exclude = cfg_listelt_value(element); 1286 str = cfg_obj_asstring(exclude); 1287 isc_buffer_init(&b, str, strlen(str)); 1288 isc_buffer_add(&b, strlen(str)); 1289 CHECK(dns_name_fromtext(name, &b, dns_rootname, 1290 ISC_FALSE, NULL)); 1291 CHECK(dns_view_excludedelegationonly(view, 1292 name)); 1293 } 1294 } 1295 } else 1296 dns_view_setrootdelonly(view, ISC_FALSE); 1297 1298 result = ISC_R_SUCCESS; 1299 1300 cleanup: 1301 if (dispatch4 != NULL) 1302 dns_dispatch_detach(&dispatch4); 1303 if (dispatch6 != NULL) 1304 dns_dispatch_detach(&dispatch6); 1305 if (order != NULL) 1306 dns_order_detach(&order); 1307 if (cmctx != NULL) 1308 isc_mem_detach(&cmctx); 1309 1310 if (cache != NULL) 1311 dns_cache_detach(&cache); 1312 1313 return (result); 1314} 1315 1316static isc_result_t 1317configure_hints(dns_view_t *view, const char *filename) { 1318 isc_result_t result; 1319 dns_db_t *db; 1320 1321 db = NULL; 1322 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db); 1323 if (result == ISC_R_SUCCESS) { 1324 dns_view_sethints(view, db); 1325 dns_db_detach(&db); 1326 } 1327 1328 return (result); 1329} 1330 1331static isc_result_t 1332configure_alternates(const cfg_obj_t *config, dns_view_t *view, 1333 const cfg_obj_t *alternates) 1334{ 1335 const cfg_obj_t *portobj; 1336 const cfg_obj_t *addresses; 1337 const cfg_listelt_t *element; 1338 isc_result_t result = ISC_R_SUCCESS; 1339 in_port_t port; 1340 1341 /* 1342 * Determine which port to send requests to. 1343 */ 1344 if (ns_g_lwresdonly && ns_g_port != 0) 1345 port = ns_g_port; 1346 else 1347 CHECKM(ns_config_getport(config, &port), "port"); 1348 1349 if (alternates != NULL) { 1350 portobj = cfg_tuple_get(alternates, "port"); 1351 if (cfg_obj_isuint32(portobj)) { 1352 isc_uint32_t val = cfg_obj_asuint32(portobj); 1353 if (val > ISC_UINT16_MAX) { 1354 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1355 "port '%u' out of range", val); 1356 return (ISC_R_RANGE); 1357 } 1358 port = (in_port_t) val; 1359 } 1360 } 1361 1362 addresses = NULL; 1363 if (alternates != NULL) 1364 addresses = cfg_tuple_get(alternates, "addresses"); 1365 1366 for (element = cfg_list_first(addresses); 1367 element != NULL; 1368 element = cfg_list_next(element)) 1369 { 1370 const cfg_obj_t *alternate = cfg_listelt_value(element); 1371 isc_sockaddr_t sa; 1372 1373 if (!cfg_obj_issockaddr(alternate)) { 1374 dns_fixedname_t fixed; 1375 dns_name_t *name; 1376 const char *str = cfg_obj_asstring(cfg_tuple_get( 1377 alternate, "name")); 1378 isc_buffer_t buffer; 1379 in_port_t myport = port; 1380 1381 isc_buffer_init(&buffer, str, strlen(str)); 1382 isc_buffer_add(&buffer, strlen(str)); 1383 dns_fixedname_init(&fixed); 1384 name = dns_fixedname_name(&fixed); 1385 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 1386 ISC_FALSE, NULL)); 1387 1388 portobj = cfg_tuple_get(alternate, "port"); 1389 if (cfg_obj_isuint32(portobj)) { 1390 isc_uint32_t val = cfg_obj_asuint32(portobj); 1391 if (val > ISC_UINT16_MAX) { 1392 cfg_obj_log(portobj, ns_g_lctx, 1393 ISC_LOG_ERROR, 1394 "port '%u' out of range", 1395 val); 1396 return (ISC_R_RANGE); 1397 } 1398 myport = (in_port_t) val; 1399 } 1400 CHECK(dns_resolver_addalternate(view->resolver, NULL, 1401 name, myport)); 1402 continue; 1403 } 1404 1405 sa = *cfg_obj_assockaddr(alternate); 1406 if (isc_sockaddr_getport(&sa) == 0) 1407 isc_sockaddr_setport(&sa, port); 1408 CHECK(dns_resolver_addalternate(view->resolver, &sa, 1409 NULL, 0)); 1410 } 1411 1412 cleanup: 1413 return (result); 1414} 1415 1416static isc_result_t 1417configure_forward(const cfg_obj_t *config, dns_view_t *view, dns_name_t *origin, 1418 const cfg_obj_t *forwarders, const cfg_obj_t *forwardtype) 1419{ 1420 const cfg_obj_t *portobj; 1421 const cfg_obj_t *faddresses; 1422 const cfg_listelt_t *element; 1423 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none; 1424 isc_sockaddrlist_t addresses; 1425 isc_sockaddr_t *sa; 1426 isc_result_t result; 1427 in_port_t port; 1428 1429 /* 1430 * Determine which port to send forwarded requests to. 1431 */ 1432 if (ns_g_lwresdonly && ns_g_port != 0) 1433 port = ns_g_port; 1434 else 1435 CHECKM(ns_config_getport(config, &port), "port"); 1436 1437 if (forwarders != NULL) { 1438 portobj = cfg_tuple_get(forwarders, "port"); 1439 if (cfg_obj_isuint32(portobj)) { 1440 isc_uint32_t val = cfg_obj_asuint32(portobj); 1441 if (val > ISC_UINT16_MAX) { 1442 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 1443 "port '%u' out of range", val); 1444 return (ISC_R_RANGE); 1445 } 1446 port = (in_port_t) val; 1447 } 1448 } 1449 1450 faddresses = NULL; 1451 if (forwarders != NULL) 1452 faddresses = cfg_tuple_get(forwarders, "addresses"); 1453 1454 ISC_LIST_INIT(addresses); 1455 1456 for (element = cfg_list_first(faddresses); 1457 element != NULL; 1458 element = cfg_list_next(element)) 1459 { 1460 const cfg_obj_t *forwarder = cfg_listelt_value(element); 1461 sa = isc_mem_get(view->mctx, sizeof(isc_sockaddr_t)); 1462 if (sa == NULL) { 1463 result = ISC_R_NOMEMORY; 1464 goto cleanup; 1465 } 1466 *sa = *cfg_obj_assockaddr(forwarder); 1467 if (isc_sockaddr_getport(sa) == 0) 1468 isc_sockaddr_setport(sa, port); 1469 ISC_LINK_INIT(sa, link); 1470 ISC_LIST_APPEND(addresses, sa, link); 1471 } 1472 1473 if (ISC_LIST_EMPTY(addresses)) { 1474 if (forwardtype != NULL) 1475 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 1476 "no forwarders seen; disabling " 1477 "forwarding"); 1478 fwdpolicy = dns_fwdpolicy_none; 1479 } else { 1480 if (forwardtype == NULL) 1481 fwdpolicy = dns_fwdpolicy_first; 1482 else { 1483 const char *forwardstr = cfg_obj_asstring(forwardtype); 1484 if (strcasecmp(forwardstr, "first") == 0) 1485 fwdpolicy = dns_fwdpolicy_first; 1486 else if (strcasecmp(forwardstr, "only") == 0) 1487 fwdpolicy = dns_fwdpolicy_only; 1488 else 1489 INSIST(0); 1490 } 1491 } 1492 1493 result = dns_fwdtable_add(view->fwdtable, origin, &addresses, 1494 fwdpolicy); 1495 if (result != ISC_R_SUCCESS) { 1496 char namebuf[DNS_NAME_FORMATSIZE]; 1497 dns_name_format(origin, namebuf, sizeof(namebuf)); 1498 cfg_obj_log(forwarders, ns_g_lctx, ISC_LOG_WARNING, 1499 "could not set up forwarding for domain '%s': %s", 1500 namebuf, isc_result_totext(result)); 1501 goto cleanup; 1502 } 1503 1504 result = ISC_R_SUCCESS; 1505 1506 cleanup: 1507 1508 while (!ISC_LIST_EMPTY(addresses)) { 1509 sa = ISC_LIST_HEAD(addresses); 1510 ISC_LIST_UNLINK(addresses, sa, link); 1511 isc_mem_put(view->mctx, sa, sizeof(isc_sockaddr_t)); 1512 } 1513 1514 return (result); 1515} 1516 1517/* 1518 * Create a new view and add it to the list. 1519 * 1520 * If 'vconfig' is NULL, create the default view. 1521 * 1522 * The view created is attached to '*viewp'. 1523 */ 1524static isc_result_t 1525create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, 1526 dns_view_t **viewp) 1527{ 1528 isc_result_t result; 1529 const char *viewname; 1530 dns_rdataclass_t viewclass; 1531 dns_view_t *view = NULL; 1532 1533 if (vconfig != NULL) { 1534 const cfg_obj_t *classobj = NULL; 1535 1536 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 1537 classobj = cfg_tuple_get(vconfig, "class"); 1538 result = ns_config_getclass(classobj, dns_rdataclass_in, 1539 &viewclass); 1540 } else { 1541 viewname = "_default"; 1542 viewclass = dns_rdataclass_in; 1543 } 1544 result = dns_viewlist_find(viewlist, viewname, viewclass, &view); 1545 if (result == ISC_R_SUCCESS) 1546 return (ISC_R_EXISTS); 1547 if (result != ISC_R_NOTFOUND) 1548 return (result); 1549 INSIST(view == NULL); 1550 1551 result = dns_view_create(ns_g_mctx, viewclass, viewname, &view); 1552 if (result != ISC_R_SUCCESS) 1553 return (result); 1554 1555 ISC_LIST_APPEND(*viewlist, view, link); 1556 dns_view_attach(view, viewp); 1557 return (ISC_R_SUCCESS); 1558} 1559 1560/* 1561 * Configure or reconfigure a zone. 1562 */ 1563static isc_result_t 1564configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, 1565 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, 1566 ns_aclconfctx_t *aclconf) 1567{ 1568 dns_view_t *pview = NULL; /* Production view */ 1569 dns_zone_t *zone = NULL; /* New or reused zone */ 1570 dns_zone_t *dupzone = NULL; 1571 const cfg_obj_t *options = NULL; 1572 const cfg_obj_t *zoptions = NULL; 1573 const cfg_obj_t *typeobj = NULL; 1574 const cfg_obj_t *forwarders = NULL; 1575 const cfg_obj_t *forwardtype = NULL; 1576 const cfg_obj_t *only = NULL; 1577 isc_result_t result; 1578 isc_result_t tresult; 1579 isc_buffer_t buffer; 1580 dns_fixedname_t fixorigin; 1581 dns_name_t *origin; 1582 const char *zname; 1583 dns_rdataclass_t zclass; 1584 const char *ztypestr; 1585 1586 options = NULL; 1587 (void)cfg_map_get(config, "options", &options); 1588 1589 zoptions = cfg_tuple_get(zconfig, "options"); 1590 1591 /* 1592 * Get the zone origin as a dns_name_t. 1593 */ 1594 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 1595 isc_buffer_init(&buffer, zname, strlen(zname)); 1596 isc_buffer_add(&buffer, strlen(zname)); 1597 dns_fixedname_init(&fixorigin); 1598 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin), 1599 &buffer, dns_rootname, ISC_FALSE, NULL)); 1600 origin = dns_fixedname_name(&fixorigin); 1601 1602 CHECK(ns_config_getclass(cfg_tuple_get(zconfig, "class"), 1603 view->rdclass, &zclass)); 1604 if (zclass != view->rdclass) { 1605 const char *vname = NULL; 1606 if (vconfig != NULL) 1607 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, 1608 "name")); 1609 else 1610 vname = "<default view>"; 1611 1612 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1613 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 1614 "zone '%s': wrong class for view '%s'", 1615 zname, vname); 1616 result = ISC_R_FAILURE; 1617 goto cleanup; 1618 } 1619 1620 (void)cfg_map_get(zoptions, "type", &typeobj); 1621 if (typeobj == NULL) { 1622 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 1623 "zone '%s' 'type' not specified", zname); 1624 return (ISC_R_FAILURE); 1625 } 1626 ztypestr = cfg_obj_asstring(typeobj); 1627 1628 /* 1629 * "hints zones" aren't zones. If we've got one, 1630 * configure it and return. 1631 */ 1632 if (strcasecmp(ztypestr, "hint") == 0) { 1633 const cfg_obj_t *fileobj = NULL; 1634 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) { 1635 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1636 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 1637 "zone '%s': 'file' not specified", 1638 zname); 1639 result = ISC_R_FAILURE; 1640 goto cleanup; 1641 } 1642 if (dns_name_equal(origin, dns_rootname)) { 1643 const char *hintsfile = cfg_obj_asstring(fileobj); 1644 1645 result = configure_hints(view, hintsfile); 1646 if (result != ISC_R_SUCCESS) { 1647 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1648 NS_LOGMODULE_SERVER, 1649 ISC_LOG_ERROR, 1650 "could not configure root hints " 1651 "from '%s': %s", hintsfile, 1652 isc_result_totext(result)); 1653 goto cleanup; 1654 } 1655 /* 1656 * Hint zones may also refer to delegation only points. 1657 */ 1658 only = NULL; 1659 tresult = cfg_map_get(zoptions, "delegation-only", 1660 &only); 1661 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only)) 1662 CHECK(dns_view_adddelegationonly(view, origin)); 1663 } else { 1664 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1665 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1666 "ignoring non-root hint zone '%s'", 1667 zname); 1668 result = ISC_R_SUCCESS; 1669 } 1670 /* Skip ordinary zone processing. */ 1671 goto cleanup; 1672 } 1673 1674 /* 1675 * "forward zones" aren't zones either. Translate this syntax into 1676 * the appropriate selective forwarding configuration and return. 1677 */ 1678 if (strcasecmp(ztypestr, "forward") == 0) { 1679 forwardtype = NULL; 1680 forwarders = NULL; 1681 1682 (void)cfg_map_get(zoptions, "forward", &forwardtype); 1683 (void)cfg_map_get(zoptions, "forwarders", &forwarders); 1684 result = configure_forward(config, view, origin, forwarders, 1685 forwardtype); 1686 goto cleanup; 1687 } 1688 1689 /* 1690 * "delegation-only zones" aren't zones either. 1691 */ 1692 if (strcasecmp(ztypestr, "delegation-only") == 0) { 1693 result = dns_view_adddelegationonly(view, origin); 1694 goto cleanup; 1695 } 1696 1697 /* 1698 * Check for duplicates in the new zone table. 1699 */ 1700 result = dns_view_findzone(view, origin, &dupzone); 1701 if (result == ISC_R_SUCCESS) { 1702 /* 1703 * We already have this zone! 1704 */ 1705 cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, 1706 "zone '%s' already exists", zname); 1707 dns_zone_detach(&dupzone); 1708 result = ISC_R_EXISTS; 1709 goto cleanup; 1710 } 1711 INSIST(dupzone == NULL); 1712 1713 /* 1714 * See if we can reuse an existing zone. This is 1715 * only possible if all of these are true: 1716 * - The zone's view exists 1717 * - A zone with the right name exists in the view 1718 * - The zone is compatible with the config 1719 * options (e.g., an existing master zone cannot 1720 * be reused if the options specify a slave zone) 1721 */ 1722 result = dns_viewlist_find(&ns_g_server->viewlist, 1723 view->name, view->rdclass, 1724 &pview); 1725 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 1726 goto cleanup; 1727 if (pview != NULL) 1728 result = dns_view_findzone(pview, origin, &zone); 1729 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) 1730 goto cleanup; 1731 if (zone != NULL) { 1732 if (! ns_zone_reusable(zone, zconfig)) 1733 dns_zone_detach(&zone); 1734 } 1735 1736 if (zone != NULL) { 1737 /* 1738 * We found a reusable zone. Make it use the 1739 * new view. 1740 */ 1741 dns_zone_setview(zone, view); 1742 } else { 1743 /* 1744 * We cannot reuse an existing zone, we have 1745 * to create a new one. 1746 */ 1747 CHECK(dns_zone_create(&zone, mctx)); 1748 CHECK(dns_zone_setorigin(zone, origin)); 1749 dns_zone_setview(zone, view); 1750 CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); 1751 } 1752 1753 /* 1754 * If the zone contains a 'forwarders' statement, configure 1755 * selective forwarding. 1756 */ 1757 forwarders = NULL; 1758 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) 1759 { 1760 forwardtype = NULL; 1761 (void)cfg_map_get(zoptions, "forward", &forwardtype); 1762 CHECK(configure_forward(config, view, origin, forwarders, 1763 forwardtype)); 1764 } 1765 1766 /* 1767 * Stub and forward zones may also refer to delegation only points. 1768 */ 1769 only = NULL; 1770 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS) 1771 { 1772 if (cfg_obj_asboolean(only)) 1773 CHECK(dns_view_adddelegationonly(view, origin)); 1774 } 1775 1776 /* 1777 * Configure the zone. 1778 */ 1779 CHECK(ns_zone_configure(config, vconfig, zconfig, aclconf, zone)); 1780 1781 /* 1782 * Add the zone to its view in the new view list. 1783 */ 1784 CHECK(dns_view_addzone(view, zone)); 1785 1786 cleanup: 1787 if (zone != NULL) 1788 dns_zone_detach(&zone); 1789 if (pview != NULL) 1790 dns_view_detach(&pview); 1791 1792 return (result); 1793} 1794 1795/* 1796 * Configure a single server quota. 1797 */ 1798static void 1799configure_server_quota(const cfg_obj_t **maps, const char *name, 1800 isc_quota_t *quota) 1801{ 1802 const cfg_obj_t *obj = NULL; 1803 isc_result_t result; 1804 1805 result = ns_config_get(maps, name, &obj); 1806 INSIST(result == ISC_R_SUCCESS); 1807 isc_quota_max(quota, cfg_obj_asuint32(obj)); 1808} 1809 1810/* 1811 * This function is called as soon as the 'directory' statement has been 1812 * parsed. This can be extended to support other options if necessary. 1813 */ 1814static isc_result_t 1815directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 1816 isc_result_t result; 1817 const char *directory; 1818 1819 REQUIRE(strcasecmp("directory", clausename) == 0); 1820 1821 UNUSED(arg); 1822 UNUSED(clausename); 1823 1824 /* 1825 * Change directory. 1826 */ 1827 directory = cfg_obj_asstring(obj); 1828 1829 if (! isc_file_ischdiridempotent(directory)) 1830 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, 1831 "option 'directory' contains relative path '%s'", 1832 directory); 1833 1834 result = isc_dir_chdir(directory); 1835 if (result != ISC_R_SUCCESS) { 1836 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, 1837 "change directory to '%s' failed: %s", 1838 directory, isc_result_totext(result)); 1839 return (result); 1840 } 1841 1842 return (ISC_R_SUCCESS); 1843} 1844 1845static void 1846scan_interfaces(ns_server_t *server, isc_boolean_t verbose) { 1847 isc_boolean_t match_mapped = server->aclenv.match_mapped; 1848 1849 ns_interfacemgr_scan(server->interfacemgr, verbose); 1850 /* 1851 * Update the "localhost" and "localnets" ACLs to match the 1852 * current set of network interfaces. 1853 */ 1854 dns_aclenv_copy(&server->aclenv, 1855 ns_interfacemgr_getaclenv(server->interfacemgr)); 1856 1857 server->aclenv.match_mapped = match_mapped; 1858} 1859 1860static isc_result_t 1861add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) { 1862 ns_listenelt_t *lelt = NULL; 1863 dns_acl_t *src_acl = NULL; 1864 dns_aclelement_t aelt; 1865 isc_result_t result; 1866 isc_sockaddr_t any_sa6; 1867 1868 REQUIRE(isc_sockaddr_pf(addr) == AF_INET6); 1869 1870 isc_sockaddr_any6(&any_sa6); 1871 if (!isc_sockaddr_equal(&any_sa6, addr)) { 1872 aelt.type = dns_aclelementtype_ipprefix; 1873 aelt.negative = ISC_FALSE; 1874 aelt.u.ip_prefix.prefixlen = 128; 1875 isc_netaddr_fromin6(&aelt.u.ip_prefix.address, 1876 &addr->type.sin6.sin6_addr); 1877 1878 result = dns_acl_create(mctx, 1, &src_acl); 1879 if (result != ISC_R_SUCCESS) 1880 return (result); 1881 result = dns_acl_appendelement(src_acl, &aelt); 1882 if (result != ISC_R_SUCCESS) 1883 goto clean; 1884 1885 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr), 1886 src_acl, &lelt); 1887 if (result != ISC_R_SUCCESS) 1888 goto clean; 1889 ISC_LIST_APPEND(list->elts, lelt, link); 1890 } 1891 1892 return (ISC_R_SUCCESS); 1893 1894 clean: 1895 INSIST(lelt == NULL); 1896 dns_acl_detach(&src_acl); 1897 1898 return (result); 1899} 1900 1901/* 1902 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust() 1903 * to update the listening interfaces accordingly. 1904 * We currently only consider IPv6, because this only affects IPv6 wildcard 1905 * sockets. 1906 */ 1907static void 1908adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { 1909 isc_result_t result; 1910 ns_listenlist_t *list = NULL; 1911 dns_view_t *view; 1912 dns_zone_t *zone, *next; 1913 isc_sockaddr_t addr, *addrp; 1914 1915 result = ns_listenlist_create(mctx, &list); 1916 if (result != ISC_R_SUCCESS) 1917 return; 1918 1919 for (view = ISC_LIST_HEAD(server->viewlist); 1920 view != NULL; 1921 view = ISC_LIST_NEXT(view, link)) { 1922 dns_dispatch_t *dispatch6; 1923 1924 dispatch6 = dns_resolver_dispatchv6(view->resolver); 1925 if (dispatch6 == NULL) 1926 continue; 1927 result = dns_dispatch_getlocaladdress(dispatch6, &addr); 1928 if (result != ISC_R_SUCCESS) 1929 goto fail; 1930 result = add_listenelt(mctx, list, &addr); 1931 if (result != ISC_R_SUCCESS) 1932 goto fail; 1933 } 1934 1935 zone = NULL; 1936 for (result = dns_zone_first(server->zonemgr, &zone); 1937 result == ISC_R_SUCCESS; 1938 next = NULL, result = dns_zone_next(zone, &next), zone = next) { 1939 dns_view_t *zoneview; 1940 1941 /* 1942 * At this point the zone list may contain a stale zone 1943 * just removed from the configuration. To see the validity, 1944 * check if the corresponding view is in our current view list. 1945 * There may also be old zones that are still in the process 1946 * of shutting down and have detached from their old view 1947 * (zoneview == NULL). 1948 */ 1949 zoneview = dns_zone_getview(zone); 1950 if (zoneview == NULL) 1951 continue; 1952 for (view = ISC_LIST_HEAD(server->viewlist); 1953 view != NULL && view != zoneview; 1954 view = ISC_LIST_NEXT(view, link)) 1955 ; 1956 if (view == NULL) 1957 continue; 1958 1959 addrp = dns_zone_getnotifysrc6(zone); 1960 result = add_listenelt(mctx, list, addrp); 1961 if (result != ISC_R_SUCCESS) 1962 goto fail; 1963 1964 addrp = dns_zone_getxfrsource6(zone); 1965 result = add_listenelt(mctx, list, addrp); 1966 if (result != ISC_R_SUCCESS) 1967 goto fail; 1968 } 1969 1970 ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE); 1971 1972 clean: 1973 ns_listenlist_detach(&list); 1974 return; 1975 1976 fail: 1977 /* 1978 * Even when we failed the procedure, most of other interfaces 1979 * should work correctly. We therefore just warn it. 1980 */ 1981 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 1982 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 1983 "could not adjust the listen-on list; " 1984 "some interfaces may not work"); 1985 goto clean; 1986} 1987 1988/* 1989 * This event callback is invoked to do periodic network 1990 * interface scanning. 1991 */ 1992static void 1993interface_timer_tick(isc_task_t *task, isc_event_t *event) { 1994 isc_result_t result; 1995 ns_server_t *server = (ns_server_t *) event->ev_arg; 1996 INSIST(task == server->task); 1997 UNUSED(task); 1998 isc_event_free(&event); 1999 /* 2000 * XXX should scan interfaces unlocked and get exclusive access 2001 * only to replace ACLs. 2002 */ 2003 result = isc_task_beginexclusive(server->task); 2004 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2005 scan_interfaces(server, ISC_FALSE); 2006 isc_task_endexclusive(server->task); 2007} 2008 2009static void 2010heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) { 2011 ns_server_t *server = (ns_server_t *) event->ev_arg; 2012 dns_view_t *view; 2013 2014 UNUSED(task); 2015 isc_event_free(&event); 2016 view = ISC_LIST_HEAD(server->viewlist); 2017 while (view != NULL) { 2018 dns_view_dialup(view); 2019 view = ISC_LIST_NEXT(view, link); 2020 } 2021} 2022 2023/* 2024 * Replace the current value of '*field', a dynamically allocated 2025 * string or NULL, with a dynamically allocated copy of the 2026 * null-terminated string pointed to by 'value', or NULL. 2027 */ 2028static isc_result_t 2029setstring(ns_server_t *server, char **field, const char *value) { 2030 char *copy; 2031 2032 if (value != NULL) { 2033 copy = isc_mem_strdup(server->mctx, value); 2034 if (copy == NULL) 2035 return (ISC_R_NOMEMORY); 2036 } else { 2037 copy = NULL; 2038 } 2039 2040 if (*field != NULL) 2041 isc_mem_free(server->mctx, *field); 2042 2043 *field = copy; 2044 return (ISC_R_SUCCESS); 2045} 2046 2047/* 2048 * Replace the current value of '*field', a dynamically allocated 2049 * string or NULL, with another dynamically allocated string 2050 * or NULL if whether 'obj' is a string or void value, respectively. 2051 */ 2052static isc_result_t 2053setoptstring(ns_server_t *server, char **field, const cfg_obj_t *obj) { 2054 if (cfg_obj_isvoid(obj)) 2055 return (setstring(server, field, NULL)); 2056 else 2057 return (setstring(server, field, cfg_obj_asstring(obj))); 2058} 2059 2060static void 2061set_limit(const cfg_obj_t **maps, const char *configname, 2062 const char *description, isc_resource_t resourceid, 2063 isc_resourcevalue_t defaultvalue) 2064{ 2065 const cfg_obj_t *obj = NULL; 2066 const char *resource; 2067 isc_resourcevalue_t value; 2068 isc_result_t result; 2069 2070 if (ns_config_get(maps, configname, &obj) != ISC_R_SUCCESS) 2071 return; 2072 2073 if (cfg_obj_isstring(obj)) { 2074 resource = cfg_obj_asstring(obj); 2075 if (strcasecmp(resource, "unlimited") == 0) 2076 value = ISC_RESOURCE_UNLIMITED; 2077 else { 2078 INSIST(strcasecmp(resource, "default") == 0); 2079 value = defaultvalue; 2080 } 2081 } else 2082 value = cfg_obj_asuint64(obj); 2083 2084 result = isc_resource_setlimit(resourceid, value); 2085 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2086 result == ISC_R_SUCCESS ? 2087 ISC_LOG_DEBUG(3) : ISC_LOG_WARNING, 2088 "set maximum %s to %" ISC_PRINT_QUADFORMAT "d: %s", 2089 description, value, isc_result_totext(result)); 2090} 2091 2092#define SETLIMIT(cfgvar, resource, description) \ 2093 set_limit(maps, cfgvar, description, isc_resource_ ## resource, \ 2094 ns_g_init ## resource) 2095 2096static void 2097set_limits(const cfg_obj_t **maps) { 2098 SETLIMIT("stacksize", stacksize, "stack size"); 2099 SETLIMIT("datasize", datasize, "data size"); 2100 SETLIMIT("coresize", coresize, "core size"); 2101 SETLIMIT("files", openfiles, "open files"); 2102} 2103 2104static isc_result_t 2105portlist_fromconf(dns_portlist_t *portlist, unsigned int family, 2106 const cfg_obj_t *ports) 2107{ 2108 const cfg_listelt_t *element; 2109 isc_result_t result = ISC_R_SUCCESS; 2110 2111 for (element = cfg_list_first(ports); 2112 element != NULL; 2113 element = cfg_list_next(element)) { 2114 const cfg_obj_t *obj = cfg_listelt_value(element); 2115 in_port_t port = (in_port_t)cfg_obj_asuint32(obj); 2116 2117 result = dns_portlist_add(portlist, family, port); 2118 if (result != ISC_R_SUCCESS) 2119 break; 2120 } 2121 return (result); 2122} 2123 2124static isc_result_t 2125load_configuration(const char *filename, ns_server_t *server, 2126 isc_boolean_t first_time) 2127{ 2128 isc_result_t result; 2129 cfg_parser_t *parser = NULL; 2130 cfg_obj_t *config; 2131 const cfg_obj_t *options; 2132 const cfg_obj_t *views; 2133 const cfg_obj_t *obj; 2134 const cfg_obj_t *v4ports, *v6ports; 2135 const cfg_obj_t *maps[3]; 2136 const cfg_obj_t *builtin_views; 2137 const cfg_listelt_t *element; 2138 dns_view_t *view = NULL; 2139 dns_view_t *view_next; 2140 dns_viewlist_t viewlist; 2141 dns_viewlist_t tmpviewlist; 2142 ns_aclconfctx_t aclconfctx; 2143 isc_uint32_t interface_interval; 2144 isc_uint32_t heartbeat_interval; 2145 isc_uint32_t udpsize; 2146 in_port_t listen_port; 2147 int i; 2148 2149 ns_aclconfctx_init(&aclconfctx); 2150 ISC_LIST_INIT(viewlist); 2151 2152 /* Ensure exclusive access to configuration data. */ 2153 result = isc_task_beginexclusive(server->task); 2154 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2155 2156 /* 2157 * Parse the global default pseudo-config file. 2158 */ 2159 if (first_time) { 2160 CHECK(ns_config_parsedefaults(ns_g_parser, &ns_g_config)); 2161 RUNTIME_CHECK(cfg_map_get(ns_g_config, "options", 2162 &ns_g_defaults) == 2163 ISC_R_SUCCESS); 2164 } 2165 2166 /* 2167 * Parse the configuration file using the new config code. 2168 */ 2169 result = ISC_R_FAILURE; 2170 config = NULL; 2171 2172 /* 2173 * Unless this is lwresd with the -C option, parse the config file. 2174 */ 2175 if (!(ns_g_lwresdonly && lwresd_g_useresolvconf)) { 2176 isc_log_write(ns_g_lctx, 2177 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2178 ISC_LOG_INFO, "loading configuration from '%s'", 2179 filename); 2180 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2181 cfg_parser_setcallback(parser, directory_callback, NULL); 2182 result = cfg_parse_file(parser, filename, &cfg_type_namedconf, 2183 &config); 2184 } 2185 2186 /* 2187 * If this is lwresd with the -C option, or lwresd with no -C or -c 2188 * option where the above parsing failed, parse resolv.conf. 2189 */ 2190 if (ns_g_lwresdonly && 2191 (lwresd_g_useresolvconf || 2192 (!ns_g_conffileset && result == ISC_R_FILENOTFOUND))) 2193 { 2194 isc_log_write(ns_g_lctx, 2195 NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2196 ISC_LOG_INFO, "loading configuration from '%s'", 2197 lwresd_g_resolvconffile); 2198 if (parser != NULL) 2199 cfg_parser_destroy(&parser); 2200 CHECK(cfg_parser_create(ns_g_mctx, ns_g_lctx, &parser)); 2201 result = ns_lwresd_parseeresolvconf(ns_g_mctx, parser, 2202 &config); 2203 } 2204 CHECK(result); 2205 2206 /* 2207 * Check the validity of the configuration. 2208 */ 2209 CHECK(bind9_check_namedconf(config, ns_g_lctx, ns_g_mctx)); 2210 2211 /* 2212 * Fill in the maps array, used for resolving defaults. 2213 */ 2214 i = 0; 2215 options = NULL; 2216 result = cfg_map_get(config, "options", &options); 2217 if (result == ISC_R_SUCCESS) 2218 maps[i++] = options; 2219 maps[i++] = ns_g_defaults; 2220 maps[i++] = NULL; 2221 2222 /* 2223 * Set process limits, which (usually) needs to be done as root. 2224 */ 2225 set_limits(maps); 2226 2227 /* 2228 * Configure various server options. 2229 */ 2230 configure_server_quota(maps, "transfers-out", &server->xfroutquota); 2231 configure_server_quota(maps, "tcp-clients", &server->tcpquota); 2232 configure_server_quota(maps, "recursive-clients", 2233 &server->recursionquota); 2234 if (server->recursionquota.max > 1000) 2235 isc_quota_soft(&server->recursionquota, 2236 server->recursionquota.max - 100); 2237 else 2238 isc_quota_soft(&server->recursionquota, 0); 2239 2240 CHECK(configure_view_acl(NULL, config, "blackhole", &aclconfctx, 2241 ns_g_mctx, &server->blackholeacl)); 2242 if (server->blackholeacl != NULL) 2243 dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, 2244 server->blackholeacl); 2245 2246 obj = NULL; 2247 result = ns_config_get(maps, "match-mapped-addresses", &obj); 2248 INSIST(result == ISC_R_SUCCESS); 2249 server->aclenv.match_mapped = cfg_obj_asboolean(obj); 2250 2251 v4ports = NULL; 2252 v6ports = NULL; 2253 (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports); 2254 (void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports); 2255 if (v4ports != NULL || v6ports != NULL) { 2256 dns_portlist_t *portlist = NULL; 2257 result = dns_portlist_create(ns_g_mctx, &portlist); 2258 if (result == ISC_R_SUCCESS && v4ports != NULL) 2259 result = portlist_fromconf(portlist, AF_INET, v4ports); 2260 if (result == ISC_R_SUCCESS && v6ports != NULL) 2261 portlist_fromconf(portlist, AF_INET6, v6ports); 2262 if (result == ISC_R_SUCCESS) 2263 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist); 2264 if (portlist != NULL) 2265 dns_portlist_detach(&portlist); 2266 CHECK(result); 2267 } else 2268 dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL); 2269 2270 /* 2271 * Set the EDNS UDP size when we don't match a view. 2272 */ 2273 obj = NULL; 2274 result = ns_config_get(maps, "edns-udp-size", &obj); 2275 INSIST(result == ISC_R_SUCCESS); 2276 udpsize = cfg_obj_asuint32(obj); 2277 if (udpsize < 512) 2278 udpsize = 512; 2279 if (udpsize > 4096) 2280 udpsize = 4096; 2281 ns_g_udpsize = (isc_uint16_t)udpsize; 2282 2283 /* 2284 * Configure the zone manager. 2285 */ 2286 obj = NULL; 2287 result = ns_config_get(maps, "transfers-in", &obj); 2288 INSIST(result == ISC_R_SUCCESS); 2289 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj)); 2290 2291 obj = NULL; 2292 result = ns_config_get(maps, "transfers-per-ns", &obj); 2293 INSIST(result == ISC_R_SUCCESS); 2294 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj)); 2295 2296 obj = NULL; 2297 result = ns_config_get(maps, "serial-query-rate", &obj); 2298 INSIST(result == ISC_R_SUCCESS); 2299 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj)); 2300 2301 /* 2302 * Determine which port to use for listening for incoming connections. 2303 */ 2304 if (ns_g_port != 0) 2305 listen_port = ns_g_port; 2306 else 2307 CHECKM(ns_config_getport(config, &listen_port), "port"); 2308 2309 /* 2310 * Find the listen queue depth. 2311 */ 2312 obj = NULL; 2313 result = ns_config_get(maps, "tcp-listen-queue", &obj); 2314 INSIST(result == ISC_R_SUCCESS); 2315 ns_g_listen = cfg_obj_asuint32(obj); 2316 if (ns_g_listen < 3) 2317 ns_g_listen = 3; 2318 2319 /* 2320 * Configure the interface manager according to the "listen-on" 2321 * statement. 2322 */ 2323 { 2324 const cfg_obj_t *clistenon = NULL; 2325 ns_listenlist_t *listenon = NULL; 2326 2327 clistenon = NULL; 2328 /* 2329 * Even though listen-on is present in the default 2330 * configuration, we can't use it here, since it isn't 2331 * used if we're in lwresd mode. This way is easier. 2332 */ 2333 if (options != NULL) 2334 (void)cfg_map_get(options, "listen-on", &clistenon); 2335 if (clistenon != NULL) { 2336 result = ns_listenlist_fromconfig(clistenon, 2337 config, 2338 &aclconfctx, 2339 ns_g_mctx, 2340 &listenon); 2341 } else if (!ns_g_lwresdonly) { 2342 /* 2343 * Not specified, use default. 2344 */ 2345 CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2346 ISC_TRUE, &listenon)); 2347 } 2348 if (listenon != NULL) { 2349 ns_interfacemgr_setlistenon4(server->interfacemgr, 2350 listenon); 2351 ns_listenlist_detach(&listenon); 2352 } 2353 } 2354 /* 2355 * Ditto for IPv6. 2356 */ 2357 { 2358 const cfg_obj_t *clistenon = NULL; 2359 ns_listenlist_t *listenon = NULL; 2360 2361 if (options != NULL) 2362 (void)cfg_map_get(options, "listen-on-v6", &clistenon); 2363 if (clistenon != NULL) { 2364 result = ns_listenlist_fromconfig(clistenon, 2365 config, 2366 &aclconfctx, 2367 ns_g_mctx, 2368 &listenon); 2369 } else if (!ns_g_lwresdonly) { 2370 /* 2371 * Not specified, use default. 2372 */ 2373 CHECK(ns_listenlist_default(ns_g_mctx, listen_port, 2374 ISC_FALSE, &listenon)); 2375 } 2376 if (listenon != NULL) { 2377 ns_interfacemgr_setlistenon6(server->interfacemgr, 2378 listenon); 2379 ns_listenlist_detach(&listenon); 2380 } 2381 } 2382 2383 /* 2384 * Rescan the interface list to pick up changes in the 2385 * listen-on option. It's important that we do this before we try 2386 * to configure the query source, since the dispatcher we use might 2387 * be shared with an interface. 2388 */ 2389 scan_interfaces(server, ISC_TRUE); 2390 2391 /* 2392 * Arrange for further interface scanning to occur periodically 2393 * as specified by the "interface-interval" option. 2394 */ 2395 obj = NULL; 2396 result = ns_config_get(maps, "interface-interval", &obj); 2397 INSIST(result == ISC_R_SUCCESS); 2398 interface_interval = cfg_obj_asuint32(obj) * 60; 2399 if (interface_interval == 0) { 2400 CHECK(isc_timer_reset(server->interface_timer, 2401 isc_timertype_inactive, 2402 NULL, NULL, ISC_TRUE)); 2403 } else if (server->interface_interval != interface_interval) { 2404 isc_interval_t interval; 2405 isc_interval_set(&interval, interface_interval, 0); 2406 CHECK(isc_timer_reset(server->interface_timer, 2407 isc_timertype_ticker, 2408 NULL, &interval, ISC_FALSE)); 2409 } 2410 server->interface_interval = interface_interval; 2411 2412 /* 2413 * Configure the dialup heartbeat timer. 2414 */ 2415 obj = NULL; 2416 result = ns_config_get(maps, "heartbeat-interval", &obj); 2417 INSIST(result == ISC_R_SUCCESS); 2418 heartbeat_interval = cfg_obj_asuint32(obj) * 60; 2419 if (heartbeat_interval == 0) { 2420 CHECK(isc_timer_reset(server->heartbeat_timer, 2421 isc_timertype_inactive, 2422 NULL, NULL, ISC_TRUE)); 2423 } else if (server->heartbeat_interval != heartbeat_interval) { 2424 isc_interval_t interval; 2425 isc_interval_set(&interval, heartbeat_interval, 0); 2426 CHECK(isc_timer_reset(server->heartbeat_timer, 2427 isc_timertype_ticker, 2428 NULL, &interval, ISC_FALSE)); 2429 } 2430 server->heartbeat_interval = heartbeat_interval; 2431 2432 /* 2433 * Configure and freeze all explicit views. Explicit 2434 * views that have zones were already created at parsing 2435 * time, but views with no zones must be created here. 2436 */ 2437 views = NULL; 2438 (void)cfg_map_get(config, "view", &views); 2439 for (element = cfg_list_first(views); 2440 element != NULL; 2441 element = cfg_list_next(element)) 2442 { 2443 const cfg_obj_t *vconfig = cfg_listelt_value(element); 2444 view = NULL; 2445 2446 CHECK(create_view(vconfig, &viewlist, &view)); 2447 INSIST(view != NULL); 2448 CHECK(configure_view(view, config, vconfig, 2449 ns_g_mctx, &aclconfctx, ISC_TRUE)); 2450 dns_view_freeze(view); 2451 dns_view_detach(&view); 2452 } 2453 2454 /* 2455 * Make sure we have a default view if and only if there 2456 * were no explicit views. 2457 */ 2458 if (views == NULL) { 2459 /* 2460 * No explicit views; there ought to be a default view. 2461 * There may already be one created as a side effect 2462 * of zone statements, or we may have to create one. 2463 * In either case, we need to configure and freeze it. 2464 */ 2465 CHECK(create_view(NULL, &viewlist, &view)); 2466 CHECK(configure_view(view, config, NULL, ns_g_mctx, 2467 &aclconfctx, ISC_TRUE)); 2468 dns_view_freeze(view); 2469 dns_view_detach(&view); 2470 } 2471 2472 /* 2473 * Create (or recreate) the built-in views. Currently 2474 * there is only one, the _bind view. 2475 */ 2476 builtin_views = NULL; 2477 RUNTIME_CHECK(cfg_map_get(ns_g_config, "view", 2478 &builtin_views) == ISC_R_SUCCESS); 2479 for (element = cfg_list_first(builtin_views); 2480 element != NULL; 2481 element = cfg_list_next(element)) 2482 { 2483 const cfg_obj_t *vconfig = cfg_listelt_value(element); 2484 CHECK(create_view(vconfig, &viewlist, &view)); 2485 CHECK(configure_view(view, config, vconfig, ns_g_mctx, 2486 &aclconfctx, ISC_FALSE)); 2487 dns_view_freeze(view); 2488 dns_view_detach(&view); 2489 view = NULL; 2490 } 2491 2492 /* 2493 * Swap our new view list with the production one. 2494 */ 2495 tmpviewlist = server->viewlist; 2496 server->viewlist = viewlist; 2497 viewlist = tmpviewlist; 2498 2499 /* 2500 * Load the TKEY information from the configuration. 2501 */ 2502 if (options != NULL) { 2503 dns_tkeyctx_t *t = NULL; 2504 CHECKM(ns_tkeyctx_fromconfig(options, ns_g_mctx, ns_g_entropy, 2505 &t), 2506 "configuring TKEY"); 2507 if (server->tkeyctx != NULL) 2508 dns_tkeyctx_destroy(&server->tkeyctx); 2509 server->tkeyctx = t; 2510 } 2511 2512 /* 2513 * Bind the control port(s). 2514 */ 2515 CHECKM(ns_controls_configure(ns_g_server->controls, config, 2516 &aclconfctx), 2517 "binding control channel(s)"); 2518 2519 /* 2520 * Bind the lwresd port(s). 2521 */ 2522 CHECKM(ns_lwresd_configure(ns_g_mctx, config), 2523 "binding lightweight resolver ports"); 2524 2525 /* 2526 * Open the source of entropy. 2527 */ 2528 if (first_time) { 2529 obj = NULL; 2530 result = ns_config_get(maps, "random-device", &obj); 2531 if (result != ISC_R_SUCCESS) { 2532 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2533 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 2534 "no source of entropy found"); 2535 } else { 2536 const char *randomdev = cfg_obj_asstring(obj); 2537 result = isc_entropy_createfilesource(ns_g_entropy, 2538 randomdev); 2539 if (result != ISC_R_SUCCESS) 2540 isc_log_write(ns_g_lctx, 2541 NS_LOGCATEGORY_GENERAL, 2542 NS_LOGMODULE_SERVER, 2543 ISC_LOG_INFO, 2544 "could not open entropy source " 2545 "%s: %s", 2546 randomdev, 2547 isc_result_totext(result)); 2548#ifdef PATH_RANDOMDEV 2549 if (ns_g_fallbackentropy != NULL) { 2550 if (result != ISC_R_SUCCESS) { 2551 isc_log_write(ns_g_lctx, 2552 NS_LOGCATEGORY_GENERAL, 2553 NS_LOGMODULE_SERVER, 2554 ISC_LOG_INFO, 2555 "using pre-chroot entropy source " 2556 "%s", 2557 PATH_RANDOMDEV); 2558 isc_entropy_detach(&ns_g_entropy); 2559 isc_entropy_attach(ns_g_fallbackentropy, 2560 &ns_g_entropy); 2561 } 2562 isc_entropy_detach(&ns_g_fallbackentropy); 2563 } 2564#endif 2565 } 2566 } 2567 2568 /* 2569 * Relinquish root privileges. 2570 */ 2571 if (first_time) 2572 ns_os_changeuser(); 2573 2574 /* 2575 * Configure the logging system. 2576 * 2577 * Do this after changing UID to make sure that any log 2578 * files specified in named.conf get created by the 2579 * unprivileged user, not root. 2580 */ 2581 if (ns_g_logstderr) { 2582 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2583 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 2584 "ignoring config file logging " 2585 "statement due to -g option"); 2586 } else { 2587 const cfg_obj_t *logobj = NULL; 2588 isc_logconfig_t *logc = NULL; 2589 2590 CHECKM(isc_logconfig_create(ns_g_lctx, &logc), 2591 "creating new logging configuration"); 2592 2593 logobj = NULL; 2594 (void)cfg_map_get(config, "logging", &logobj); 2595 if (logobj != NULL) { 2596 CHECKM(ns_log_configure(logc, logobj), 2597 "configuring logging"); 2598 } else { 2599 CHECKM(ns_log_setdefaultchannels(logc), 2600 "setting up default logging channels"); 2601 CHECKM(ns_log_setunmatchedcategory(logc), 2602 "setting up default 'category unmatched'"); 2603 CHECKM(ns_log_setdefaultcategory(logc), 2604 "setting up default 'category default'"); 2605 } 2606 2607 result = isc_logconfig_use(ns_g_lctx, logc); 2608 if (result != ISC_R_SUCCESS) { 2609 isc_logconfig_destroy(&logc); 2610 CHECKM(result, "installing logging configuration"); 2611 } 2612 2613 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 2614 NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), 2615 "now using logging configuration from " 2616 "config file"); 2617 } 2618 2619 /* 2620 * Set the default value of the query logging flag depending 2621 * whether a "queries" category has been defined. This is 2622 * a disgusting hack, but we need to do this for BIND 8 2623 * compatibility. 2624 */ 2625 if (first_time) { 2626 const cfg_obj_t *logobj = NULL; 2627 const cfg_obj_t *categories = NULL; 2628 2629 obj = NULL; 2630 if (ns_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) { 2631 server->log_queries = cfg_obj_asboolean(obj); 2632 } else { 2633 2634 (void)cfg_map_get(config, "logging", &logobj); 2635 if (logobj != NULL) 2636 (void)cfg_map_get(logobj, "category", 2637 &categories); 2638 if (categories != NULL) { 2639 const cfg_listelt_t *element; 2640 for (element = cfg_list_first(categories); 2641 element != NULL; 2642 element = cfg_list_next(element)) 2643 { 2644 const cfg_obj_t *catobj; 2645 const char *str; 2646 2647 obj = cfg_listelt_value(element); 2648 catobj = cfg_tuple_get(obj, "name"); 2649 str = cfg_obj_asstring(catobj); 2650 if (strcasecmp(str, "queries") == 0) 2651 server->log_queries = ISC_TRUE; 2652 } 2653 } 2654 } 2655 } 2656 2657 obj = NULL; 2658 if (ns_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) 2659 if (cfg_obj_isvoid(obj)) 2660 ns_os_writepidfile(NULL, first_time); 2661 else 2662 ns_os_writepidfile(cfg_obj_asstring(obj), first_time); 2663 else if (ns_g_lwresdonly) 2664 ns_os_writepidfile(lwresd_g_defaultpidfile, first_time); 2665 else 2666 ns_os_writepidfile(ns_g_defaultpidfile, first_time); 2667 2668 obj = NULL; 2669 if (options != NULL && 2670 cfg_map_get(options, "memstatistics-file", &obj) == ISC_R_SUCCESS) 2671 ns_main_setmemstats(cfg_obj_asstring(obj)); 2672 else 2673 ns_main_setmemstats(NULL); 2674 2675 obj = NULL; 2676 result = ns_config_get(maps, "statistics-file", &obj); 2677 INSIST(result == ISC_R_SUCCESS); 2678 CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)), 2679 "strdup"); 2680 2681 obj = NULL; 2682 result = ns_config_get(maps, "dump-file", &obj); 2683 INSIST(result == ISC_R_SUCCESS); 2684 CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)), 2685 "strdup"); 2686 2687 obj = NULL; 2688 result = ns_config_get(maps, "recursing-file", &obj); 2689 INSIST(result == ISC_R_SUCCESS); 2690 CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)), 2691 "strdup"); 2692 2693 obj = NULL; 2694 result = ns_config_get(maps, "version", &obj); 2695 if (result == ISC_R_SUCCESS) { 2696 CHECKM(setoptstring(server, &server->version, obj), "strdup"); 2697 server->version_set = ISC_TRUE; 2698 } else { 2699 server->version_set = ISC_FALSE; 2700 } 2701 2702 obj = NULL; 2703 result = ns_config_get(maps, "hostname", &obj); 2704 if (result == ISC_R_SUCCESS) { 2705 CHECKM(setoptstring(server, &server->hostname, obj), "strdup"); 2706 server->hostname_set = ISC_TRUE; 2707 } else { 2708 server->hostname_set = ISC_FALSE; 2709 } 2710 2711 obj = NULL; 2712 result = ns_config_get(maps, "server-id", &obj); 2713 server->server_usehostname = ISC_FALSE; 2714 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) { 2715 server->server_usehostname = ISC_TRUE; 2716 } else if (result == ISC_R_SUCCESS) { 2717 CHECKM(setoptstring(server, &server->server_id, obj), "strdup"); 2718 } else { 2719 result = setoptstring(server, &server->server_id, NULL); 2720 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2721 } 2722 2723 obj = NULL; 2724 result = ns_config_get(maps, "flush-zones-on-shutdown", &obj); 2725 if (result == ISC_R_SUCCESS) { 2726 server->flushonshutdown = cfg_obj_asboolean(obj); 2727 } else { 2728 server->flushonshutdown = ISC_FALSE; 2729 } 2730 2731 result = ISC_R_SUCCESS; 2732 2733 cleanup: 2734 ns_aclconfctx_destroy(&aclconfctx); 2735 2736 if (parser != NULL) { 2737 if (config != NULL) 2738 cfg_obj_destroy(parser, &config); 2739 cfg_parser_destroy(&parser); 2740 } 2741 2742 if (view != NULL) 2743 dns_view_detach(&view); 2744 2745 /* 2746 * This cleans up either the old production view list 2747 * or our temporary list depending on whether they 2748 * were swapped above or not. 2749 */ 2750 for (view = ISC_LIST_HEAD(viewlist); 2751 view != NULL; 2752 view = view_next) { 2753 view_next = ISC_LIST_NEXT(view, link); 2754 ISC_LIST_UNLINK(viewlist, view, link); 2755 dns_view_detach(&view); 2756 2757 } 2758 2759 /* 2760 * Adjust the listening interfaces in accordance with the source 2761 * addresses specified in views and zones. 2762 */ 2763 if (isc_net_probeipv6() == ISC_R_SUCCESS) 2764 adjust_interfaces(server, ns_g_mctx); 2765 2766 /* Relinquish exclusive access to configuration data. */ 2767 isc_task_endexclusive(server->task); 2768 2769 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2770 ISC_LOG_DEBUG(1), "load_configuration: %s", 2771 isc_result_totext(result)); 2772 2773 return (result); 2774} 2775 2776static isc_result_t 2777load_zones(ns_server_t *server, isc_boolean_t stop) { 2778 isc_result_t result; 2779 dns_view_t *view; 2780 2781 result = isc_task_beginexclusive(server->task); 2782 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2783 2784 /* 2785 * Load zone data from disk. 2786 */ 2787 for (view = ISC_LIST_HEAD(server->viewlist); 2788 view != NULL; 2789 view = ISC_LIST_NEXT(view, link)) 2790 { 2791 CHECK(dns_view_load(view, stop)); 2792 } 2793 2794 /* 2795 * Force zone maintenance. Do this after loading 2796 * so that we know when we need to force AXFR of 2797 * slave zones whose master files are missing. 2798 */ 2799 CHECK(dns_zonemgr_forcemaint(server->zonemgr)); 2800 cleanup: 2801 isc_task_endexclusive(server->task); 2802 return (result); 2803} 2804 2805static isc_result_t 2806load_new_zones(ns_server_t *server, isc_boolean_t stop) { 2807 isc_result_t result; 2808 dns_view_t *view; 2809 2810 result = isc_task_beginexclusive(server->task); 2811 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2812 2813 /* 2814 * Load zone data from disk. 2815 */ 2816 for (view = ISC_LIST_HEAD(server->viewlist); 2817 view != NULL; 2818 view = ISC_LIST_NEXT(view, link)) 2819 { 2820 CHECK(dns_view_loadnew(view, stop)); 2821 } 2822 /* 2823 * Force zone maintenance. Do this after loading 2824 * so that we know when we need to force AXFR of 2825 * slave zones whose master files are missing. 2826 */ 2827 dns_zonemgr_resumexfrs(server->zonemgr); 2828 cleanup: 2829 isc_task_endexclusive(server->task); 2830 return (result); 2831} 2832 2833static void 2834run_server(isc_task_t *task, isc_event_t *event) { 2835 isc_result_t result; 2836 ns_server_t *server = (ns_server_t *)event->ev_arg; 2837 2838 INSIST(task == server->task); 2839 2840 isc_event_free(&event); 2841 2842 CHECKFATAL(dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, 2843 &ns_g_dispatchmgr), 2844 "creating dispatch manager"); 2845 2846 CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 2847 ns_g_socketmgr, ns_g_dispatchmgr, 2848 &server->interfacemgr), 2849 "creating interface manager"); 2850 2851 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 2852 NULL, NULL, server->task, 2853 interface_timer_tick, 2854 server, &server->interface_timer), 2855 "creating interface timer"); 2856 2857 CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive, 2858 NULL, NULL, server->task, 2859 heartbeat_timer_tick, 2860 server, &server->heartbeat_timer), 2861 "creating heartbeat timer"); 2862 2863 CHECKFATAL(cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser), 2864 "creating default configuration parser"); 2865 2866 if (ns_g_lwresdonly) 2867 CHECKFATAL(load_configuration(lwresd_g_conffile, server, 2868 ISC_TRUE), 2869 "loading configuration"); 2870 else 2871 CHECKFATAL(load_configuration(ns_g_conffile, server, ISC_TRUE), 2872 "loading configuration"); 2873 2874 isc_hash_init(); 2875 2876 CHECKFATAL(load_zones(server, ISC_FALSE), "loading zones"); 2877 2878 ns_os_started(); 2879 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2880 ISC_LOG_NOTICE, "running"); 2881} 2882 2883void 2884ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush) { 2885 2886 REQUIRE(NS_SERVER_VALID(server)); 2887 2888 server->flushonshutdown = flush; 2889} 2890 2891static void 2892shutdown_server(isc_task_t *task, isc_event_t *event) { 2893 isc_result_t result; 2894 dns_view_t *view, *view_next; 2895 ns_server_t *server = (ns_server_t *)event->ev_arg; 2896 isc_boolean_t flush = server->flushonshutdown; 2897 2898 UNUSED(task); 2899 INSIST(task == server->task); 2900 2901 result = isc_task_beginexclusive(server->task); 2902 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2903 2904 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 2905 ISC_LOG_INFO, "shutting down%s", 2906 flush ? ": flushing changes" : ""); 2907 2908 ns_controls_shutdown(server->controls); 2909 end_reserved_dispatches(server, ISC_TRUE); 2910 2911 cfg_obj_destroy(ns_g_parser, &ns_g_config); 2912 cfg_parser_destroy(&ns_g_parser); 2913 2914 for (view = ISC_LIST_HEAD(server->viewlist); 2915 view != NULL; 2916 view = view_next) { 2917 view_next = ISC_LIST_NEXT(view, link); 2918 ISC_LIST_UNLINK(server->viewlist, view, link); 2919 if (flush) 2920 dns_view_flushanddetach(&view); 2921 else 2922 dns_view_detach(&view); 2923 } 2924 2925 isc_timer_detach(&server->interface_timer); 2926 isc_timer_detach(&server->heartbeat_timer); 2927 2928 ns_interfacemgr_shutdown(server->interfacemgr); 2929 ns_interfacemgr_detach(&server->interfacemgr); 2930 2931 dns_dispatchmgr_destroy(&ns_g_dispatchmgr); 2932 2933 dns_zonemgr_shutdown(server->zonemgr); 2934 2935 if (server->blackholeacl != NULL) 2936 dns_acl_detach(&server->blackholeacl); 2937 2938 dns_db_detach(&server->in_roothints); 2939 2940 isc_task_endexclusive(server->task); 2941 2942 isc_task_detach(&server->task); 2943 2944 isc_event_free(&event); 2945} 2946 2947void 2948ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { 2949 isc_result_t result; 2950 2951 ns_server_t *server = isc_mem_get(mctx, sizeof(*server)); 2952 if (server == NULL) 2953 fatal("allocating server object", ISC_R_NOMEMORY); 2954 2955 server->mctx = mctx; 2956 server->task = NULL; 2957 2958 /* Initialize configuration data with default values. */ 2959 2960 result = isc_quota_init(&server->xfroutquota, 10); 2961 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2962 result = isc_quota_init(&server->tcpquota, 10); 2963 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2964 result = isc_quota_init(&server->recursionquota, 100); 2965 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2966 2967 result = dns_aclenv_init(mctx, &server->aclenv); 2968 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2969 2970 /* Initialize server data structures. */ 2971 server->zonemgr = NULL; 2972 server->interfacemgr = NULL; 2973 ISC_LIST_INIT(server->viewlist); 2974 server->in_roothints = NULL; 2975 server->blackholeacl = NULL; 2976 2977 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, 2978 &server->in_roothints), 2979 "setting up root hints"); 2980 2981 CHECKFATAL(isc_mutex_init(&server->reload_event_lock), 2982 "initializing reload event lock"); 2983 server->reload_event = 2984 isc_event_allocate(ns_g_mctx, server, 2985 NS_EVENT_RELOAD, 2986 ns_server_reload, 2987 server, 2988 sizeof(isc_event_t)); 2989 CHECKFATAL(server->reload_event == NULL ? 2990 ISC_R_NOMEMORY : ISC_R_SUCCESS, 2991 "allocating reload event"); 2992 2993 CHECKFATAL(dst_lib_init(ns_g_mctx, ns_g_entropy, ISC_ENTROPY_GOODONLY), 2994 "initializing DST"); 2995 2996 server->tkeyctx = NULL; 2997 CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, 2998 &server->tkeyctx), 2999 "creating TKEY context"); 3000 3001 /* 3002 * Setup the server task, which is responsible for coordinating 3003 * startup and shutdown of the server. 3004 */ 3005 CHECKFATAL(isc_task_create(ns_g_taskmgr, 0, &server->task), 3006 "creating server task"); 3007 isc_task_setname(server->task, "server", server); 3008 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server), 3009 "isc_task_onshutdown"); 3010 CHECKFATAL(isc_app_onrun(ns_g_mctx, server->task, run_server, server), 3011 "isc_app_onrun"); 3012 3013 server->interface_timer = NULL; 3014 server->heartbeat_timer = NULL; 3015 3016 server->interface_interval = 0; 3017 server->heartbeat_interval = 0; 3018 3019 CHECKFATAL(dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr, 3020 ns_g_socketmgr, &server->zonemgr), 3021 "dns_zonemgr_create"); 3022 3023 server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); 3024 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3025 "isc_mem_strdup"); 3026 server->querystats = NULL; 3027 3028 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); 3029 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3030 "isc_mem_strdup"); 3031 3032 server->recfile = isc_mem_strdup(server->mctx, "named.recursing"); 3033 CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, 3034 "isc_mem_strdup"); 3035 3036 server->hostname_set = ISC_FALSE; 3037 server->hostname = NULL; 3038 server->version_set = ISC_FALSE; 3039 server->version = NULL; 3040 server->server_usehostname = ISC_FALSE; 3041 server->server_id = NULL; 3042 3043 CHECKFATAL(dns_stats_alloccounters(ns_g_mctx, &server->querystats), 3044 "dns_stats_alloccounters"); 3045 3046 server->flushonshutdown = ISC_FALSE; 3047 server->log_queries = ISC_FALSE; 3048 3049 server->controls = NULL; 3050 CHECKFATAL(ns_controls_create(server, &server->controls), 3051 "ns_controls_create"); 3052 server->dispatchgen = 0; 3053 ISC_LIST_INIT(server->dispatches); 3054 3055 server->magic = NS_SERVER_MAGIC; 3056 *serverp = server; 3057} 3058 3059void 3060ns_server_destroy(ns_server_t **serverp) { 3061 ns_server_t *server = *serverp; 3062 REQUIRE(NS_SERVER_VALID(server)); 3063 3064 ns_controls_destroy(&server->controls); 3065 3066 dns_stats_freecounters(server->mctx, &server->querystats); 3067 3068 isc_mem_free(server->mctx, server->statsfile); 3069 isc_mem_free(server->mctx, server->dumpfile); 3070 isc_mem_free(server->mctx, server->recfile); 3071 3072 if (server->version != NULL) 3073 isc_mem_free(server->mctx, server->version); 3074 if (server->hostname != NULL) 3075 isc_mem_free(server->mctx, server->hostname); 3076 if (server->server_id != NULL) 3077 isc_mem_free(server->mctx, server->server_id); 3078 3079 dns_zonemgr_detach(&server->zonemgr); 3080 3081 if (server->tkeyctx != NULL) 3082 dns_tkeyctx_destroy(&server->tkeyctx); 3083 3084 dst_lib_destroy(); 3085 3086 isc_event_free(&server->reload_event); 3087 3088 INSIST(ISC_LIST_EMPTY(server->viewlist)); 3089 3090 dns_aclenv_destroy(&server->aclenv); 3091 3092 isc_quota_destroy(&server->recursionquota); 3093 isc_quota_destroy(&server->tcpquota); 3094 isc_quota_destroy(&server->xfroutquota); 3095 3096 server->magic = 0; 3097 isc_mem_put(server->mctx, server, sizeof(*server)); 3098 *serverp = NULL; 3099} 3100 3101static void 3102fatal(const char *msg, isc_result_t result) { 3103 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3104 ISC_LOG_CRITICAL, "%s: %s", msg, 3105 isc_result_totext(result)); 3106 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 3107 ISC_LOG_CRITICAL, "exiting (due to fatal error)"); 3108 exit(1); 3109} 3110 3111static void 3112start_reserved_dispatches(ns_server_t *server) { 3113 3114 REQUIRE(NS_SERVER_VALID(server)); 3115 3116 server->dispatchgen++; 3117} 3118 3119static void 3120end_reserved_dispatches(ns_server_t *server, isc_boolean_t all) { 3121 ns_dispatch_t *dispatch, *nextdispatch; 3122 3123 REQUIRE(NS_SERVER_VALID(server)); 3124 3125 for (dispatch = ISC_LIST_HEAD(server->dispatches); 3126 dispatch != NULL; 3127 dispatch = nextdispatch) { 3128 nextdispatch = ISC_LIST_NEXT(dispatch, link); 3129 if (!all && server->dispatchgen == dispatch-> dispatchgen) 3130 continue; 3131 ISC_LIST_UNLINK(server->dispatches, dispatch, link); 3132 dns_dispatch_detach(&dispatch->dispatch); 3133 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3134 } 3135} 3136 3137void 3138ns_add_reserved_dispatch(ns_server_t *server, const isc_sockaddr_t *addr) { 3139 ns_dispatch_t *dispatch; 3140 in_port_t port; 3141 char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 3142 isc_result_t result; 3143 unsigned int attrs, attrmask; 3144 3145 REQUIRE(NS_SERVER_VALID(server)); 3146 3147 port = isc_sockaddr_getport(addr); 3148 if (port == 0 || port >= 1024) 3149 return; 3150 3151 for (dispatch = ISC_LIST_HEAD(server->dispatches); 3152 dispatch != NULL; 3153 dispatch = ISC_LIST_NEXT(dispatch, link)) { 3154 if (isc_sockaddr_equal(&dispatch->addr, addr)) 3155 break; 3156 } 3157 if (dispatch != NULL) { 3158 dispatch->dispatchgen = server->dispatchgen; 3159 return; 3160 } 3161 3162 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch)); 3163 if (dispatch == NULL) { 3164 result = ISC_R_NOMEMORY; 3165 goto cleanup; 3166 } 3167 3168 dispatch->addr = *addr; 3169 dispatch->dispatchgen = server->dispatchgen; 3170 dispatch->dispatch = NULL; 3171 3172 attrs = 0; 3173 attrs |= DNS_DISPATCHATTR_UDP; 3174 switch (isc_sockaddr_pf(addr)) { 3175 case AF_INET: 3176 attrs |= DNS_DISPATCHATTR_IPV4; 3177 break; 3178 case AF_INET6: 3179 attrs |= DNS_DISPATCHATTR_IPV6; 3180 break; 3181 default: 3182 result = ISC_R_NOTIMPLEMENTED; 3183 goto cleanup; 3184 } 3185 attrmask = 0; 3186 attrmask |= DNS_DISPATCHATTR_UDP; 3187 attrmask |= DNS_DISPATCHATTR_TCP; 3188 attrmask |= DNS_DISPATCHATTR_IPV4; 3189 attrmask |= DNS_DISPATCHATTR_IPV6; 3190 3191 result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, 3192 ns_g_taskmgr, &dispatch->addr, 4096, 3193 1000, 32768, 16411, 16433, 3194 attrs, attrmask, &dispatch->dispatch); 3195 if (result != ISC_R_SUCCESS) 3196 goto cleanup; 3197 3198 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link); 3199 3200 return; 3201 3202 cleanup: 3203 if (dispatch != NULL) 3204 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch)); 3205 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 3206 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3207 NS_LOGMODULE_SERVER, ISC_LOG_WARNING, 3208 "unable to create dispatch for reserved port %s: %s", 3209 addrbuf, isc_result_totext(result)); 3210} 3211 3212 3213static isc_result_t 3214loadconfig(ns_server_t *server) { 3215 isc_result_t result; 3216 start_reserved_dispatches(server); 3217 result = load_configuration(ns_g_lwresdonly ? 3218 lwresd_g_conffile : ns_g_conffile, 3219 server, ISC_FALSE); 3220 if (result == ISC_R_SUCCESS) 3221 end_reserved_dispatches(server, ISC_FALSE); 3222 else 3223 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3224 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3225 "reloading configuration failed: %s", 3226 isc_result_totext(result)); 3227 return (result); 3228} 3229 3230static isc_result_t 3231reload(ns_server_t *server) { 3232 isc_result_t result; 3233 CHECK(loadconfig(server)); 3234 3235 result = load_zones(server, ISC_FALSE); 3236 if (result != ISC_R_SUCCESS) { 3237 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3238 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3239 "reloading zones failed: %s", 3240 isc_result_totext(result)); 3241 } 3242 cleanup: 3243 return (result); 3244} 3245 3246static void 3247reconfig(ns_server_t *server) { 3248 isc_result_t result; 3249 CHECK(loadconfig(server)); 3250 3251 result = load_new_zones(server, ISC_FALSE); 3252 if (result != ISC_R_SUCCESS) { 3253 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3254 NS_LOGMODULE_SERVER, ISC_LOG_ERROR, 3255 "loading new zones failed: %s", 3256 isc_result_totext(result)); 3257 } 3258 cleanup: ; 3259} 3260 3261/* 3262 * Handle a reload event (from SIGHUP). 3263 */ 3264static void 3265ns_server_reload(isc_task_t *task, isc_event_t *event) { 3266 ns_server_t *server = (ns_server_t *)event->ev_arg; 3267 3268 INSIST(task = server->task); 3269 UNUSED(task); 3270 3271 (void)reload(server); 3272 3273 LOCK(&server->reload_event_lock); 3274 INSIST(server->reload_event == NULL); 3275 server->reload_event = event; 3276 UNLOCK(&server->reload_event_lock); 3277} 3278 3279void 3280ns_server_reloadwanted(ns_server_t *server) { 3281 LOCK(&server->reload_event_lock); 3282 if (server->reload_event != NULL) 3283 isc_task_send(server->task, &server->reload_event); 3284 UNLOCK(&server->reload_event_lock); 3285} 3286 3287static char * 3288next_token(char **stringp, const char *delim) { 3289 char *res; 3290 3291 do { 3292 res = strsep(stringp, delim); 3293 if (res == NULL) 3294 break; 3295 } while (*res == '\0'); 3296 return (res); 3297} 3298 3299/* 3300 * Find the zone specified in the control channel command 'args', 3301 * if any. If a zone is specified, point '*zonep' at it, otherwise 3302 * set '*zonep' to NULL. 3303 */ 3304static isc_result_t 3305zone_from_args(ns_server_t *server, char *args, dns_zone_t **zonep) { 3306 char *input, *ptr; 3307 const char *zonetxt; 3308 char *classtxt; 3309 const char *viewtxt = NULL; 3310 dns_fixedname_t name; 3311 isc_result_t result; 3312 isc_buffer_t buf; 3313 dns_view_t *view = NULL; 3314 dns_rdataclass_t rdclass; 3315 3316 REQUIRE(zonep != NULL && *zonep == NULL); 3317 3318 input = args; 3319 3320 /* Skip the command name. */ 3321 ptr = next_token(&input, " \t"); 3322 if (ptr == NULL) 3323 return (ISC_R_UNEXPECTEDEND); 3324 3325 /* Look for the zone name. */ 3326 zonetxt = next_token(&input, " \t"); 3327 if (zonetxt == NULL) 3328 return (ISC_R_SUCCESS); 3329 3330 /* Look for the optional class name. */ 3331 classtxt = next_token(&input, " \t"); 3332 if (classtxt != NULL) { 3333 /* Look for the optional view name. */ 3334 viewtxt = next_token(&input, " \t"); 3335 } 3336 3337 isc_buffer_init(&buf, zonetxt, strlen(zonetxt)); 3338 isc_buffer_add(&buf, strlen(zonetxt)); 3339 dns_fixedname_init(&name); 3340 result = dns_name_fromtext(dns_fixedname_name(&name), 3341 &buf, dns_rootname, ISC_FALSE, NULL); 3342 if (result != ISC_R_SUCCESS) 3343 goto fail1; 3344 3345 if (classtxt != NULL) { 3346 isc_textregion_t r; 3347 r.base = classtxt; 3348 r.length = strlen(classtxt); 3349 result = dns_rdataclass_fromtext(&rdclass, &r); 3350 if (result != ISC_R_SUCCESS) 3351 goto fail1; 3352 } else { 3353 rdclass = dns_rdataclass_in; 3354 } 3355 3356 if (viewtxt == NULL) 3357 viewtxt = "_default"; 3358 result = dns_viewlist_find(&server->viewlist, viewtxt, 3359 rdclass, &view); 3360 if (result != ISC_R_SUCCESS) 3361 goto fail1; 3362 3363 result = dns_zt_find(view->zonetable, dns_fixedname_name(&name), 3364 0, NULL, zonep); 3365 /* Partial match? */ 3366 if (result != ISC_R_SUCCESS && *zonep != NULL) 3367 dns_zone_detach(zonep); 3368 dns_view_detach(&view); 3369 fail1: 3370 return (result); 3371} 3372 3373/* 3374 * Act on a "retransfer" command from the command channel. 3375 */ 3376isc_result_t 3377ns_server_retransfercommand(ns_server_t *server, char *args) { 3378 isc_result_t result; 3379 dns_zone_t *zone = NULL; 3380 dns_zonetype_t type; 3381 3382 result = zone_from_args(server, args, &zone); 3383 if (result != ISC_R_SUCCESS) 3384 return (result); 3385 if (zone == NULL) 3386 return (ISC_R_UNEXPECTEDEND); 3387 type = dns_zone_gettype(zone); 3388 if (type == dns_zone_slave || type == dns_zone_stub) 3389 dns_zone_forcereload(zone); 3390 else 3391 result = ISC_R_NOTFOUND; 3392 dns_zone_detach(&zone); 3393 return (result); 3394} 3395 3396/* 3397 * Act on a "reload" command from the command channel. 3398 */ 3399isc_result_t 3400ns_server_reloadcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 3401 isc_result_t result; 3402 dns_zone_t *zone = NULL; 3403 dns_zonetype_t type; 3404 const char *msg = NULL; 3405 3406 result = zone_from_args(server, args, &zone); 3407 if (result != ISC_R_SUCCESS) 3408 return (result); 3409 if (zone == NULL) { 3410 result = reload(server); 3411 if (result == ISC_R_SUCCESS) 3412 msg = "server reload successful"; 3413 } else { 3414 type = dns_zone_gettype(zone); 3415 if (type == dns_zone_slave || type == dns_zone_stub) { 3416 dns_zone_refresh(zone); 3417 msg = "zone refresh queued"; 3418 } else { 3419 result = dns_zone_load(zone); 3420 dns_zone_detach(&zone); 3421 switch (result) { 3422 case ISC_R_SUCCESS: 3423 msg = "zone reload successful"; 3424 break; 3425 case DNS_R_CONTINUE: 3426 msg = "zone reload queued"; 3427 result = ISC_R_SUCCESS; 3428 break; 3429 case DNS_R_UPTODATE: 3430 msg = "zone reload up-to-date"; 3431 result = ISC_R_SUCCESS; 3432 break; 3433 default: 3434 /* failure message will be generated by rndc */ 3435 break; 3436 } 3437 } 3438 } 3439 if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) 3440 isc_buffer_putmem(text, (const unsigned char *)msg, 3441 strlen(msg) + 1); 3442 return (result); 3443} 3444 3445/* 3446 * Act on a "reconfig" command from the command channel. 3447 */ 3448isc_result_t 3449ns_server_reconfigcommand(ns_server_t *server, char *args) { 3450 UNUSED(args); 3451 3452 reconfig(server); 3453 return (ISC_R_SUCCESS); 3454} 3455 3456/* 3457 * Act on a "refresh" command from the command channel. 3458 */ 3459isc_result_t 3460ns_server_refreshcommand(ns_server_t *server, char *args, isc_buffer_t *text) { 3461 isc_result_t result; 3462 dns_zone_t *zone = NULL; 3463 const unsigned char msg1[] = "zone refresh queued"; 3464 const unsigned char msg2[] = "not a slave or stub zone"; 3465 dns_zonetype_t type; 3466 3467 result = zone_from_args(server, args, &zone); 3468 if (result != ISC_R_SUCCESS) 3469 return (result); 3470 if (zone == NULL) 3471 return (ISC_R_UNEXPECTEDEND); 3472 3473 type = dns_zone_gettype(zone); 3474 if (type == dns_zone_slave || type == dns_zone_stub) { 3475 dns_zone_refresh(zone); 3476 dns_zone_detach(&zone); 3477 if (sizeof(msg1) <= isc_buffer_availablelength(text)) 3478 isc_buffer_putmem(text, msg1, sizeof(msg1)); 3479 return (ISC_R_SUCCESS); 3480 } 3481 3482 dns_zone_detach(&zone); 3483 if (sizeof(msg2) <= isc_buffer_availablelength(text)) 3484 isc_buffer_putmem(text, msg2, sizeof(msg2)); 3485 return (ISC_R_FAILURE); 3486} 3487 3488isc_result_t 3489ns_server_togglequerylog(ns_server_t *server) { 3490 server->log_queries = server->log_queries ? ISC_FALSE : ISC_TRUE; 3491 3492 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3493 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3494 "query logging is now %s", 3495 server->log_queries ? "on" : "off"); 3496 return (ISC_R_SUCCESS); 3497} 3498 3499static isc_result_t 3500ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config, 3501 ns_aclconfctx_t *actx, 3502 isc_mem_t *mctx, ns_listenlist_t **target) 3503{ 3504 isc_result_t result; 3505 const cfg_listelt_t *element; 3506 ns_listenlist_t *dlist = NULL; 3507 3508 REQUIRE(target != NULL && *target == NULL); 3509 3510 result = ns_listenlist_create(mctx, &dlist); 3511 if (result != ISC_R_SUCCESS) 3512 return (result); 3513 3514 for (element = cfg_list_first(listenlist); 3515 element != NULL; 3516 element = cfg_list_next(element)) 3517 { 3518 ns_listenelt_t *delt = NULL; 3519 const cfg_obj_t *listener = cfg_listelt_value(element); 3520 result = ns_listenelt_fromconfig(listener, config, actx, 3521 mctx, &delt); 3522 if (result != ISC_R_SUCCESS) 3523 goto cleanup; 3524 ISC_LIST_APPEND(dlist->elts, delt, link); 3525 } 3526 *target = dlist; 3527 return (ISC_R_SUCCESS); 3528 3529 cleanup: 3530 ns_listenlist_detach(&dlist); 3531 return (result); 3532} 3533 3534/* 3535 * Create a listen list from the corresponding configuration 3536 * data structure. 3537 */ 3538static isc_result_t 3539ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, 3540 ns_aclconfctx_t *actx, 3541 isc_mem_t *mctx, ns_listenelt_t **target) 3542{ 3543 isc_result_t result; 3544 const cfg_obj_t *portobj; 3545 in_port_t port; 3546 ns_listenelt_t *delt = NULL; 3547 REQUIRE(target != NULL && *target == NULL); 3548 3549 portobj = cfg_tuple_get(listener, "port"); 3550 if (!cfg_obj_isuint32(portobj)) { 3551 if (ns_g_port != 0) { 3552 port = ns_g_port; 3553 } else { 3554 result = ns_config_getport(config, &port); 3555 if (result != ISC_R_SUCCESS) 3556 return (result); 3557 } 3558 } else { 3559 if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { 3560 cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, 3561 "port value '%u' is out of range", 3562 cfg_obj_asuint32(portobj)); 3563 return (ISC_R_RANGE); 3564 } 3565 port = (in_port_t)cfg_obj_asuint32(portobj); 3566 } 3567 3568 result = ns_listenelt_create(mctx, port, NULL, &delt); 3569 if (result != ISC_R_SUCCESS) 3570 return (result); 3571 3572 result = ns_acl_fromconfig(cfg_tuple_get(listener, "acl"), 3573 config, actx, mctx, &delt->acl); 3574 if (result != ISC_R_SUCCESS) { 3575 ns_listenelt_destroy(delt); 3576 return (result); 3577 } 3578 *target = delt; 3579 return (ISC_R_SUCCESS); 3580} 3581 3582isc_result_t 3583ns_server_dumpstats(ns_server_t *server) { 3584 isc_result_t result; 3585 dns_zone_t *zone, *next; 3586 isc_stdtime_t now; 3587 FILE *fp = NULL; 3588 int i; 3589 int ncounters; 3590 3591 isc_stdtime_get(&now); 3592 3593 CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), 3594 "could not open statistics dump file", server->statsfile); 3595 3596 ncounters = DNS_STATS_NCOUNTERS; 3597 fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); 3598 3599 for (i = 0; i < ncounters; i++) 3600 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", 3601 dns_statscounter_names[i], 3602 server->querystats[i]); 3603 3604 zone = NULL; 3605 for (result = dns_zone_first(server->zonemgr, &zone); 3606 result == ISC_R_SUCCESS; 3607 next = NULL, result = dns_zone_next(zone, &next), zone = next) 3608 { 3609 isc_uint64_t *zonestats = dns_zone_getstatscounters(zone); 3610 if (zonestats != NULL) { 3611 char zonename[DNS_NAME_FORMATSIZE]; 3612 dns_view_t *view; 3613 char *viewname; 3614 3615 dns_name_format(dns_zone_getorigin(zone), 3616 zonename, sizeof(zonename)); 3617 view = dns_zone_getview(zone); 3618 viewname = view->name; 3619 for (i = 0; i < ncounters; i++) { 3620 fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT 3621 "u %s", 3622 dns_statscounter_names[i], 3623 zonestats[i], 3624 zonename); 3625 if (strcmp(viewname, "_default") != 0) 3626 fprintf(fp, " %s", viewname); 3627 fprintf(fp, "\n"); 3628 } 3629 } 3630 } 3631 if (result == ISC_R_NOMORE) 3632 result = ISC_R_SUCCESS; 3633 CHECK(result); 3634 3635 fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); 3636 3637 cleanup: 3638 if (fp != NULL) 3639 (void)isc_stdio_close(fp); 3640 return (result); 3641} 3642 3643static isc_result_t 3644add_zone_tolist(dns_zone_t *zone, void *uap) { 3645 struct dumpcontext *dctx = uap; 3646 struct zonelistentry *zle; 3647 3648 zle = isc_mem_get(dctx->mctx, sizeof *zle); 3649 if (zle == NULL) 3650 return (ISC_R_NOMEMORY); 3651 zle->zone = NULL; 3652 dns_zone_attach(zone, &zle->zone); 3653 ISC_LINK_INIT(zle, link); 3654 ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link); 3655 return (ISC_R_SUCCESS); 3656} 3657 3658static isc_result_t 3659add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) { 3660 struct viewlistentry *vle; 3661 isc_result_t result = ISC_R_SUCCESS; 3662 3663 /* 3664 * Prevent duplicate views. 3665 */ 3666 for (vle = ISC_LIST_HEAD(dctx->viewlist); 3667 vle != NULL; 3668 vle = ISC_LIST_NEXT(vle, link)) 3669 if (vle->view == view) 3670 return (ISC_R_SUCCESS); 3671 3672 vle = isc_mem_get(dctx->mctx, sizeof *vle); 3673 if (vle == NULL) 3674 return (ISC_R_NOMEMORY); 3675 vle->view = NULL; 3676 dns_view_attach(view, &vle->view); 3677 ISC_LINK_INIT(vle, link); 3678 ISC_LIST_INIT(vle->zonelist); 3679 ISC_LIST_APPEND(dctx->viewlist, vle, link); 3680 if (dctx->dumpzones) 3681 result = dns_zt_apply(view->zonetable, ISC_TRUE, 3682 add_zone_tolist, dctx); 3683 return (result); 3684} 3685 3686static void 3687dumpcontext_destroy(struct dumpcontext *dctx) { 3688 struct viewlistentry *vle; 3689 struct zonelistentry *zle; 3690 3691 vle = ISC_LIST_HEAD(dctx->viewlist); 3692 while (vle != NULL) { 3693 ISC_LIST_UNLINK(dctx->viewlist, vle, link); 3694 zle = ISC_LIST_HEAD(vle->zonelist); 3695 while (zle != NULL) { 3696 ISC_LIST_UNLINK(vle->zonelist, zle, link); 3697 dns_zone_detach(&zle->zone); 3698 isc_mem_put(dctx->mctx, zle, sizeof *zle); 3699 zle = ISC_LIST_HEAD(vle->zonelist); 3700 } 3701 dns_view_detach(&vle->view); 3702 isc_mem_put(dctx->mctx, vle, sizeof *vle); 3703 vle = ISC_LIST_HEAD(dctx->viewlist); 3704 } 3705 if (dctx->version != NULL) 3706 dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE); 3707 if (dctx->db != NULL) 3708 dns_db_detach(&dctx->db); 3709 if (dctx->cache != NULL) 3710 dns_db_detach(&dctx->cache); 3711 if (dctx->task != NULL) 3712 isc_task_detach(&dctx->task); 3713 if (dctx->fp != NULL) 3714 (void)isc_stdio_close(dctx->fp); 3715 if (dctx->mdctx != NULL) 3716 dns_dumpctx_detach(&dctx->mdctx); 3717 isc_mem_put(dctx->mctx, dctx, sizeof *dctx); 3718} 3719 3720static void 3721dumpdone(void *arg, isc_result_t result) { 3722 struct dumpcontext *dctx = arg; 3723 char buf[1024+32]; 3724 const dns_master_style_t *style; 3725 3726 if (result != ISC_R_SUCCESS) 3727 goto cleanup; 3728 if (dctx->mdctx != NULL) 3729 dns_dumpctx_detach(&dctx->mdctx); 3730 if (dctx->view == NULL) { 3731 dctx->view = ISC_LIST_HEAD(dctx->viewlist); 3732 if (dctx->view == NULL) 3733 goto done; 3734 INSIST(dctx->zone == NULL); 3735 } else 3736 goto resume; 3737 nextview: 3738 fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name); 3739 resume: 3740 if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) { 3741 style = &dns_master_style_cache; 3742 /* start cache dump */ 3743 if (dctx->view->view->cachedb != NULL) 3744 dns_db_attach(dctx->view->view->cachedb, &dctx->cache); 3745 if (dctx->cache != NULL) { 3746 3747 fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n", 3748 dctx->view->view->name); 3749 result = dns_master_dumptostreaminc(dctx->mctx, 3750 dctx->cache, NULL, 3751 style, dctx->fp, 3752 dctx->task, 3753 dumpdone, dctx, 3754 &dctx->mdctx); 3755 if (result == DNS_R_CONTINUE) 3756 return; 3757 if (result == ISC_R_NOTIMPLEMENTED) 3758 fprintf(dctx->fp, "; %s\n", 3759 dns_result_totext(result)); 3760 else if (result != ISC_R_SUCCESS) 3761 goto cleanup; 3762 } 3763 } 3764 if (dctx->cache != NULL) { 3765 dns_adb_dump(dctx->view->view->adb, dctx->fp); 3766 dns_db_detach(&dctx->cache); 3767 } 3768 if (dctx->dumpzones) { 3769 style = &dns_master_style_full; 3770 nextzone: 3771 if (dctx->version != NULL) 3772 dns_db_closeversion(dctx->db, &dctx->version, 3773 ISC_FALSE); 3774 if (dctx->db != NULL) 3775 dns_db_detach(&dctx->db); 3776 if (dctx->zone == NULL) 3777 dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist); 3778 else 3779 dctx->zone = ISC_LIST_NEXT(dctx->zone, link); 3780 if (dctx->zone != NULL) { 3781 /* start zone dump */ 3782 dns_zone_name(dctx->zone->zone, buf, sizeof(buf)); 3783 fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf); 3784 result = dns_zone_getdb(dctx->zone->zone, &dctx->db); 3785 if (result != ISC_R_SUCCESS) { 3786 fprintf(dctx->fp, "; %s\n", 3787 dns_result_totext(result)); 3788 goto nextzone; 3789 } 3790 dns_db_currentversion(dctx->db, &dctx->version); 3791 result = dns_master_dumptostreaminc(dctx->mctx, 3792 dctx->db, 3793 dctx->version, 3794 style, dctx->fp, 3795 dctx->task, 3796 dumpdone, dctx, 3797 &dctx->mdctx); 3798 if (result == DNS_R_CONTINUE) 3799 return; 3800 if (result == ISC_R_NOTIMPLEMENTED) { 3801 fprintf(dctx->fp, "; %s\n", 3802 dns_result_totext(result)); 3803 result = ISC_R_SUCCESS; 3804 goto nextzone; 3805 } 3806 if (result != ISC_R_SUCCESS) 3807 goto cleanup; 3808 } 3809 } 3810 if (dctx->view != NULL) 3811 dctx->view = ISC_LIST_NEXT(dctx->view, link); 3812 if (dctx->view != NULL) 3813 goto nextview; 3814 done: 3815 fprintf(dctx->fp, "; Dump complete\n"); 3816 result = isc_stdio_flush(dctx->fp); 3817 if (result == ISC_R_SUCCESS) 3818 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3819 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3820 "dumpdb complete"); 3821 cleanup: 3822 if (result != ISC_R_SUCCESS) 3823 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3824 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3825 "dumpdb failed: %s", dns_result_totext(result)); 3826 dumpcontext_destroy(dctx); 3827} 3828 3829isc_result_t 3830ns_server_dumpdb(ns_server_t *server, char *args) { 3831 struct dumpcontext *dctx = NULL; 3832 dns_view_t *view; 3833 isc_result_t result; 3834 char *ptr; 3835 const char *sep; 3836 3837 /* Skip the command name. */ 3838 ptr = next_token(&args, " \t"); 3839 if (ptr == NULL) 3840 return (ISC_R_UNEXPECTEDEND); 3841 3842 dctx = isc_mem_get(server->mctx, sizeof(*dctx)); 3843 if (dctx == NULL) 3844 return (ISC_R_NOMEMORY); 3845 3846 dctx->mctx = server->mctx; 3847 dctx->dumpcache = ISC_TRUE; 3848 dctx->dumpzones = ISC_FALSE; 3849 dctx->fp = NULL; 3850 ISC_LIST_INIT(dctx->viewlist); 3851 dctx->view = NULL; 3852 dctx->zone = NULL; 3853 dctx->cache = NULL; 3854 dctx->mdctx = NULL; 3855 dctx->db = NULL; 3856 dctx->cache = NULL; 3857 dctx->task = NULL; 3858 dctx->version = NULL; 3859 isc_task_attach(server->task, &dctx->task); 3860 3861 CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp), 3862 "could not open dump file", server->dumpfile); 3863 3864 sep = (args == NULL) ? "" : ": "; 3865 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 3866 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 3867 "dumpdb started%s%s", sep, (args != NULL) ? args : ""); 3868 3869 ptr = next_token(&args, " \t"); 3870 if (ptr != NULL && strcmp(ptr, "-all") == 0) { 3871 dctx->dumpzones = ISC_TRUE; 3872 dctx->dumpcache = ISC_TRUE; 3873 ptr = next_token(&args, " \t"); 3874 } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) { 3875 dctx->dumpzones = ISC_FALSE; 3876 dctx->dumpcache = ISC_TRUE; 3877 ptr = next_token(&args, " \t"); 3878 } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) { 3879 dctx->dumpzones = ISC_TRUE; 3880 dctx->dumpcache = ISC_FALSE; 3881 ptr = next_token(&args, " \t"); 3882 } 3883 3884 nextview: 3885 for (view = ISC_LIST_HEAD(server->viewlist); 3886 view != NULL; 3887 view = ISC_LIST_NEXT(view, link)) 3888 { 3889 if (ptr != NULL && strcmp(view->name, ptr) != 0) 3890 continue; 3891 CHECK(add_view_tolist(dctx, view)); 3892 } 3893 if (ptr != NULL) { 3894 ptr = next_token(&args, " \t"); 3895 if (ptr != NULL) 3896 goto nextview; 3897 } 3898 dumpdone(dctx, ISC_R_SUCCESS); 3899 return (ISC_R_SUCCESS); 3900 3901 cleanup: 3902 if (dctx != NULL) 3903 dumpcontext_destroy(dctx); 3904 return (result); 3905} 3906 3907isc_result_t 3908ns_server_dumprecursing(ns_server_t *server) { 3909 FILE *fp = NULL; 3910 isc_result_t result; 3911 3912 CHECKMF(isc_stdio_open(server->recfile, "w", &fp), 3913 "could not open dump file", server->recfile); 3914 fprintf(fp,";\n; Recursing Queries\n;\n"); 3915 ns_interfacemgr_dumprecursing(fp, server->interfacemgr); 3916 fprintf(fp, "; Dump complete\n"); 3917 3918 cleanup: 3919 if (fp != NULL) 3920 result = isc_stdio_close(fp); 3921 return (result); 3922} 3923 3924isc_result_t 3925ns_server_setdebuglevel(ns_server_t *server, char *args) { 3926 char *ptr; 3927 char *levelstr; 3928 char *endp; 3929 long newlevel; 3930 3931 UNUSED(server); 3932 3933 /* Skip the command name. */ 3934 ptr = next_token(&args, " \t"); 3935 if (ptr == NULL) 3936 return (ISC_R_UNEXPECTEDEND); 3937 3938 /* Look for the new level name. */ 3939 levelstr = next_token(&args, " \t"); 3940 if (levelstr == NULL) { 3941 if (ns_g_debuglevel < 99) 3942 ns_g_debuglevel++; 3943 } else { 3944 newlevel = strtol(levelstr, &endp, 10); 3945 if (*endp != '\0' || newlevel < 0 || newlevel > 99) 3946 return (ISC_R_RANGE); 3947 ns_g_debuglevel = (unsigned int)newlevel; 3948 } 3949 isc_log_setdebuglevel(ns_g_lctx, ns_g_debuglevel); 3950 return (ISC_R_SUCCESS); 3951} 3952 3953isc_result_t 3954ns_server_flushcache(ns_server_t *server, char *args) { 3955 char *ptr, *viewname; 3956 dns_view_t *view; 3957 isc_boolean_t flushed = ISC_FALSE; 3958 isc_result_t result; 3959 3960 /* Skip the command name. */ 3961 ptr = next_token(&args, " \t"); 3962 if (ptr == NULL) 3963 return (ISC_R_UNEXPECTEDEND); 3964 3965 /* Look for the view name. */ 3966 viewname = next_token(&args, " \t"); 3967 3968 result = isc_task_beginexclusive(server->task); 3969 RUNTIME_CHECK(result == ISC_R_SUCCESS); 3970 for (view = ISC_LIST_HEAD(server->viewlist); 3971 view != NULL; 3972 view = ISC_LIST_NEXT(view, link)) 3973 { 3974 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 3975 continue; 3976 result = dns_view_flushcache(view); 3977 if (result != ISC_R_SUCCESS) 3978 goto out; 3979 flushed = ISC_TRUE; 3980 } 3981 if (flushed) 3982 result = ISC_R_SUCCESS; 3983 else 3984 result = ISC_R_FAILURE; 3985 out: 3986 isc_task_endexclusive(server->task); 3987 return (result); 3988} 3989 3990isc_result_t 3991ns_server_flushname(ns_server_t *server, char *args) { 3992 char *ptr, *target, *viewname; 3993 dns_view_t *view; 3994 isc_boolean_t flushed = ISC_FALSE; 3995 isc_result_t result; 3996 isc_buffer_t b; 3997 dns_fixedname_t fixed; 3998 dns_name_t *name; 3999 4000 /* Skip the command name. */ 4001 ptr = next_token(&args, " \t"); 4002 if (ptr == NULL) 4003 return (ISC_R_UNEXPECTEDEND); 4004 4005 /* Find the domain name to flush. */ 4006 target = next_token(&args, " \t"); 4007 if (target == NULL) 4008 return (ISC_R_UNEXPECTEDEND); 4009 4010 isc_buffer_init(&b, target, strlen(target)); 4011 isc_buffer_add(&b, strlen(target)); 4012 dns_fixedname_init(&fixed); 4013 name = dns_fixedname_name(&fixed); 4014 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL); 4015 if (result != ISC_R_SUCCESS) 4016 return (result); 4017 4018 /* Look for the view name. */ 4019 viewname = next_token(&args, " \t"); 4020 4021 result = isc_task_beginexclusive(server->task); 4022 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4023 flushed = ISC_TRUE; 4024 for (view = ISC_LIST_HEAD(server->viewlist); 4025 view != NULL; 4026 view = ISC_LIST_NEXT(view, link)) 4027 { 4028 if (viewname != NULL && strcasecmp(viewname, view->name) != 0) 4029 continue; 4030 result = dns_view_flushname(view, name); 4031 if (result != ISC_R_SUCCESS) 4032 flushed = ISC_FALSE; 4033 } 4034 if (flushed) 4035 result = ISC_R_SUCCESS; 4036 else 4037 result = ISC_R_FAILURE; 4038 isc_task_endexclusive(server->task); 4039 return (result); 4040} 4041 4042isc_result_t 4043ns_server_status(ns_server_t *server, isc_buffer_t *text) { 4044 int zonecount, xferrunning, xferdeferred, soaqueries; 4045 unsigned int n; 4046 4047 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY); 4048 xferrunning = dns_zonemgr_getcount(server->zonemgr, 4049 DNS_ZONESTATE_XFERRUNNING); 4050 xferdeferred = dns_zonemgr_getcount(server->zonemgr, 4051 DNS_ZONESTATE_XFERDEFERRED); 4052 soaqueries = dns_zonemgr_getcount(server->zonemgr, 4053 DNS_ZONESTATE_SOAQUERY); 4054 n = snprintf((char *)isc_buffer_used(text), 4055 isc_buffer_availablelength(text), 4056 "number of zones: %u\n" 4057 "debug level: %d\n" 4058 "xfers running: %u\n" 4059 "xfers deferred: %u\n" 4060 "soa queries in progress: %u\n" 4061 "query logging is %s\n" 4062 "recursive clients: %d/%d\n" 4063 "tcp clients: %d/%d\n" 4064 "server is up and running", 4065 zonecount, ns_g_debuglevel, xferrunning, xferdeferred, 4066 soaqueries, server->log_queries ? "ON" : "OFF", 4067 server->recursionquota.used, server->recursionquota.max, 4068 server->tcpquota.used, server->tcpquota.max); 4069 if (n >= isc_buffer_availablelength(text)) 4070 return (ISC_R_NOSPACE); 4071 isc_buffer_add(text, n); 4072 return (ISC_R_SUCCESS); 4073} 4074 4075/* 4076 * Act on a "freeze" or "unfreeze" command from the command channel. 4077 */ 4078isc_result_t 4079ns_server_freeze(ns_server_t *server, isc_boolean_t freeze, char *args) { 4080 isc_result_t result; 4081 dns_zone_t *zone = NULL; 4082 dns_zonetype_t type; 4083 char classstr[DNS_RDATACLASS_FORMATSIZE]; 4084 char zonename[DNS_NAME_FORMATSIZE]; 4085 dns_view_t *view; 4086 char *journal; 4087 const char *vname, *sep; 4088 isc_boolean_t frozen; 4089 4090 result = zone_from_args(server, args, &zone); 4091 if (result != ISC_R_SUCCESS) 4092 return (result); 4093 if (zone == NULL) 4094 return (ISC_R_UNEXPECTEDEND); 4095 type = dns_zone_gettype(zone); 4096 if (type != dns_zone_master) { 4097 dns_zone_detach(&zone); 4098 return (ISC_R_NOTFOUND); 4099 } 4100 4101 frozen = dns_zone_getupdatedisabled(zone); 4102 if (freeze) { 4103 if (frozen) 4104 result = DNS_R_FROZEN; 4105 if (result == ISC_R_SUCCESS) 4106 result = dns_zone_flush(zone); 4107 if (result == ISC_R_SUCCESS) { 4108 journal = dns_zone_getjournal(zone); 4109 if (journal != NULL) 4110 (void)isc_file_remove(journal); 4111 } 4112 } else { 4113 if (frozen) { 4114 result = dns_zone_load(zone); 4115 if (result == DNS_R_CONTINUE || 4116 result == DNS_R_UPTODATE) 4117 result = ISC_R_SUCCESS; 4118 } 4119 } 4120 if (result == ISC_R_SUCCESS) 4121 dns_zone_setupdatedisabled(zone, freeze); 4122 4123 view = dns_zone_getview(zone); 4124 if (strcmp(view->name, "_bind") == 0 || 4125 strcmp(view->name, "_default") == 0) 4126 { 4127 vname = ""; 4128 sep = ""; 4129 } else { 4130 vname = view->name; 4131 sep = " "; 4132 } 4133 dns_rdataclass_format(dns_zone_getclass(zone), classstr, 4134 sizeof(classstr)); 4135 dns_name_format(dns_zone_getorigin(zone), 4136 zonename, sizeof(zonename)); 4137 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 4138 NS_LOGMODULE_SERVER, ISC_LOG_INFO, 4139 "%s zone '%s/%s'%s%s: %s", 4140 freeze ? "freezing" : "unfreezing", 4141 zonename, classstr, sep, vname, 4142 isc_result_totext(result)); 4143 dns_zone_detach(&zone); 4144 return (result); 4145} 4146 4147#ifdef HAVE_LIBSCF 4148/* 4149 * This function adds a message for rndc to echo if named 4150 * is managed by smf and is also running chroot. 4151 */ 4152isc_result_t 4153ns_smf_add_message(isc_buffer_t *text) { 4154 unsigned int n; 4155 4156 n = snprintf((char *)isc_buffer_used(text), 4157 isc_buffer_availablelength(text), 4158 "use svcadm(1M) to manage named"); 4159 if (n >= isc_buffer_availablelength(text)) 4160 return (ISC_R_NOSPACE); 4161 isc_buffer_add(text, n); 4162 return (ISC_R_SUCCESS); 4163} 4164#endif /* HAVE_LIBSCF */ 4165