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