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
log_start(struct passwd * ent_pw,int errfd)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
log_reopen(char * log_file)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
free_entry(void)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
log_write(void)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 */
my_syslog(int priority,const char * format,...)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
set_log_writer(fd_set * set,int * maxfdp)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
check_log_writer(fd_set * set)354 void check_log_writer(fd_set* set) {
355 if (log_fd != -1 && (!set || FD_ISSET(log_fd, set))) log_write();
356 }
357
flush_log(void)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
die(char * message,char * arg1,int exit_code)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