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
log_start(struct passwd * ent_pw,int errfd)57 int 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
log_reopen(char * log_file)104 int 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
free_entry(void)137 static 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
log_write(void)145 static 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 */
my_syslog(int priority,const char * format,...)257 void 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
set_log_writer(fd_set * set,int * maxfdp)395 void 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
check_log_writer(fd_set * set)404 void check_log_writer(fd_set *set)
405 {
406 if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
407 log_write();
408 }
409
flush_log(void)410 void 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
die(char * message,char * arg1,int exit_code)423 void 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