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