Home | History | Annotate | Download | only in src
      1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
      2 
      3    This program is free software; you can redistribute it and/or modify
      4    it under the terms of the GNU General Public License as published by
      5    the Free Software Foundation; version 2 dated June, 1991, or
      6    (at your option) version 3 dated 29 June, 2007.
      7 
      8    This program is distributed in the hope that it will be useful,
      9    but WITHOUT ANY WARRANTY; without even the implied warranty of
     10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11    GNU General Public License for more details.
     12 
     13    You should have received a copy of the GNU General Public License
     14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 */
     16 
     17 #include "dnsmasq.h"
     18 
     19 #ifdef __ANDROID__
     20 #include <android/log.h>
     21 #endif
     22 
     23 /* Implement logging to /dev/log asynchronously. If syslogd is
     24    making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
     25    syslogd, then the two daemons can deadlock. We get around this
     26    by not blocking when talking to syslog, instead we queue up to
     27    MAX_LOGS messages. If more are queued, they will be dropped,
     28    and the drop event itself logged. */
     29 
     30 /* The "wire" protocol for logging is defined in RFC 3164 */
     31 
     32 /* From RFC 3164 */
     33 #define MAX_MESSAGE 1024
     34 
     35 /* defaults in case we die() before we log_start() */
     36 static int log_fac = LOG_DAEMON;
     37 static int log_stderr = 0;
     38 static int log_fd = -1;
     39 static int log_to_file = 0;
     40 static int entries_alloced = 0;
     41 static int entries_lost = 0;
     42 static int connection_good = 1;
     43 static int max_logs = 0;
     44 static int connection_type = SOCK_DGRAM;
     45 
     46 struct log_entry {
     47     int offset, length;
     48     pid_t pid; /* to avoid duplicates over a fork */
     49     struct log_entry* next;
     50     char payload[MAX_MESSAGE];
     51 };
     52 
     53 static struct log_entry* entries = NULL;
     54 static struct log_entry* free_entries = NULL;
     55 
     56 int log_start(struct passwd* ent_pw, int errfd) {
     57     int ret = 0;
     58 
     59     log_stderr = !!(daemon->options & OPT_DEBUG);
     60 
     61     if (daemon->log_fac != -1) log_fac = daemon->log_fac;
     62 #ifdef LOG_LOCAL0
     63     else if (daemon->options & OPT_DEBUG)
     64         log_fac = LOG_LOCAL0;
     65 #endif
     66 
     67     if (daemon->log_file) {
     68         log_to_file = 1;
     69         daemon->max_logs = 0;
     70     }
     71 
     72     max_logs = daemon->max_logs;
     73 
     74     if (!log_reopen(daemon->log_file)) {
     75         send_event(errfd, EVENT_LOG_ERR, errno);
     76         _exit(0);
     77     }
     78 
     79     /* if queuing is inhibited, make sure we allocate
     80        the one required buffer now. */
     81     if (max_logs == 0) {
     82         free_entries = safe_malloc(sizeof(struct log_entry));
     83         free_entries->next = NULL;
     84         entries_alloced = 1;
     85     }
     86 
     87     /* If we're running as root and going to change uid later,
     88        change the ownership here so that the file is always owned by
     89        the dnsmasq user. Then logrotate can just copy the owner.
     90        Failure of the chown call is OK, (for instance when started as non-root) */
     91     if (log_to_file && ent_pw && ent_pw->pw_uid != 0 && fchown(log_fd, ent_pw->pw_uid, -1) != 0)
     92         ret = errno;
     93 
     94     return ret;
     95 }
     96 
     97 int log_reopen(char* log_file) {
     98     if (log_fd != -1) close(log_fd);
     99 
    100     /* NOTE: umask is set to 022 by the time this gets called */
    101 
    102     if (log_file) {
    103         log_fd = open(log_file, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP);
    104         return log_fd != -1;
    105     } else
    106 #if defined(__ANDROID__)
    107 #define _PATH_LOG "" /* dummy */
    108         log_fd = -1;
    109 #else
    110     {
    111         int flags;
    112         log_fd = socket(AF_UNIX, connection_type, 0);
    113 
    114         if (log_fd == -1) return 0;
    115 
    116         /* if max_logs is zero, leave the socket blocking */
    117         if (max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
    118             fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
    119     }
    120 #endif
    121 
    122     return 1;
    123 }
    124 
    125 static void free_entry(void) {
    126     struct log_entry* tmp = entries;
    127     entries = tmp->next;
    128     tmp->next = free_entries;
    129     free_entries = tmp;
    130 }
    131 
    132 static void log_write(void) {
    133     ssize_t rc;
    134 
    135     while (entries) {
    136         /* Avoid duplicates over a fork() */
    137         if (entries->pid != getpid()) {
    138             free_entry();
    139             continue;
    140         }
    141 
    142         connection_good = 1;
    143 
    144         if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1) {
    145             entries->length -= rc;
    146             entries->offset += rc;
    147             if (entries->length == 0) {
    148                 free_entry();
    149                 if (entries_lost != 0) {
    150                     int e = entries_lost;
    151                     entries_lost = 0; /* avoid wild recursion */
    152                     my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
    153                 }
    154             }
    155             continue;
    156         }
    157 
    158         if (errno == EINTR) continue;
    159 
    160         if (errno == EAGAIN) return; /* syslogd busy, go again when select() or poll() says so */
    161 
    162         if (errno == ENOBUFS) {
    163             connection_good = 0;
    164             return;
    165         }
    166 
    167         /* errors handling after this assumes sockets */
    168         if (!log_to_file) {
    169             /* Once a stream socket hits EPIPE, we have to close and re-open
    170                (we ignore SIGPIPE) */
    171             if (errno == EPIPE) {
    172                 if (log_reopen(NULL)) continue;
    173             } else if (errno == ECONNREFUSED || errno == ENOTCONN || errno == EDESTADDRREQ ||
    174                        errno == ECONNRESET) {
    175                 /* socket went (syslogd down?), try and reconnect. If we fail,
    176                stop trying until the next call to my_syslog()
    177                ECONNREFUSED -> connection went down
    178                ENOTCONN -> nobody listening
    179                (ECONNRESET, EDESTADDRREQ are *BSD equivalents) */
    180 
    181                 struct sockaddr_un logaddr;
    182 
    183                 logaddr.sun_family = AF_UNIX;
    184                 strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
    185 
    186                 /* Got connection back? try again. */
    187                 if (connect(log_fd, (struct sockaddr*) &logaddr, sizeof(logaddr)) != -1) continue;
    188 
    189                 /* errors from connect which mean we should keep trying */
    190                 if (errno == ENOENT || errno == EALREADY || errno == ECONNREFUSED ||
    191                     errno == EISCONN || errno == EINTR || errno == EAGAIN) {
    192                     /* try again on next syslog() call */
    193                     connection_good = 0;
    194                     return;
    195                 }
    196 
    197                 /* try the other sort of socket... */
    198                 if (errno == EPROTOTYPE) {
    199                     connection_type = connection_type == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
    200                     if (log_reopen(NULL)) continue;
    201                 }
    202             }
    203         }
    204 
    205         /* give up - fall back to syslog() - this handles out-of-space
    206        when logging to a file, for instance. */
    207         log_fd = -1;
    208         my_syslog(LOG_CRIT, _("log failed: %s"), strerror(errno));
    209         return;
    210     }
    211 }
    212 
    213 /* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
    214    OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
    215    DNS, DHCP and TFTP services.
    216 */
    217 void my_syslog(int priority, const char* format, ...) {
    218     va_list ap;
    219     struct log_entry* entry;
    220     time_t time_now;
    221     char* p;
    222     size_t len;
    223     pid_t pid = getpid();
    224     char* func = "";
    225 #ifdef __ANDROID__
    226     int alog_lvl;
    227 #endif
    228 
    229     if ((LOG_FACMASK & priority) == MS_TFTP)
    230         func = "-tftp";
    231     else if ((LOG_FACMASK & priority) == MS_DHCP)
    232         func = "-dhcp";
    233 
    234     priority = LOG_PRI(priority);
    235 
    236     if (log_stderr) {
    237         fprintf(stderr, "dnsmasq%s: ", func);
    238         va_start(ap, format);
    239         vfprintf(stderr, format, ap);
    240         va_end(ap);
    241         fputc('\n', stderr);
    242     }
    243 
    244 #ifdef __ANDROID__
    245     if (priority <= LOG_ERR)
    246         alog_lvl = ANDROID_LOG_ERROR;
    247     else if (priority == LOG_WARNING)
    248         alog_lvl = ANDROID_LOG_WARN;
    249     else if (priority <= LOG_INFO)
    250         alog_lvl = ANDROID_LOG_INFO;
    251     else
    252         alog_lvl = ANDROID_LOG_DEBUG;
    253     va_start(ap, format);
    254     __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
    255     va_end(ap);
    256 #else
    257 
    258     if (log_fd == -1) {
    259         /* fall-back to syslog if we die during startup or fail during running. */
    260         static int isopen = 0;
    261         if (!isopen) {
    262             openlog("dnsmasq", LOG_PID, log_fac);
    263             isopen = 1;
    264         }
    265         va_start(ap, format);
    266         vsyslog(priority, format, ap);
    267         va_end(ap);
    268         return;
    269     }
    270 
    271     if ((entry = free_entries))
    272         free_entries = entry->next;
    273     else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
    274         entries_alloced++;
    275 
    276     if (!entry)
    277         entries_lost++;
    278     else {
    279         /* add to end of list, consumed from the start */
    280         entry->next = NULL;
    281         if (!entries)
    282             entries = entry;
    283         else {
    284             struct log_entry* tmp;
    285             for (tmp = entries; tmp->next; tmp = tmp->next)
    286                 ;
    287             tmp->next = entry;
    288         }
    289 
    290         time(&time_now);
    291         p = entry->payload;
    292         if (!log_to_file) p += sprintf(p, "<%d>", priority | log_fac);
    293 
    294         p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int) pid);
    295 
    296         len = p - entry->payload;
    297         va_start(ap, format);
    298         len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
    299         va_end(ap);
    300         entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
    301         entry->offset = 0;
    302         entry->pid = pid;
    303 
    304         /* replace terminator with \n */
    305         if (log_to_file) entry->payload[entry->length - 1] = '\n';
    306     }
    307 
    308     /* almost always, logging won't block, so try and write this now,
    309        to save collecting too many log messages during a select loop. */
    310     log_write();
    311 
    312     /* Since we're doing things asynchronously, a cache-dump, for instance,
    313        can now generate log lines very fast. With a small buffer (desirable),
    314        that means it can overflow the log-buffer very quickly,
    315        so that the cache dump becomes mainly a count of how many lines
    316        overflowed. To avoid this, we delay here, the delay is controlled
    317        by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
    318        The scaling stuff ensures that when the queue is bigger than 8, the delay
    319        only occurs for the last 8 entries. Once the queue is full, we stop delaying
    320        to preserve performance.
    321     */
    322 
    323     if (entries && max_logs != 0) {
    324         int d;
    325 
    326         for (d = 0, entry = entries; entry; entry = entry->next, d++)
    327             ;
    328 
    329         if (d == max_logs)
    330             d = 0;
    331         else if (max_logs > 8)
    332             d -= max_logs - 8;
    333 
    334         if (d > 0) {
    335             struct timespec waiter;
    336             waiter.tv_sec = 0;
    337             waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
    338             nanosleep(&waiter, NULL);
    339 
    340             /* Have another go now */
    341             log_write();
    342         }
    343     }
    344 #endif
    345 }
    346 
    347 void set_log_writer(fd_set* set, int* maxfdp) {
    348     if (entries && log_fd != -1 && connection_good) {
    349         FD_SET(log_fd, set);
    350         bump_maxfd(log_fd, maxfdp);
    351     }
    352 }
    353 
    354 void check_log_writer(fd_set* set) {
    355     if (log_fd != -1 && (!set || FD_ISSET(log_fd, set))) log_write();
    356 }
    357 
    358 void flush_log(void) {
    359     /* block until queue empty */
    360     if (log_fd != -1) {
    361         int flags;
    362         if ((flags = fcntl(log_fd, F_GETFL)) != -1) fcntl(log_fd, F_SETFL, flags & ~O_NONBLOCK);
    363         log_write();
    364         close(log_fd);
    365     }
    366 }
    367 
    368 void die(char* message, char* arg1, int exit_code) {
    369     char* errmess = strerror(errno);
    370 
    371     if (!arg1) arg1 = errmess;
    372 
    373     log_stderr = 1;      /* print as well as log when we die.... */
    374     fputc('\n', stderr); /* prettyfy  startup-script message */
    375     my_syslog(LOG_CRIT, message, arg1, errmess);
    376 
    377     log_stderr = 0;
    378     my_syslog(LOG_CRIT, _("FAILED to start up"));
    379     flush_log();
    380 
    381     exit(exit_code);
    382 }
    383