blob: 00551a18671ac6ee2fadf952cc572e769fcc2e0b [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 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 Kelleyc72daea2012-01-05 21:33:27 +000017/* Declare static char *compiler_opts in config.h */
18#define DNSMASQ_COMPILE_OPTS
19
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020#include "dnsmasq.h"
21
Simon Kelley5aabfc72007-08-29 11:24:47 +010022struct daemon *daemon;
23
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static volatile pid_t pid = 0;
25static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley5aabfc72007-08-29 11:24:47 +010027static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
28static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010029static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010030static void async_event(int pipe, time_t now);
Simon Kelleyc72daea2012-01-05 21:33:27 +000031static void fatal_event(struct event_desc *ev, char *msg);
32static int read_event(int fd, struct event_desc *evp, char **msg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000033
34int main (int argc, char **argv)
35{
Simon Kelleyde379512004-06-22 20:23:33 +010036 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000037 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000038 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000039 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010040 int piperead, pipefd[2], err_pipe[2];
41 struct passwd *ent_pw = NULL;
Simon Kelleyc72daea2012-01-05 21:33:27 +000042#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010043 uid_t script_uid = 0;
44 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010045#endif
46 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010047 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010048 char *baduser = NULL;
49 int log_err;
50#if defined(HAVE_LINUX_NETWORK)
51 cap_user_header_t hdr = NULL;
52 cap_user_data_t data = NULL;
53#endif
Simon Kelley1f776932012-12-16 19:46:08 +000054 struct dhcp_context *context;
Simon Kelley5aabfc72007-08-29 11:24:47 +010055
Simon Kelley824af852008-02-12 20:43:05 +000056#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000057 setlocale(LC_ALL, "");
58 bindtextdomain("dnsmasq", LOCALEDIR);
59 textdomain("dnsmasq");
60#endif
61
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 sigact.sa_handler = sig_handler;
63 sigact.sa_flags = 0;
64 sigemptyset(&sigact.sa_mask);
65 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010066 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000067 sigaction(SIGHUP, &sigact, NULL);
68 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000069 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010070 sigaction(SIGCHLD, &sigact, NULL);
71
72 /* ignore SIGPIPE */
73 sigact.sa_handler = SIG_IGN;
74 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000075
Simon Kelley5aabfc72007-08-29 11:24:47 +010076 umask(022); /* known umask, create leases and pid files as 0644 */
77
78 read_opts(argc, argv, compile_opts);
79
Simon Kelley3be34542004-09-11 19:12:13 +010080 if (daemon->edns_pktsz < PACKETSZ)
81 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +000082 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
83 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
84 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +010085
Simon Kelleyc72daea2012-01-05 21:33:27 +000086 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
87
Simon Kelley4f7b3042012-11-28 21:27:02 +000088
Simon Kelley7622fc02009-06-04 20:32:05 +010089#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +010090 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000091 {
Simon Kelley52b92f42012-01-22 16:05:15 +000092 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +010093 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000094 }
Simon Kelley7622fc02009-06-04 20:32:05 +010095#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000096
Simon Kelleya2761752012-01-18 16:07:21 +000097 /* Close any file descriptors we inherited apart from std{in|out|err}
98
99 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
100 otherwise file descriptors we create can end up being 0, 1, or 2
101 and then get accidentally closed later when we make 0, 1, and 2
102 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
103 but it's not guaranteed. By opening /dev/null three times, we
104 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100105 for (i = 0; i < max_fd; i++)
106 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
107 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000108 else
109 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110
Simon Kelley801ca9a2012-03-06 19:30:17 +0000111#ifndef HAVE_LINUX_NETWORK
112# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000113 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100114 {
115 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000116 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100117 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000118# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100119
120 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100121 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100122 {
123 bind_fallback = 1;
124 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100125 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100126 }
Simon Kelley309331f2006-04-22 15:05:01 +0100127#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100128
Simon Kelley832af0b2007-01-21 20:01:28 +0000129#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100130 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100131 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000132#endif
133
Simon Kelley7de060b2011-08-26 17:24:52 +0100134#ifdef HAVE_CONNTRACK
135 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
136 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
137#else
138 if (option_bool(OPT_CONNTRACK))
139 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
140#endif
141
Simon Kelley824af852008-02-12 20:43:05 +0000142#ifdef HAVE_SOLARIS_NETWORK
143 if (daemon->max_logs != 0)
144 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
145#endif
146
Simon Kelley572b41e2011-02-18 18:11:18 +0000147#ifdef __ANDROID__
148 if (daemon->max_logs != 0)
149 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
150#endif
151
Simon Kelley4820dce2012-12-18 18:30:30 +0000152#ifndef HAVE_AUTH
153 if (daemon->authserver)
154 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
155#endif
156
Simon Kelley1a6bca82008-07-11 11:11:42 +0100157 rand_init();
158
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100159 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000160
161 /* Create a serial at startup is not configured. */
162 if (daemon->authinterface && daemon->soa_sn == 0)
163#ifdef HAVE_BROKEN_RTC
164 die(_("zone serial must be configured in --auth-soa"));
165#else
166 daemon->soa_sn = now;
167#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000168
Simon Kelley7622fc02009-06-04 20:32:05 +0100169#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000170 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley1f776932012-12-16 19:46:08 +0000171 {
172
173# ifdef HAVE_DHCP6
174 if (daemon->dhcp6)
175 {
176 daemon->doing_ra = option_bool(OPT_RA);
177
178 for (context = daemon->dhcp6; context; context = context->next)
179 {
180 if (context->flags & CONTEXT_DHCP)
181 daemon->doing_dhcp6 = 1;
Simon Kelleybb86e852012-12-17 22:00:53 +0000182 if (context->flags & CONTEXT_RA)
Simon Kelley1f776932012-12-16 19:46:08 +0000183 daemon->doing_ra = 1;
Simon Kelleybb86e852012-12-17 22:00:53 +0000184#ifndef HAVE_LINUX_NETWORK
185 if (context->flags & CONTEXT_TEMPLATE)
Simon Kelley9d299492012-12-18 21:48:15 +0000186 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000187#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000188 }
189 }
190# endif
191
Simon Kelley5aabfc72007-08-29 11:24:47 +0100192 /* Note that order matters here, we must call lease_init before
193 creating any file descriptors which shouldn't be leaked
Simon Kelley4cb1b322012-02-06 14:30:41 +0000194 to the lease-script init process. We need to call common_init
195 before lease_init to allocate buffers it uses.*/
Simon Kelley1f776932012-12-16 19:46:08 +0000196 if (daemon->dhcp || daemon->doing_dhcp6)
197 {
198 dhcp_common_init();
199 lease_init(now);
200 }
201
Simon Kelley52b92f42012-01-22 16:05:15 +0000202 if (daemon->dhcp)
203 dhcp_init();
Simon Kelley1f776932012-12-16 19:46:08 +0000204
Simon Kelley843c96b2012-02-27 17:42:38 +0000205# ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000206 if (daemon->doing_ra)
207 ra_init(now);
Simon Kelley843c96b2012-02-27 17:42:38 +0000208
Simon Kelley1f776932012-12-16 19:46:08 +0000209 if (daemon->doing_dhcp6)
210 dhcp6_init();
Simon Kelley843c96b2012-02-27 17:42:38 +0000211# endif
Simon Kelley1f776932012-12-16 19:46:08 +0000212 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000213
Simon Kelley7622fc02009-06-04 20:32:05 +0100214#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100215
Simon Kelley801ca9a2012-03-06 19:30:17 +0000216#ifdef HAVE_LINUX_NETWORK
Simon Kelley801ca9a2012-03-06 19:30:17 +0000217 netlink_init();
Simon Kelley8445f5d2012-12-17 21:54:08 +0000218
Simon Kelley54dd3932012-06-20 11:23:38 +0100219 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
220 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000221#endif
222
Simon Kelley5aabfc72007-08-29 11:24:47 +0100223 if (!enumerate_interfaces())
224 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000225
Simon Kelley54dd3932012-06-20 11:23:38 +0100226 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100227 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100228 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100229
230 if (!option_bool(OPT_CLEVERBIND))
231 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
232 if (if_tmp->name && !if_tmp->used)
233 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100234
235#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
236 /* after enumerate_interfaces() */
237 if (daemon->dhcp)
238 {
239 bindtodevice(daemon->dhcpfd);
240 if (daemon->enable_pxe)
241 bindtodevice(daemon->pxefd);
242 }
243#endif
244
245#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
246 if (daemon->dhcp6)
247 bindtodevice(daemon->dhcp6fd);
248#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100249 }
Simon Kelley28866e92011-02-14 20:19:14 +0000250 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100251 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000252
253#ifdef HAVE_DHCP6
254 /* after enumerate_interfaces() */
255 if (daemon->doing_dhcp6 || daemon->doing_ra)
256 join_multicast(1);
257#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100258
Simon Kelley824af852008-02-12 20:43:05 +0000259 if (daemon->port != 0)
260 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100261
Simon Kelley28866e92011-02-14 20:19:14 +0000262 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100263#ifdef HAVE_DBUS
264 {
265 char *err;
266 daemon->dbus = NULL;
267 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100268 if ((err = dbus_init()))
269 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100270 }
271#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100272 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100273#endif
274
Simon Kelley824af852008-02-12 20:43:05 +0000275 if (daemon->port != 0)
276 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100277
Simon Kelleyc72daea2012-01-05 21:33:27 +0000278#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100279 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000280 if ((daemon->dhcp || daemon->dhcp6) &&
281 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000282 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100283 {
284 if ((ent_pw = getpwnam(daemon->scriptuser)))
285 {
286 script_uid = ent_pw->pw_uid;
287 script_gid = ent_pw->pw_gid;
288 }
289 else
290 baduser = daemon->scriptuser;
291 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100292#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000293
Simon Kelley1a6bca82008-07-11 11:11:42 +0100294 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
295 baduser = daemon->username;
296 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
297 baduser = daemon->groupname;
298
299 if (baduser)
300 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
301
302 /* implement group defaults, "dip" if available, or group associated with uid */
303 if (!daemon->group_set && !gp)
304 {
305 if (!(gp = getgrnam(CHGRP)) && ent_pw)
306 gp = getgrgid(ent_pw->pw_gid);
307
308 /* for error message */
309 if (gp)
310 daemon->groupname = gp->gr_name;
311 }
312
313#if defined(HAVE_LINUX_NETWORK)
314 /* determine capability API version here, while we can still
315 call safe_malloc */
316 if (ent_pw && ent_pw->pw_uid != 0)
317 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100318 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100319 hdr = safe_malloc(sizeof(*hdr));
320
Simon Kelley1a6bca82008-07-11 11:11:42 +0100321 /* find version supported by kernel */
322 memset(hdr, 0, sizeof(*hdr));
323 capget(hdr, NULL);
324
325 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
326 {
327 /* if unknown version, use largest supported version (3) */
328 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
329 hdr->version = LINUX_CAPABILITY_VERSION_3;
330 capsize = 2;
331 }
332
333 data = safe_malloc(sizeof(*data) * capsize);
334 memset(data, 0, sizeof(*data) * capsize);
335 }
336#endif
337
Simon Kelley5aabfc72007-08-29 11:24:47 +0100338 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100339 in a race-free manner and another to carry errors to daemon-invoking process */
340 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100341
342 piperead = pipefd[0];
343 pipewrite = pipefd[1];
344 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000345 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100346
347 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100348
Simon Kelley28866e92011-02-14 20:19:14 +0000349 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000350 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000351 /* The following code "daemonizes" the process.
352 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100353
Simon Kelley9e038942008-05-30 20:06:34 +0100354 if (chdir("/") != 0)
355 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
356
Simon Kelley16972692006-10-16 20:04:18 +0100357#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000358 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100359 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100360 pid_t pid;
361
Simon Kelley1a6bca82008-07-11 11:11:42 +0100362 /* pipe to carry errors back to original process.
363 When startup is complete we close this and the process terminates. */
364 safe_pipe(err_pipe, 0);
365
Simon Kelley7622fc02009-06-04 20:32:05 +0100366 if ((pid = fork()) == -1)
367 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000368 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100369
Simon Kelley5aabfc72007-08-29 11:24:47 +0100370 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100371 {
372 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000373 char *msg;
374
Simon Kelley1a6bca82008-07-11 11:11:42 +0100375 /* close our copy of write-end */
376 close(err_pipe[1]);
377
378 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000379 if (read_event(err_pipe[0], &ev, &msg))
380 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381
382 _exit(EC_GOOD);
383 }
384
385 close(err_pipe[0]);
386
387 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100388
389 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100390
391 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000392 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100393
394 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100395 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100396 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000397#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100398
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000399 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100400 if (daemon->runfile)
401 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100402 int fd, err = 0;
403
404 sprintf(daemon->namebuff, "%d\n", (int) getpid());
405
406 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
407 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
408 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
409 extent that an attacker running as the unprivileged user could replace the pidfile with a
410 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
411
412 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
413 ensuring that the open() fails should there be any existing file (because the unlink() failed,
414 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
415 attack can succeed.
416
417 Any compromise of the non-privileged user still theoretically allows the pid-file to be
418 replaced whilst dnsmasq is running. The worst that could allow is that the usual
419 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
420
421 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
422 failure to write the pid-file.
423 */
424
425 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426
Simon Kelley79cfefd2012-09-02 13:29:51 +0100427 if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100428 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100429 /* only complain if started as root */
430 if (getuid() == 0)
431 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100432 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100433 else
434 {
435 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
436 err = 1;
437
438 while (!err && close(fd) == -1)
439 if (!retry_send())
440 err = 1;
441 }
442
443 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100444 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000445 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100446 _exit(0);
447 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000448 }
Simon Kelley16972692006-10-16 20:04:18 +0100449 }
450
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100451 log_err = log_start(ent_pw, err_pipe[1]);
452
Simon Kelley28866e92011-02-14 20:19:14 +0000453 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100454 {
455 /* open stdout etc to /dev/null */
456 int nullfd = open("/dev/null", O_RDWR);
457 dup2(nullfd, STDOUT_FILENO);
458 dup2(nullfd, STDERR_FILENO);
459 dup2(nullfd, STDIN_FILENO);
460 close(nullfd);
461 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100462
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 /* if we are to run scripts, we need to fork a helper before dropping root. */
464 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000465#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000466 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100467 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
468#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100469
Simon Kelley28866e92011-02-14 20:19:14 +0000470 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100471 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100472 int bad_capabilities = 0;
473 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100474
Simon Kelley1a6bca82008-07-11 11:11:42 +0100475 /* remove all supplimentary groups */
476 if (gp &&
477 (setgroups(0, &dummy) == -1 ||
478 setgid(gp->gr_gid) == -1))
479 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000480 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481 _exit(0);
482 }
483
Simon Kelley7cebd202006-05-06 14:13:33 +0100484 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100485 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100486#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100487 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100488 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100489 ports because of DAD, or we're doing it dynamically,
490 we need CAP_NET_BIND_SERVICE too. */
491 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100492 data->effective = data->permitted = data->inheritable =
493 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
494 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
495 else
496 data->effective = data->permitted = data->inheritable =
497 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100498
Simon Kelley16972692006-10-16 20:04:18 +0100499 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000500 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100501 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100502
Simon Kelley7622fc02009-06-04 20:32:05 +0100503#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000504 /* http://developers.sun.com/solaris/articles/program_privileges.html */
505 priv_set_t *priv_set;
506
507 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
508 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
509 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
510 bad_capabilities = errno;
511
512 if (priv_set && bad_capabilities == 0)
513 {
514 priv_inverse(priv_set);
515
516 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
517 bad_capabilities = errno;
518 }
519
520 if (priv_set)
521 priv_freeset(priv_set);
522
Simon Kelley824af852008-02-12 20:43:05 +0000523#endif
524
Simon Kelley1a6bca82008-07-11 11:11:42 +0100525 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100526 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000527 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100528 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100529 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100530
531 /* finally drop root */
532 if (setuid(ent_pw->pw_uid) == -1)
533 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000534 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100535 _exit(0);
536 }
537
538#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100539 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100540 data->effective = data->permitted =
541 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
542 else
543 data->effective = data->permitted =
544 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100545 data->inheritable = 0;
546
547 /* lose the setuid and setgid capbilities */
548 if (capset(hdr, data) == -1)
549 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000550 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100551 _exit(0);
552 }
553#endif
554
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000555 }
Simon Kelley849a8352006-06-09 21:02:31 +0100556 }
Simon Kelley16972692006-10-16 20:04:18 +0100557
Simon Kelley16972692006-10-16 20:04:18 +0100558#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000559 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000560 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100561#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100562
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100563#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100564 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100565 {
566 DIR *dir;
567 struct tftp_prefix *p;
568
569 if (daemon->tftp_prefix)
570 {
571 if (!((dir = opendir(daemon->tftp_prefix))))
572 {
573 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
574 _exit(0);
575 }
576 closedir(dir);
577 }
578
579 for (p = daemon->if_prefix; p; p = p->next)
580 {
581 if (!((dir = opendir(p->prefix))))
582 {
583 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
584 _exit(0);
585 }
586 closedir(dir);
587 }
588 }
589#endif
590
Simon Kelley824af852008-02-12 20:43:05 +0000591 if (daemon->port == 0)
592 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
593 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100594 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100596 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100597
Simon Kelleyf2621c72007-04-29 19:47:21 +0100598 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100599
Simon Kelley3d8df262005-08-29 12:19:27 +0100600#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000601 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100602 {
603 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100604 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100605 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100606 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100607 }
608#endif
609
Simon Kelley1a6bca82008-07-11 11:11:42 +0100610 if (log_err != 0)
611 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
612 daemon->log_file, strerror(log_err));
613
Simon Kelleyde379512004-06-22 20:23:33 +0100614 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100615 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100616
Simon Kelley28866e92011-02-14 20:19:14 +0000617 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000618 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
619 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100620 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100621
Simon Kelley28866e92011-02-14 20:19:14 +0000622 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100623 {
624 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100625 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100626 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000627 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100628 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100629 }
630
Simon Kelleyf2621c72007-04-29 19:47:21 +0100631 if (daemon->max_logs != 0)
632 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000633
Simon Kelleyf2621c72007-04-29 19:47:21 +0100634
Simon Kelley7622fc02009-06-04 20:32:05 +0100635#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000636 for (context = daemon->dhcp; context; context = context->next)
637 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100638
Simon Kelley1f776932012-12-16 19:46:08 +0000639# ifdef HAVE_DHCP6
640 for (context = daemon->dhcp6; context; context = context->next)
641 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000642
Simon Kelley1f776932012-12-16 19:46:08 +0000643 if (daemon->doing_dhcp6 || daemon->doing_ra)
644 dhcp_construct_contexts(now);
645
646 if (option_bool(OPT_RA))
647 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
648# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649
Simon Kelley8445f5d2012-12-17 21:54:08 +0000650 /* after dhcp_contruct_contexts */
651 if (daemon->dhcp || daemon->doing_dhcp6)
652 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000653#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000654
Simon Kelley832af0b2007-01-21 20:01:28 +0000655#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100656 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000657 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000658#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100659 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000660 max_fd = FD_SETSIZE;
661#endif
662
Simon Kelley7622fc02009-06-04 20:32:05 +0100663 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100664 daemon->tftp_prefix ? _("root is ") : _("enabled"),
665 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000666 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100667
Simon Kelley832af0b2007-01-21 20:01:28 +0000668 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100669 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000670 a single file will be sent to may clients (the file only needs
671 one fd). */
672
673 max_fd -= 30; /* use other than TFTP */
674
675 if (max_fd < 0)
676 max_fd = 5;
677 else if (max_fd < 100)
678 max_fd = max_fd/2;
679 else
680 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000681
682 /* if we have to use a limited range of ports,
683 that will limit the number of transfers */
684 if (daemon->start_tftp_port != 0 &&
685 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
686 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000687
688 if (daemon->tftp_max > max_fd)
689 {
690 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100691 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100692 _("restricting maximum simultaneous TFTP transfers to %d"),
693 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000694 }
695 }
696#endif
697
Simon Kelley1a6bca82008-07-11 11:11:42 +0100698 /* finished start-up - release original process */
699 if (err_pipe[1] != -1)
700 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000701
Simon Kelley824af852008-02-12 20:43:05 +0000702 if (daemon->port != 0)
703 check_servers();
704
Simon Kelley7cebd202006-05-06 14:13:33 +0100705 pid = getpid();
706
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100707 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000708 {
Simon Kelley16972692006-10-16 20:04:18 +0100709 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100710 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100711 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000712
713 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100714 FD_ZERO(&wset);
715 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000716
Simon Kelley16972692006-10-16 20:04:18 +0100717 /* if we are out of resources, find how long we have to wait
718 for some to come free, we'll loop around then and restart
719 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100720 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100721 {
722 t.tv_usec = 0;
723 tp = &t;
724 }
725
Simon Kelley832af0b2007-01-21 20:01:28 +0000726 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
727 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000728 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000729 {
Simon Kelley16972692006-10-16 20:04:18 +0100730 t.tv_sec = 0;
731 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100732 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000733 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100734 /* Wake every second whilst waiting for DAD to complete */
735 else if (is_dad_listeners())
736 {
737 t.tv_sec = 1;
738 t.tv_usec = 0;
739 tp = &t;
740 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100741
Simon Kelley832af0b2007-01-21 20:01:28 +0000742#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100743 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100744#endif
745
Simon Kelley7622fc02009-06-04 20:32:05 +0100746#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100747 if (daemon->dhcp)
748 {
749 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100750 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000751 if (daemon->pxefd != -1)
752 {
753 FD_SET(daemon->pxefd, &rset);
754 bump_maxfd(daemon->pxefd, &maxfd);
755 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100756 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100757#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100758
Simon Kelley52b92f42012-01-22 16:05:15 +0000759#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000760 if (daemon->doing_dhcp6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000761 {
762 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000763 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000764 }
765
Simon Kelley1f776932012-12-16 19:46:08 +0000766 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000767 {
768 FD_SET(daemon->icmp6fd, &rset);
769 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000770 }
771#endif
772
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100773#ifdef HAVE_LINUX_NETWORK
774 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100775 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100776#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100777
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100778 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100779 bump_maxfd(piperead, &maxfd);
780
Simon Kelley7622fc02009-06-04 20:32:05 +0100781#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100782# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100783 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100784
Simon Kelleya9530962012-03-20 22:07:35 +0000785# ifdef HAVE_TFTP
786 while (helper_buf_empty() && do_tftp_script_run());
787# endif
788
Simon Kelley16972692006-10-16 20:04:18 +0100789 if (!helper_buf_empty())
790 {
791 FD_SET(daemon->helperfd, &wset);
792 bump_maxfd(daemon->helperfd, &maxfd);
793 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100794# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100795 /* need this for other side-effects */
796 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000797
798# ifdef HAVE_TFTP
799 while (do_tftp_script_run());
800# endif
801
Simon Kelley7622fc02009-06-04 20:32:05 +0100802# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100803#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100804
Simon Kelleyf2621c72007-04-29 19:47:21 +0100805 /* must do this just before select(), when we know no
806 more calls to my_syslog() can occur */
807 set_log_writer(&wset, &maxfd);
808
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100809 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
810 {
811 /* otherwise undefined after error */
812 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
813 }
814
815 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816
Simon Kelleyf2621c72007-04-29 19:47:21 +0100817 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100818
819 /* Check the interfaces to see if any have exited DAD state
820 and if so, bind the address. */
821 if (is_dad_listeners())
822 {
823 enumerate_interfaces();
824 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
825 create_bound_listeners(0);
826 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100827
Simon Kelleyc52e1892010-06-07 22:01:39 +0100828#ifdef HAVE_LINUX_NETWORK
829 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000830 netlink_multicast(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100831#endif
832
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100834 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000835 if (daemon->last_resolv == 0 ||
836 difftime(now, daemon->last_resolv) > 1.0 ||
837 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000838 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100839 /* poll_resolv doesn't need to reload first time through, since
840 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100841
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100842 poll_resolv(0, daemon->last_resolv != 0, now);
843 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000844 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100845
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100846 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100847 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100848
Simon Kelley3d8df262005-08-29 12:19:27 +0100849#ifdef HAVE_DBUS
850 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000851 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100852 {
853 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100854 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100855 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100856 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100857 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100858 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100859 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100860#endif
Simon Kelley824af852008-02-12 20:43:05 +0000861
Simon Kelley5aabfc72007-08-29 11:24:47 +0100862 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000863
864#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100865 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000866#endif
867
Simon Kelley7622fc02009-06-04 20:32:05 +0100868#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000869 if (daemon->dhcp)
870 {
871 if (FD_ISSET(daemon->dhcpfd, &rset))
872 dhcp_packet(now, 0);
873 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
874 dhcp_packet(now, 1);
875 }
Simon Kelley16972692006-10-16 20:04:18 +0100876
Simon Kelley52b92f42012-01-22 16:05:15 +0000877#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000878 if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100879 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000880
Simon Kelley1f776932012-12-16 19:46:08 +0000881 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
882 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000883#endif
884
Simon Kelley1f15b812009-10-13 17:49:32 +0100885# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100886 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100887 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100888# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100889#endif
890
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000891 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000892}
893
Simon Kelley3be34542004-09-11 19:12:13 +0100894static void sig_handler(int sig)
895{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100896 if (pid == 0)
897 {
Simon Kelley16972692006-10-16 20:04:18 +0100898 /* ignore anything other than TERM during startup
899 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100900 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100901 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100902 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100903 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100904 {
Simon Kelley16972692006-10-16 20:04:18 +0100905 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100906 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100907 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100908 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100909 else
910 {
911 /* master process */
912 int event, errsave = errno;
913
914 if (sig == SIGHUP)
915 event = EVENT_RELOAD;
916 else if (sig == SIGCHLD)
917 event = EVENT_CHILD;
918 else if (sig == SIGALRM)
919 event = EVENT_ALARM;
920 else if (sig == SIGTERM)
921 event = EVENT_TERM;
922 else if (sig == SIGUSR1)
923 event = EVENT_DUMP;
924 else if (sig == SIGUSR2)
925 event = EVENT_REOPEN;
926 else
927 return;
928
Simon Kelleyc72daea2012-01-05 21:33:27 +0000929 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 errno = errsave;
931 }
Simon Kelley3be34542004-09-11 19:12:13 +0100932}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000933
Simon Kelley353ae4d2012-03-19 20:07:51 +0000934/* now == 0 -> queue immediate callback */
935void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000936{
Simon Kelley884a6df2012-03-20 16:20:22 +0000937 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000938 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000939 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
940 if ((now == 0 || difftime(event, now) <= 0.0))
941 send_event(pipewrite, EVENT_ALARM, 0, NULL);
942 else
943 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000944 }
Simon Kelley741c2952012-02-25 13:09:18 +0000945}
946
Simon Kelleyc72daea2012-01-05 21:33:27 +0000947void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100948{
949 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000950 struct iovec iov[2];
951
Simon Kelley5aabfc72007-08-29 11:24:47 +0100952 ev.event = event;
953 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000954 ev.msg_sz = msg ? strlen(msg) : 0;
955
956 iov[0].iov_base = &ev;
957 iov[0].iov_len = sizeof(ev);
958 iov[1].iov_base = msg;
959 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100960
961 /* error pipe, debug mode. */
962 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000963 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100964 else
965 /* pipe is non-blocking and struct event_desc is smaller than
966 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000967 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100968}
Simon Kelley3d8df262005-08-29 12:19:27 +0100969
Simon Kelleyc72daea2012-01-05 21:33:27 +0000970/* NOTE: the memory used to return msg is leaked: use msgs in events only
971 to describe fatal errors. */
972static int read_event(int fd, struct event_desc *evp, char **msg)
973{
974 char *buf;
975
976 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
977 return 0;
978
979 *msg = NULL;
980
981 if (evp->msg_sz != 0 &&
982 (buf = malloc(evp->msg_sz + 1)) &&
983 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
984 {
985 buf[evp->msg_sz] = 0;
986 *msg = buf;
987 }
988
989 return 1;
990}
991
992static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100993{
994 errno = ev->data;
995
996 switch (ev->event)
997 {
998 case EVENT_DIE:
999 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001000
1001 case EVENT_FORK_ERR:
1002 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001003
1004 case EVENT_PIPE_ERR:
1005 die(_("failed to create helper: %s"), NULL, EC_MISC);
1006
1007 case EVENT_CAP_ERR:
1008 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1009
1010 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001011 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001012
1013 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001014 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001015
1016 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001017 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001018
1019 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001020 die(_("cannot open log %s: %s"), msg, EC_FILE);
1021
1022 case EVENT_LUA_ERR:
1023 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001024
1025 case EVENT_TFTP_ERR:
1026 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001027 }
1028}
1029
Simon Kelley5aabfc72007-08-29 11:24:47 +01001030static void async_event(int pipe, time_t now)
1031{
1032 pid_t p;
1033 struct event_desc ev;
1034 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001035 char *msg;
1036
1037 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1038 to describe fatal errors. */
1039
1040 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001041 switch (ev.event)
1042 {
1043 case EVENT_RELOAD:
1044 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001045 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001046 {
1047 reload_servers(daemon->resolv_files->name);
1048 check_servers();
1049 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001050#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001051 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001052#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001053 break;
1054
1055 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001056 if (daemon->port != 0)
1057 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001058 break;
1059
1060 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001061#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001062 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001063 {
1064 lease_prune(NULL, now);
1065 lease_update_file(now);
1066 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001067#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001068 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001069 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1070 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001071#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001072#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001073 break;
1074
1075 case EVENT_CHILD:
1076 /* See Stevens 5.10 */
1077 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1078 if (p == -1)
1079 {
1080 if (errno != EINTR)
1081 break;
1082 }
1083 else
1084 for (i = 0 ; i < MAX_PROCS; i++)
1085 if (daemon->tcp_pids[i] == p)
1086 daemon->tcp_pids[i] = 0;
1087 break;
1088
1089 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001090 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001091 break;
1092
1093 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001094 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001095 break;
1096
1097 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001098 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1099 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001100 break;
1101
Simon Kelley1a6bca82008-07-11 11:11:42 +01001102 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001103 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001104 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001105 case EVENT_LUA_ERR:
1106 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001107 break;
1108
Simon Kelley5aabfc72007-08-29 11:24:47 +01001109 case EVENT_REOPEN:
1110 /* Note: this may leave TCP-handling processes with the old file still open.
1111 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1112 we leave them logging to the old file. */
1113 if (daemon->log_file != NULL)
1114 log_reopen(daemon->log_file);
1115 break;
1116
1117 case EVENT_TERM:
1118 /* Knock all our children on the head. */
1119 for (i = 0; i < MAX_PROCS; i++)
1120 if (daemon->tcp_pids[i] != 0)
1121 kill(daemon->tcp_pids[i], SIGALRM);
1122
Simon Kelleyc72daea2012-01-05 21:33:27 +00001123#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001124 /* handle pending lease transitions */
1125 if (daemon->helperfd != -1)
1126 {
1127 /* block in writes until all done */
1128 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1129 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1130 do {
1131 helper_write();
1132 } while (!helper_buf_empty() || do_script_run(now));
1133 close(daemon->helperfd);
1134 }
1135#endif
1136
1137 if (daemon->lease_stream)
1138 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001139
1140 if (daemon->runfile)
1141 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001142
1143 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1144 flush_log();
1145 exit(EC_GOOD);
1146 }
1147}
1148
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001149void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001150{
1151 struct resolvc *res, *latest;
1152 struct stat statbuf;
1153 time_t last_change = 0;
1154 /* There may be more than one possible file.
1155 Go through and find the one which changed _last_.
1156 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001157
Simon Kelley28866e92011-02-14 20:19:14 +00001158 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001159 return;
1160
Simon Kelley5aabfc72007-08-29 11:24:47 +01001161 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1162 if (stat(res->name, &statbuf) == -1)
1163 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001164 if (force)
1165 {
1166 res->mtime = 0;
1167 continue;
1168 }
1169
Simon Kelley5aabfc72007-08-29 11:24:47 +01001170 if (!res->logged)
1171 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1172 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001173
1174 if (res->mtime != 0)
1175 {
1176 /* existing file evaporated, force selection of the latest
1177 file even if its mtime hasn't changed since we last looked */
1178 poll_resolv(1, do_reload, now);
1179 return;
1180 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001181 }
1182 else
1183 {
1184 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001185 if (force || (statbuf.st_mtime != res->mtime))
1186 {
1187 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001188 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1189 {
1190 last_change = statbuf.st_mtime;
1191 latest = res;
1192 }
1193 }
1194 }
1195
1196 if (latest)
1197 {
1198 static int warned = 0;
1199 if (reload_servers(latest->name))
1200 {
1201 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1202 warned = 0;
1203 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001204 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001205 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001206 }
1207 else
1208 {
1209 latest->mtime = 0;
1210 if (!warned)
1211 {
1212 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1213 warned = 1;
1214 }
1215 }
1216 }
1217}
1218
1219void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001220{
Simon Kelley824af852008-02-12 20:43:05 +00001221 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001222 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001223
Simon Kelley7622fc02009-06-04 20:32:05 +01001224#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001225 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001226 {
Simon Kelley28866e92011-02-14 20:19:14 +00001227 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001228 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001229 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001230 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001231 lease_update_from_configs();
1232 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001233 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001234 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001235#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001236 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001237 /* Not doing DHCP, so no lease system, manage
1238 alarms for ra only */
1239 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001240#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001241#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001242}
1243
Simon Kelley5aabfc72007-08-29 11:24:47 +01001244static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001245{
1246 struct serverfd *serverfdp;
1247 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001248 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001249
1250#ifdef HAVE_TFTP
1251 int tftp = 0;
1252 struct tftp_transfer *transfer;
1253 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1254 {
1255 tftp++;
1256 FD_SET(transfer->sockfd, set);
1257 bump_maxfd(transfer->sockfd, maxfdp);
1258 }
1259#endif
1260
Simon Kelley16972692006-10-16 20:04:18 +01001261 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001262 if (daemon->port != 0)
1263 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001264
Simon Kelley3be34542004-09-11 19:12:13 +01001265 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1266 {
1267 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001268 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001269 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001270
1271 if (daemon->port != 0 && !daemon->osport)
1272 for (i = 0; i < RANDOM_SOCKS; i++)
1273 if (daemon->randomsocks[i].refcount != 0)
1274 {
1275 FD_SET(daemon->randomsocks[i].fd, set);
1276 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1277 }
1278
Simon Kelley3be34542004-09-11 19:12:13 +01001279 for (listener = daemon->listeners; listener; listener = listener->next)
1280 {
Simon Kelley16972692006-10-16 20:04:18 +01001281 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001282 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001283 {
1284 FD_SET(listener->fd, set);
1285 bump_maxfd(listener->fd, maxfdp);
1286 }
1287
1288 /* death of a child goes through the select loop, so
1289 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001290 if (listener->tcpfd != -1)
1291 for (i = 0; i < MAX_PROCS; i++)
1292 if (daemon->tcp_pids[i] == 0)
1293 {
1294 FD_SET(listener->tcpfd, set);
1295 bump_maxfd(listener->tcpfd, maxfdp);
1296 break;
1297 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001298
Simon Kelley832af0b2007-01-21 20:01:28 +00001299#ifdef HAVE_TFTP
1300 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1301 {
1302 FD_SET(listener->tftpfd, set);
1303 bump_maxfd(listener->tftpfd, maxfdp);
1304 }
1305#endif
1306
1307 }
1308
Simon Kelley16972692006-10-16 20:04:18 +01001309 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001310}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001311
Simon Kelley5aabfc72007-08-29 11:24:47 +01001312static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001313{
1314 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001315 struct listener *listener;
1316 int i;
1317
Simon Kelley832af0b2007-01-21 20:01:28 +00001318 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1319 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001320 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1321
1322 if (daemon->port != 0 && !daemon->osport)
1323 for (i = 0; i < RANDOM_SOCKS; i++)
1324 if (daemon->randomsocks[i].refcount != 0 &&
1325 FD_ISSET(daemon->randomsocks[i].fd, set))
1326 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001327
1328 for (listener = daemon->listeners; listener; listener = listener->next)
1329 {
Simon Kelley824af852008-02-12 20:43:05 +00001330 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001331 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001332
Simon Kelley832af0b2007-01-21 20:01:28 +00001333#ifdef HAVE_TFTP
1334 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001335 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001336#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001337
Simon Kelley824af852008-02-12 20:43:05 +00001338 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001339 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001340 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001341 struct irec *iface = NULL;
1342 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001343 union mysockaddr tcp_addr;
1344 socklen_t tcp_len = sizeof(union mysockaddr);
1345
1346 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001347
Simon Kelley46b06652013-02-04 21:47:59 +00001348 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001349 continue;
Simon Kelley22ce5502013-01-22 13:53:04 +00001350
Simon Kelley46b06652013-02-04 21:47:59 +00001351 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1352 {
1353 close(confd);
1354 continue;
1355 }
1356
Simon Kelley22ce5502013-01-22 13:53:04 +00001357 if (option_bool(OPT_NOWILD))
Simon Kelley52d4abf2012-03-21 21:39:48 +00001358 iface = listener->iface; /* May be NULL */
Simon Kelley22ce5502013-01-22 13:53:04 +00001359 else
1360 {
1361 int if_index;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001362 char intr_name[IF_NAMESIZE];
1363
Simon Kelley22ce5502013-01-22 13:53:04 +00001364 /* In full wildcard mode, need to refresh interface list.
1365 This happens automagically in CLEVERBIND */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001366 if (!option_bool(OPT_CLEVERBIND))
1367 enumerate_interfaces();
1368
1369 /* if we can find the arrival interface, check it's one that's allowed */
1370 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1371 indextoname(listener->tcpfd, if_index, intr_name))
Simon Kelley22ce5502013-01-22 13:53:04 +00001372 {
Simon Kelleye25db1f2013-01-29 22:10:26 +00001373 struct all_addr addr;
1374 addr.addr.addr4 = tcp_addr.in.sin_addr;
1375#ifdef HAVE_IPV6
1376 if (tcp_addr.sa.sa_family == AF_INET6)
1377 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
1378#endif
1379
Simon Kelley22ce5502013-01-22 13:53:04 +00001380 for (iface = daemon->interfaces; iface; iface = iface->next)
1381 if (iface->index == if_index)
1382 break;
1383
Simon Kelleye25db1f2013-01-29 22:10:26 +00001384 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
Simon Kelley22ce5502013-01-22 13:53:04 +00001385 client_ok = 0;
1386 }
1387
1388 if (option_bool(OPT_CLEVERBIND))
1389 iface = listener->iface; /* May be NULL */
1390 else
1391 {
Simon Kelleye25db1f2013-01-29 22:10:26 +00001392 /* Check for allowed interfaces when binding the wildcard address:
1393 we do this by looking for an interface with the same address as
1394 the local address of the TCP connection, then looking to see if that's
1395 an allowed interface. As a side effect, we get the netmask of the
Simon Kelley22ce5502013-01-22 13:53:04 +00001396 interface too, for localisation. */
1397
1398 for (iface = daemon->interfaces; iface; iface = iface->next)
1399 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1400 break;
1401
1402 if (!iface)
1403 client_ok = 0;
1404 }
1405 }
1406
1407 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001408 {
1409 shutdown(confd, SHUT_RDWR);
1410 close(confd);
1411 }
1412#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001413 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001414 {
1415 if (p != -1)
1416 {
1417 int i;
1418 for (i = 0; i < MAX_PROCS; i++)
1419 if (daemon->tcp_pids[i] == 0)
1420 {
1421 daemon->tcp_pids[i] = p;
1422 break;
1423 }
1424 }
1425 close(confd);
1426 }
1427#endif
1428 else
1429 {
1430 unsigned char *buff;
1431 struct server *s;
1432 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001433 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001434 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001435
1436 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001437 {
1438 netmask = iface->netmask;
1439 auth_dns = iface->dns_auth;
1440 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001441 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001442 {
1443 netmask.s_addr = 0;
1444 auth_dns = 0;
1445 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001446
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001447#ifndef NO_FORK
1448 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1449 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001450 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001451 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001452#endif
1453
Simon Kelley832af0b2007-01-21 20:01:28 +00001454 /* start with no upstream connections. */
1455 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001456 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001457
1458 /* The connected socket inherits non-blocking
1459 attribute from the listening socket.
1460 Reset that here. */
1461 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1462 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1463
Simon Kelley4f7b3042012-11-28 21:27:02 +00001464 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001465
Simon Kelley832af0b2007-01-21 20:01:28 +00001466 shutdown(confd, SHUT_RDWR);
1467 close(confd);
1468
1469 if (buff)
1470 free(buff);
1471
1472 for (s = daemon->servers; s; s = s->next)
1473 if (s->tcpfd != -1)
1474 {
1475 shutdown(s->tcpfd, SHUT_RDWR);
1476 close(s->tcpfd);
1477 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001478#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001479 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001480 {
1481 flush_log();
1482 _exit(0);
1483 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001484#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001485 }
1486 }
1487 }
Simon Kelley3be34542004-09-11 19:12:13 +01001488}
1489
Simon Kelley7622fc02009-06-04 20:32:05 +01001490#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001491int make_icmp_sock(void)
1492{
Simon Kelley7cebd202006-05-06 14:13:33 +01001493 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001494 int zeroopt = 0;
1495
1496 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1497 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001498 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001499 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1500 {
1501 close(fd);
1502 fd = -1;
1503 }
1504 }
1505
1506 return fd;
1507}
1508
Simon Kelley5aabfc72007-08-29 11:24:47 +01001509int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001510{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001511 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001512
1513 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001514 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001515 better not use any resources our caller has in use...)
1516 but we remain deaf to signals or further DHCP packets. */
1517
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001518 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001519 struct sockaddr_in saddr;
1520 struct {
1521 struct ip ip;
1522 struct icmp icmp;
1523 } packet;
1524 unsigned short id = rand16();
1525 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001526 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001527 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001528
Simon Kelley824af852008-02-12 20:43:05 +00001529#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001530 if ((fd = make_icmp_sock()) == -1)
1531 return 0;
1532#else
1533 int opt = 2000;
1534 fd = daemon->dhcp_icmp_fd;
1535 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1536#endif
1537
Simon Kelley3be34542004-09-11 19:12:13 +01001538 saddr.sin_family = AF_INET;
1539 saddr.sin_port = 0;
1540 saddr.sin_addr = addr;
1541#ifdef HAVE_SOCKADDR_SA_LEN
1542 saddr.sin_len = sizeof(struct sockaddr_in);
1543#endif
1544
1545 memset(&packet.icmp, 0, sizeof(packet.icmp));
1546 packet.icmp.icmp_type = ICMP_ECHO;
1547 packet.icmp.icmp_id = id;
1548 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1549 j += ((u16 *)&packet.icmp)[i];
1550 while (j>>16)
1551 j = (j & 0xffff) + (j >> 16);
1552 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1553
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001554 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001555 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1556 retry_send());
1557
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001558 for (now = start = dnsmasq_time();
1559 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001560 {
1561 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001562 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001563 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001564 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001565 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001566
1567 tv.tv_usec = 250000;
1568 tv.tv_sec = 0;
1569
1570 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001571 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001572 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001573 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001574 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001575
1576#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001577 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001578 {
1579 FD_SET(daemon->icmp6fd, &rset);
1580 bump_maxfd(daemon->icmp6fd, &maxfd);
1581 }
1582#endif
1583
Simon Kelleyf2621c72007-04-29 19:47:21 +01001584 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1585 {
1586 FD_ZERO(&rset);
1587 FD_ZERO(&wset);
1588 }
1589
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001590 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001591
1592 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001593 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001594
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001595#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001596 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1597 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001598#endif
1599
Simon Kelley832af0b2007-01-21 20:01:28 +00001600#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001601 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001602#endif
1603
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001604 if (FD_ISSET(fd, &rset) &&
1605 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001606 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1607 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1608 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1609 packet.icmp.icmp_seq == 0 &&
1610 packet.icmp.icmp_id == id)
1611 {
1612 gotreply = 1;
1613 break;
1614 }
1615 }
1616
Simon Kelley824af852008-02-12 20:43:05 +00001617#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001618 close(fd);
1619#else
Simon Kelley3be34542004-09-11 19:12:13 +01001620 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001621 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1622#endif
1623
Simon Kelley3be34542004-09-11 19:12:13 +01001624 return gotreply;
1625}
Simon Kelley7622fc02009-06-04 20:32:05 +01001626#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001627
1628