"Fossies" - the Fresh Open Source Software Archive

Member "rbldnsd-0.998/rbldnsd.c" (6 Apr 2013, 30274 Bytes) of package /linux/misc/dns/rbldnsd-0.998.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rbldnsd.c" see the Fossies "Dox" file reference documentation.

    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 
   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 
  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 
  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
  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
  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
  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 
  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 
  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 
  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 
  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 
  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 
  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
  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 }
  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 
  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 
  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 
  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 
  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 
 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 
 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 
 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 }