blob: 727d5e2e94cec3a005c36f9b5de40ac5203f0375 [file] [log] [blame]
Simon Kelley316e2732010-01-22 20:16:09 +00001/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley5aabfc72007-08-29 11:24:47 +010019struct daemon *daemon;
20
Simon Kelley3d8df262005-08-29 12:19:27 +010021static char *compile_opts =
22#ifndef HAVE_IPV6
23"no-"
24#endif
25"IPv6 "
26#ifndef HAVE_GETOPT_LONG
27"no-"
28#endif
29"GNU-getopt "
30#ifdef HAVE_BROKEN_RTC
31"no-RTC "
32#endif
Simon Kelley16972692006-10-16 20:04:18 +010033#ifdef NO_FORK
34"no-MMU "
35#endif
Simon Kelley3d8df262005-08-29 12:19:27 +010036#ifndef HAVE_DBUS
37"no-"
38#endif
Simon Kelleyb8187c82005-11-26 21:46:27 +000039"DBus "
Simon Kelley824af852008-02-12 20:43:05 +000040#ifndef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000041"no-"
42#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000043"I18N "
Simon Kelley7622fc02009-06-04 20:32:05 +010044#ifndef HAVE_DHCP
45"no-"
46#endif
47"DHCP "
Simon Kelley1f15b812009-10-13 17:49:32 +010048#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
49"no-scripts "
50#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000051#ifndef HAVE_TFTP
52"no-"
53#endif
54"TFTP";
Simon Kelley3d8df262005-08-29 12:19:27 +010055
Simon Kelley1f15b812009-10-13 17:49:32 +010056
57
Simon Kelley5aabfc72007-08-29 11:24:47 +010058static volatile pid_t pid = 0;
59static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000060
Simon Kelley5aabfc72007-08-29 11:24:47 +010061static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
62static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010063static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010064static void async_event(int pipe, time_t now);
Simon Kelley1a6bca82008-07-11 11:11:42 +010065static void fatal_event(struct event_desc *ev);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000066
67int main (int argc, char **argv)
68{
Simon Kelleyde379512004-06-22 20:23:33 +010069 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000070 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000071 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000072 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010073 int piperead, pipefd[2], err_pipe[2];
74 struct passwd *ent_pw = NULL;
Simon Kelley1f15b812009-10-13 17:49:32 +010075#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010076 uid_t script_uid = 0;
77 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010078#endif
79 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010080 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010081 char *baduser = NULL;
82 int log_err;
83#if defined(HAVE_LINUX_NETWORK)
84 cap_user_header_t hdr = NULL;
85 cap_user_data_t data = NULL;
86#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010087
Simon Kelley824af852008-02-12 20:43:05 +000088#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000089 setlocale(LC_ALL, "");
90 bindtextdomain("dnsmasq", LOCALEDIR);
91 textdomain("dnsmasq");
92#endif
93
Simon Kelley9e4abcb2004-01-22 19:47:41 +000094 sigact.sa_handler = sig_handler;
95 sigact.sa_flags = 0;
96 sigemptyset(&sigact.sa_mask);
97 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010098 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000099 sigaction(SIGHUP, &sigact, NULL);
100 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +0000101 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100102 sigaction(SIGCHLD, &sigact, NULL);
103
104 /* ignore SIGPIPE */
105 sigact.sa_handler = SIG_IGN;
106 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107
Simon Kelley5aabfc72007-08-29 11:24:47 +0100108 umask(022); /* known umask, create leases and pid files as 0644 */
109
110 read_opts(argc, argv, compile_opts);
111
Simon Kelley3be34542004-09-11 19:12:13 +0100112 if (daemon->edns_pktsz < PACKETSZ)
113 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +0000114 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
115 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
116 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100117
Simon Kelley7622fc02009-06-04 20:32:05 +0100118#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100119 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120 {
Simon Kelley3be34542004-09-11 19:12:13 +0100121 if (daemon->dhcp)
122 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000123 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100124#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000125
Simon Kelley5aabfc72007-08-29 11:24:47 +0100126 /* Close any file descriptors we inherited apart from std{in|out|err} */
127 for (i = 0; i < max_fd; i++)
128 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
129 close(i);
130
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100131#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100132 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100133#elif !(defined(IP_RECVDSTADDR) && \
134 defined(IP_RECVIF) && \
135 defined(IP_SENDSRCADDR))
136 if (!(daemon->options & OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100137 {
138 bind_fallback = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100139 daemon->options |= OPT_NOWILD;
Simon Kelleyde379512004-06-22 20:23:33 +0100140 }
Simon Kelley309331f2006-04-22 15:05:01 +0100141#endif
142
Simon Kelley832af0b2007-01-21 20:01:28 +0000143#ifndef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100144 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100145 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000146#endif
147
Simon Kelley824af852008-02-12 20:43:05 +0000148#ifdef HAVE_SOLARIS_NETWORK
149 if (daemon->max_logs != 0)
150 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
151#endif
152
Simon Kelley1a6bca82008-07-11 11:11:42 +0100153 rand_init();
154
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100155 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000156
Simon Kelley7622fc02009-06-04 20:32:05 +0100157#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100158 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000159 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100160 /* Note that order matters here, we must call lease_init before
161 creating any file descriptors which shouldn't be leaked
162 to the lease-script init process. */
163 lease_init(now);
164 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000165 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100166#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100167
Simon Kelley5aabfc72007-08-29 11:24:47 +0100168 if (!enumerate_interfaces())
169 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
170
171 if (daemon->options & OPT_NOWILD)
172 {
173 daemon->listeners = create_bound_listeners();
174
175 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
176 if (if_tmp->name && !if_tmp->used)
177 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
178
179 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
180 if (!if_tmp->used)
181 {
182 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
183 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
184 }
185 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100186 else if ((daemon->port != 0 || daemon->tftp_interfaces || daemon->tftp_unlimited) &&
Simon Kelley824af852008-02-12 20:43:05 +0000187 !(daemon->listeners = create_wildcard_listeners()))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100188 die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
189
Simon Kelley824af852008-02-12 20:43:05 +0000190 if (daemon->port != 0)
191 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100192
Simon Kelley3d8df262005-08-29 12:19:27 +0100193 if (daemon->options & OPT_DBUS)
194#ifdef HAVE_DBUS
195 {
196 char *err;
197 daemon->dbus = NULL;
198 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100199 if ((err = dbus_init()))
200 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100201 }
202#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100203 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100204#endif
205
Simon Kelley824af852008-02-12 20:43:05 +0000206 if (daemon->port != 0)
207 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100208
Simon Kelley1f15b812009-10-13 17:49:32 +0100209#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100210 /* Note getpwnam returns static storage */
211 if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
212 {
213 if ((ent_pw = getpwnam(daemon->scriptuser)))
214 {
215 script_uid = ent_pw->pw_uid;
216 script_gid = ent_pw->pw_gid;
217 }
218 else
219 baduser = daemon->scriptuser;
220 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100221#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000222
Simon Kelley1a6bca82008-07-11 11:11:42 +0100223 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
224 baduser = daemon->username;
225 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
226 baduser = daemon->groupname;
227
228 if (baduser)
229 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
230
231 /* implement group defaults, "dip" if available, or group associated with uid */
232 if (!daemon->group_set && !gp)
233 {
234 if (!(gp = getgrnam(CHGRP)) && ent_pw)
235 gp = getgrgid(ent_pw->pw_gid);
236
237 /* for error message */
238 if (gp)
239 daemon->groupname = gp->gr_name;
240 }
241
242#if defined(HAVE_LINUX_NETWORK)
243 /* determine capability API version here, while we can still
244 call safe_malloc */
245 if (ent_pw && ent_pw->pw_uid != 0)
246 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100247 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100248 hdr = safe_malloc(sizeof(*hdr));
249
Simon Kelley1a6bca82008-07-11 11:11:42 +0100250 /* find version supported by kernel */
251 memset(hdr, 0, sizeof(*hdr));
252 capget(hdr, NULL);
253
254 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
255 {
256 /* if unknown version, use largest supported version (3) */
257 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
258 hdr->version = LINUX_CAPABILITY_VERSION_3;
259 capsize = 2;
260 }
261
262 data = safe_malloc(sizeof(*data) * capsize);
263 memset(data, 0, sizeof(*data) * capsize);
264 }
265#endif
266
Simon Kelley5aabfc72007-08-29 11:24:47 +0100267 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100268 in a race-free manner and another to carry errors to daemon-invoking process */
269 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100270
271 piperead = pipefd[0];
272 pipewrite = pipefd[1];
273 /* prime the pipe to load stuff first time. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100274 send_event(pipewrite, EVENT_RELOAD, 0);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100275
276 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100277
278 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000279 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000280 /* The following code "daemonizes" the process.
281 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100282
Simon Kelley9e038942008-05-30 20:06:34 +0100283 if (chdir("/") != 0)
284 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
285
Simon Kelley16972692006-10-16 20:04:18 +0100286#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100287 if (!(daemon->options & OPT_NO_FORK))
288 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100289 pid_t pid;
290
Simon Kelley1a6bca82008-07-11 11:11:42 +0100291 /* pipe to carry errors back to original process.
292 When startup is complete we close this and the process terminates. */
293 safe_pipe(err_pipe, 0);
294
Simon Kelley7622fc02009-06-04 20:32:05 +0100295 if ((pid = fork()) == -1)
296 /* fd == -1 since we've not forked, never returns. */
297 send_event(-1, EVENT_FORK_ERR, errno);
Simon Kelley9e038942008-05-30 20:06:34 +0100298
Simon Kelley5aabfc72007-08-29 11:24:47 +0100299 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100300 {
301 struct event_desc ev;
302
303 /* close our copy of write-end */
304 close(err_pipe[1]);
305
306 /* check for errors after the fork */
307 if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
308 fatal_event(&ev);
309
310 _exit(EC_GOOD);
311 }
312
313 close(err_pipe[0]);
314
315 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100316
317 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100318
319 if ((pid = fork()) == -1)
320 send_event(err_pipe[1], EVENT_FORK_ERR, errno);
321
322 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100323 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100324 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000325#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100326
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000327 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100328 if (daemon->runfile)
329 {
330 FILE *pidfile;
331
332 /* only complain if started as root */
333 if ((pidfile = fopen(daemon->runfile, "w")))
334 {
335 fprintf(pidfile, "%d\n", (int) getpid());
336 fclose(pidfile);
337 }
338 else if (getuid() == 0)
339 {
340 send_event(err_pipe[1], EVENT_PIDFILE, errno);
341 _exit(0);
342 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343 }
Simon Kelley16972692006-10-16 20:04:18 +0100344 }
345
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100346 log_err = log_start(ent_pw, err_pipe[1]);
347
348 if (!(daemon->options & OPT_DEBUG))
349 {
350 /* open stdout etc to /dev/null */
351 int nullfd = open("/dev/null", O_RDWR);
352 dup2(nullfd, STDOUT_FILENO);
353 dup2(nullfd, STDERR_FILENO);
354 dup2(nullfd, STDIN_FILENO);
355 close(nullfd);
356 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100357
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 /* if we are to run scripts, we need to fork a helper before dropping root. */
359 daemon->helperfd = -1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100360#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100361 if (daemon->dhcp && daemon->lease_change_command)
362 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
363#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100364
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365 if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100366 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100367 int bad_capabilities = 0;
368 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100369
Simon Kelley1a6bca82008-07-11 11:11:42 +0100370 /* remove all supplimentary groups */
371 if (gp &&
372 (setgroups(0, &dummy) == -1 ||
373 setgid(gp->gr_gid) == -1))
374 {
375 send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
376 _exit(0);
377 }
378
Simon Kelley7cebd202006-05-06 14:13:33 +0100379 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100380 {
Simon Kelley824af852008-02-12 20:43:05 +0000381#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100382 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
383 CAP_NET_RAW (for icmp) if we're doing dhcp */
Simon Kelley16972692006-10-16 20:04:18 +0100384 data->effective = data->permitted = data->inheritable =
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100386
Simon Kelley16972692006-10-16 20:04:18 +0100387 /* Tell kernel to not clear capabilities when dropping root */
388 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
389 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390
Simon Kelley7622fc02009-06-04 20:32:05 +0100391#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000392 /* http://developers.sun.com/solaris/articles/program_privileges.html */
393 priv_set_t *priv_set;
394
395 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
396 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
397 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
398 bad_capabilities = errno;
399
400 if (priv_set && bad_capabilities == 0)
401 {
402 priv_inverse(priv_set);
403
404 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
405 bad_capabilities = errno;
406 }
407
408 if (priv_set)
409 priv_freeset(priv_set);
410
Simon Kelley824af852008-02-12 20:43:05 +0000411#endif
412
Simon Kelley1a6bca82008-07-11 11:11:42 +0100413 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100414 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100415 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
416 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100417 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418
419 /* finally drop root */
420 if (setuid(ent_pw->pw_uid) == -1)
421 {
422 send_event(err_pipe[1], EVENT_USER_ERR, errno);
423 _exit(0);
424 }
425
426#ifdef HAVE_LINUX_NETWORK
427 data->effective = data->permitted =
428 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
429 data->inheritable = 0;
430
431 /* lose the setuid and setgid capbilities */
432 if (capset(hdr, data) == -1)
433 {
434 send_event(err_pipe[1], EVENT_CAP_ERR, errno);
435 _exit(0);
436 }
437#endif
438
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000439 }
Simon Kelley849a8352006-06-09 21:02:31 +0100440 }
Simon Kelley16972692006-10-16 20:04:18 +0100441
Simon Kelley16972692006-10-16 20:04:18 +0100442#ifdef HAVE_LINUX_NETWORK
443 if (daemon->options & OPT_DEBUG)
444 prctl(PR_SET_DUMPABLE, 1);
445#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100446
Simon Kelley824af852008-02-12 20:43:05 +0000447 if (daemon->port == 0)
448 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
449 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100450 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000451 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100452 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100453
Simon Kelleyf2621c72007-04-29 19:47:21 +0100454 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100455
Simon Kelley3d8df262005-08-29 12:19:27 +0100456#ifdef HAVE_DBUS
457 if (daemon->options & OPT_DBUS)
458 {
459 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100460 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100461 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100462 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100463 }
464#endif
465
Simon Kelley1a6bca82008-07-11 11:11:42 +0100466 if (log_err != 0)
467 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
468 daemon->log_file, strerror(log_err));
469
Simon Kelleyde379512004-06-22 20:23:33 +0100470 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100471 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100472
Simon Kelley26128d22004-11-14 16:43:54 +0000473 if (!(daemon->options & OPT_NOWILD))
474 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
475 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100476 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100477
Simon Kelley824af852008-02-12 20:43:05 +0000478 if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100479 {
480 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100481 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100482 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000483 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100484 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100485 }
486
Simon Kelleyf2621c72007-04-29 19:47:21 +0100487 if (daemon->max_logs != 0)
488 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
489
Simon Kelley7622fc02009-06-04 20:32:05 +0100490#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100491 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000492 {
Simon Kelley3be34542004-09-11 19:12:13 +0100493 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000494
Simon Kelley3be34542004-09-11 19:12:13 +0100495 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100496 {
Simon Kelley0a852542005-03-23 20:28:59 +0000497 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100498 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelley7622fc02009-06-04 20:32:05 +0100499 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100500 (dhcp_tmp->flags & CONTEXT_STATIC) ?
501 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100502 (dhcp_tmp->flags & CONTEXT_PROXY) ?
503 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100504 _("DHCP, IP range %s -- %s, lease time %s"),
505 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100506 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000507 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100508#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000509
Simon Kelley832af0b2007-01-21 20:01:28 +0000510#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100511 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000512 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000513#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100514 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000515 max_fd = FD_SETSIZE;
516#endif
517
Simon Kelley7622fc02009-06-04 20:32:05 +0100518 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100519 daemon->tftp_prefix ? _("root is ") : _("enabled"),
520 daemon->tftp_prefix ? daemon->tftp_prefix: "",
521 daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
522
Simon Kelley832af0b2007-01-21 20:01:28 +0000523 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100524 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000525 a single file will be sent to may clients (the file only needs
526 one fd). */
527
528 max_fd -= 30; /* use other than TFTP */
529
530 if (max_fd < 0)
531 max_fd = 5;
532 else if (max_fd < 100)
533 max_fd = max_fd/2;
534 else
535 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000536
537 /* if we have to use a limited range of ports,
538 that will limit the number of transfers */
539 if (daemon->start_tftp_port != 0 &&
540 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
541 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000542
543 if (daemon->tftp_max > max_fd)
544 {
545 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100546 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100547 _("restricting maximum simultaneous TFTP transfers to %d"),
548 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000549 }
550 }
551#endif
552
Simon Kelley1a6bca82008-07-11 11:11:42 +0100553 /* finished start-up - release original process */
554 if (err_pipe[1] != -1)
555 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000556
Simon Kelley824af852008-02-12 20:43:05 +0000557 if (daemon->port != 0)
558 check_servers();
559
Simon Kelley7cebd202006-05-06 14:13:33 +0100560 pid = getpid();
561
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100562 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000563 {
Simon Kelley16972692006-10-16 20:04:18 +0100564 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100565 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100566 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000567
568 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100569 FD_ZERO(&wset);
570 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000571
Simon Kelley16972692006-10-16 20:04:18 +0100572 /* if we are out of resources, find how long we have to wait
573 for some to come free, we'll loop around then and restart
574 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100575 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100576 {
577 t.tv_usec = 0;
578 tp = &t;
579 }
580
Simon Kelley832af0b2007-01-21 20:01:28 +0000581 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
582 if (daemon->tftp_trans ||
583 ((daemon->options & OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000584 {
Simon Kelley16972692006-10-16 20:04:18 +0100585 t.tv_sec = 0;
586 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100587 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000588 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100589
Simon Kelley832af0b2007-01-21 20:01:28 +0000590#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100591 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100592#endif
593
Simon Kelley7622fc02009-06-04 20:32:05 +0100594#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100595 if (daemon->dhcp)
596 {
597 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100598 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000599 if (daemon->pxefd != -1)
600 {
601 FD_SET(daemon->pxefd, &rset);
602 bump_maxfd(daemon->pxefd, &maxfd);
603 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100604 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100605#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100606
607#ifdef HAVE_LINUX_NETWORK
608 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100609 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100610#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100611
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100612 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100613 bump_maxfd(piperead, &maxfd);
614
Simon Kelley7622fc02009-06-04 20:32:05 +0100615#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100616# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100617 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100618
619 if (!helper_buf_empty())
620 {
621 FD_SET(daemon->helperfd, &wset);
622 bump_maxfd(daemon->helperfd, &maxfd);
623 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100624# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100625 /* need this for other side-effects */
626 while (do_script_run(now));
Simon Kelley7622fc02009-06-04 20:32:05 +0100627# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100628#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100629
Simon Kelleyf2621c72007-04-29 19:47:21 +0100630 /* must do this just before select(), when we know no
631 more calls to my_syslog() can occur */
632 set_log_writer(&wset, &maxfd);
633
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100634 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
635 {
636 /* otherwise undefined after error */
637 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
638 }
639
640 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000641
Simon Kelleyf2621c72007-04-29 19:47:21 +0100642 check_log_writer(&wset);
643
Simon Kelleyc52e1892010-06-07 22:01:39 +0100644#ifdef HAVE_LINUX_NETWORK
645 if (FD_ISSET(daemon->netlinkfd, &rset))
646 netlink_multicast();
647#endif
648
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100650 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000651 if (daemon->last_resolv == 0 ||
652 difftime(now, daemon->last_resolv) > 1.0 ||
653 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000654 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100655 /* poll_resolv doesn't need to reload first time through, since
656 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100657
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100658 poll_resolv(0, daemon->last_resolv != 0, now);
659 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000660 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100661
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100662 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100663 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100664
Simon Kelley3d8df262005-08-29 12:19:27 +0100665#ifdef HAVE_DBUS
666 /* if we didn't create a DBus connection, retry now. */
Simon Kelley7cebd202006-05-06 14:13:33 +0100667 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100668 {
669 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100670 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100671 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100672 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100673 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100674 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100675 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100676#endif
Simon Kelley824af852008-02-12 20:43:05 +0000677
Simon Kelley5aabfc72007-08-29 11:24:47 +0100678 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000679
680#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100681 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000682#endif
683
Simon Kelley7622fc02009-06-04 20:32:05 +0100684#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000685 if (daemon->dhcp)
686 {
687 if (FD_ISSET(daemon->dhcpfd, &rset))
688 dhcp_packet(now, 0);
689 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
690 dhcp_packet(now, 1);
691 }
Simon Kelley16972692006-10-16 20:04:18 +0100692
Simon Kelley1f15b812009-10-13 17:49:32 +0100693# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100694 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100695 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100696# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100697#endif
698
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000699 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000700}
701
Simon Kelley3be34542004-09-11 19:12:13 +0100702static void sig_handler(int sig)
703{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100704 if (pid == 0)
705 {
Simon Kelley16972692006-10-16 20:04:18 +0100706 /* ignore anything other than TERM during startup
707 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100708 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100709 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100710 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100711 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100712 {
Simon Kelley16972692006-10-16 20:04:18 +0100713 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100714 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100715 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100716 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100717 else
718 {
719 /* master process */
720 int event, errsave = errno;
721
722 if (sig == SIGHUP)
723 event = EVENT_RELOAD;
724 else if (sig == SIGCHLD)
725 event = EVENT_CHILD;
726 else if (sig == SIGALRM)
727 event = EVENT_ALARM;
728 else if (sig == SIGTERM)
729 event = EVENT_TERM;
730 else if (sig == SIGUSR1)
731 event = EVENT_DUMP;
732 else if (sig == SIGUSR2)
733 event = EVENT_REOPEN;
734 else
735 return;
736
737 send_event(pipewrite, event, 0);
738 errno = errsave;
739 }
Simon Kelley3be34542004-09-11 19:12:13 +0100740}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000741
Simon Kelley5aabfc72007-08-29 11:24:47 +0100742void send_event(int fd, int event, int data)
743{
744 struct event_desc ev;
745
746 ev.event = event;
747 ev.data = data;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100748
749 /* error pipe, debug mode. */
750 if (fd == -1)
751 fatal_event(&ev);
752 else
753 /* pipe is non-blocking and struct event_desc is smaller than
754 PIPE_BUF, so this either fails or writes everything */
755 while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100756}
Simon Kelley3d8df262005-08-29 12:19:27 +0100757
Simon Kelley1a6bca82008-07-11 11:11:42 +0100758static void fatal_event(struct event_desc *ev)
759{
760 errno = ev->data;
761
762 switch (ev->event)
763 {
764 case EVENT_DIE:
765 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100766
767 case EVENT_FORK_ERR:
768 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100769
770 case EVENT_PIPE_ERR:
771 die(_("failed to create helper: %s"), NULL, EC_MISC);
772
773 case EVENT_CAP_ERR:
774 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
775
776 case EVENT_USER_ERR:
777 case EVENT_HUSER_ERR:
778 die(_("failed to change user-id to %s: %s"),
779 ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
780 EC_MISC);
781
782 case EVENT_GROUP_ERR:
783 die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
784
785 case EVENT_PIDFILE:
786 die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
787
788 case EVENT_LOG_ERR:
789 die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
790 }
791}
792
Simon Kelley5aabfc72007-08-29 11:24:47 +0100793static void async_event(int pipe, time_t now)
794{
795 pid_t p;
796 struct event_desc ev;
797 int i;
798
799 if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
800 switch (ev.event)
801 {
802 case EVENT_RELOAD:
803 clear_cache_and_reload(now);
Simon Kelley824af852008-02-12 20:43:05 +0000804 if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100805 {
806 reload_servers(daemon->resolv_files->name);
807 check_servers();
808 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100809#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100810 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100811#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100812 break;
813
814 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000815 if (daemon->port != 0)
816 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100817 break;
818
819 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +0100820#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100821 if (daemon->dhcp)
822 {
823 lease_prune(NULL, now);
824 lease_update_file(now);
825 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100826#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100827 break;
828
829 case EVENT_CHILD:
830 /* See Stevens 5.10 */
831 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
832 if (p == -1)
833 {
834 if (errno != EINTR)
835 break;
836 }
837 else
838 for (i = 0 ; i < MAX_PROCS; i++)
839 if (daemon->tcp_pids[i] == p)
840 daemon->tcp_pids[i] = 0;
841 break;
842
843 case EVENT_KILLED:
844 my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
845 break;
846
847 case EVENT_EXITED:
848 my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
849 break;
850
851 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +0100852 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
853 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100854 break;
855
Simon Kelley1a6bca82008-07-11 11:11:42 +0100856 /* necessary for fatal errors in helper */
857 case EVENT_HUSER_ERR:
858 case EVENT_DIE:
859 fatal_event(&ev);
Simon Kelley9e038942008-05-30 20:06:34 +0100860 break;
861
Simon Kelley5aabfc72007-08-29 11:24:47 +0100862 case EVENT_REOPEN:
863 /* Note: this may leave TCP-handling processes with the old file still open.
864 Since any such process will die in CHILD_LIFETIME or probably much sooner,
865 we leave them logging to the old file. */
866 if (daemon->log_file != NULL)
867 log_reopen(daemon->log_file);
868 break;
869
870 case EVENT_TERM:
871 /* Knock all our children on the head. */
872 for (i = 0; i < MAX_PROCS; i++)
873 if (daemon->tcp_pids[i] != 0)
874 kill(daemon->tcp_pids[i], SIGALRM);
875
Simon Kelley1f15b812009-10-13 17:49:32 +0100876#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100877 /* handle pending lease transitions */
878 if (daemon->helperfd != -1)
879 {
880 /* block in writes until all done */
881 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
882 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
883 do {
884 helper_write();
885 } while (!helper_buf_empty() || do_script_run(now));
886 close(daemon->helperfd);
887 }
888#endif
889
890 if (daemon->lease_stream)
891 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +0000892
893 if (daemon->runfile)
894 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100895
896 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
897 flush_log();
898 exit(EC_GOOD);
899 }
900}
901
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100902void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100903{
904 struct resolvc *res, *latest;
905 struct stat statbuf;
906 time_t last_change = 0;
907 /* There may be more than one possible file.
908 Go through and find the one which changed _last_.
909 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100910
911 if (daemon->port == 0 || (daemon->options & OPT_NO_POLL))
912 return;
913
Simon Kelley5aabfc72007-08-29 11:24:47 +0100914 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
915 if (stat(res->name, &statbuf) == -1)
916 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100917 if (force)
918 {
919 res->mtime = 0;
920 continue;
921 }
922
Simon Kelley5aabfc72007-08-29 11:24:47 +0100923 if (!res->logged)
924 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
925 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100926
927 if (res->mtime != 0)
928 {
929 /* existing file evaporated, force selection of the latest
930 file even if its mtime hasn't changed since we last looked */
931 poll_resolv(1, do_reload, now);
932 return;
933 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100934 }
935 else
936 {
937 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100938 if (force || (statbuf.st_mtime != res->mtime))
939 {
940 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100941 if (difftime(statbuf.st_mtime, last_change) > 0.0)
942 {
943 last_change = statbuf.st_mtime;
944 latest = res;
945 }
946 }
947 }
948
949 if (latest)
950 {
951 static int warned = 0;
952 if (reload_servers(latest->name))
953 {
954 my_syslog(LOG_INFO, _("reading %s"), latest->name);
955 warned = 0;
956 check_servers();
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100957 if ((daemon->options & OPT_RELOAD) && do_reload)
958 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100959 }
960 else
961 {
962 latest->mtime = 0;
963 if (!warned)
964 {
965 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
966 warned = 1;
967 }
968 }
969 }
970}
971
972void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +0100973{
Simon Kelley824af852008-02-12 20:43:05 +0000974 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +0100975 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +0000976
Simon Kelley7622fc02009-06-04 20:32:05 +0100977#ifdef HAVE_DHCP
Simon Kelley3d8df262005-08-29 12:19:27 +0100978 if (daemon->dhcp)
979 {
980 if (daemon->options & OPT_ETHERS)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100981 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +0000982 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +0100983 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +0000984 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100985 lease_update_from_configs();
986 lease_update_file(now);
987 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +0100988 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100989#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100990}
991
Simon Kelley5aabfc72007-08-29 11:24:47 +0100992static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +0100993{
994 struct serverfd *serverfdp;
995 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +0000996 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +0000997
998#ifdef HAVE_TFTP
999 int tftp = 0;
1000 struct tftp_transfer *transfer;
1001 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1002 {
1003 tftp++;
1004 FD_SET(transfer->sockfd, set);
1005 bump_maxfd(transfer->sockfd, maxfdp);
1006 }
1007#endif
1008
Simon Kelley16972692006-10-16 20:04:18 +01001009 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001010 if (daemon->port != 0)
1011 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001012
Simon Kelley3be34542004-09-11 19:12:13 +01001013 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1014 {
1015 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001016 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001017 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001018
1019 if (daemon->port != 0 && !daemon->osport)
1020 for (i = 0; i < RANDOM_SOCKS; i++)
1021 if (daemon->randomsocks[i].refcount != 0)
1022 {
1023 FD_SET(daemon->randomsocks[i].fd, set);
1024 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1025 }
1026
Simon Kelley3be34542004-09-11 19:12:13 +01001027 for (listener = daemon->listeners; listener; listener = listener->next)
1028 {
Simon Kelley16972692006-10-16 20:04:18 +01001029 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001030 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001031 {
1032 FD_SET(listener->fd, set);
1033 bump_maxfd(listener->fd, maxfdp);
1034 }
1035
1036 /* death of a child goes through the select loop, so
1037 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001038 if (listener->tcpfd != -1)
1039 for (i = 0; i < MAX_PROCS; i++)
1040 if (daemon->tcp_pids[i] == 0)
1041 {
1042 FD_SET(listener->tcpfd, set);
1043 bump_maxfd(listener->tcpfd, maxfdp);
1044 break;
1045 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001046
Simon Kelley832af0b2007-01-21 20:01:28 +00001047#ifdef HAVE_TFTP
1048 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1049 {
1050 FD_SET(listener->tftpfd, set);
1051 bump_maxfd(listener->tftpfd, maxfdp);
1052 }
1053#endif
1054
1055 }
1056
Simon Kelley16972692006-10-16 20:04:18 +01001057 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001058}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001059
Simon Kelley5aabfc72007-08-29 11:24:47 +01001060static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001061{
1062 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001063 struct listener *listener;
1064 int i;
1065
Simon Kelley832af0b2007-01-21 20:01:28 +00001066 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1067 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001068 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1069
1070 if (daemon->port != 0 && !daemon->osport)
1071 for (i = 0; i < RANDOM_SOCKS; i++)
1072 if (daemon->randomsocks[i].refcount != 0 &&
1073 FD_ISSET(daemon->randomsocks[i].fd, set))
1074 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001075
1076 for (listener = daemon->listeners; listener; listener = listener->next)
1077 {
Simon Kelley824af852008-02-12 20:43:05 +00001078 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001079 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001080
Simon Kelley832af0b2007-01-21 20:01:28 +00001081#ifdef HAVE_TFTP
1082 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001083 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001084#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001085
Simon Kelley824af852008-02-12 20:43:05 +00001086 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001087 {
1088 int confd;
1089 struct irec *iface = NULL;
1090 pid_t p;
1091
1092 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1093
1094 if (confd == -1)
1095 continue;
1096
1097 if (daemon->options & OPT_NOWILD)
1098 iface = listener->iface;
1099 else
1100 {
1101 union mysockaddr tcp_addr;
1102 socklen_t tcp_len = sizeof(union mysockaddr);
1103 /* Check for allowed interfaces when binding the wildcard address:
1104 we do this by looking for an interface with the same address as
1105 the local address of the TCP connection, then looking to see if that's
1106 an allowed interface. As a side effect, we get the netmask of the
1107 interface too, for localisation. */
1108
1109 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001110 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001111 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1112 for (iface = daemon->interfaces; iface; iface = iface->next)
1113 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1114 break;
1115 }
1116
1117 if (!iface)
1118 {
1119 shutdown(confd, SHUT_RDWR);
1120 close(confd);
1121 }
1122#ifndef NO_FORK
1123 else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
1124 {
1125 if (p != -1)
1126 {
1127 int i;
1128 for (i = 0; i < MAX_PROCS; i++)
1129 if (daemon->tcp_pids[i] == 0)
1130 {
1131 daemon->tcp_pids[i] = p;
1132 break;
1133 }
1134 }
1135 close(confd);
1136 }
1137#endif
1138 else
1139 {
1140 unsigned char *buff;
1141 struct server *s;
1142 int flags;
1143 struct in_addr dst_addr_4;
1144
1145 dst_addr_4.s_addr = 0;
1146
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001147#ifndef NO_FORK
1148 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1149 terminate the process. */
Simon Kelley832af0b2007-01-21 20:01:28 +00001150 if (!(daemon->options & OPT_DEBUG))
1151 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001152#endif
1153
Simon Kelley832af0b2007-01-21 20:01:28 +00001154 /* start with no upstream connections. */
1155 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001156 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001157
1158 /* The connected socket inherits non-blocking
1159 attribute from the listening socket.
1160 Reset that here. */
1161 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1162 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1163
1164 if (listener->family == AF_INET)
1165 dst_addr_4 = iface->addr.in.sin_addr;
1166
Simon Kelley5aabfc72007-08-29 11:24:47 +01001167 buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001168
Simon Kelley832af0b2007-01-21 20:01:28 +00001169 shutdown(confd, SHUT_RDWR);
1170 close(confd);
1171
1172 if (buff)
1173 free(buff);
1174
1175 for (s = daemon->servers; s; s = s->next)
1176 if (s->tcpfd != -1)
1177 {
1178 shutdown(s->tcpfd, SHUT_RDWR);
1179 close(s->tcpfd);
1180 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001181#ifndef NO_FORK
Simon Kelley832af0b2007-01-21 20:01:28 +00001182 if (!(daemon->options & OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001183 {
1184 flush_log();
1185 _exit(0);
1186 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001187#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001188 }
1189 }
1190 }
Simon Kelley3be34542004-09-11 19:12:13 +01001191}
1192
Simon Kelley7622fc02009-06-04 20:32:05 +01001193#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001194int make_icmp_sock(void)
1195{
Simon Kelley7cebd202006-05-06 14:13:33 +01001196 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001197 int zeroopt = 0;
1198
1199 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1200 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001201 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001202 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1203 {
1204 close(fd);
1205 fd = -1;
1206 }
1207 }
1208
1209 return fd;
1210}
1211
Simon Kelley5aabfc72007-08-29 11:24:47 +01001212int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001213{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001214 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001215
1216 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001217 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001218 better not use any resources our caller has in use...)
1219 but we remain deaf to signals or further DHCP packets. */
1220
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001221 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001222 struct sockaddr_in saddr;
1223 struct {
1224 struct ip ip;
1225 struct icmp icmp;
1226 } packet;
1227 unsigned short id = rand16();
1228 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001229 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001230 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001231
Simon Kelley824af852008-02-12 20:43:05 +00001232#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001233 if ((fd = make_icmp_sock()) == -1)
1234 return 0;
1235#else
1236 int opt = 2000;
1237 fd = daemon->dhcp_icmp_fd;
1238 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1239#endif
1240
Simon Kelley3be34542004-09-11 19:12:13 +01001241 saddr.sin_family = AF_INET;
1242 saddr.sin_port = 0;
1243 saddr.sin_addr = addr;
1244#ifdef HAVE_SOCKADDR_SA_LEN
1245 saddr.sin_len = sizeof(struct sockaddr_in);
1246#endif
1247
1248 memset(&packet.icmp, 0, sizeof(packet.icmp));
1249 packet.icmp.icmp_type = ICMP_ECHO;
1250 packet.icmp.icmp_id = id;
1251 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1252 j += ((u16 *)&packet.icmp)[i];
1253 while (j>>16)
1254 j = (j & 0xffff) + (j >> 16);
1255 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1256
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001257 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001258 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1259 retry_send());
1260
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001261 for (now = start = dnsmasq_time();
1262 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001263 {
1264 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001265 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001266 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001267 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001268 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001269
1270 tv.tv_usec = 250000;
1271 tv.tv_sec = 0;
1272
1273 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001274 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001275 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001276 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001277 set_log_writer(&wset, &maxfd);
1278
1279 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1280 {
1281 FD_ZERO(&rset);
1282 FD_ZERO(&wset);
1283 }
1284
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001285 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001286
1287 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001288 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001289
1290#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001291 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001292#endif
1293
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001294 if (FD_ISSET(fd, &rset) &&
1295 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001296 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1297 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1298 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1299 packet.icmp.icmp_seq == 0 &&
1300 packet.icmp.icmp_id == id)
1301 {
1302 gotreply = 1;
1303 break;
1304 }
1305 }
1306
Simon Kelley824af852008-02-12 20:43:05 +00001307#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001308 close(fd);
1309#else
Simon Kelley3be34542004-09-11 19:12:13 +01001310 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001311 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1312#endif
1313
Simon Kelley3be34542004-09-11 19:12:13 +01001314 return gotreply;
1315}
Simon Kelley7622fc02009-06-04 20:32:05 +01001316#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001317
1318