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