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() */
36static int log_fac = LOG_DAEMON;
37static int log_stderr = 0;
38static int log_fd = -1;
39static int log_to_file = 0;
40static int entries_alloced = 0;
41static int entries_lost = 0;
42static int connection_good = 1;
43static int max_logs = 0;
44static int connection_type = SOCK_DGRAM;
45
46struct 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
53static struct log_entry *entries = NULL;
54static struct log_entry *free_entries = NULL;
55
56
57int log_start(struct passwd *ent_pw, int errfd)
58{
59  int ret = 0;
60
61  log_stderr = !!(daemon->options & OPT_DEBUG);
62
63  if (daemon->log_fac != -1)
64    log_fac = daemon->log_fac;
65#ifdef LOG_LOCAL0
66  else if (daemon->options & OPT_DEBUG)
67    log_fac = LOG_LOCAL0;
68#endif
69
70  if (daemon->log_file)
71    {
72      log_to_file = 1;
73      daemon->max_logs = 0;
74    }
75
76  max_logs = daemon->max_logs;
77
78  if (!log_reopen(daemon->log_file))
79    {
80      send_event(errfd, EVENT_LOG_ERR, errno);
81      _exit(0);
82    }
83
84  /* if queuing is inhibited, make sure we allocate
85     the one required buffer now. */
86  if (max_logs == 0)
87    {
88      free_entries = safe_malloc(sizeof(struct log_entry));
89      free_entries->next = NULL;
90      entries_alloced = 1;
91    }
92
93  /* If we're running as root and going to change uid later,
94     change the ownership here so that the file is always owned by
95     the dnsmasq user. Then logrotate can just copy the owner.
96     Failure of the chown call is OK, (for instance when started as non-root) */
97  if (log_to_file && ent_pw && ent_pw->pw_uid != 0 &&
98      fchown(log_fd, ent_pw->pw_uid, -1) != 0)
99    ret = errno;
100
101  return ret;
102}
103
104int log_reopen(char *log_file)
105{
106  if (log_fd != -1)
107    close(log_fd);
108
109  /* NOTE: umask is set to 022 by the time this gets called */
110
111  if (log_file)
112    {
113      log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
114      return log_fd != -1;
115    }
116  else
117#if defined(__ANDROID__)
118#   define _PATH_LOG ""  /* dummy */
119    log_fd = -1;
120#else
121    {
122       int flags;
123       log_fd = socket(AF_UNIX, connection_type, 0);
124
125      if (log_fd == -1)
126	return 0;
127
128      /* if max_logs is zero, leave the socket blocking */
129      if (max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
130	fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
131    }
132#endif
133
134  return 1;
135}
136
137static void free_entry(void)
138{
139  struct log_entry *tmp = entries;
140  entries = tmp->next;
141  tmp->next = free_entries;
142  free_entries = tmp;
143}
144
145static void log_write(void)
146{
147  ssize_t rc;
148
149  while (entries)
150    {
151      /* Avoid duplicates over a fork() */
152      if (entries->pid != getpid())
153	{
154	  free_entry();
155	  continue;
156	}
157
158      connection_good = 1;
159
160      if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
161	{
162	  entries->length -= rc;
163	  entries->offset += rc;
164	  if (entries->length == 0)
165	    {
166	      free_entry();
167	      if (entries_lost != 0)
168		{
169		  int e = entries_lost;
170		  entries_lost = 0; /* avoid wild recursion */
171		  my_syslog(LOG_WARNING, _("overflow: %d log entries lost"), e);
172		}
173	    }
174	  continue;
175	}
176
177      if (errno == EINTR)
178	continue;
179
180      if (errno == EAGAIN)
181	return; /* syslogd busy, go again when select() or poll() says so */
182
183      if (errno == ENOBUFS)
184	{
185	  connection_good = 0;
186	  return;
187	}
188
189      /* errors handling after this assumes sockets */
190      if (!log_to_file)
191	{
192	  /* Once a stream socket hits EPIPE, we have to close and re-open
193	     (we ignore SIGPIPE) */
194	  if (errno == EPIPE)
195	    {
196	      if (log_reopen(NULL))
197		continue;
198	    }
199	  else if (errno == ECONNREFUSED ||
200		   errno == ENOTCONN ||
201		   errno == EDESTADDRREQ ||
202		   errno == ECONNRESET)
203	    {
204	      /* socket went (syslogd down?), try and reconnect. If we fail,
205		 stop trying until the next call to my_syslog()
206		 ECONNREFUSED -> connection went down
207		 ENOTCONN -> nobody listening
208		 (ECONNRESET, EDESTADDRREQ are *BSD equivalents) */
209
210	      struct sockaddr_un logaddr;
211
212#ifdef HAVE_SOCKADDR_SA_LEN
213	      logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
214#endif
215	      logaddr.sun_family = AF_UNIX;
216	      strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
217
218	      /* Got connection back? try again. */
219	      if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
220		continue;
221
222	      /* errors from connect which mean we should keep trying */
223	      if (errno == ENOENT ||
224		  errno == EALREADY ||
225		  errno == ECONNREFUSED ||
226		  errno == EISCONN ||
227		  errno == EINTR ||
228		  errno == EAGAIN)
229		{
230		  /* try again on next syslog() call */
231		  connection_good = 0;
232		  return;
233		}
234
235	      /* try the other sort of socket... */
236	      if (errno == EPROTOTYPE)
237		{
238		  connection_type = connection_type == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
239		  if (log_reopen(NULL))
240		    continue;
241		}
242	    }
243	}
244
245      /* give up - fall back to syslog() - this handles out-of-space
246	 when logging to a file, for instance. */
247      log_fd = -1;
248      my_syslog(LOG_CRIT, _("log failed: %s"), strerror(errno));
249      return;
250    }
251}
252
253/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
254   OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
255   DNS, DHCP and TFTP services.
256*/
257void my_syslog(int priority, const char *format, ...)
258{
259  va_list ap;
260  struct log_entry *entry;
261  time_t time_now;
262  char *p;
263  size_t len;
264  pid_t pid = getpid();
265  char *func = "";
266#ifdef __ANDROID__
267  int alog_lvl;
268#endif
269
270  if ((LOG_FACMASK & priority) == MS_TFTP)
271    func = "-tftp";
272  else if ((LOG_FACMASK & priority) == MS_DHCP)
273    func = "-dhcp";
274
275  priority = LOG_PRI(priority);
276
277  if (log_stderr)
278    {
279      fprintf(stderr, "dnsmasq%s: ", func);
280      va_start(ap, format);
281      vfprintf(stderr, format, ap);
282      va_end(ap);
283      fputc('\n', stderr);
284    }
285
286#ifdef __ANDROID__
287    if (priority <= LOG_ERR)
288      alog_lvl = ANDROID_LOG_ERROR;
289    else if (priority == LOG_WARNING)
290      alog_lvl = ANDROID_LOG_WARN;
291    else if (priority <= LOG_INFO)
292      alog_lvl = ANDROID_LOG_INFO;
293    else
294      alog_lvl = ANDROID_LOG_DEBUG;
295    va_start(ap, format);
296    __android_log_vprint(alog_lvl, "dnsmasq", format, ap);
297    va_end(ap);
298#else
299
300  if (log_fd == -1)
301    {
302      /* fall-back to syslog if we die during startup or fail during running. */
303      static int isopen = 0;
304      if (!isopen)
305	{
306	  openlog("dnsmasq", LOG_PID, log_fac);
307	  isopen = 1;
308	}
309      va_start(ap, format);
310      vsyslog(priority, format, ap);
311      va_end(ap);
312      return;
313    }
314
315  if ((entry = free_entries))
316    free_entries = entry->next;
317  else if (entries_alloced < max_logs && (entry = malloc(sizeof(struct log_entry))))
318    entries_alloced++;
319
320  if (!entry)
321    entries_lost++;
322  else
323    {
324      /* add to end of list, consumed from the start */
325      entry->next = NULL;
326      if (!entries)
327	entries = entry;
328      else
329	{
330	  struct log_entry *tmp;
331	  for (tmp = entries; tmp->next; tmp = tmp->next);
332	  tmp->next = entry;
333	}
334
335      time(&time_now);
336      p = entry->payload;
337      if (!log_to_file)
338	p += sprintf(p, "<%d>", priority | log_fac);
339
340      p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
341
342      len = p - entry->payload;
343      va_start(ap, format);
344      len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
345      va_end(ap);
346      entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
347      entry->offset = 0;
348      entry->pid = pid;
349
350      /* replace terminator with \n */
351      if (log_to_file)
352	entry->payload[entry->length - 1] = '\n';
353    }
354
355  /* almost always, logging won't block, so try and write this now,
356     to save collecting too many log messages during a select loop. */
357  log_write();
358
359  /* Since we're doing things asynchronously, a cache-dump, for instance,
360     can now generate log lines very fast. With a small buffer (desirable),
361     that means it can overflow the log-buffer very quickly,
362     so that the cache dump becomes mainly a count of how many lines
363     overflowed. To avoid this, we delay here, the delay is controlled
364     by queue-occupancy, and grows exponentially. The delay is limited to (2^8)ms.
365     The scaling stuff ensures that when the queue is bigger than 8, the delay
366     only occurs for the last 8 entries. Once the queue is full, we stop delaying
367     to preserve performance.
368  */
369
370  if (entries && max_logs != 0)
371    {
372      int d;
373
374      for (d = 0,entry = entries; entry; entry = entry->next, d++);
375
376      if (d == max_logs)
377	d = 0;
378      else if (max_logs > 8)
379	d -= max_logs - 8;
380
381      if (d > 0)
382	{
383	  struct timespec waiter;
384	  waiter.tv_sec = 0;
385	  waiter.tv_nsec = 1000000 << (d - 1); /* 1 ms */
386	  nanosleep(&waiter, NULL);
387
388	  /* Have another go now */
389	  log_write();
390	}
391    }
392#endif
393}
394
395void set_log_writer(fd_set *set, int *maxfdp)
396{
397  if (entries && log_fd != -1 && connection_good)
398    {
399      FD_SET(log_fd, set);
400      bump_maxfd(log_fd, maxfdp);
401    }
402}
403
404void check_log_writer(fd_set *set)
405{
406  if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
407    log_write();
408}
409
410void flush_log(void)
411{
412  /* block until queue empty */
413  if (log_fd != -1)
414    {
415      int flags;
416      if ((flags = fcntl(log_fd, F_GETFL)) != -1)
417	fcntl(log_fd, F_SETFL, flags & ~O_NONBLOCK);
418      log_write();
419      close(log_fd);
420    }
421}
422
423void die(char *message, char *arg1, int exit_code)
424{
425  char *errmess = strerror(errno);
426
427  if (!arg1)
428    arg1 = errmess;
429
430  log_stderr = 1; /* print as well as log when we die.... */
431  fputc('\n', stderr); /* prettyfy  startup-script message */
432  my_syslog(LOG_CRIT, message, arg1, errmess);
433
434  log_stderr = 0;
435  my_syslog(LOG_CRIT, _("FAILED to start up"));
436  flush_log();
437
438  exit(exit_code);
439}
440