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