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