nsd.c revision 1.1.1.4 1 /*
2 * nsd.c -- nsd(8)
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9
10 #include "config.h"
11
12 #include <sys/types.h>
13 #include <sys/param.h>
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/uio.h>
17 #include <sys/wait.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #ifdef HAVE_GRP_H
21 #include <grp.h>
22 #endif /* HAVE_GRP_H */
23 #ifdef HAVE_SETUSERCONTEXT
24 #include <login_cap.h>
25 #endif /* HAVE_SETUSERCONTEXT */
26
27 #include <assert.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <netdb.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42
43 #include "nsd.h"
44 #include "options.h"
45 #include "tsig.h"
46 #include "remote.h"
47 #include "xfrd-disk.h"
48 #ifdef USE_DNSTAP
49 #include "dnstap/dnstap_collector.h"
50 #endif
51
52 /* The server handler... */
53 struct nsd nsd;
54 static char hostname[MAXHOSTNAMELEN];
55 extern config_parser_state_type* cfg_parser;
56 static void version(void) ATTR_NORETURN;
57
58 /*
59 * Print the help text.
60 *
61 */
62 static void
63 usage (void)
64 {
65 fprintf(stderr, "Usage: nsd [OPTION]...\n");
66 fprintf(stderr, "Name Server Daemon.\n\n");
67 fprintf(stderr,
68 "Supported options:\n"
69 " -4 Only listen to IPv4 connections.\n"
70 " -6 Only listen to IPv6 connections.\n"
71 " -a ip-address[@port] Listen to the specified incoming IP address (and port)\n"
72 " May be specified multiple times).\n"
73 " -c configfile Read specified configfile instead of %s.\n"
74 " -d do not fork as a daemon process.\n"
75 #ifndef NDEBUG
76 " -F facilities Specify the debug facilities.\n"
77 #endif /* NDEBUG */
78 " -f database Specify the database to load.\n"
79 " -h Print this help information.\n"
80 , CONFIGFILE);
81 fprintf(stderr,
82 " -i identity Specify the identity when queried for id.server CHAOS TXT.\n"
83 " -I nsid Specify the NSID. This must be a hex string.\n"
84 #ifndef NDEBUG
85 " -L level Specify the debug level.\n"
86 #endif /* NDEBUG */
87 " -l filename Specify the log file.\n"
88 " -N server-count The number of servers to start.\n"
89 " -n tcp-count The maximum number of TCP connections per server.\n"
90 " -P pidfile Specify the PID file to write.\n"
91 " -p port Specify the port to listen to.\n"
92 " -s seconds Dump statistics every SECONDS seconds.\n"
93 " -t chrootdir Change root to specified directory on startup.\n"
94 );
95 fprintf(stderr,
96 " -u user Change effective uid to the specified user.\n"
97 " -V level Specify verbosity level.\n"
98 " -v Print version information.\n"
99 );
100 fprintf(stderr, "Version %s. Report bugs to <%s>.\n",
101 PACKAGE_VERSION, PACKAGE_BUGREPORT);
102 }
103
104 /*
105 * Print the version exit.
106 *
107 */
108 static void
109 version(void)
110 {
111 fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
112 fprintf(stderr, "Written by NLnet Labs.\n\n");
113 fprintf(stderr,
114 "Copyright (C) 2001-2006 NLnet Labs. This is free software.\n"
115 "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
116 "FOR A PARTICULAR PURPOSE.\n");
117 exit(0);
118 }
119
120 void
121 get_ip_port_frm_str(const char* arg, const char** hostname,
122 const char** port)
123 {
124 /* parse src[@port] option */
125 char* delim = NULL;
126 if (arg) {
127 delim = strchr(arg, '@');
128 }
129
130 if (delim) {
131 *delim = '\0';
132 *port = delim+1;
133 }
134 *hostname = arg;
135 }
136
137 /* append interface to interface array (names, udp, tcp) */
138 void
139 add_interface(char*** nodes, struct nsd* nsd, char* ip)
140 {
141 /* realloc the arrays */
142 if(nsd->ifs == 0) {
143 *nodes = xalloc_zero(sizeof(*nodes));
144 nsd->udp = xalloc_zero(sizeof(*nsd->udp));
145 nsd->tcp = xalloc_zero(sizeof(*nsd->udp));
146 } else {
147 region_remove_cleanup(nsd->region, free, *nodes);
148 region_remove_cleanup(nsd->region, free, nsd->udp);
149 region_remove_cleanup(nsd->region, free, nsd->tcp);
150 *nodes = xrealloc(*nodes, (nsd->ifs+1)*sizeof(*nodes));
151 nsd->udp = xrealloc(nsd->udp, (nsd->ifs+1)*sizeof(*nsd->udp));
152 nsd->tcp = xrealloc(nsd->tcp, (nsd->ifs+1)*sizeof(*nsd->udp));
153 (*nodes)[nsd->ifs] = NULL;
154 memset(&nsd->udp[nsd->ifs], 0, sizeof(*nsd->udp));
155 memset(&nsd->tcp[nsd->ifs], 0, sizeof(*nsd->tcp));
156 }
157 region_add_cleanup(nsd->region, free, *nodes);
158 region_add_cleanup(nsd->region, free, nsd->udp);
159 region_add_cleanup(nsd->region, free, nsd->tcp);
160
161 /* add it */
162 (*nodes)[nsd->ifs] = ip;
163 ++nsd->ifs;
164 }
165
166 /*
167 * Fetch the nsd parent process id from the nsd pidfile
168 *
169 */
170 pid_t
171 readpid(const char *file)
172 {
173 int fd;
174 pid_t pid;
175 char pidbuf[16];
176 char *t;
177 int l;
178
179 if ((fd = open(file, O_RDONLY)) == -1) {
180 return -1;
181 }
182
183 if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
184 close(fd);
185 return -1;
186 }
187
188 close(fd);
189
190 /* Empty pidfile means no pidfile... */
191 if (l == 0) {
192 errno = ENOENT;
193 return -1;
194 }
195
196 pid = (pid_t) strtol(pidbuf, &t, 10);
197
198 if (*t && *t != '\n') {
199 return -1;
200 }
201 return pid;
202 }
203
204 /*
205 * Store the nsd parent process id in the nsd pidfile
206 *
207 */
208 int
209 writepid(struct nsd *nsd)
210 {
211 FILE * fd;
212 char pidbuf[32];
213
214 snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long) nsd->pid);
215
216 if ((fd = fopen(nsd->pidfile, "w")) == NULL ) {
217 log_msg(LOG_ERR, "cannot open pidfile %s: %s",
218 nsd->pidfile, strerror(errno));
219 return -1;
220 }
221
222 if (!write_data(fd, pidbuf, strlen(pidbuf))) {
223 log_msg(LOG_ERR, "cannot write pidfile %s: %s",
224 nsd->pidfile, strerror(errno));
225 fclose(fd);
226 return -1;
227 }
228 fclose(fd);
229
230 if (chown(nsd->pidfile, nsd->uid, nsd->gid) == -1) {
231 log_msg(LOG_ERR, "cannot chown %u.%u %s: %s",
232 (unsigned) nsd->uid, (unsigned) nsd->gid,
233 nsd->pidfile, strerror(errno));
234 return -1;
235 }
236
237 return 0;
238 }
239
240 void
241 unlinkpid(const char* file)
242 {
243 int fd = -1;
244
245 if (file) {
246 /* truncate pidfile */
247 fd = open(file, O_WRONLY | O_TRUNC, 0644);
248 if (fd == -1) {
249 /* Truncate the pid file. */
250 log_msg(LOG_ERR, "can not truncate the pid file %s: %s", file, strerror(errno));
251 } else
252 close(fd);
253
254 /* unlink pidfile */
255 if (unlink(file) == -1)
256 log_msg(LOG_WARNING, "failed to unlink pidfile %s: %s",
257 file, strerror(errno));
258 }
259 }
260
261 /*
262 * Incoming signals, set appropriate actions.
263 *
264 */
265 void
266 sig_handler(int sig)
267 {
268 /* To avoid race cond. We really don't want to use log_msg() in this handler */
269
270 /* Are we a child server? */
271 if (nsd.server_kind != NSD_SERVER_MAIN) {
272 switch (sig) {
273 case SIGCHLD:
274 nsd.signal_hint_child = 1;
275 break;
276 case SIGALRM:
277 break;
278 case SIGINT:
279 case SIGTERM:
280 nsd.signal_hint_quit = 1;
281 break;
282 case SIGILL:
283 case SIGUSR1: /* Dump stats on SIGUSR1. */
284 nsd.signal_hint_statsusr = 1;
285 break;
286 default:
287 break;
288 }
289 return;
290 }
291
292 /* We are the main process */
293 switch (sig) {
294 case SIGCHLD:
295 nsd.signal_hint_child = 1;
296 return;
297 case SIGHUP:
298 nsd.signal_hint_reload_hup = 1;
299 return;
300 case SIGALRM:
301 nsd.signal_hint_stats = 1;
302 break;
303 case SIGILL:
304 /*
305 * For backwards compatibility with BIND 8 and older
306 * versions of NSD.
307 */
308 nsd.signal_hint_statsusr = 1;
309 break;
310 case SIGUSR1:
311 /* Dump statistics. */
312 nsd.signal_hint_statsusr = 1;
313 break;
314 case SIGINT:
315 case SIGTERM:
316 default:
317 nsd.signal_hint_shutdown = 1;
318 break;
319 }
320 }
321
322 /*
323 * Statistic output...
324 *
325 */
326 #ifdef BIND8_STATS
327 void
328 bind8_stats (struct nsd *nsd)
329 {
330 char buf[MAXSYSLOGMSGLEN];
331 char *msg, *t;
332 int i, len;
333
334 /* Current time... */
335 time_t now;
336 if(!nsd->st.period)
337 return;
338 time(&now);
339
340 /* NSTATS */
341 t = msg = buf + snprintf(buf, MAXSYSLOGMSGLEN, "NSTATS %lld %lu",
342 (long long) now, (unsigned long) nsd->st.boot);
343 for (i = 0; i <= 255; i++) {
344 /* How much space left? */
345 if ((len = buf + MAXSYSLOGMSGLEN - t) < 32) {
346 log_msg(LOG_INFO, "%s", buf);
347 t = msg;
348 len = buf + MAXSYSLOGMSGLEN - t;
349 }
350
351 if (nsd->st.qtype[i] != 0) {
352 t += snprintf(t, len, " %s=%lu", rrtype_to_string(i), nsd->st.qtype[i]);
353 }
354 }
355 if (t > msg)
356 log_msg(LOG_INFO, "%s", buf);
357
358 /* XSTATS */
359 /* Only print it if we're in the main daemon or have anything to report... */
360 if (nsd->server_kind == NSD_SERVER_MAIN
361 || nsd->st.dropped || nsd->st.raxfr || (nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped)
362 || nsd->st.txerr || nsd->st.opcode[OPCODE_QUERY] || nsd->st.opcode[OPCODE_IQUERY]
363 || nsd->st.wrongzone || nsd->st.ctcp + nsd->st.ctcp6 || nsd->st.rcode[RCODE_SERVFAIL]
364 || nsd->st.rcode[RCODE_FORMAT] || nsd->st.nona || nsd->st.rcode[RCODE_NXDOMAIN]
365 || nsd->st.opcode[OPCODE_UPDATE]) {
366
367 log_msg(LOG_INFO, "XSTATS %lld %lu"
368 " RR=%lu RNXD=%lu RFwdR=%lu RDupR=%lu RFail=%lu RFErr=%lu RErr=%lu RAXFR=%lu"
369 " RLame=%lu ROpts=%lu SSysQ=%lu SAns=%lu SFwdQ=%lu SDupQ=%lu SErr=%lu RQ=%lu"
370 " RIQ=%lu RFwdQ=%lu RDupQ=%lu RTCP=%lu SFwdR=%lu SFail=%lu SFErr=%lu SNaAns=%lu"
371 " SNXD=%lu RUQ=%lu RURQ=%lu RUXFR=%lu RUUpd=%lu",
372 (long long) now, (unsigned long) nsd->st.boot,
373 nsd->st.dropped, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0,
374 (unsigned long)0, (unsigned long)0, nsd->st.raxfr, (unsigned long)0, (unsigned long)0,
375 (unsigned long)0, nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped, (unsigned long)0,
376 (unsigned long)0, nsd->st.txerr,
377 nsd->st.opcode[OPCODE_QUERY], nsd->st.opcode[OPCODE_IQUERY], nsd->st.wrongzone,
378 (unsigned long)0, nsd->st.ctcp + nsd->st.ctcp6,
379 (unsigned long)0, nsd->st.rcode[RCODE_SERVFAIL], nsd->st.rcode[RCODE_FORMAT],
380 nsd->st.nona, nsd->st.rcode[RCODE_NXDOMAIN],
381 (unsigned long)0, (unsigned long)0, (unsigned long)0, nsd->st.opcode[OPCODE_UPDATE]);
382 }
383
384 }
385 #endif /* BIND8_STATS */
386
387 extern char *optarg;
388 extern int optind;
389
390 int
391 main(int argc, char *argv[])
392 {
393 /* Scratch variables... */
394 int c;
395 pid_t oldpid;
396 size_t i;
397 struct sigaction action;
398 #ifdef HAVE_GETPWNAM
399 struct passwd *pwd = NULL;
400 #endif /* HAVE_GETPWNAM */
401
402 struct addrinfo hints[2];
403 int hints_in_use = 1;
404 char** nodes = NULL; /* array of address strings, size nsd.ifs */
405 const char *udp_port = 0;
406 const char *tcp_port = 0;
407
408 const char *configfile = CONFIGFILE;
409
410 char* argv0 = (argv0 = strrchr(argv[0], '/')) ? argv0 + 1 : argv[0];
411
412 log_init(argv0);
413
414 /* Initialize the server handler... */
415 memset(&nsd, 0, sizeof(struct nsd));
416 nsd.region = region_create(xalloc, free);
417 nsd.dbfile = 0;
418 nsd.pidfile = 0;
419 nsd.server_kind = NSD_SERVER_MAIN;
420 memset(&hints, 0, sizeof(*hints)*2);
421 hints[0].ai_family = DEFAULT_AI_FAMILY;
422 hints[0].ai_flags = AI_PASSIVE;
423 hints[1].ai_family = DEFAULT_AI_FAMILY;
424 hints[1].ai_flags = AI_PASSIVE;
425 nsd.identity = 0;
426 nsd.version = VERSION;
427 nsd.username = 0;
428 nsd.chrootdir = 0;
429 nsd.nsid = NULL;
430 nsd.nsid_len = 0;
431
432 nsd.child_count = 0;
433 nsd.maximum_tcp_count = 0;
434 nsd.current_tcp_count = 0;
435 nsd.grab_ip6_optional = 0;
436 nsd.file_rotation_ok = 0;
437
438 /* Set up our default identity to gethostname(2) */
439 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
440 nsd.identity = hostname;
441 } else {
442 log_msg(LOG_ERR,
443 "failed to get the host name: %s - using default identity",
444 strerror(errno));
445 nsd.identity = IDENTITY;
446 }
447
448 /* Parse the command line... */
449 while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:s:u:t:X:V:v"
450 #ifndef NDEBUG /* <mattthijs> only when configured with --enable-checking */
451 "F:L:"
452 #endif /* NDEBUG */
453 )) != -1) {
454 switch (c) {
455 case '4':
456 hints[0].ai_family = AF_INET;
457 break;
458 case '6':
459 #ifdef INET6
460 hints[0].ai_family = AF_INET6;
461 #else /* !INET6 */
462 error("IPv6 support not enabled.");
463 #endif /* INET6 */
464 break;
465 case 'a':
466 add_interface(&nodes, &nsd, optarg);
467 break;
468 case 'c':
469 configfile = optarg;
470 break;
471 case 'd':
472 nsd.debug = 1;
473 break;
474 case 'f':
475 nsd.dbfile = optarg;
476 break;
477 case 'h':
478 usage();
479 exit(0);
480 case 'i':
481 nsd.identity = optarg;
482 break;
483 case 'I':
484 if (nsd.nsid_len != 0) {
485 /* can only be given once */
486 break;
487 }
488 if (strncasecmp(optarg, "ascii_", 6) == 0) {
489 nsd.nsid = xalloc(strlen(optarg+6));
490 nsd.nsid_len = strlen(optarg+6);
491 memmove(nsd.nsid, optarg+6, nsd.nsid_len);
492 } else {
493 if (strlen(optarg) % 2 != 0) {
494 error("the NSID must be a hex string of an even length.");
495 }
496 nsd.nsid = xalloc(strlen(optarg) / 2);
497 nsd.nsid_len = strlen(optarg) / 2;
498 if (hex_pton(optarg, nsd.nsid, nsd.nsid_len) == -1) {
499 error("hex string cannot be parsed '%s' in NSID.", optarg);
500 }
501 }
502 break;
503 case 'l':
504 nsd.log_filename = optarg;
505 break;
506 case 'N':
507 i = atoi(optarg);
508 if (i <= 0) {
509 error("number of child servers must be greater than zero.");
510 } else {
511 nsd.child_count = i;
512 }
513 break;
514 case 'n':
515 i = atoi(optarg);
516 if (i <= 0) {
517 error("number of concurrent TCP connections must greater than zero.");
518 } else {
519 nsd.maximum_tcp_count = i;
520 }
521 break;
522 case 'P':
523 nsd.pidfile = optarg;
524 break;
525 case 'p':
526 if (atoi(optarg) == 0) {
527 error("port argument must be numeric.");
528 }
529 tcp_port = optarg;
530 udp_port = optarg;
531 break;
532 case 's':
533 #ifdef BIND8_STATS
534 nsd.st.period = atoi(optarg);
535 #else /* !BIND8_STATS */
536 error("BIND 8 statistics not enabled.");
537 #endif /* BIND8_STATS */
538 break;
539 case 't':
540 #ifdef HAVE_CHROOT
541 nsd.chrootdir = optarg;
542 #else /* !HAVE_CHROOT */
543 error("chroot not supported on this platform.");
544 #endif /* HAVE_CHROOT */
545 break;
546 case 'u':
547 nsd.username = optarg;
548 break;
549 case 'V':
550 verbosity = atoi(optarg);
551 break;
552 case 'v':
553 version();
554 /* version exits */
555 break;
556 #ifndef NDEBUG
557 case 'F':
558 sscanf(optarg, "%x", &nsd_debug_facilities);
559 break;
560 case 'L':
561 sscanf(optarg, "%d", &nsd_debug_level);
562 break;
563 #endif /* NDEBUG */
564 case '?':
565 default:
566 usage();
567 exit(1);
568 }
569 }
570 argc -= optind;
571 /* argv += optind; */
572
573 /* Commandline parse error */
574 if (argc != 0) {
575 usage();
576 exit(1);
577 }
578
579 if (strlen(nsd.identity) > UCHAR_MAX) {
580 error("server identity too long (%u characters)",
581 (unsigned) strlen(nsd.identity));
582 }
583 if(!tsig_init(nsd.region))
584 error("init tsig failed");
585
586 /* Read options */
587 nsd.options = nsd_options_create(region_create_custom(xalloc, free,
588 DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
589 DEFAULT_INITIAL_CLEANUP_SIZE, 1));
590 if(!parse_options_file(nsd.options, configfile, NULL, NULL)) {
591 error("could not read config: %s\n", configfile);
592 }
593 if(!parse_zone_list_file(nsd.options)) {
594 error("could not read zonelist file %s\n",
595 nsd.options->zonelistfile);
596 }
597 if(nsd.options->do_ip4 && !nsd.options->do_ip6) {
598 hints[0].ai_family = AF_INET;
599 }
600 #ifdef INET6
601 if(nsd.options->do_ip6 && !nsd.options->do_ip4) {
602 hints[0].ai_family = AF_INET6;
603 }
604 #endif /* INET6 */
605 if(nsd.options->ip_addresses)
606 {
607 ip_address_option_type* ip = nsd.options->ip_addresses;
608 while(ip) {
609 add_interface(&nodes, &nsd, ip->address);
610 ip = ip->next;
611 }
612 }
613 if (verbosity == 0)
614 verbosity = nsd.options->verbosity;
615 #ifndef NDEBUG
616 if (nsd_debug_level > 0 && verbosity == 0)
617 verbosity = nsd_debug_level;
618 #endif /* NDEBUG */
619 if(nsd.options->debug_mode) nsd.debug=1;
620 if(!nsd.dbfile)
621 {
622 if(nsd.options->database)
623 nsd.dbfile = nsd.options->database;
624 else
625 nsd.dbfile = DBFILE;
626 }
627 if(!nsd.pidfile)
628 {
629 if(nsd.options->pidfile)
630 nsd.pidfile = nsd.options->pidfile;
631 else
632 nsd.pidfile = PIDFILE;
633 }
634 if(strcmp(nsd.identity, hostname)==0 || strcmp(nsd.identity,IDENTITY)==0)
635 {
636 if(nsd.options->identity)
637 nsd.identity = nsd.options->identity;
638 }
639 if(nsd.options->version) {
640 nsd.version = nsd.options->version;
641 }
642 if (nsd.options->logfile && !nsd.log_filename) {
643 nsd.log_filename = nsd.options->logfile;
644 }
645 if(nsd.child_count == 0) {
646 nsd.child_count = nsd.options->server_count;
647 }
648 #ifdef SO_REUSEPORT
649 if(nsd.options->reuseport && nsd.child_count > 1) {
650 nsd.reuseport = nsd.child_count;
651 }
652 #endif /* SO_REUSEPORT */
653 if(nsd.maximum_tcp_count == 0) {
654 nsd.maximum_tcp_count = nsd.options->tcp_count;
655 }
656 nsd.tcp_timeout = nsd.options->tcp_timeout;
657 nsd.tcp_query_count = nsd.options->tcp_query_count;
658 nsd.tcp_mss = nsd.options->tcp_mss;
659 nsd.outgoing_tcp_mss = nsd.options->outgoing_tcp_mss;
660 nsd.ipv4_edns_size = nsd.options->ipv4_edns_size;
661 nsd.ipv6_edns_size = nsd.options->ipv6_edns_size;
662
663 if(udp_port == 0)
664 {
665 if(nsd.options->port != 0) {
666 udp_port = nsd.options->port;
667 tcp_port = nsd.options->port;
668 } else {
669 udp_port = UDP_PORT;
670 tcp_port = TCP_PORT;
671 }
672 }
673 #ifdef BIND8_STATS
674 if(nsd.st.period == 0) {
675 nsd.st.period = nsd.options->statistics;
676 }
677 #endif /* BIND8_STATS */
678 #ifdef HAVE_CHROOT
679 if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot;
680 #ifdef CHROOTDIR
681 /* if still no chrootdir, fallback to default */
682 if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR;
683 #endif /* CHROOTDIR */
684 #endif /* HAVE_CHROOT */
685 if(nsd.username == 0) {
686 if(nsd.options->username) nsd.username = nsd.options->username;
687 else nsd.username = USER;
688 }
689 if(nsd.options->zonesdir && nsd.options->zonesdir[0]) {
690 if(chdir(nsd.options->zonesdir)) {
691 error("cannot chdir to '%s': %s",
692 nsd.options->zonesdir, strerror(errno));
693 }
694 DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s",
695 nsd.options->zonesdir));
696 }
697
698 /* EDNS0 */
699 edns_init_data(&nsd.edns_ipv4, nsd.options->ipv4_edns_size);
700 #if defined(INET6)
701 #if defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU)
702 edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size);
703 #else /* no way to set IPV6 MTU, send no bigger than that. */
704 if (nsd.options->ipv6_edns_size < IPV6_MIN_MTU)
705 edns_init_data(&nsd.edns_ipv6, nsd.options->ipv6_edns_size);
706 else
707 edns_init_data(&nsd.edns_ipv6, IPV6_MIN_MTU);
708 #endif /* IPV6 MTU) */
709 #endif /* defined(INET6) */
710
711 if (nsd.nsid_len == 0 && nsd.options->nsid) {
712 if (strlen(nsd.options->nsid) % 2 != 0) {
713 error("the NSID must be a hex string of an even length.");
714 }
715 nsd.nsid = xalloc(strlen(nsd.options->nsid) / 2);
716 nsd.nsid_len = strlen(nsd.options->nsid) / 2;
717 if (hex_pton(nsd.options->nsid, nsd.nsid, nsd.nsid_len) == -1) {
718 error("hex string cannot be parsed '%s' in NSID.", nsd.options->nsid);
719 }
720 }
721 edns_init_nsid(&nsd.edns_ipv4, nsd.nsid_len);
722 #if defined(INET6)
723 edns_init_nsid(&nsd.edns_ipv6, nsd.nsid_len);
724 #endif /* defined(INET6) */
725
726 /* Number of child servers to fork. */
727 nsd.children = (struct nsd_child *) region_alloc_array(
728 nsd.region, nsd.child_count, sizeof(struct nsd_child));
729 for (i = 0; i < nsd.child_count; ++i) {
730 nsd.children[i].kind = NSD_SERVER_BOTH;
731 nsd.children[i].pid = -1;
732 nsd.children[i].child_fd = -1;
733 nsd.children[i].parent_fd = -1;
734 nsd.children[i].handler = NULL;
735 nsd.children[i].need_to_send_STATS = 0;
736 nsd.children[i].need_to_send_QUIT = 0;
737 nsd.children[i].need_to_exit = 0;
738 nsd.children[i].has_exited = 0;
739 #ifdef BIND8_STATS
740 nsd.children[i].query_count = 0;
741 #endif
742 }
743
744 nsd.this_child = NULL;
745
746 /* We need at least one active interface */
747 if (nsd.ifs == 0) {
748 add_interface(&nodes, &nsd, NULL);
749
750 /*
751 * With IPv6 we'd like to open two separate sockets,
752 * one for IPv4 and one for IPv6, both listening to
753 * the wildcard address (unless the -4 or -6 flags are
754 * specified).
755 *
756 * However, this is only supported on platforms where
757 * we can turn the socket option IPV6_V6ONLY _on_.
758 * Otherwise we just listen to a single IPv6 socket
759 * and any incoming IPv4 connections will be
760 * automatically mapped to our IPv6 socket.
761 */
762 #ifdef INET6
763 if (hints[0].ai_family == AF_UNSPEC) {
764 #ifdef IPV6_V6ONLY
765 add_interface(&nodes, &nsd, NULL);
766 hints[0].ai_family = AF_INET6;
767 hints[1].ai_family = AF_INET;
768 hints_in_use = 2;
769 nsd.grab_ip6_optional = 1;
770 #else /* !IPV6_V6ONLY */
771 hints[0].ai_family = AF_INET6;
772 #endif /* IPV6_V6ONLY */
773 }
774 #endif /* INET6 */
775 }
776
777 /* Set up the address info structures with real interface/port data */
778 assert(nodes);
779 for (i = 0; i < nsd.ifs; ++i) {
780 int r;
781 const char* node = NULL;
782 const char* service = NULL;
783 int h = ((hints_in_use == 1)?0:i%hints_in_use);
784
785 /* We don't perform name-lookups */
786 if (nodes[i] != NULL)
787 hints[h].ai_flags |= AI_NUMERICHOST;
788 get_ip_port_frm_str(nodes[i], &node, &service);
789
790 hints[h].ai_socktype = SOCK_DGRAM;
791 if ((r=getaddrinfo(node, (service?service:udp_port), &hints[h], &nsd.udp[i].addr)) != 0) {
792 #ifdef INET6
793 if(nsd.grab_ip6_optional && hints[0].ai_family == AF_INET6) {
794 log_msg(LOG_WARNING, "No IPv6, fallback to IPv4. getaddrinfo: %s",
795 r==EAI_SYSTEM?strerror(errno):gai_strerror(r));
796 continue;
797 }
798 #endif
799 error("cannot parse address '%s': getaddrinfo: %s %s",
800 nodes[i]?nodes[i]:"(null)",
801 gai_strerror(r),
802 r==EAI_SYSTEM?strerror(errno):"");
803 }
804
805 hints[h].ai_socktype = SOCK_STREAM;
806 if ((r=getaddrinfo(node, (service?service:tcp_port), &hints[h], &nsd.tcp[i].addr)) != 0) {
807 error("cannot parse address '%s': getaddrinfo: %s %s",
808 nodes[i]?nodes[i]:"(null)",
809 gai_strerror(r),
810 r==EAI_SYSTEM?strerror(errno):"");
811 }
812 }
813
814 /* Parse the username into uid and gid */
815 nsd.gid = getgid();
816 nsd.uid = getuid();
817 #ifdef HAVE_GETPWNAM
818 /* Parse the username into uid and gid */
819 if (*nsd.username) {
820 if (isdigit((unsigned char)*nsd.username)) {
821 char *t;
822 nsd.uid = strtol(nsd.username, &t, 10);
823 if (*t != 0) {
824 if (*t != '.' || !isdigit((unsigned char)*++t)) {
825 error("-u user or -u uid or -u uid.gid");
826 }
827 nsd.gid = strtol(t, &t, 10);
828 } else {
829 /* Lookup the group id in /etc/passwd */
830 if ((pwd = getpwuid(nsd.uid)) == NULL) {
831 error("user id %u does not exist.", (unsigned) nsd.uid);
832 } else {
833 nsd.gid = pwd->pw_gid;
834 }
835 }
836 } else {
837 /* Lookup the user id in /etc/passwd */
838 if ((pwd = getpwnam(nsd.username)) == NULL) {
839 error("user '%s' does not exist.", nsd.username);
840 } else {
841 nsd.uid = pwd->pw_uid;
842 nsd.gid = pwd->pw_gid;
843 }
844 }
845 }
846 /* endpwent(); */
847 #endif /* HAVE_GETPWNAM */
848
849 #if defined(HAVE_SSL)
850 key_options_tsig_add(nsd.options);
851 #endif
852
853 append_trailing_slash(&nsd.options->xfrdir, nsd.options->region);
854 /* Check relativity of pathnames to chroot */
855 if (nsd.chrootdir && nsd.chrootdir[0]) {
856 /* existing chrootdir: append trailing slash for strncmp checking */
857 append_trailing_slash(&nsd.chrootdir, nsd.region);
858 append_trailing_slash(&nsd.options->zonesdir, nsd.options->region);
859
860 /* zonesdir must be absolute and within chroot,
861 * all other pathnames may be relative to zonesdir */
862 if (strncmp(nsd.options->zonesdir, nsd.chrootdir, strlen(nsd.chrootdir)) != 0) {
863 error("zonesdir %s has to be an absolute path that starts with the chroot path %s",
864 nsd.options->zonesdir, nsd.chrootdir);
865 } else if (!file_inside_chroot(nsd.pidfile, nsd.chrootdir)) {
866 error("pidfile %s is not relative to %s: chroot not possible",
867 nsd.pidfile, nsd.chrootdir);
868 } else if (!file_inside_chroot(nsd.dbfile, nsd.chrootdir)) {
869 error("database %s is not relative to %s: chroot not possible",
870 nsd.dbfile, nsd.chrootdir);
871 } else if (!file_inside_chroot(nsd.options->xfrdfile, nsd.chrootdir)) {
872 error("xfrdfile %s is not relative to %s: chroot not possible",
873 nsd.options->xfrdfile, nsd.chrootdir);
874 } else if (!file_inside_chroot(nsd.options->zonelistfile, nsd.chrootdir)) {
875 error("zonelistfile %s is not relative to %s: chroot not possible",
876 nsd.options->zonelistfile, nsd.chrootdir);
877 } else if (!file_inside_chroot(nsd.options->xfrdir, nsd.chrootdir)) {
878 error("xfrdir %s is not relative to %s: chroot not possible",
879 nsd.options->xfrdir, nsd.chrootdir);
880 }
881 }
882
883 /* Set up the logging */
884 log_open(LOG_PID, FACILITY, nsd.log_filename);
885 if (!nsd.log_filename)
886 log_set_log_function(log_syslog);
887 else if (nsd.uid && nsd.gid) {
888 if(chown(nsd.log_filename, nsd.uid, nsd.gid) != 0)
889 VERBOSITY(2, (LOG_WARNING, "chown %s failed: %s",
890 nsd.log_filename, strerror(errno)));
891 }
892 log_msg(LOG_NOTICE, "%s starting (%s)", argv0, PACKAGE_STRING);
893
894 /* Do we have a running nsd? */
895 if ((oldpid = readpid(nsd.pidfile)) == -1) {
896 if (errno != ENOENT) {
897 log_msg(LOG_ERR, "can't read pidfile %s: %s",
898 nsd.pidfile, strerror(errno));
899 }
900 } else {
901 if (kill(oldpid, 0) == 0 || errno == EPERM) {
902 log_msg(LOG_WARNING,
903 "%s is already running as %u, continuing",
904 argv0, (unsigned) oldpid);
905 } else {
906 log_msg(LOG_ERR,
907 "...stale pid file from process %u",
908 (unsigned) oldpid);
909 }
910 }
911
912 /* Setup the signal handling... */
913 action.sa_handler = sig_handler;
914 sigfillset(&action.sa_mask);
915 action.sa_flags = 0;
916 sigaction(SIGTERM, &action, NULL);
917 sigaction(SIGHUP, &action, NULL);
918 sigaction(SIGINT, &action, NULL);
919 sigaction(SIGILL, &action, NULL);
920 sigaction(SIGUSR1, &action, NULL);
921 sigaction(SIGALRM, &action, NULL);
922 sigaction(SIGCHLD, &action, NULL);
923 action.sa_handler = SIG_IGN;
924 sigaction(SIGPIPE, &action, NULL);
925
926 /* Initialize... */
927 nsd.mode = NSD_RUN;
928 nsd.signal_hint_child = 0;
929 nsd.signal_hint_reload = 0;
930 nsd.signal_hint_reload_hup = 0;
931 nsd.signal_hint_quit = 0;
932 nsd.signal_hint_shutdown = 0;
933 nsd.signal_hint_stats = 0;
934 nsd.signal_hint_statsusr = 0;
935 nsd.quit_sync_done = 0;
936
937 /* Initialize the server... */
938 if (server_init(&nsd) != 0) {
939 error("server initialization failed, %s could "
940 "not be started", argv0);
941 }
942 #if defined(HAVE_SSL)
943 if(nsd.options->control_enable) {
944 /* read ssl keys while superuser and outside chroot */
945 if(!(nsd.rc = daemon_remote_create(nsd.options)))
946 error("could not perform remote control setup");
947 }
948 #endif /* HAVE_SSL */
949
950 /* Unless we're debugging, fork... */
951 if (!nsd.debug) {
952 int fd;
953
954 /* Take off... */
955 switch ((nsd.pid = fork())) {
956 case 0:
957 /* Child */
958 break;
959 case -1:
960 error("fork() failed: %s", strerror(errno));
961 break;
962 default:
963 /* Parent is done */
964 server_close_all_sockets(nsd.udp, nsd.ifs);
965 server_close_all_sockets(nsd.tcp, nsd.ifs);
966 exit(0);
967 }
968
969 /* Detach ourselves... */
970 if (setsid() == -1) {
971 error("setsid() failed: %s", strerror(errno));
972 }
973
974 if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
975 (void)dup2(fd, STDIN_FILENO);
976 (void)dup2(fd, STDOUT_FILENO);
977 (void)dup2(fd, STDERR_FILENO);
978 if (fd > 2)
979 (void)close(fd);
980 }
981 }
982
983 /* Get our process id */
984 nsd.pid = getpid();
985
986 /* Set user context */
987 #ifdef HAVE_GETPWNAM
988 if (*nsd.username) {
989 #ifdef HAVE_SETUSERCONTEXT
990 /* setusercontext does initgroups, setuid, setgid, and
991 * also resource limits from login config, but we
992 * still call setresuid, setresgid to be sure to set all uid */
993 if (setusercontext(NULL, pwd, nsd.uid,
994 LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
995 log_msg(LOG_WARNING, "unable to setusercontext %s: %s",
996 nsd.username, strerror(errno));
997 #endif /* HAVE_SETUSERCONTEXT */
998 }
999 #endif /* HAVE_GETPWNAM */
1000
1001 /* Chroot */
1002 #ifdef HAVE_CHROOT
1003 if (nsd.chrootdir && nsd.chrootdir[0]) {
1004 int l = strlen(nsd.chrootdir)-1; /* ends in trailing slash */
1005
1006 if (file_inside_chroot(nsd.log_filename, nsd.chrootdir))
1007 nsd.file_rotation_ok = 1;
1008
1009 /* strip chroot from pathnames if they're absolute */
1010 nsd.options->zonesdir += l;
1011 if (nsd.log_filename){
1012 if (nsd.log_filename[0] == '/')
1013 nsd.log_filename += l;
1014 }
1015 if (nsd.pidfile[0] == '/')
1016 nsd.pidfile += l;
1017 if (nsd.dbfile[0] == '/')
1018 nsd.dbfile += l;
1019 if (nsd.options->xfrdfile[0] == '/')
1020 nsd.options->xfrdfile += l;
1021 if (nsd.options->zonelistfile[0] == '/')
1022 nsd.options->zonelistfile += l;
1023 if (nsd.options->xfrdir[0] == '/')
1024 nsd.options->xfrdir += l;
1025
1026 /* strip chroot from pathnames of "include:" statements
1027 * on subsequent repattern commands */
1028 cfg_parser->chroot = nsd.chrootdir;
1029
1030 #ifdef HAVE_TZSET
1031 /* set timezone whilst not yet in chroot */
1032 tzset();
1033 #endif
1034 if (chroot(nsd.chrootdir)) {
1035 error("unable to chroot: %s", strerror(errno));
1036 }
1037 if (chdir("/")) {
1038 error("unable to chdir to chroot: %s", strerror(errno));
1039 }
1040 DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s",
1041 nsd.chrootdir));
1042 /* chdir to zonesdir again after chroot */
1043 if(nsd.options->zonesdir && nsd.options->zonesdir[0]) {
1044 if(chdir(nsd.options->zonesdir)) {
1045 error("unable to chdir to '%s': %s",
1046 nsd.options->zonesdir, strerror(errno));
1047 }
1048 DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s",
1049 nsd.options->zonesdir));
1050 }
1051 }
1052 else
1053 #endif /* HAVE_CHROOT */
1054 nsd.file_rotation_ok = 1;
1055
1056 DEBUG(DEBUG_IPC,1, (LOG_INFO, "file rotation on %s %sabled",
1057 nsd.log_filename, nsd.file_rotation_ok?"en":"dis"));
1058
1059 /* Write pidfile */
1060 if (writepid(&nsd) == -1) {
1061 log_msg(LOG_ERR, "cannot overwrite the pidfile %s: %s",
1062 nsd.pidfile, strerror(errno));
1063 }
1064
1065 /* Drop the permissions */
1066 #ifdef HAVE_GETPWNAM
1067 if (*nsd.username) {
1068 #ifdef HAVE_INITGROUPS
1069 if(initgroups(nsd.username, nsd.gid) != 0)
1070 log_msg(LOG_WARNING, "unable to initgroups %s: %s",
1071 nsd.username, strerror(errno));
1072 #endif /* HAVE_INITGROUPS */
1073 endpwent();
1074
1075 #ifdef HAVE_SETRESGID
1076 if(setresgid(nsd.gid,nsd.gid,nsd.gid) != 0)
1077 #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
1078 if(setregid(nsd.gid,nsd.gid) != 0)
1079 #else /* use setgid */
1080 if(setgid(nsd.gid) != 0)
1081 #endif /* HAVE_SETRESGID */
1082 error("unable to set group id of %s: %s",
1083 nsd.username, strerror(errno));
1084
1085 #ifdef HAVE_SETRESUID
1086 if(setresuid(nsd.uid,nsd.uid,nsd.uid) != 0)
1087 #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
1088 if(setreuid(nsd.uid,nsd.uid) != 0)
1089 #else /* use setuid */
1090 if(setuid(nsd.uid) != 0)
1091 #endif /* HAVE_SETRESUID */
1092 error("unable to set user id of %s: %s",
1093 nsd.username, strerror(errno));
1094
1095 DEBUG(DEBUG_IPC,1, (LOG_INFO, "dropped user privileges, run as %s",
1096 nsd.username));
1097 }
1098 #endif /* HAVE_GETPWNAM */
1099 xfrd_make_tempdir(&nsd);
1100 #ifdef USE_ZONE_STATS
1101 options_zonestatnames_create(nsd.options);
1102 server_zonestat_alloc(&nsd);
1103 #endif /* USE_ZONE_STATS */
1104 #ifdef USE_DNSTAP
1105 if(nsd.options->dnstap_enable) {
1106 nsd.dt_collector = dt_collector_create(&nsd);
1107 dt_collector_start(nsd.dt_collector, &nsd);
1108 }
1109 #endif /* USE_DNSTAP */
1110
1111 if(nsd.server_kind == NSD_SERVER_MAIN) {
1112 server_prepare_xfrd(&nsd);
1113 /* xfrd forks this before reading database, so it does not get
1114 * the memory size of the database */
1115 server_start_xfrd(&nsd, 0, 0);
1116 /* close zonelistfile in non-xfrd processes */
1117 zone_list_close(nsd.options);
1118 }
1119 if (server_prepare(&nsd) != 0) {
1120 unlinkpid(nsd.pidfile);
1121 error("server preparation failed, %s could "
1122 "not be started", argv0);
1123 }
1124 if(nsd.server_kind == NSD_SERVER_MAIN) {
1125 server_send_soa_xfrd(&nsd, 0);
1126 }
1127
1128 /* Really take off */
1129 log_msg(LOG_NOTICE, "%s started (%s), pid %d",
1130 argv0, PACKAGE_STRING, (int) nsd.pid);
1131
1132 if (nsd.server_kind == NSD_SERVER_MAIN) {
1133 server_main(&nsd);
1134 } else {
1135 server_child(&nsd);
1136 }
1137
1138 /* NOTREACH */
1139 exit(0);
1140 }
1141