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