/contrib/bind9/bin/named/main.c

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