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