1 /* rbldnsd: main program
2 */
3
4 #define _LARGEFILE64_SOURCE /* to define O_LARGEFILE if supported */
5
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <pwd.h>
14 #include <grp.h>
15 #include <sys/socket.h>
16 #include <netdb.h>
17 #include <netinet/in.h>
18 #include <signal.h>
19 #include <syslog.h>
20 #include <time.h>
21 #include <sys/time.h> /* some systems can't include time.h and sys/time.h */
22 #include <fcntl.h>
23 #include <sys/wait.h>
24 #include "rbldnsd.h"
25
26 #ifndef NO_SELECT_H
27 # include <sys/select.h>
28 #endif
29 #ifndef NO_POLL
30 # include <sys/poll.h>
31 #endif
32 #ifndef NO_MEMINFO
33 # include <malloc.h>
34 #endif
35 #ifndef NO_TIMES
36 # include <sys/times.h>
37 #endif
38 #ifndef NO_STDINT_H
39 /* if system have stdint.h, assume it have inttypes.h too */
40 # include <inttypes.h>
41 #endif
42 #ifndef NO_STATS
43 # ifndef NO_IOVEC
44 # include <sys/uio.h>
45 # define STATS_IPC_IOVEC 1
46 # endif
47 #endif
48 #ifndef NO_DSO
49 # include <dlfcn.h>
50 #endif
51
52 #ifndef NI_MAXHOST
53 # define NI_MAXHOST 1025
54 #endif
55 #ifndef NI_MAXSERV
56 # define NI_MAXSERV 32
57 #endif
58
59 #ifndef O_LARGEFILE
60 # define O_LARGEFILE 0
61 #endif
62
63 const char *version = VERSION;
64 const char *show_version = "rbldnsd " VERSION;
65 /* version to show in version.bind CH TXT reply */
66 char *progname; /* limited to 32 chars */
67 int logto;
68
error(int errnum,const char * fmt,...)69 void error(int errnum, const char *fmt, ...) {
70 char buf[256];
71 int l, pl;
72 va_list ap;
73 l = pl = ssprintf(buf, sizeof(buf), "%.30s: ", progname);
74 va_start(ap, fmt);
75 l += vssprintf(buf + l, sizeof(buf) - l, fmt, ap);
76 if (errnum)
77 l += ssprintf(buf + l, sizeof(buf) - l, ": %.50s", strerror(errnum));
78 if (logto & LOGTO_SYSLOG) {
79 fmt = buf + pl;
80 syslog(LOG_ERR, strchr(fmt, '%') ? "%s" : fmt, fmt);
81 }
82 buf[l++] = '\n';
83 write(2, buf, l);
84 _exit(1);
85 }
86
87 static unsigned recheck = 60; /* interval between checks for reload */
88 static int initialized; /* 1 when initialized */
89 static char *logfile; /* log file name */
90 #ifndef NO_STATS
91 static char *statsfile; /* statistics file */
92 static int stats_relative; /* dump relative, not absolute, stats */
93 #endif
94 int accept_in_cidr; /* accept 127.0.0.1/8-"style" CIDRs */
95 int nouncompress; /* disable on-the-fly decompression */
96 unsigned def_ttl = 35*60; /* default record TTL 35m */
97 unsigned min_ttl, max_ttl; /* TTL constraints */
98 const char def_rr[5] = "\177\0\0\2\0"; /* default A RR */
99
100 #define MAXSOCK 20 /* maximum # of supported sockets */
101 static int sock[MAXSOCK]; /* array of active sockets */
102 static int numsock; /* number of active sockets in sock[] */
103 static FILE *flog; /* log file */
104 static int flushlog; /* flush log after each line */
105 static struct zone *zonelist; /* list of zones we're authoritative for */
106 static int numzones; /* number of zones in zonelist */
107 int lazy; /* don't return AUTH section by default */
108 static int fork_on_reload;
109 /* >0 - perform fork on reloads, <0 - this is a child of reloading parent */
110 #if STATS_IPC_IOVEC
111 static struct iovec *stats_iov;
112 #endif
113 #ifndef NO_DSO
114 int (*hook_reload_check)(), (*hook_reload)();
115 int (*hook_query_access)(), (*hook_query_result)();
116 #endif
117
118 /* a list of zonetypes. */
119 const struct dstype *ds_types[] = {
120 dstype(ip4set),
121 dstype(ip4tset),
122 dstype(ip4trie),
123 dstype(ip6tset),
124 dstype(ip6trie),
125 dstype(dnset),
126 #ifdef DNHASH
127 dstype(dnhash),
128 #endif
129 dstype(combined),
130 dstype(generic),
131 dstype(acl),
132 NULL
133 };
134
135 static int do_reload(int do_fork);
136
satoi(const char * s)137 static int satoi(const char *s) {
138 int n = 0;
139 if (*s < '0' || *s > '9') return -1;
140 do n = n * 10 + (*s++ - '0');
141 while (*s >= '0' && *s <= '9');
142 return *s ? -1 : n;
143 }
144
usage(int exitcode)145 static void NORETURN usage(int exitcode) {
146 const struct dstype **dstp;
147 printf(
148 "%s: rbl dns daemon version %s\n"
149 "Usage is: %s options zonespec...\n"
150 "where options are:\n"
151 " -u user[:group] - run as this user:group (rbldns)\n"
152 " -r rootdir - chroot to this directory\n"
153 " -w workdir - working directory with zone files\n"
154 " -b address[/port] - bind to (listen on) this address (required)\n"
155 #ifndef NO_IPv6
156 " -4 - use IPv4 socket type\n"
157 " -6 - use IPv6 socket type\n"
158 #endif
159 " -t ttl - default TTL value to set in answers (35m)\n"
160 " -v - hide version information in replies to version.bind CH TXT\n"
161 " (second -v makes rbldnsd to refuse such requests completely)\n"
162 " -e - enable CIDR ranges where prefix is not on the range boundary\n"
163 " (by default ranges such 127.0.0.1/8 will be rejected)\n"
164 " -c check - time interval to check for data file updates (1m)\n"
165 " -p pidfile - write pid to specified file\n"
166 " -n - do not become a daemon\n"
167 " -f - fork a child process while reloading zones, to process requests\n"
168 " during reload (may double memory requiriments)\n"
169 " -q - quickstart, load zones after backgrounding\n"
170 " -l [+]logfile - log queries and answers to this file (+ for unbuffered)\n"
171 #ifndef NO_STATS
172 " -s [+]statsfile - write a line with short statistics summary into this\n"
173 " file every `check' (-c) secounds, for rrdtool-like applications\n"
174 " (+ to log relative, not absolute, statistics counters)\n"
175 #endif
176 " -a - omit AUTH section from regular replies, do not return list of\n"
177 " nameservers, but only return NS info when explicitly asked.\n"
178 " This is an equivalent of bind9 \"minimal-answers\" setting.\n"
179 " In future versions this mode will be the default.\n"
180 " -A - put AUTH section in every reply.\n"
181 #ifndef NO_ZLIB
182 " -C - disable on-the-fly decompression of dataset files\n"
183 #endif
184 #ifndef NO_DZO
185 " -x extension - load given extension module (.so file)\n"
186 " -X extarg - pass extarg to extension init routine\n"
187 #endif
188 " -d - dump all zones in BIND format to standard output and exit\n"
189 "each zone specified using `name:type:file,file...'\n"
190 "syntax, repeated names constitute the same zone.\n"
191 "Available dataset types:\n"
192 , progname, version, progname);
193 for(dstp = ds_types; *dstp; ++dstp)
194 printf(" %s - %s\n", (*dstp)->dst_name, (*dstp)->dst_descr);
195 exit(exitcode);
196 }
197
198 static volatile int signalled;
199 #define SIGNALLED_RELOAD 0x01
200 #define SIGNALLED_RELOG 0x02
201 #define SIGNALLED_LSTATS 0x04
202 #define SIGNALLED_SSTATS 0x08
203 #define SIGNALLED_ZSTATS 0x10
204 #define SIGNALLED_TERM 0x20
205
206 #ifdef NO_IPv6
newsocket(struct sockaddr_in * sin)207 static void newsocket(struct sockaddr_in *sin) {
208 int fd;
209 const char *host = ip4atos(ntohl(sin->sin_addr.s_addr));
210 if (numsock >= MAXSOCK)
211 error(0, "too many listening sockets (%d max)", MAXSOCK);
212 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
213 if (fd < 0)
214 error(errno, "unable to create socket");
215 if (bind(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0)
216 error(errno, "unable to bind to %s/%d", host, ntohs(sin->sin_port));
217
218 dslog(LOG_INFO, 0, "listening on %s/%d", host, ntohs(sin->sin_port));
219 sock[numsock++] = fd;
220 }
221 #else
newsocket(struct addrinfo * ai)222 static int newsocket(struct addrinfo *ai) {
223 int fd;
224 char host[NI_MAXHOST], serv[NI_MAXSERV];
225
226 if (numsock >= MAXSOCK)
227 error(0, "too many listening sockets (%d max)", MAXSOCK);
228 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
229 if (fd < 0) {
230 if (errno == EAFNOSUPPORT) return 0;
231 error(errno, "unable to create socket");
232 }
233 getnameinfo(ai->ai_addr, ai->ai_addrlen,
234 host, sizeof(host), serv, sizeof(serv),
235 NI_NUMERICHOST|NI_NUMERICSERV);
236 if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
237 error(errno, "unable to bind to %s/%s", host, serv);
238
239 dslog(LOG_INFO, 0, "listening on %s/%s", host, serv);
240 sock[numsock++] = fd;
241 return 1;
242 }
243 #endif
244
245 static void
initsockets(const char * bindaddr[MAXSOCK],int nba,int UNUSED family)246 initsockets(const char *bindaddr[MAXSOCK], int nba, int UNUSED family) {
247
248 int i, x;
249 char *host, *serv;
250 const char *ba;
251
252 #ifdef NO_IPv6
253
254 struct sockaddr_in sin;
255 ip4addr_t sinaddr;
256 int port;
257 struct servent *se;
258 struct hostent *he;
259
260 memset(&sin, 0, sizeof(sin));
261 sin.sin_family = AF_INET;
262
263 if (!(se = getservbyname("domain", "udp")))
264 port = htons(DNS_PORT);
265 else
266 port = se->s_port;
267
268 #else
269
270 struct addrinfo hints, *aires, *ai;
271
272 memset(&hints, 0, sizeof(hints));
273 hints.ai_family = family;
274 hints.ai_socktype = SOCK_DGRAM;
275 hints.ai_flags = AI_PASSIVE;
276
277 #endif
278
279 for (i = 0; i < nba; ++i) {
280 ba = bindaddr[i];
281 host = estrdup(ba);
282
283 serv = strchr(host, '/');
284 if (serv) {
285 *serv++ = '\0';
286 if (!*host)
287 error(0, "missing host part in bind address `%.60s'", ba);
288 }
289
290 #ifdef NO_IPv6
291
292 if (!serv || !*serv)
293 sin.sin_port = port;
294 else if ((x = satoi(serv)) > 0 && x <= 0xffff)
295 sin.sin_port = htons(x);
296 else if (!(se = getservbyname(serv, "udp")))
297 error(0, "unknown service in `%.60s'", ba);
298 else
299 sin.sin_port = se->s_port;
300
301 if (ip4addr(host, &sinaddr, NULL) > 0) {
302 sin.sin_addr.s_addr = htonl(sinaddr);
303 newsocket(&sin);
304 }
305 else if (!(he = gethostbyname(host))
306 || he->h_addrtype != AF_INET
307 || he->h_length != 4
308 || !he->h_addr_list[0])
309 error(0, "unknown host in `%.60s'", ba);
310 else {
311 for(x = 0; he->h_addr_list[x]; ++x) {
312 memcpy(&sin.sin_addr, he->h_addr_list[x], 4);
313 newsocket(&sin);
314 }
315 }
316
317 #else
318
319 if (!serv || !*serv)
320 serv = "domain";
321
322 x = getaddrinfo(host, serv, &hints, &aires);
323 if (x != 0)
324 error(0, "%.60s: %s", ba, gai_strerror(x));
325 for(ai = aires, x = 0; ai; ai = ai->ai_next)
326 if (newsocket(ai))
327 ++x;
328 if (!x)
329 error(0, "%.60s: no available protocols", ba);
330 freeaddrinfo(aires);
331
332 #endif
333
334 free(host);
335 }
336 endservent();
337 endhostent();
338
339 for (i = 0; i < numsock; ++i) {
340 x = 65536;
341 do
342 if (setsockopt(sock[i], SOL_SOCKET, SO_RCVBUF, (void*)&x, sizeof x) == 0)
343 break;
344 while ((x -= (x >> 5)) >= 1024);
345 }
346 }
347
init(int argc,char ** argv)348 static void init(int argc, char **argv) {
349 int c;
350 char *p;
351 const char *user = NULL;
352 const char *rootdir = NULL, *workdir = NULL, *pidfile = NULL;
353 const char *bindaddr[MAXSOCK];
354 int nba = 0;
355 uid_t uid = 0;
356 gid_t gid = 0;
357 int nodaemon = 0, quickstart = 0, dump = 0, nover = 0, forkon = 0;
358 int family = AF_UNSPEC;
359 int cfd = -1;
360 const struct zone *z;
361 #ifndef NO_DSO
362 char *ext = NULL, *extarg = NULL;
363 int (*extinit)(const char *arg, struct zone *zonelist) = NULL;
364 #endif
365
366 if ((progname = strrchr(argv[0], '/')) != NULL)
367 argv[0] = ++progname;
368 else
369 progname = argv[0];
370
371 if (argc <= 1) usage(1);
372
373 while((c = getopt(argc, argv, "u:r:b:w:t:c:p:nel:qs:h46dvaAfCx:X:")) != EOF)
374 switch(c) {
375 case 'u': user = optarg; break;
376 case 'r': rootdir = optarg; break;
377 case 'b':
378 if (nba >= MAXSOCK)
379 error(0, "too many addresses to listen on (%d max)", MAXSOCK);
380 bindaddr[nba++] = optarg;
381 break;
382 #ifndef NO_IPv6
383 case '4': family = AF_INET; break;
384 case '6': family = AF_INET6; break;
385 #else
386 case '4': break;
387 case '6': error(0, "IPv6 support isn't compiled in");
388 #endif
389 case 'w': workdir = optarg; break;
390 case 'p': pidfile = optarg; break;
391 case 't':
392 p = optarg;
393 if (*p == ':') ++p;
394 else {
395 if (!(p = parse_time(p, &def_ttl)) || !def_ttl ||
396 (*p && *p++ != ':'))
397 error(0, "invalid ttl (-t) value `%.50s'", optarg);
398 }
399 if (*p == ':') ++p;
400 else if (*p) {
401 if (!(p = parse_time(p, &min_ttl)) || (*p && *p++ != ':'))
402 error(0, "invalid minttl (-t) value `%.50s'", optarg);
403 }
404 if (*p == ':') ++p;
405 else if (*p) {
406 if (!(p = parse_time(p, &max_ttl)) || (*p && *p++ != ':'))
407 error(0, "invalid maxttl (-t) value `%.50s'", optarg);
408 }
409 if (*p)
410 error(0, "invalid value for -t (ttl) option: `%.50s'", optarg);
411 if ((min_ttl && max_ttl && min_ttl > max_ttl) ||
412 (min_ttl && def_ttl < min_ttl) ||
413 (max_ttl && def_ttl > max_ttl))
414 error(0, "inconsistent def:min:max ttl: %u:%u:%u",
415 def_ttl, min_ttl, max_ttl);
416 break;
417 case 'c':
418 if (!(p = parse_time(optarg, &recheck)) || *p)
419 error(0, "invalid check interval (-c) value `%.50s'", optarg);
420 break;
421 case 'n': nodaemon = 1; break;
422 case 'e': accept_in_cidr = 1; break;
423 case 'l':
424 logfile = optarg;
425 if (*logfile != '+') flushlog = 0;
426 else ++logfile, flushlog = 1;
427 if (!*logfile) logfile = NULL, flushlog = 0;
428 else if (logfile[0] == '-' && logfile[1] == '\0')
429 logfile = NULL, flog = stdout;
430 break;
431 break;
432 case 's':
433 #ifdef NO_STATS
434 fprintf(stderr,
435 "%s: warning: no statistics counters support is compiled in\n",
436 progname);
437 #else
438 statsfile = optarg;
439 if (*statsfile != '+') stats_relative = 0;
440 else ++statsfile, stats_relative = 1;
441 if (!*statsfile) statsfile = NULL;
442 #endif
443 break;
444 case 'q': quickstart = 1; break;
445 case 'd':
446 #ifdef NO_MASTER_DUMP
447 error(0, "master-format dump option (-d) isn't compiled in");
448 #endif
449 dump = 1;
450 break;
451 case 'v': show_version = nover++ ? NULL : "rbldnsd"; break;
452 case 'a': lazy = 1; break;
453 case 'A': lazy = 0; break;
454 case 'f': forkon = 1; break;
455 case 'C': nouncompress = 1; break;
456 #ifndef NO_DSO
457 case 'x': ext = optarg; break;
458 case 'X': extarg = optarg; break;
459 #else
460 case 'x':
461 case 'X':
462 error(0, "extension support is not compiled in");
463 #endif
464 case 'h': usage(0);
465 default: error(0, "type `%.50s -h' for help", progname);
466 }
467
468 if (!(argc -= optind))
469 error(0, "no zone(s) to service specified (-h for help)");
470 argv += optind;
471
472 #ifndef NO_MASTER_DUMP
473 if (dump) {
474 time_t now;
475 logto = LOGTO_STDERR;
476 for(c = 0; c < argc; ++c)
477 zonelist = addzone(zonelist, argv[c]);
478 init_zones_caches(zonelist);
479 if (rootdir && (chdir(rootdir) < 0 || chroot(rootdir) < 0))
480 error(errno, "unable to chroot to %.50s", rootdir);
481 if (workdir && chdir(workdir) < 0)
482 error(errno, "unable to chdir to %.50s", workdir);
483 if (!do_reload(0))
484 error(0, "zone loading errors, aborting");
485 now = time(NULL);
486 printf("; zone dump made %s", ctime(&now));
487 printf("; rbldnsd version %s\n", version);
488 for (z = zonelist; z; z = z->z_next)
489 dumpzone(z, stdout);
490 fflush(stdout);
491 exit(ferror(stdout) ? 1 : 0);
492 }
493 #endif
494
495 if (!nba)
496 error(0, "no address to listen on (-b option) specified");
497
498 tzset();
499 if (nodaemon)
500 logto = LOGTO_STDOUT|LOGTO_STDERR;
501 else {
502 /* fork early so that logging will be from right pid */
503 int pfd[2];
504 if (pipe(pfd) < 0) error(errno, "pipe() failed");
505 c = fork();
506 if (c < 0) error(errno, "fork() failed");
507 if (c > 0) {
508 close(pfd[1]);
509 if (read(pfd[0], &c, 1) < 1) exit(1);
510 else exit(0);
511 }
512 cfd = pfd[1];
513 close(pfd[0]);
514 openlog(progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
515 logto = LOGTO_STDERR|LOGTO_SYSLOG;
516 if (!quickstart && !flog) logto |= LOGTO_STDOUT;
517 }
518
519 initsockets(bindaddr, nba, family);
520
521 #ifndef NO_DSO
522 if (ext) {
523 void *handle = dlopen(ext, RTLD_NOW);
524 if (!handle)
525 error(0, "unable to load extension `%s': %s", ext, dlerror());
526 extinit = dlsym(handle, "rbldnsd_extension_init");
527 if (!extinit)
528 error(0, "unable to find extension init routine in `%s'", ext);
529 }
530 #endif
531
532 if (!user && !(uid = getuid()))
533 user = "rbldns";
534
535 if (!user)
536 p = NULL;
537 else {
538 if ((p = strchr(user, ':')) != NULL)
539 *p++ = '\0';
540 if ((c = satoi(user)) >= 0)
541 uid = c, gid = c;
542 else {
543 struct passwd *pw = getpwnam(user);
544 if (!pw)
545 error(0, "unknown user `%s'", user);
546 uid = pw->pw_uid;
547 gid = pw->pw_gid;
548 endpwent();
549 }
550 }
551 if (!uid)
552 error(0, "daemon should not run as root, specify -u option");
553 if (p) {
554 if ((c = satoi(p)) >= 0)
555 gid = c;
556 else {
557 struct group *gr = getgrnam(p);
558 if (!gr)
559 error(0, "unknown group `%s'", p);
560 gid = gr->gr_gid;
561 endgrent();
562 }
563 p[-1] = ':';
564 }
565
566 if (pidfile) {
567 int fdpid;
568 char buf[40];
569 c = sprintf(buf, "%ld\n", (long)getpid());
570 fdpid = open(pidfile, O_CREAT|O_WRONLY|O_TRUNC, 0644);
571 if (fdpid < 0 || write(fdpid, buf, c) < c)
572 error(errno, "unable to write pidfile");
573 close(fdpid);
574 }
575
576 if (rootdir && (chdir(rootdir) < 0 || chroot(rootdir) < 0))
577 error(errno, "unable to chroot to %.50s", rootdir);
578 if (workdir && chdir(workdir) < 0)
579 error(errno, "unable to chdir to %.50s", workdir);
580
581 if (user)
582 if (setgroups(1, &gid) < 0 || setgid(gid) < 0 || setuid(uid) < 0)
583 error(errno, "unable to setuid(%d:%d)", (int)uid, (int)gid);
584
585 for(c = 0; c < argc; ++c)
586 zonelist = addzone(zonelist, argv[c]);
587 init_zones_caches(zonelist);
588
589 #ifndef NO_DSO
590 if (extinit && extinit(extarg, zonelist) != 0)
591 error(0, "unable to iniitialize extension `%s'", ext);
592 #endif
593
594 if (!quickstart && !do_reload(0))
595 error(0, "zone loading errors, aborting");
596
597 /* count number of zones */
598 for(c = 0, z = zonelist; z; z = z->z_next)
599 ++c;
600 numzones = c;
601
602 #if STATS_IPC_IOVEC
603 stats_iov = (struct iovec *)emalloc(numzones * sizeof(struct iovec));
604 for(c = 0, z = zonelist; z; z = z->z_next, ++c) {
605 stats_iov[c].iov_base = (char*)&z->z_stats;
606 stats_iov[c].iov_len = sizeof(z->z_stats);
607 }
608 #endif
609 dslog(LOG_INFO, 0, "rbldnsd version %s started (%d socket(s), %d zone(s))",
610 version, numsock, numzones);
611 initialized = 1;
612
613 if (cfd >= 0) {
614 write(cfd, "", 1);
615 close(cfd);
616 close(0); close(2);
617 if (!flog) close(1);
618 setsid();
619 logto = LOGTO_SYSLOG;
620 }
621
622 if (quickstart)
623 do_reload(0);
624
625 /* only set "main" fork_on_reload after first reload */
626 fork_on_reload = forkon;
627 }
628
sighandler(int sig)629 static void sighandler(int sig) {
630 switch(sig) {
631 case SIGHUP:
632 signalled |= SIGNALLED_RELOG|SIGNALLED_RELOAD;
633 break;
634 case SIGALRM:
635 #ifndef HAVE_SETITIMER
636 alarm(recheck);
637 #endif
638 signalled |= SIGNALLED_RELOAD|SIGNALLED_SSTATS;
639 break;
640 #ifndef NO_STATS
641 case SIGUSR1:
642 signalled |= SIGNALLED_LSTATS|SIGNALLED_SSTATS;
643 break;
644 case SIGUSR2:
645 signalled |= SIGNALLED_LSTATS|SIGNALLED_SSTATS|SIGNALLED_ZSTATS;
646 break;
647 #endif
648 case SIGTERM:
649 case SIGINT:
650 signalled |= SIGNALLED_TERM;
651 break;
652 }
653 }
654
655 static sigset_t ssblock; /* signals to block during zone reload */
656 static sigset_t ssempty; /* empty set */
657
setup_signals(void)658 static void setup_signals(void) {
659 struct sigaction sa;
660 memset(&sa, 0, sizeof(sa));
661 sa.sa_handler = sighandler;
662 sigemptyset(&ssblock);
663 sigemptyset(&ssempty);
664 sigaction(SIGHUP, &sa, NULL);
665 sigaddset(&ssblock, SIGHUP);
666 sigaction(SIGALRM, &sa, NULL);
667 sigaddset(&ssblock, SIGALRM);
668 #ifndef NO_STATS
669 sigaction(SIGUSR1, &sa, NULL);
670 sigaddset(&ssblock, SIGUSR1);
671 sigaction(SIGUSR2, &sa, NULL);
672 sigaddset(&ssblock, SIGUSR2);
673 #endif
674 sigaction(SIGTERM, &sa, NULL);
675 sigaction(SIGINT, &sa, NULL);
676 signal(SIGPIPE, SIG_IGN); /* in case logfile is FIFO */
677 }
678
679 #ifndef NO_STATS
680
681 struct dnsstats gstats;
682 static struct dnsstats gptot;
683 static time_t stats_time;
684
dumpstats(void)685 static void dumpstats(void) {
686 struct dnsstats tot;
687 char name[DNS_MAXDOMAIN+1];
688 FILE *f;
689 struct zone *z;
690
691 f = fopen(statsfile, "a");
692
693 if (f)
694 fprintf(f, "%ld", (long)time(NULL));
695
696 #define C ":%" PRI_DNSCNT
697 tot = gstats;
698 for(z = zonelist; z; z = z->z_next) {
699 #define add(x) tot.x += z->z_stats.x
700 add(b_in); add(b_out);
701 add(q_ok); add(q_nxd); add(q_err);
702 #undef add
703 if (f) {
704 dns_dntop(z->z_dn, name, sizeof(name));
705 #define delta(x) z->z_stats.x - z->z_pstats.x
706 fprintf(f, " %s" C C C C C,
707 name,
708 delta(q_ok) + delta(q_nxd) + delta(q_err),
709 delta(q_ok), delta(q_nxd),
710 delta(b_in), delta(b_out));
711 #undef delta
712 }
713 if (stats_relative)
714 z->z_pstats = z->z_stats;
715 }
716 if (f) {
717 #define delta(x) tot.x - gptot.x
718 fprintf(f, " *" C C C C C "\n",
719 delta(q_ok) + delta(q_nxd) + delta(q_err),
720 delta(q_ok), delta(q_nxd),
721 delta(b_in), delta(b_out));
722 #undef delta
723 fclose(f);
724 }
725 if (stats_relative)
726 gptot = tot;
727 #undef C
728 }
729
dumpstats_z(void)730 static void dumpstats_z(void) {
731 FILE *f = fopen(statsfile, "a");
732 if (f) {
733 fprintf(f, "%ld\n", (long)time(NULL));
734 fclose(f);
735 }
736 }
737
logstats(int reset)738 static void logstats(int reset) {
739 time_t t = time(NULL);
740 time_t d = t - stats_time;
741 struct dnsstats tot = gstats;
742 char name[DNS_MAXDOMAIN+1];
743 struct zone *z;
744
745 #define C(x) " " #x "=%" PRI_DNSCNT
746 for(z = zonelist; z; z = z->z_next) {
747 #define add(x) tot.x += z->z_stats.x
748 add(b_in); add(b_out);
749 add(q_ok); add(q_nxd); add(q_err);
750 #undef add
751 dns_dntop(z->z_dn, name, sizeof(name));
752 dslog(LOG_INFO, 0,
753 "stats for %ldsecs zone %.60s:" C(tot) C(ok) C(nxd) C(err) C(in) C(out),
754 (long)d, name,
755 z->z_stats.q_ok + z->z_stats.q_nxd + z->z_stats.q_err,
756 z->z_stats.q_ok, z->z_stats.q_nxd, z->z_stats.q_err,
757 z->z_stats.b_in, z->z_stats.b_out);
758 }
759 dslog(LOG_INFO, 0,
760 "stats for %ldsec:" C(tot) C(ok) C(nxd) C(err) C(in) C(out),
761 (long)d,
762 tot.q_ok + tot.q_nxd + tot.q_err,
763 tot.q_ok, tot.q_nxd, tot.q_err,
764 tot.b_in, tot.b_out);
765 #undef C
766 if (reset) {
767 for(z = zonelist; z; z = z->z_next) {
768 memset(&z->z_stats, 0, sizeof(z->z_stats));
769 memset(&z->z_pstats, 0, sizeof(z->z_pstats));
770 }
771 memset(&gstats, 0, sizeof(gstats));
772 memset(&gptot, 0, sizeof(gptot));
773 stats_time = t;
774 }
775 }
776
777 #if STATS_IPC_IOVEC
778 # define ipc_read_stats(fd) readv(fd, stats_iov, numzones)
779 # define ipc_write_stats(fd) writev(fd, stats_iov, numzones)
780 #else
ipc_read_stats(int fd)781 static void ipc_read_stats(int fd) {
782 struct zone *z;
783 for(z = zonelist; z; z = z->z_next)
784 if (read(fd, &z->z_stats, sizeof(z->z_stats)) <= 0)
785 break;
786 }
ipc_write_stats(int fd)787 static void ipc_write_stats(int fd) {
788 const struct zone *z;
789 for(z = zonelist; z; z = z->z_next)
790 if (write(fd, &z->z_stats, sizeof(z->z_stats)) <= 0)
791 break;
792 }
793 #endif
794
795 #else
796 # define ipc_read_stats(fd)
797 # define ipc_write_stats(fd)
798 #endif
799
reopenlog(void)800 static void reopenlog(void) {
801 if (logfile) {
802 int fd;
803 if (flog) fclose(flog);
804 fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT|O_NONBLOCK|O_LARGEFILE, 0644);
805 if (fd < 0 || (flog = fdopen(fd, "a")) == NULL) {
806 dslog(LOG_WARNING, 0, "error (re)opening logfile `%.50s': %s",
807 logfile, strerror(errno));
808 if (fd >= 0) close(fd);
809 flog = NULL;
810 }
811 }
812 else if (flog && !flushlog) { /* log to stdout */
813 clearerr(flog);
814 fflush(flog);
815 }
816 }
817
check_expires(void)818 static void check_expires(void) {
819 struct zone *zone;
820 time_t now = time(NULL);
821 for (zone = zonelist; zone; zone = zone->z_next) {
822 if (!zone->z_stamp)
823 continue;
824 if (zone->z_expires && zone->z_expires < now) {
825 zlog(LOG_WARNING, zone, "zone data expired, zone will not be serviced");
826 zone->z_stamp = 0;
827 }
828 }
829 }
830
do_reload(int do_fork)831 static int do_reload(int do_fork) {
832 int r;
833 char ibuf[150];
834 int ip;
835 struct dataset *ds;
836 struct zone *zone;
837 pid_t cpid = 0; /* child pid; =0 to make gcc happy */
838 int cfd = 0; /* child stats fd; =0 to make gcc happy */
839 #ifndef NO_TIMES
840 struct tms tms;
841 clock_t utm, etm;
842 #ifndef HZ
843 static clock_t HZ;
844 #endif
845 #endif /* NO_TIMES */
846
847 ds = nextdataset2reload(NULL);
848 if (!ds && call_hook(reload_check, (zonelist)) == 0) {
849 check_expires();
850 return 1; /* nothing to reload */
851 }
852
853 if (do_fork) {
854 int pfd[2];
855 if (flog && !flushlog)
856 fflush(flog);
857 /* forking reload. if anything fails, just do a non-forking one */
858 if (pipe(pfd) < 0)
859 do_fork = 0;
860 else if ((cpid = fork()) < 0) { /* fork failed, close the pipe */
861 close(pfd[0]);
862 close(pfd[1]);
863 do_fork = 0;
864 }
865 else if (!cpid) { /* child, continue answering queries */
866 signal(SIGALRM, SIG_IGN);
867 signal(SIGHUP, SIG_IGN);
868 #ifndef NO_STATS
869 signal(SIGUSR1, SIG_IGN);
870 signal(SIGUSR2, SIG_IGN);
871 #endif
872 close(pfd[0]);
873 /* set up the fd#1 to write stats later on SIGTERM */
874 if (pfd[1] != 1) {
875 dup2(pfd[1], 1);
876 close(pfd[1]);
877 }
878 fork_on_reload = -1;
879 return 1;
880 }
881 else {
882 close(pfd[1]);
883 cfd = pfd[0];
884 }
885 }
886
887 #ifndef NO_TIMES
888 #ifndef HZ
889 if (!HZ)
890 HZ = sysconf(_SC_CLK_TCK);
891 #endif
892 etm = times(&tms);
893 utm = tms.tms_utime;
894 #endif /* NO_TIMES */
895
896 r = 1;
897 while(ds) {
898 if (!loaddataset(ds))
899 r = 0;
900 ds = nextdataset2reload(ds);
901 }
902
903 for (zone = zonelist; zone; zone = zone->z_next) {
904 time_t stamp = 0;
905 time_t expires = 0;
906 const struct dssoa *dssoa = NULL;
907 const struct dsns *dsns = NULL;
908 unsigned nsttl = 0;
909 struct dslist *dsl;
910
911 for(dsl = zone->z_dsl; dsl; dsl = dsl->dsl_next) {
912 const struct dataset *ds = dsl->dsl_ds;
913 if (!ds->ds_stamp) {
914 stamp = 0;
915 break;
916 }
917 if (stamp < ds->ds_stamp)
918 stamp = ds->ds_stamp;
919 if (ds->ds_expires && (!expires || expires > ds->ds_expires))
920 expires = ds->ds_expires;
921 if (!dssoa)
922 dssoa = ds->ds_dssoa;
923 if (!dsns)
924 dsns = ds->ds_dsns, nsttl = ds->ds_nsttl;
925 }
926
927 zone->z_expires = expires;
928 zone->z_stamp = stamp;
929 if (!stamp) {
930 zlog(LOG_WARNING, zone,
931 "not all datasets are loaded, zone will not be serviced");
932 r = 0;
933 }
934 else if (!update_zone_soa(zone, dssoa) ||
935 !update_zone_ns(zone, dsns, nsttl, zonelist))
936 zlog(LOG_WARNING, zone,
937 "NS or SOA RRs are too long, will be ignored");
938 }
939
940 if (call_hook(reload, (zonelist)) != 0)
941 r = 0;
942
943 ip = ssprintf(ibuf, sizeof(ibuf), "zones reloaded");
944 #ifndef NO_TIMES
945 etm = times(&tms) - etm;
946 utm = tms.tms_utime - utm;
947 # define sec(tm) (unsigned long)(tm/HZ), (unsigned long)((tm*100/HZ)%100)
948 ip += ssprintf(ibuf + ip, sizeof(ibuf) - ip,
949 ", time %lu.%lue/%lu.%luu sec", sec(etm), sec(utm));
950 # undef sec
951 #endif /* NO_TIMES */
952 #ifndef NO_MEMINFO
953 {
954 struct mallinfo mi = mallinfo();
955 # define kb(x) ((mi.x + 512)>>10)
956 ip += ssprintf(ibuf + ip, sizeof(ibuf) - ip,
957 ", mem arena=%d free=%d mmap=%d Kb",
958 kb(arena), kb(fordblks), kb(hblkhd));
959 # undef kb
960 }
961 #endif /* NO_MEMINFO */
962 dslog(LOG_INFO, 0, ibuf);
963
964 check_expires();
965
966 /* ok, (something) loaded. */
967
968 if (do_fork) {
969 /* here we should notify query-answering child (send SIGTERM to it),
970 * and wait for it to complete.
971 * Unfortunately at least on linux, the SIGTERM sometimes gets ignored
972 * by the child process, so we're trying several times here, in a loop.
973 */
974 int s, n;
975 fd_set fds;
976 struct timeval tv;
977
978 for(n = 1; ++n;) {
979 if (kill(cpid, SIGTERM) != 0)
980 dslog(LOG_WARNING, 0, "kill(qchild): %s", strerror(errno));
981 FD_ZERO(&fds);
982 FD_SET(cfd, &fds);
983 tv.tv_sec = 0;
984 tv.tv_usec = 500000;
985 s = select(cfd+1, &fds, NULL, NULL, &tv);
986 if (s > 0) break;
987 dslog(LOG_WARNING, 0, "waiting for qchild process: %s, retrying",
988 s ? strerror(errno) : "timeout");
989 }
990 ipc_read_stats(cfd);
991 close(cfd);
992 wait(&s);
993 }
994
995 return r;
996 }
997
do_signalled(void)998 static void do_signalled(void) {
999 sigprocmask(SIG_SETMASK, &ssblock, NULL);
1000 if (signalled & SIGNALLED_TERM) {
1001 if (fork_on_reload < 0) { /* this is a temp child; dump stats and exit */
1002 ipc_write_stats(1);
1003 if (flog && !flushlog)
1004 fflush(flog);
1005 _exit(0);
1006 }
1007 dslog(LOG_INFO, 0, "terminating");
1008 #ifndef NO_STATS
1009 if (statsfile)
1010 dumpstats();
1011 logstats(0);
1012 if (statsfile)
1013 dumpstats_z();
1014 #endif
1015 exit(0);
1016 }
1017 #ifndef NO_STATS
1018 if (signalled & SIGNALLED_SSTATS && statsfile)
1019 dumpstats();
1020 if (signalled & SIGNALLED_LSTATS) {
1021 logstats(signalled & SIGNALLED_ZSTATS);
1022 if (signalled & SIGNALLED_ZSTATS && statsfile)
1023 dumpstats_z();
1024 }
1025 #endif
1026 if (signalled & SIGNALLED_RELOG)
1027 reopenlog();
1028 if (signalled & SIGNALLED_RELOAD)
1029 do_reload(fork_on_reload);
1030 signalled = 0;
1031 sigprocmask(SIG_SETMASK, &ssempty, NULL);
1032 }
1033
1034 #ifndef NO_IPv6
1035 static struct sockaddr_storage peer_sa;
1036 #else
1037 static struct sockaddr_in peer_sa;
1038 #endif
1039 static struct dnspacket pkt;
1040
request(int fd)1041 static void request(int fd) {
1042 int q, r;
1043 socklen_t salen = sizeof(peer_sa);
1044
1045 q = recvfrom(fd, (void*)pkt.p_buf, sizeof(pkt.p_buf), 0,
1046 (struct sockaddr *)&peer_sa, &salen);
1047 if (q <= 0) /* interrupted? */
1048 return;
1049
1050 pkt.p_peerlen = salen;
1051 r = replypacket(&pkt, q, zonelist);
1052 if (!r)
1053 return;
1054 if (flog)
1055 logreply(&pkt, flog, flushlog);
1056
1057 /* finally, send a reply */
1058 while(sendto(fd, (void*)pkt.p_buf, r, 0,
1059 (struct sockaddr *)&peer_sa, salen) < 0)
1060 if (errno != EINTR) break;
1061
1062 }
1063
main(int argc,char ** argv)1064 int main(int argc, char **argv) {
1065 init(argc, argv);
1066 setup_signals();
1067 reopenlog();
1068 #ifdef HAVE_SETITIMER
1069 if (recheck) {
1070 struct itimerval itv;
1071 itv.it_interval.tv_sec = itv.it_value.tv_sec = recheck;
1072 itv.it_interval.tv_usec = itv.it_value.tv_usec = 0;
1073 if (setitimer(ITIMER_REAL, &itv, NULL) < 0)
1074 error(errno, "unable to setitimer()");
1075 }
1076 #else
1077 alarm(recheck);
1078 #endif
1079 #ifndef NO_STATS
1080 stats_time = time(NULL);
1081 if (statsfile)
1082 dumpstats_z();
1083 #endif
1084
1085 pkt.p_peer = (struct sockaddr *)&peer_sa;
1086
1087 if (numsock == 1) {
1088 /* optimized case for only one socket */
1089 int fd = sock[0];
1090 for(;;) {
1091 if (signalled) do_signalled();
1092 request(fd);
1093 }
1094 }
1095 else {
1096 /* several sockets, do select/poll loop */
1097 #ifdef NO_POLL
1098 fd_set rfds;
1099 int maxfd = 0;
1100 int *fdi, *fde = sock + numsock;
1101 FD_ZERO(&rfds);
1102 for (fdi = sock; fdi < fde; ++fdi) {
1103 FD_SET(*fdi, &rfds);
1104 if (*fdi > maxfd) maxfd = *fdi;
1105 }
1106 ++maxfd;
1107 for(;;) {
1108 fd_set rfd = rfds;
1109 if (signalled) do_signalled();
1110 if (select(maxfd, &rfd, NULL, NULL, NULL) <= 0)
1111 continue;
1112 for(fdi = sock; fdi < fde; ++fdi) {
1113 if (FD_ISSET(*fdi, &rfd))
1114 request(*fdi);
1115 }
1116 }
1117 #else /* !NO_POLL */
1118 struct pollfd pfda[MAXSOCK];
1119 struct pollfd *pfdi, *pfde = pfda + numsock;
1120 int r;
1121 for(r = 0; r < numsock; ++r) {
1122 pfda[r].fd = sock[r];
1123 pfda[r].events = POLLIN;
1124 }
1125 for(;;) {
1126 if (signalled) do_signalled();
1127 r = poll(pfda, numsock, -1);
1128 if (r <= 0) continue;
1129 for(pfdi = pfda; pfdi < pfde; ++pfdi) {
1130 if (!(pfdi->revents & POLLIN)) continue;
1131 request(pfdi->fd);
1132 if (!--r) break;
1133 }
1134 }
1135 #endif /* NO_POLL */
1136 }
1137 }
1138
oom(void)1139 void oom(void) {
1140 if (initialized)
1141 dslog(LOG_ERR, 0, "out of memory loading dataset");
1142 else
1143 error(0, "out of memory");
1144 }
1145