1/* 2 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or 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: main.c,v 1.180.14.4 2011/11/05 00:45:52 each Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <ctype.h> 25#include <stdlib.h> 26#include <string.h> 27 28#include <isc/app.h> 29#include <isc/backtrace.h> 30#include <isc/commandline.h> 31#include <isc/dir.h> 32#include <isc/entropy.h> 33#include <isc/file.h> 34#include <isc/hash.h> 35#include <isc/os.h> 36#include <isc/platform.h> 37#include <isc/print.h> 38#include <isc/resource.h> 39#include <isc/stdio.h> 40#include <isc/string.h> 41#include <isc/task.h> 42#include <isc/timer.h> 43#include <isc/util.h> 44 45#include <isccc/result.h> 46 47#include <dns/dispatch.h> 48#include <dns/name.h> 49#include <dns/result.h> 50#include <dns/view.h> 51 52#include <dst/result.h> 53 54#include <dlz/dlz_dlopen_driver.h> 55 56/* 57 * Defining NS_MAIN provides storage declarations (rather than extern) 58 * for variables in named/globals.h. 59 */ 60#define NS_MAIN 1 61 62#include <named/builtin.h> 63#include <named/control.h> 64#include <named/globals.h> /* Explicit, though named/log.h includes it. */ 65#include <named/interfacemgr.h> 66#include <named/log.h> 67#include <named/os.h> 68#include <named/server.h> 69#include <named/lwresd.h> 70#include <named/main.h> 71#ifdef HAVE_LIBSCF 72#include <named/ns_smf_globals.h> 73#endif 74 75#include <notify.h> 76#include <notify_keys.h> 77 78#ifdef OPENSSL 79#include <openssl/opensslv.h> 80#endif 81#ifdef HAVE_LIBXML2 82#include <libxml/xmlversion.h> 83#endif 84/* 85 * Include header files for database drivers here. 86 */ 87/* #include "xxdb.h" */ 88 89#ifdef CONTRIB_DLZ 90/* 91 * Include contributed DLZ drivers if appropriate. 92 */ 93#include <dlz/dlz_drivers.h> 94#endif 95 96/* 97 * The maximum number of stack frames to dump on assertion failure. 98 */ 99#ifndef BACKTRACE_MAXFRAME 100#define BACKTRACE_MAXFRAME 128 101#endif 102 103static isc_boolean_t want_stats = ISC_FALSE; 104static char program_name[ISC_DIR_NAMEMAX] = "named"; 105static char absolute_conffile[ISC_DIR_PATHMAX]; 106static char saved_command_line[512]; 107static char version[512]; 108static unsigned int maxsocks = 0; 109static int maxudp = 0; 110 111void 112ns_main_earlywarning(const char *format, ...) { 113 va_list args; 114 115 va_start(args, format); 116 if (ns_g_lctx != NULL) { 117 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 118 NS_LOGMODULE_MAIN, ISC_LOG_WARNING, 119 format, args); 120 } else { 121 fprintf(stderr, "%s: ", program_name); 122 vfprintf(stderr, format, args); 123 fprintf(stderr, "\n"); 124 fflush(stderr); 125 } 126 va_end(args); 127} 128 129void 130ns_main_earlyfatal(const char *format, ...) { 131 va_list args; 132 133 va_start(args, format); 134 if (ns_g_lctx != NULL) { 135 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 136 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 137 format, args); 138 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 139 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 140 "exiting (due to early fatal error)"); 141 } else { 142 fprintf(stderr, "%s: ", program_name); 143 vfprintf(stderr, format, args); 144 fprintf(stderr, "\n"); 145 fflush(stderr); 146 } 147 va_end(args); 148 149 exit(1); 150} 151 152ISC_PLATFORM_NORETURN_PRE static void 153assertion_failed(const char *file, int line, isc_assertiontype_t type, 154 const char *cond) ISC_PLATFORM_NORETURN_POST; 155 156static void 157assertion_failed(const char *file, int line, isc_assertiontype_t type, 158 const char *cond) 159{ 160 void *tracebuf[BACKTRACE_MAXFRAME]; 161 int i, nframes; 162 isc_result_t result; 163 const char *logsuffix = ""; 164 const char *fname; 165 166 /* 167 * Handle assertion failures. 168 */ 169 170 if (ns_g_lctx != NULL) { 171 /* 172 * Reset the assertion callback in case it is the log 173 * routines causing the assertion. 174 */ 175 isc_assertion_setcallback(NULL); 176 177 result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, 178 &nframes); 179 if (result == ISC_R_SUCCESS && nframes > 0) 180 logsuffix = ", back trace"; 181 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 182 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 183 "%s:%d: %s(%s) failed%s", file, line, 184 isc_assertion_typetotext(type), cond, logsuffix); 185 if (result == ISC_R_SUCCESS) { 186 for (i = 0; i < nframes; i++) { 187 unsigned long offset; 188 189 fname = NULL; 190 result = isc_backtrace_getsymbol(tracebuf[i], 191 &fname, 192 &offset); 193 if (result == ISC_R_SUCCESS) { 194 isc_log_write(ns_g_lctx, 195 NS_LOGCATEGORY_GENERAL, 196 NS_LOGMODULE_MAIN, 197 ISC_LOG_CRITICAL, 198 "#%d %p in %s()+0x%lx", i, 199 tracebuf[i], fname, 200 offset); 201 } else { 202 isc_log_write(ns_g_lctx, 203 NS_LOGCATEGORY_GENERAL, 204 NS_LOGMODULE_MAIN, 205 ISC_LOG_CRITICAL, 206 "#%d %p in ??", i, 207 tracebuf[i]); 208 } 209 } 210 } 211 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 212 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 213 "exiting (due to assertion failure)"); 214 } else { 215 fprintf(stderr, "%s:%d: %s(%s) failed\n", 216 file, line, isc_assertion_typetotext(type), cond); 217 fflush(stderr); 218 } 219 220 if (ns_g_coreok) 221 abort(); 222 exit(1); 223} 224 225ISC_PLATFORM_NORETURN_PRE static void 226library_fatal_error(const char *file, int line, const char *format, 227 va_list args) 228ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST; 229 230static void 231library_fatal_error(const char *file, int line, const char *format, 232 va_list args) 233{ 234 /* 235 * Handle isc_error_fatal() calls from our libraries. 236 */ 237 238 if (ns_g_lctx != NULL) { 239 /* 240 * Reset the error callback in case it is the log 241 * routines causing the assertion. 242 */ 243 isc_error_setfatal(NULL); 244 245 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 246 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 247 "%s:%d: fatal error:", file, line); 248 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 249 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 250 format, args); 251 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 252 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL, 253 "exiting (due to fatal error in library)"); 254 } else { 255 fprintf(stderr, "%s:%d: fatal error: ", file, line); 256 vfprintf(stderr, format, args); 257 fprintf(stderr, "\n"); 258 fflush(stderr); 259 } 260 261 if (ns_g_coreok) 262 abort(); 263 exit(1); 264} 265 266static void 267library_unexpected_error(const char *file, int line, const char *format, 268 va_list args) ISC_FORMAT_PRINTF(3, 0); 269 270static void 271library_unexpected_error(const char *file, int line, const char *format, 272 va_list args) 273{ 274 /* 275 * Handle isc_error_unexpected() calls from our libraries. 276 */ 277 278 if (ns_g_lctx != NULL) { 279 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 280 NS_LOGMODULE_MAIN, ISC_LOG_ERROR, 281 "%s:%d: unexpected error:", file, line); 282 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 283 NS_LOGMODULE_MAIN, ISC_LOG_ERROR, 284 format, args); 285 } else { 286 fprintf(stderr, "%s:%d: fatal error: ", file, line); 287 vfprintf(stderr, format, args); 288 fprintf(stderr, "\n"); 289 fflush(stderr); 290 } 291} 292 293static void 294lwresd_usage(void) { 295 fprintf(stderr, 296 "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] " 297 "[-d debuglevel]\n" 298 " [-f|-g] [-n number_of_cpus] [-p port] " 299 "[-P listen-port] [-s]\n" 300 " [-t chrootdir] [-u username] [-i pidfile]\n" 301 " [-m {usage|trace|record|size|mctx}]\n"); 302} 303 304static void 305usage(void) { 306 if (ns_g_lwresdonly) { 307 lwresd_usage(); 308 return; 309 } 310 fprintf(stderr, 311 "usage: named [-4|-6] [-c conffile] [-d debuglevel] " 312 "[-E engine] [-f|-g]\n" 313 " [-n number_of_cpus] [-p port] [-s] " 314 "[-t chrootdir] [-u username]\n" 315 " [-m {usage|trace|record|size|mctx}]\n"); 316} 317 318static void 319save_command_line(int argc, char *argv[]) { 320 int i; 321 char *src; 322 char *dst; 323 char *eob; 324 const char truncated[] = "..."; 325 isc_boolean_t quoted = ISC_FALSE; 326 327 dst = saved_command_line; 328 eob = saved_command_line + sizeof(saved_command_line); 329 330 for (i = 1; i < argc && dst < eob; i++) { 331 *dst++ = ' '; 332 333 src = argv[i]; 334 while (*src != '\0' && dst < eob) { 335 /* 336 * This won't perfectly produce a shell-independent 337 * pastable command line in all circumstances, but 338 * comes close, and for practical purposes will 339 * nearly always be fine. 340 */ 341 if (quoted || isalnum(*src & 0xff) || 342 *src == '-' || *src == '_' || 343 *src == '.' || *src == '/') { 344 *dst++ = *src++; 345 quoted = ISC_FALSE; 346 } else { 347 *dst++ = '\\'; 348 quoted = ISC_TRUE; 349 } 350 } 351 } 352 353 INSIST(sizeof(saved_command_line) >= sizeof(truncated)); 354 355 if (dst == eob) 356 strcpy(eob - sizeof(truncated), truncated); 357 else 358 *dst = '\0'; 359} 360 361static int 362parse_int(char *arg, const char *desc) { 363 char *endp; 364 int tmp; 365 long int ltmp; 366 367 ltmp = strtol(arg, &endp, 10); 368 tmp = (int) ltmp; 369 if (*endp != '\0') 370 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg); 371 if (tmp < 0 || tmp != ltmp) 372 ns_main_earlyfatal("%s '%s' out of range", desc, arg); 373 return (tmp); 374} 375 376static struct flag_def { 377 const char *name; 378 unsigned int value; 379} mem_debug_flags[] = { 380 { "trace", ISC_MEM_DEBUGTRACE }, 381 { "record", ISC_MEM_DEBUGRECORD }, 382 { "usage", ISC_MEM_DEBUGUSAGE }, 383 { "size", ISC_MEM_DEBUGSIZE }, 384 { "mctx", ISC_MEM_DEBUGCTX }, 385 { NULL, 0 } 386}; 387 388static void 389set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) { 390 for (;;) { 391 const struct flag_def *def; 392 const char *end = strchr(arg, ','); 393 int arglen; 394 if (end == NULL) 395 end = arg + strlen(arg); 396 arglen = end - arg; 397 for (def = defs; def->name != NULL; def++) { 398 if (arglen == (int)strlen(def->name) && 399 memcmp(arg, def->name, arglen) == 0) { 400 *ret |= def->value; 401 goto found; 402 } 403 } 404 ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg); 405 found: 406 if (*end == '\0') 407 break; 408 arg = end + 1; 409 } 410} 411 412static void 413parse_command_line(int argc, char *argv[]) { 414 int ch; 415 int port; 416 isc_boolean_t disable6 = ISC_FALSE; 417 isc_boolean_t disable4 = ISC_FALSE; 418 419 save_command_line(argc, argv); 420 421 isc_commandline_errprint = ISC_FALSE; 422 while ((ch = isc_commandline_parse(argc, argv, 423 "46c:C:d:E:fFgi:lm:n:N:p:P:" 424 "sS:t:T:u:vVx:")) != -1) { 425 switch (ch) { 426 case '4': 427 if (disable4) 428 ns_main_earlyfatal("cannot specify -4 and -6"); 429 if (isc_net_probeipv4() != ISC_R_SUCCESS) 430 ns_main_earlyfatal("IPv4 not supported by OS"); 431 isc_net_disableipv6(); 432 disable6 = ISC_TRUE; 433 break; 434 case '6': 435 if (disable6) 436 ns_main_earlyfatal("cannot specify -4 and -6"); 437 if (isc_net_probeipv6() != ISC_R_SUCCESS) 438 ns_main_earlyfatal("IPv6 not supported by OS"); 439 isc_net_disableipv4(); 440 disable4 = ISC_TRUE; 441 break; 442 case 'c': 443 ns_g_conffile = isc_commandline_argument; 444 lwresd_g_conffile = isc_commandline_argument; 445 if (lwresd_g_useresolvconf) 446 ns_main_earlyfatal("cannot specify -c and -C"); 447 ns_g_conffileset = ISC_TRUE; 448 break; 449 case 'C': 450 lwresd_g_resolvconffile = isc_commandline_argument; 451 if (ns_g_conffileset) 452 ns_main_earlyfatal("cannot specify -c and -C"); 453 lwresd_g_useresolvconf = ISC_TRUE; 454 break; 455 case 'd': 456 ns_g_debuglevel = parse_int(isc_commandline_argument, 457 "debug level"); 458 break; 459 case 'E': 460 ns_g_engine = isc_commandline_argument; 461 break; 462 case 'f': 463 ns_g_foreground = ISC_TRUE; 464 break; 465 case 'g': 466 ns_g_foreground = ISC_TRUE; 467 ns_g_logstderr = ISC_TRUE; 468 break; 469 /* XXXBEW -i should be removed */ 470 case 'i': 471 lwresd_g_defaultpidfile = isc_commandline_argument; 472 break; 473 case 'l': 474 ns_g_lwresdonly = ISC_TRUE; 475 break; 476 case 'm': 477 set_flags(isc_commandline_argument, mem_debug_flags, 478 &isc_mem_debugging); 479 break; 480 case 'N': /* Deprecated. */ 481 case 'n': 482 ns_g_cpus = parse_int(isc_commandline_argument, 483 "number of cpus"); 484 if (ns_g_cpus == 0) 485 ns_g_cpus = 1; 486 break; 487 case 'p': 488 port = parse_int(isc_commandline_argument, "port"); 489 if (port < 1 || port > 65535) 490 ns_main_earlyfatal("port '%s' out of range", 491 isc_commandline_argument); 492 ns_g_port = port; 493 break; 494 /* XXXBEW Should -P be removed? */ 495 case 'P': 496 port = parse_int(isc_commandline_argument, "port"); 497 if (port < 1 || port > 65535) 498 ns_main_earlyfatal("port '%s' out of range", 499 isc_commandline_argument); 500 lwresd_g_listenport = port; 501 break; 502 case 's': 503 /* XXXRTH temporary syntax */ 504 want_stats = ISC_TRUE; 505 break; 506 case 'S': 507 maxsocks = parse_int(isc_commandline_argument, 508 "max number of sockets"); 509 break; 510 case 't': 511 /* XXXJAB should we make a copy? */ 512 ns_g_chrootdir = isc_commandline_argument; 513 break; 514 case 'T': /* NOT DOCUMENTED */ 515 /* 516 * clienttest: make clients single shot with their 517 * own memory context. 518 */ 519 if (!strcmp(isc_commandline_argument, "clienttest")) 520 ns_g_clienttest = ISC_TRUE; 521 else if (!strcmp(isc_commandline_argument, "nosoa")) 522 ns_g_nosoa = ISC_TRUE; 523 else if (!strcmp(isc_commandline_argument, "noaa")) 524 ns_g_noaa = ISC_TRUE; 525 else if (!strcmp(isc_commandline_argument, "maxudp512")) 526 maxudp = 512; 527 else if (!strcmp(isc_commandline_argument, "maxudp1460")) 528 maxudp = 1460; 529 else 530 fprintf(stderr, "unknown -T flag '%s\n", 531 isc_commandline_argument); 532 break; 533 case 'u': 534 ns_g_username = isc_commandline_argument; 535 break; 536 case 'v': 537 printf("BIND %s\n", ns_g_version); 538 exit(0); 539 case 'V': 540 printf("BIND %s built with %s\n", ns_g_version, 541 ns_g_configargs); 542#ifdef OPENSSL 543 printf("using OpenSSL version: %s\n", 544 OPENSSL_VERSION_TEXT); 545#endif 546#ifdef HAVE_LIBXML2 547 printf("using libxml2 version: %s\n", 548 LIBXML_DOTTED_VERSION); 549#endif 550 exit(0); 551 case 'F': 552 /* Reserved for FIPS mode */ 553 /* FALLTHROUGH */ 554 case '?': 555 usage(); 556 if (isc_commandline_option == '?') 557 exit(0); 558 ns_main_earlyfatal("unknown option '-%c'", 559 isc_commandline_option); 560 /* FALLTHROUGH */ 561 default: 562 ns_main_earlyfatal("parsing options returned %d", ch); 563 } 564 } 565 566 argc -= isc_commandline_index; 567 argv += isc_commandline_index; 568 POST(argv); 569 570 if (argc > 0) { 571 usage(); 572 ns_main_earlyfatal("extra command line arguments"); 573 } 574} 575 576static isc_result_t 577create_managers(void) { 578 isc_result_t result; 579 unsigned int socks; 580 581#ifdef ISC_PLATFORM_USETHREADS 582 if (ns_g_cpus == 0) 583 ns_g_cpus = ns_g_cpus_detected; 584 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, 585 ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s", 586 ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s", 587 ns_g_cpus, ns_g_cpus == 1 ? "" : "s"); 588#else 589 ns_g_cpus = 1; 590#endif 591 result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr); 592 if (result != ISC_R_SUCCESS) { 593 UNEXPECTED_ERROR(__FILE__, __LINE__, 594 "isc_taskmgr_create() failed: %s", 595 isc_result_totext(result)); 596 return (ISC_R_UNEXPECTED); 597 } 598 599 result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr); 600 if (result != ISC_R_SUCCESS) { 601 UNEXPECTED_ERROR(__FILE__, __LINE__, 602 "isc_timermgr_create() failed: %s", 603 isc_result_totext(result)); 604 return (ISC_R_UNEXPECTED); 605 } 606 607 result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks); 608 if (result != ISC_R_SUCCESS) { 609 UNEXPECTED_ERROR(__FILE__, __LINE__, 610 "isc_socketmgr_create() failed: %s", 611 isc_result_totext(result)); 612 return (ISC_R_UNEXPECTED); 613 } 614 isc__socketmgr_maxudp(ns_g_socketmgr, maxudp); 615 result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks); 616 if (result == ISC_R_SUCCESS) { 617 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 618 NS_LOGMODULE_SERVER, 619 ISC_LOG_INFO, "using up to %u sockets", socks); 620 } 621 622 result = isc_entropy_create(ns_g_mctx, &ns_g_entropy); 623 if (result != ISC_R_SUCCESS) { 624 UNEXPECTED_ERROR(__FILE__, __LINE__, 625 "isc_entropy_create() failed: %s", 626 isc_result_totext(result)); 627 return (ISC_R_UNEXPECTED); 628 } 629 630 result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE); 631 if (result != ISC_R_SUCCESS) { 632 UNEXPECTED_ERROR(__FILE__, __LINE__, 633 "isc_hash_create() failed: %s", 634 isc_result_totext(result)); 635 return (ISC_R_UNEXPECTED); 636 } 637 638 return (ISC_R_SUCCESS); 639} 640 641static void 642destroy_managers(void) { 643 ns_lwresd_shutdown(); 644 645 isc_entropy_detach(&ns_g_entropy); 646 if (ns_g_fallbackentropy != NULL) 647 isc_entropy_detach(&ns_g_fallbackentropy); 648 649 /* 650 * isc_taskmgr_destroy() will block until all tasks have exited, 651 */ 652 isc_taskmgr_destroy(&ns_g_taskmgr); 653 isc_timermgr_destroy(&ns_g_timermgr); 654 isc_socketmgr_destroy(&ns_g_socketmgr); 655 656 /* 657 * isc_hash_destroy() cannot be called as long as a resolver may be 658 * running. Calling this after isc_taskmgr_destroy() ensures the 659 * call is safe. 660 */ 661 isc_hash_destroy(); 662} 663 664static void 665dump_symboltable() { 666 int i; 667 isc_result_t result; 668 const char *fname; 669 const void *addr; 670 671 if (isc__backtrace_nsymbols == 0) 672 return; 673 674 if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99))) 675 return; 676 677 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 678 ISC_LOG_DEBUG(99), "Symbol table:"); 679 680 for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) { 681 addr = NULL; 682 fname = NULL; 683 result = isc_backtrace_getsymbolfromindex(i, &addr, &fname); 684 if (result == ISC_R_SUCCESS) { 685 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 686 NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99), 687 "[%d] %p %s", i, addr, fname); 688 } 689 } 690} 691 692static void 693setup(void) { 694 isc_result_t result; 695 isc_resourcevalue_t old_openfiles; 696#ifdef HAVE_LIBSCF 697 char *instance = NULL; 698#endif 699 700 /* 701 * Get the user and group information before changing the root 702 * directory, so the administrator does not need to keep a copy 703 * of the user and group databases in the chroot'ed environment. 704 */ 705 ns_os_inituserinfo(ns_g_username); 706 707 /* 708 * Initialize time conversion information 709 */ 710 ns_os_tzset(); 711 712 ns_os_opendevnull(); 713 714#ifdef HAVE_LIBSCF 715 /* Check if named is under smf control, before chroot. */ 716 result = ns_smf_get_instance(&instance, 0, ns_g_mctx); 717 /* We don't care about instance, just check if we got one. */ 718 if (result == ISC_R_SUCCESS) 719 ns_smf_got_instance = 1; 720 else 721 ns_smf_got_instance = 0; 722 if (instance != NULL) 723 isc_mem_free(ns_g_mctx, instance); 724#endif /* HAVE_LIBSCF */ 725 726#ifdef PATH_RANDOMDEV 727 /* 728 * Initialize system's random device as fallback entropy source 729 * if running chroot'ed. 730 */ 731 if (ns_g_chrootdir != NULL) { 732 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy); 733 if (result != ISC_R_SUCCESS) 734 ns_main_earlyfatal("isc_entropy_create() failed: %s", 735 isc_result_totext(result)); 736 737 result = isc_entropy_createfilesource(ns_g_fallbackentropy, 738 PATH_RANDOMDEV); 739 if (result != ISC_R_SUCCESS) { 740 ns_main_earlywarning("could not open pre-chroot " 741 "entropy source %s: %s", 742 PATH_RANDOMDEV, 743 isc_result_totext(result)); 744 isc_entropy_detach(&ns_g_fallbackentropy); 745 } 746 } 747#endif 748 749#ifdef ISC_PLATFORM_USETHREADS 750 /* 751 * Check for the number of cpu's before ns_os_chroot(). 752 */ 753 ns_g_cpus_detected = isc_os_ncpus(); 754#endif 755 756 ns_os_chroot(ns_g_chrootdir); 757 758 /* 759 * For operating systems which have a capability mechanism, now 760 * is the time to switch to minimal privs and change our user id. 761 * On traditional UNIX systems, this call will be a no-op, and we 762 * will change the user ID after reading the config file the first 763 * time. (We need to read the config file to know which possibly 764 * privileged ports to bind() to.) 765 */ 766 ns_os_minprivs(); 767 768 result = ns_log_init(ISC_TF(ns_g_username != NULL)); 769 if (result != ISC_R_SUCCESS) 770 ns_main_earlyfatal("ns_log_init() failed: %s", 771 isc_result_totext(result)); 772 773 /* 774 * Now is the time to daemonize (if we're not running in the 775 * foreground). We waited until now because we wanted to get 776 * a valid logging context setup. We cannot daemonize any later, 777 * because calling create_managers() will create threads, which 778 * would be lost after fork(). 779 */ 780 if (!ns_g_foreground) 781 ns_os_daemonize(); 782 783 /* 784 * We call isc_app_start() here as some versions of FreeBSD's fork() 785 * destroys all the signal handling it sets up. 786 */ 787 result = isc_app_start(); 788 if (result != ISC_R_SUCCESS) 789 ns_main_earlyfatal("isc_app_start() failed: %s", 790 isc_result_totext(result)); 791 792 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 793 ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version, 794 saved_command_line); 795 796 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 797 ISC_LOG_NOTICE, "built with %s", ns_g_configargs); 798 799 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 800 ISC_LOG_NOTICE, 801 "----------------------------------------------------"); 802 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 803 ISC_LOG_NOTICE, 804 "BIND 9 is maintained by Internet Systems Consortium,"); 805 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 806 ISC_LOG_NOTICE, 807 "Inc. (ISC), a non-profit 501(c)(3) public-benefit "); 808 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 809 ISC_LOG_NOTICE, 810 "corporation. Support and training for BIND 9 are "); 811 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 812 ISC_LOG_NOTICE, 813 "available at https://www.isc.org/support"); 814 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 815 ISC_LOG_NOTICE, 816 "----------------------------------------------------"); 817 818 dump_symboltable(); 819 820 /* 821 * Get the initial resource limits. 822 */ 823 (void)isc_resource_getlimit(isc_resource_stacksize, 824 &ns_g_initstacksize); 825 (void)isc_resource_getlimit(isc_resource_datasize, 826 &ns_g_initdatasize); 827 (void)isc_resource_getlimit(isc_resource_coresize, 828 &ns_g_initcoresize); 829 (void)isc_resource_getlimit(isc_resource_openfiles, 830 &ns_g_initopenfiles); 831 832 /* 833 * System resources cannot effectively be tuned on some systems. 834 * Raise the limit in such cases for safety. 835 */ 836 old_openfiles = ns_g_initopenfiles; 837 ns_os_adjustnofile(); 838 (void)isc_resource_getlimit(isc_resource_openfiles, 839 &ns_g_initopenfiles); 840 if (old_openfiles != ns_g_initopenfiles) { 841 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 842 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE, 843 "adjusted limit on open files from " 844 "%" ISC_PRINT_QUADFORMAT "u to " 845 "%" ISC_PRINT_QUADFORMAT "u", 846 old_openfiles, ns_g_initopenfiles); 847 } 848 849 /* 850 * If the named configuration filename is relative, prepend the current 851 * directory's name before possibly changing to another directory. 852 */ 853 if (! isc_file_isabsolute(ns_g_conffile)) { 854 result = isc_file_absolutepath(ns_g_conffile, 855 absolute_conffile, 856 sizeof(absolute_conffile)); 857 if (result != ISC_R_SUCCESS) 858 ns_main_earlyfatal("could not construct absolute path " 859 "of configuration file: %s", 860 isc_result_totext(result)); 861 ns_g_conffile = absolute_conffile; 862 } 863 864 /* 865 * Record the server's startup time. 866 */ 867 result = isc_time_now(&ns_g_boottime); 868 if (result != ISC_R_SUCCESS) 869 ns_main_earlyfatal("isc_time_now() failed: %s", 870 isc_result_totext(result)); 871 872 result = create_managers(); 873 if (result != ISC_R_SUCCESS) 874 ns_main_earlyfatal("create_managers() failed: %s", 875 isc_result_totext(result)); 876 877 ns_builtin_init(); 878 879 /* 880 * Add calls to register sdb drivers here. 881 */ 882 /* xxdb_init(); */ 883 884#ifdef ISC_DLZ_DLOPEN 885 /* 886 * Register the DLZ "dlopen" driver. 887 */ 888 result = dlz_dlopen_init(ns_g_mctx); 889 if (result != ISC_R_SUCCESS) 890 ns_main_earlyfatal("dlz_dlopen_init() failed: %s", 891 isc_result_totext(result)); 892#endif 893 894#if CONTRIB_DLZ 895 /* 896 * Register any other contributed DLZ drivers. 897 */ 898 result = dlz_drivers_init(); 899 if (result != ISC_R_SUCCESS) 900 ns_main_earlyfatal("dlz_drivers_init() failed: %s", 901 isc_result_totext(result)); 902#endif 903 904 ns_server_create(ns_g_mctx, &ns_g_server); 905} 906 907static void 908cleanup(void) { 909 910 destroy_managers(); 911 912 ns_server_destroy(&ns_g_server); 913 914 ns_builtin_deinit(); 915 916 /* 917 * Add calls to unregister sdb drivers here. 918 */ 919 /* xxdb_clear(); */ 920 921#ifdef CONTRIB_DLZ 922 /* 923 * Unregister contributed DLZ drivers. 924 */ 925 dlz_drivers_clear(); 926#endif 927#ifdef ISC_DLZ_DLOPEN 928 /* 929 * Unregister "dlopen" DLZ driver. 930 */ 931 dlz_dlopen_clear(); 932#endif 933 934 dns_name_destroy(); 935 936 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, 937 ISC_LOG_NOTICE, "exiting"); 938 ns_log_shutdown(); 939} 940 941static char *memstats = NULL; 942 943void 944ns_main_setmemstats(const char *filename) { 945 /* 946 * Caller has to ensure locking. 947 */ 948 949 if (memstats != NULL) { 950 free(memstats); 951 memstats = NULL; 952 } 953 if (filename == NULL) 954 return; 955 memstats = malloc(strlen(filename) + 1); 956 if (memstats) 957 strcpy(memstats, filename); 958} 959 960#ifdef HAVE_LIBSCF 961/* 962 * Get FMRI for the named process. 963 */ 964isc_result_t 965ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) { 966 scf_handle_t *h = NULL; 967 int namelen; 968 char *instance; 969 970 REQUIRE(ins_name != NULL && *ins_name == NULL); 971 972 if ((h = scf_handle_create(SCF_VERSION)) == NULL) { 973 if (debug) 974 UNEXPECTED_ERROR(__FILE__, __LINE__, 975 "scf_handle_create() failed: %s", 976 scf_strerror(scf_error())); 977 return (ISC_R_FAILURE); 978 } 979 980 if (scf_handle_bind(h) == -1) { 981 if (debug) 982 UNEXPECTED_ERROR(__FILE__, __LINE__, 983 "scf_handle_bind() failed: %s", 984 scf_strerror(scf_error())); 985 scf_handle_destroy(h); 986 return (ISC_R_FAILURE); 987 } 988 989 if ((namelen = scf_myname(h, NULL, 0)) == -1) { 990 if (debug) 991 UNEXPECTED_ERROR(__FILE__, __LINE__, 992 "scf_myname() failed: %s", 993 scf_strerror(scf_error())); 994 scf_handle_destroy(h); 995 return (ISC_R_FAILURE); 996 } 997 998 if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) { 999 UNEXPECTED_ERROR(__FILE__, __LINE__, 1000 "ns_smf_get_instance memory " 1001 "allocation failed: %s", 1002 isc_result_totext(ISC_R_NOMEMORY)); 1003 scf_handle_destroy(h); 1004 return (ISC_R_FAILURE); 1005 } 1006 1007 if (scf_myname(h, instance, namelen + 1) == -1) { 1008 if (debug) 1009 UNEXPECTED_ERROR(__FILE__, __LINE__, 1010 "scf_myname() failed: %s", 1011 scf_strerror(scf_error())); 1012 scf_handle_destroy(h); 1013 isc_mem_free(mctx, instance); 1014 return (ISC_R_FAILURE); 1015 } 1016 1017 scf_handle_destroy(h); 1018 *ins_name = instance; 1019 return (ISC_R_SUCCESS); 1020} 1021#endif /* HAVE_LIBSCF */ 1022 1023int 1024main(int argc, char *argv[]) { 1025 isc_result_t result; 1026#ifdef HAVE_LIBSCF 1027 char *instance = NULL; 1028#endif 1029 int nctoken; 1030 1031 /* 1032 * Record version in core image. 1033 * strings named.core | grep "named version:" 1034 */ 1035 strlcat(version, 1036#if defined(NO_VERSION_DATE) || !defined(__DATE__) 1037 "named version: BIND " VERSION, 1038#else 1039 "named version: BIND " VERSION " (" __DATE__ ")", 1040#endif 1041 sizeof(version)); 1042 result = isc_file_progname(*argv, program_name, sizeof(program_name)); 1043 if (result != ISC_R_SUCCESS) 1044 ns_main_earlyfatal("program name too long"); 1045 1046 if (strcmp(program_name, "lwresd") == 0) 1047 ns_g_lwresdonly = ISC_TRUE; 1048 1049 if (result != ISC_R_SUCCESS) 1050 ns_main_earlyfatal("failed to build internal symbol table"); 1051 1052 isc_assertion_setcallback(assertion_failed); 1053 isc_error_setfatal(library_fatal_error); 1054 isc_error_setunexpected(library_unexpected_error); 1055 1056 ns_os_init(program_name); 1057 1058 dns_result_register(); 1059 dst_result_register(); 1060 isccc_result_register(); 1061 1062 parse_command_line(argc, argv); 1063 1064 /* 1065 * Warn about common configuration error. 1066 */ 1067 if (ns_g_chrootdir != NULL) { 1068 int len = strlen(ns_g_chrootdir); 1069 if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 && 1070 (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\')) 1071 ns_main_earlywarning("config filename (-c %s) contains " 1072 "chroot path (-t %s)", 1073 ns_g_conffile, ns_g_chrootdir); 1074 } 1075 1076 result = isc_mem_create(0, 0, &ns_g_mctx); 1077 if (result != ISC_R_SUCCESS) 1078 ns_main_earlyfatal("isc_mem_create() failed: %s", 1079 isc_result_totext(result)); 1080 isc_mem_setname(ns_g_mctx, "main", NULL); 1081 1082 /* 1083 * register for a SIGHUP when there's a network configuration change 1084 */ 1085 nctoken = -1; 1086 notify_register_signal(kNotifySCNetworkChange, SIGHUP, &nctoken); 1087 1088 setup(); 1089 1090 /* 1091 * Start things running and then wait for a shutdown request 1092 * or reload. 1093 */ 1094 do { 1095 result = isc_app_run(); 1096 1097 if (result == ISC_R_RELOAD) { 1098 ns_server_reloadwanted(ns_g_server); 1099 } else if (result != ISC_R_SUCCESS) { 1100 UNEXPECTED_ERROR(__FILE__, __LINE__, 1101 "isc_app_run(): %s", 1102 isc_result_totext(result)); 1103 /* 1104 * Force exit. 1105 */ 1106 result = ISC_R_SUCCESS; 1107 } 1108 } while (result != ISC_R_SUCCESS); 1109 1110#ifdef HAVE_LIBSCF 1111 if (ns_smf_want_disable == 1) { 1112 result = ns_smf_get_instance(&instance, 1, ns_g_mctx); 1113 if (result == ISC_R_SUCCESS && instance != NULL) { 1114 if (smf_disable_instance(instance, 0) != 0) 1115 UNEXPECTED_ERROR(__FILE__, __LINE__, 1116 "smf_disable_instance() " 1117 "failed for %s : %s", 1118 instance, 1119 scf_strerror(scf_error())); 1120 } 1121 if (instance != NULL) 1122 isc_mem_free(ns_g_mctx, instance); 1123 } 1124#endif /* HAVE_LIBSCF */ 1125 1126 cleanup(); 1127 1128 if (want_stats) { 1129 isc_mem_stats(ns_g_mctx, stdout); 1130 isc_mutex_stats(stdout); 1131 } 1132 1133 if (ns_g_memstatistics && memstats != NULL) { 1134 FILE *fp = NULL; 1135 result = isc_stdio_open(memstats, "w", &fp); 1136 if (result == ISC_R_SUCCESS) { 1137 isc_mem_stats(ns_g_mctx, fp); 1138 isc_mutex_stats(fp); 1139 isc_stdio_close(fp); 1140 } 1141 } 1142 isc_mem_destroy(&ns_g_mctx); 1143 isc_mem_checkdestroyed(stderr); 1144 1145 ns_main_setmemstats(NULL); 1146 1147 isc_app_finish(); 1148 1149 ns_os_closedevnull(); 1150 1151 ns_os_shutdown(); 1152 1153 return (0); 1154} 1155