blob: 62e65a96585506918d65708bd63373d85e233337 [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
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000161 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000162 if (daemon->authinterface && daemon->soa_sn == 0)
163#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000164 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000165#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
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000216#ifdef HAVE_IPSET
217 if (daemon->ipsets)
218 ipset_init();
219#endif
220
Simon Kelley801ca9a2012-03-06 19:30:17 +0000221#ifdef HAVE_LINUX_NETWORK
Simon Kelley801ca9a2012-03-06 19:30:17 +0000222 netlink_init();
Simon Kelley8445f5d2012-12-17 21:54:08 +0000223
Simon Kelley54dd3932012-06-20 11:23:38 +0100224 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
225 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000226#endif
227
Simon Kelley115ac3e2013-05-20 11:28:32 +0100228 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100229 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000230
Simon Kelley54dd3932012-06-20 11:23:38 +0100231 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100232 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100233 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100234
235 if (!option_bool(OPT_CLEVERBIND))
236 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
237 if (if_tmp->name && !if_tmp->used)
238 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100239
240#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
241 /* after enumerate_interfaces() */
242 if (daemon->dhcp)
243 {
244 bindtodevice(daemon->dhcpfd);
245 if (daemon->enable_pxe)
246 bindtodevice(daemon->pxefd);
247 }
248#endif
249
250#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelleycfcad422013-05-17 11:32:03 +0100251 if (daemon->doing_dhcp6)
Simon Kelley9380ba72012-04-16 14:41:56 +0100252 bindtodevice(daemon->dhcp6fd);
253#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100254 }
Simon Kelley28866e92011-02-14 20:19:14 +0000255 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100256 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000257
258#ifdef HAVE_DHCP6
259 /* after enumerate_interfaces() */
260 if (daemon->doing_dhcp6 || daemon->doing_ra)
261 join_multicast(1);
262#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100263
Simon Kelley824af852008-02-12 20:43:05 +0000264 if (daemon->port != 0)
265 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100266
Simon Kelley28866e92011-02-14 20:19:14 +0000267 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100268#ifdef HAVE_DBUS
269 {
270 char *err;
271 daemon->dbus = NULL;
272 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100273 if ((err = dbus_init()))
274 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100275 }
276#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100277 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100278#endif
279
Simon Kelley824af852008-02-12 20:43:05 +0000280 if (daemon->port != 0)
281 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100282
Simon Kelleyc72daea2012-01-05 21:33:27 +0000283#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100284 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000285 if ((daemon->dhcp || daemon->dhcp6) &&
286 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000287 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100288 {
289 if ((ent_pw = getpwnam(daemon->scriptuser)))
290 {
291 script_uid = ent_pw->pw_uid;
292 script_gid = ent_pw->pw_gid;
293 }
294 else
295 baduser = daemon->scriptuser;
296 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100297#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000298
Simon Kelley1a6bca82008-07-11 11:11:42 +0100299 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
300 baduser = daemon->username;
301 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
302 baduser = daemon->groupname;
303
304 if (baduser)
305 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
306
307 /* implement group defaults, "dip" if available, or group associated with uid */
308 if (!daemon->group_set && !gp)
309 {
310 if (!(gp = getgrnam(CHGRP)) && ent_pw)
311 gp = getgrgid(ent_pw->pw_gid);
312
313 /* for error message */
314 if (gp)
315 daemon->groupname = gp->gr_name;
316 }
317
318#if defined(HAVE_LINUX_NETWORK)
319 /* determine capability API version here, while we can still
320 call safe_malloc */
321 if (ent_pw && ent_pw->pw_uid != 0)
322 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100323 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100324 hdr = safe_malloc(sizeof(*hdr));
325
Simon Kelley1a6bca82008-07-11 11:11:42 +0100326 /* find version supported by kernel */
327 memset(hdr, 0, sizeof(*hdr));
328 capget(hdr, NULL);
329
330 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
331 {
332 /* if unknown version, use largest supported version (3) */
333 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
334 hdr->version = LINUX_CAPABILITY_VERSION_3;
335 capsize = 2;
336 }
337
338 data = safe_malloc(sizeof(*data) * capsize);
339 memset(data, 0, sizeof(*data) * capsize);
340 }
341#endif
342
Simon Kelley5aabfc72007-08-29 11:24:47 +0100343 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100344 in a race-free manner and another to carry errors to daemon-invoking process */
345 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100346
347 piperead = pipefd[0];
348 pipewrite = pipefd[1];
349 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000350 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100351
352 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100353
Simon Kelley28866e92011-02-14 20:19:14 +0000354 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000355 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000356 /* The following code "daemonizes" the process.
357 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358
Simon Kelley9e038942008-05-30 20:06:34 +0100359 if (chdir("/") != 0)
360 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
361
Simon Kelley16972692006-10-16 20:04:18 +0100362#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000363 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100364 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100365 pid_t pid;
366
Simon Kelley1a6bca82008-07-11 11:11:42 +0100367 /* pipe to carry errors back to original process.
368 When startup is complete we close this and the process terminates. */
369 safe_pipe(err_pipe, 0);
370
Simon Kelley7622fc02009-06-04 20:32:05 +0100371 if ((pid = fork()) == -1)
372 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000373 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100374
Simon Kelley5aabfc72007-08-29 11:24:47 +0100375 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100376 {
377 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000378 char *msg;
379
Simon Kelley1a6bca82008-07-11 11:11:42 +0100380 /* close our copy of write-end */
381 close(err_pipe[1]);
382
383 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000384 if (read_event(err_pipe[0], &ev, &msg))
385 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100386
387 _exit(EC_GOOD);
388 }
389
390 close(err_pipe[0]);
391
392 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100393
394 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100395
396 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000397 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100398
399 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100400 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100401 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000402#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100403
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000404 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100405 if (daemon->runfile)
406 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100407 int fd, err = 0;
408
409 sprintf(daemon->namebuff, "%d\n", (int) getpid());
410
411 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
412 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
413 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
414 extent that an attacker running as the unprivileged user could replace the pidfile with a
415 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
416
417 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
418 ensuring that the open() fails should there be any existing file (because the unlink() failed,
419 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
420 attack can succeed.
421
422 Any compromise of the non-privileged user still theoretically allows the pid-file to be
423 replaced whilst dnsmasq is running. The worst that could allow is that the usual
424 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
425
426 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
427 failure to write the pid-file.
428 */
429
430 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100431
Simon Kelley79cfefd2012-09-02 13:29:51 +0100432 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 +0100433 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100434 /* only complain if started as root */
435 if (getuid() == 0)
436 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100437 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100438 else
439 {
440 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
441 err = 1;
442
443 while (!err && close(fd) == -1)
444 if (!retry_send())
445 err = 1;
446 }
447
448 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100449 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000450 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100451 _exit(0);
452 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453 }
Simon Kelley16972692006-10-16 20:04:18 +0100454 }
455
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100456 log_err = log_start(ent_pw, err_pipe[1]);
457
Simon Kelley28866e92011-02-14 20:19:14 +0000458 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100459 {
460 /* open stdout etc to /dev/null */
461 int nullfd = open("/dev/null", O_RDWR);
462 dup2(nullfd, STDOUT_FILENO);
463 dup2(nullfd, STDERR_FILENO);
464 dup2(nullfd, STDIN_FILENO);
465 close(nullfd);
466 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100467
Simon Kelley1a6bca82008-07-11 11:11:42 +0100468 /* if we are to run scripts, we need to fork a helper before dropping root. */
469 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000470#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000471 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100472 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
473#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100474
Simon Kelley28866e92011-02-14 20:19:14 +0000475 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100476 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100477 int bad_capabilities = 0;
478 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100479
Simon Kelley1a6bca82008-07-11 11:11:42 +0100480 /* remove all supplimentary groups */
481 if (gp &&
482 (setgroups(0, &dummy) == -1 ||
483 setgid(gp->gr_gid) == -1))
484 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000485 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100486 _exit(0);
487 }
488
Simon Kelley7cebd202006-05-06 14:13:33 +0100489 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100490 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100491#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100492 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100493 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100494 ports because of DAD, or we're doing it dynamically,
495 we need CAP_NET_BIND_SERVICE too. */
496 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100497 data->effective = data->permitted = data->inheritable =
498 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
499 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
500 else
501 data->effective = data->permitted = data->inheritable =
502 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100503
Simon Kelley16972692006-10-16 20:04:18 +0100504 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000505 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100506 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100507
Simon Kelley7622fc02009-06-04 20:32:05 +0100508#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000509 /* http://developers.sun.com/solaris/articles/program_privileges.html */
510 priv_set_t *priv_set;
511
512 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
513 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
514 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
515 bad_capabilities = errno;
516
517 if (priv_set && bad_capabilities == 0)
518 {
519 priv_inverse(priv_set);
520
521 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
522 bad_capabilities = errno;
523 }
524
525 if (priv_set)
526 priv_freeset(priv_set);
527
Simon Kelley824af852008-02-12 20:43:05 +0000528#endif
529
Simon Kelley1a6bca82008-07-11 11:11:42 +0100530 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100531 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000532 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100533 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100534 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100535
536 /* finally drop root */
537 if (setuid(ent_pw->pw_uid) == -1)
538 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000539 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100540 _exit(0);
541 }
542
543#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100544 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100545 data->effective = data->permitted =
546 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
547 else
548 data->effective = data->permitted =
549 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100550 data->inheritable = 0;
551
552 /* lose the setuid and setgid capbilities */
553 if (capset(hdr, data) == -1)
554 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000555 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100556 _exit(0);
557 }
558#endif
559
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000560 }
Simon Kelley849a8352006-06-09 21:02:31 +0100561 }
Simon Kelley16972692006-10-16 20:04:18 +0100562
Simon Kelley16972692006-10-16 20:04:18 +0100563#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000564 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000565 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100566#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100567
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100568#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100569 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100570 {
571 DIR *dir;
572 struct tftp_prefix *p;
573
574 if (daemon->tftp_prefix)
575 {
576 if (!((dir = opendir(daemon->tftp_prefix))))
577 {
578 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
579 _exit(0);
580 }
581 closedir(dir);
582 }
583
584 for (p = daemon->if_prefix; p; p = p->next)
585 {
586 if (!((dir = opendir(p->prefix))))
587 {
588 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
589 _exit(0);
590 }
591 closedir(dir);
592 }
593 }
594#endif
595
Simon Kelley824af852008-02-12 20:43:05 +0000596 if (daemon->port == 0)
597 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
598 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100599 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100601 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100602
Simon Kelleyf2621c72007-04-29 19:47:21 +0100603 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100604
Simon Kelley3d8df262005-08-29 12:19:27 +0100605#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000606 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100607 {
608 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100609 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100610 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100611 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100612 }
613#endif
614
Simon Kelley1a6bca82008-07-11 11:11:42 +0100615 if (log_err != 0)
616 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
617 daemon->log_file, strerror(log_err));
618
Simon Kelleyde379512004-06-22 20:23:33 +0100619 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100620 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100621
Simon Kelley28866e92011-02-14 20:19:14 +0000622 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000623 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
624 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100625 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100626
Simon Kelley28866e92011-02-14 20:19:14 +0000627 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100628 {
629 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100630 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100631 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000632 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100633 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100634 }
635
Simon Kelleyf2621c72007-04-29 19:47:21 +0100636 if (daemon->max_logs != 0)
637 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000638
Simon Kelleyf2621c72007-04-29 19:47:21 +0100639
Simon Kelley7622fc02009-06-04 20:32:05 +0100640#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000641 for (context = daemon->dhcp; context; context = context->next)
642 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100643
Simon Kelley1f776932012-12-16 19:46:08 +0000644# ifdef HAVE_DHCP6
645 for (context = daemon->dhcp6; context; context = context->next)
646 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000647
Simon Kelley1f776932012-12-16 19:46:08 +0000648 if (daemon->doing_dhcp6 || daemon->doing_ra)
649 dhcp_construct_contexts(now);
650
651 if (option_bool(OPT_RA))
652 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
653# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000654
Simon Kelley8445f5d2012-12-17 21:54:08 +0000655 /* after dhcp_contruct_contexts */
656 if (daemon->dhcp || daemon->doing_dhcp6)
657 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000658#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000659
Simon Kelley832af0b2007-01-21 20:01:28 +0000660#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100661 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000662 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000663#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100664 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000665 max_fd = FD_SETSIZE;
666#endif
667
Simon Kelley7622fc02009-06-04 20:32:05 +0100668 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100669 daemon->tftp_prefix ? _("root is ") : _("enabled"),
670 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000671 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100672
Simon Kelley832af0b2007-01-21 20:01:28 +0000673 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100674 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000675 a single file will be sent to may clients (the file only needs
676 one fd). */
677
678 max_fd -= 30; /* use other than TFTP */
679
680 if (max_fd < 0)
681 max_fd = 5;
682 else if (max_fd < 100)
683 max_fd = max_fd/2;
684 else
685 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000686
687 /* if we have to use a limited range of ports,
688 that will limit the number of transfers */
689 if (daemon->start_tftp_port != 0 &&
690 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
691 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000692
693 if (daemon->tftp_max > max_fd)
694 {
695 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100696 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100697 _("restricting maximum simultaneous TFTP transfers to %d"),
698 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000699 }
700 }
701#endif
702
Simon Kelley1a6bca82008-07-11 11:11:42 +0100703 /* finished start-up - release original process */
704 if (err_pipe[1] != -1)
705 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000706
Simon Kelley824af852008-02-12 20:43:05 +0000707 if (daemon->port != 0)
708 check_servers();
709
Simon Kelley7cebd202006-05-06 14:13:33 +0100710 pid = getpid();
711
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100712 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000713 {
Simon Kelley16972692006-10-16 20:04:18 +0100714 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100715 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100716 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000717
718 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100719 FD_ZERO(&wset);
720 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000721
Simon Kelley16972692006-10-16 20:04:18 +0100722 /* if we are out of resources, find how long we have to wait
723 for some to come free, we'll loop around then and restart
724 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100725 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100726 {
727 t.tv_usec = 0;
728 tp = &t;
729 }
730
Simon Kelley832af0b2007-01-21 20:01:28 +0000731 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
732 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000733 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000734 {
Simon Kelley16972692006-10-16 20:04:18 +0100735 t.tv_sec = 0;
736 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100737 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000738 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100739 /* Wake every second whilst waiting for DAD to complete */
740 else if (is_dad_listeners())
741 {
742 t.tv_sec = 1;
743 t.tv_usec = 0;
744 tp = &t;
745 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100746
Simon Kelley832af0b2007-01-21 20:01:28 +0000747#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100748 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100749#endif
750
Simon Kelley7622fc02009-06-04 20:32:05 +0100751#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100752 if (daemon->dhcp)
753 {
754 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100755 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000756 if (daemon->pxefd != -1)
757 {
758 FD_SET(daemon->pxefd, &rset);
759 bump_maxfd(daemon->pxefd, &maxfd);
760 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100761 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100762#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100763
Simon Kelley52b92f42012-01-22 16:05:15 +0000764#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000765 if (daemon->doing_dhcp6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000766 {
767 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000768 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000769 }
770
Simon Kelley1f776932012-12-16 19:46:08 +0000771 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000772 {
773 FD_SET(daemon->icmp6fd, &rset);
774 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000775 }
776#endif
777
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100778#ifdef HAVE_LINUX_NETWORK
779 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100780 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100781#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100782
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100783 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100784 bump_maxfd(piperead, &maxfd);
785
Simon Kelley7622fc02009-06-04 20:32:05 +0100786#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100787# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100788 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100789
Simon Kelleya9530962012-03-20 22:07:35 +0000790# ifdef HAVE_TFTP
791 while (helper_buf_empty() && do_tftp_script_run());
792# endif
793
Simon Kelley16972692006-10-16 20:04:18 +0100794 if (!helper_buf_empty())
795 {
796 FD_SET(daemon->helperfd, &wset);
797 bump_maxfd(daemon->helperfd, &maxfd);
798 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100799# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100800 /* need this for other side-effects */
801 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000802
803# ifdef HAVE_TFTP
804 while (do_tftp_script_run());
805# endif
806
Simon Kelley7622fc02009-06-04 20:32:05 +0100807# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100808#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100809
Simon Kelleyf2621c72007-04-29 19:47:21 +0100810 /* must do this just before select(), when we know no
811 more calls to my_syslog() can occur */
812 set_log_writer(&wset, &maxfd);
813
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100814 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
815 {
816 /* otherwise undefined after error */
817 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
818 }
819
820 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000821
Simon Kelleyf2621c72007-04-29 19:47:21 +0100822 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100823
824 /* prime. */
825 enumerate_interfaces(1);
826
Simon Kelley74c95c22011-10-19 09:33:39 +0100827 /* Check the interfaces to see if any have exited DAD state
828 and if so, bind the address. */
829 if (is_dad_listeners())
830 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100831 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100832 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
833 create_bound_listeners(0);
834 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100835
Simon Kelleyc52e1892010-06-07 22:01:39 +0100836#ifdef HAVE_LINUX_NETWORK
837 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000838 netlink_multicast(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100839#endif
840
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000841 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100842 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000843 if (daemon->last_resolv == 0 ||
844 difftime(now, daemon->last_resolv) > 1.0 ||
845 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000846 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100847 /* poll_resolv doesn't need to reload first time through, since
848 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100849
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100850 poll_resolv(0, daemon->last_resolv != 0, now);
851 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100854 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100855 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100856
Simon Kelley3d8df262005-08-29 12:19:27 +0100857#ifdef HAVE_DBUS
858 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000859 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100860 {
861 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100862 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100863 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100864 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100865 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100866 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100867 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100868#endif
Simon Kelley824af852008-02-12 20:43:05 +0000869
Simon Kelley5aabfc72007-08-29 11:24:47 +0100870 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000871
872#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100873 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000874#endif
875
Simon Kelley7622fc02009-06-04 20:32:05 +0100876#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000877 if (daemon->dhcp)
878 {
879 if (FD_ISSET(daemon->dhcpfd, &rset))
880 dhcp_packet(now, 0);
881 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
882 dhcp_packet(now, 1);
883 }
Simon Kelley16972692006-10-16 20:04:18 +0100884
Simon Kelley52b92f42012-01-22 16:05:15 +0000885#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000886 if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100887 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000888
Simon Kelley1f776932012-12-16 19:46:08 +0000889 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
890 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000891#endif
892
Simon Kelley1f15b812009-10-13 17:49:32 +0100893# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100894 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100895 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100896# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100897#endif
898
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000899 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000900}
901
Simon Kelley3be34542004-09-11 19:12:13 +0100902static void sig_handler(int sig)
903{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100904 if (pid == 0)
905 {
Simon Kelley16972692006-10-16 20:04:18 +0100906 /* ignore anything other than TERM during startup
907 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100908 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100909 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100910 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100911 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100912 {
Simon Kelley16972692006-10-16 20:04:18 +0100913 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100914 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100915 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100916 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100917 else
918 {
919 /* master process */
920 int event, errsave = errno;
921
922 if (sig == SIGHUP)
923 event = EVENT_RELOAD;
924 else if (sig == SIGCHLD)
925 event = EVENT_CHILD;
926 else if (sig == SIGALRM)
927 event = EVENT_ALARM;
928 else if (sig == SIGTERM)
929 event = EVENT_TERM;
930 else if (sig == SIGUSR1)
931 event = EVENT_DUMP;
932 else if (sig == SIGUSR2)
933 event = EVENT_REOPEN;
934 else
935 return;
936
Simon Kelleyc72daea2012-01-05 21:33:27 +0000937 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100938 errno = errsave;
939 }
Simon Kelley3be34542004-09-11 19:12:13 +0100940}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941
Simon Kelley353ae4d2012-03-19 20:07:51 +0000942/* now == 0 -> queue immediate callback */
943void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000944{
Simon Kelley884a6df2012-03-20 16:20:22 +0000945 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000946 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000947 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
948 if ((now == 0 || difftime(event, now) <= 0.0))
949 send_event(pipewrite, EVENT_ALARM, 0, NULL);
950 else
951 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000952 }
Simon Kelley741c2952012-02-25 13:09:18 +0000953}
954
Simon Kelleyc72daea2012-01-05 21:33:27 +0000955void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100956{
957 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000958 struct iovec iov[2];
959
Simon Kelley5aabfc72007-08-29 11:24:47 +0100960 ev.event = event;
961 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000962 ev.msg_sz = msg ? strlen(msg) : 0;
963
964 iov[0].iov_base = &ev;
965 iov[0].iov_len = sizeof(ev);
966 iov[1].iov_base = msg;
967 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100968
969 /* error pipe, debug mode. */
970 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000971 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100972 else
973 /* pipe is non-blocking and struct event_desc is smaller than
974 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000975 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100976}
Simon Kelley3d8df262005-08-29 12:19:27 +0100977
Simon Kelleyc72daea2012-01-05 21:33:27 +0000978/* NOTE: the memory used to return msg is leaked: use msgs in events only
979 to describe fatal errors. */
980static int read_event(int fd, struct event_desc *evp, char **msg)
981{
982 char *buf;
983
984 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
985 return 0;
986
987 *msg = NULL;
988
989 if (evp->msg_sz != 0 &&
990 (buf = malloc(evp->msg_sz + 1)) &&
991 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
992 {
993 buf[evp->msg_sz] = 0;
994 *msg = buf;
995 }
996
997 return 1;
998}
999
1000static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001001{
1002 errno = ev->data;
1003
1004 switch (ev->event)
1005 {
1006 case EVENT_DIE:
1007 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001008
1009 case EVENT_FORK_ERR:
1010 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001011
1012 case EVENT_PIPE_ERR:
1013 die(_("failed to create helper: %s"), NULL, EC_MISC);
1014
1015 case EVENT_CAP_ERR:
1016 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1017
1018 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001019 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001020
1021 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001022 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001023
1024 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001025 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001026
1027 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001028 die(_("cannot open log %s: %s"), msg, EC_FILE);
1029
1030 case EVENT_LUA_ERR:
1031 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001032
1033 case EVENT_TFTP_ERR:
1034 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001035 }
1036}
1037
Simon Kelley5aabfc72007-08-29 11:24:47 +01001038static void async_event(int pipe, time_t now)
1039{
1040 pid_t p;
1041 struct event_desc ev;
1042 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001043 char *msg;
1044
1045 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1046 to describe fatal errors. */
1047
1048 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001049 switch (ev.event)
1050 {
1051 case EVENT_RELOAD:
1052 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001053 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001054 {
1055 reload_servers(daemon->resolv_files->name);
1056 check_servers();
1057 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001058#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001059 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001060#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001061 break;
1062
1063 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001064 if (daemon->port != 0)
1065 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001066 break;
1067
1068 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001069#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001070 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001071 {
1072 lease_prune(NULL, now);
1073 lease_update_file(now);
1074 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001075#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001076 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001077 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1078 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001079#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001080#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001081 break;
1082
1083 case EVENT_CHILD:
1084 /* See Stevens 5.10 */
1085 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1086 if (p == -1)
1087 {
1088 if (errno != EINTR)
1089 break;
1090 }
1091 else
1092 for (i = 0 ; i < MAX_PROCS; i++)
1093 if (daemon->tcp_pids[i] == p)
1094 daemon->tcp_pids[i] = 0;
1095 break;
1096
1097 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001098 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001099 break;
1100
1101 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001102 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001103 break;
1104
1105 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001106 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1107 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001108 break;
1109
Simon Kelley1a6bca82008-07-11 11:11:42 +01001110 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001111 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001112 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001113 case EVENT_LUA_ERR:
1114 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001115 break;
1116
Simon Kelley5aabfc72007-08-29 11:24:47 +01001117 case EVENT_REOPEN:
1118 /* Note: this may leave TCP-handling processes with the old file still open.
1119 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1120 we leave them logging to the old file. */
1121 if (daemon->log_file != NULL)
1122 log_reopen(daemon->log_file);
1123 break;
1124
1125 case EVENT_TERM:
1126 /* Knock all our children on the head. */
1127 for (i = 0; i < MAX_PROCS; i++)
1128 if (daemon->tcp_pids[i] != 0)
1129 kill(daemon->tcp_pids[i], SIGALRM);
1130
Simon Kelleyc72daea2012-01-05 21:33:27 +00001131#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001132 /* handle pending lease transitions */
1133 if (daemon->helperfd != -1)
1134 {
1135 /* block in writes until all done */
1136 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1137 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1138 do {
1139 helper_write();
1140 } while (!helper_buf_empty() || do_script_run(now));
1141 close(daemon->helperfd);
1142 }
1143#endif
1144
1145 if (daemon->lease_stream)
1146 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001147
1148 if (daemon->runfile)
1149 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001150
1151 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1152 flush_log();
1153 exit(EC_GOOD);
1154 }
1155}
1156
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001157void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001158{
1159 struct resolvc *res, *latest;
1160 struct stat statbuf;
1161 time_t last_change = 0;
1162 /* There may be more than one possible file.
1163 Go through and find the one which changed _last_.
1164 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001165
Simon Kelley28866e92011-02-14 20:19:14 +00001166 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001167 return;
1168
Simon Kelley5aabfc72007-08-29 11:24:47 +01001169 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1170 if (stat(res->name, &statbuf) == -1)
1171 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001172 if (force)
1173 {
1174 res->mtime = 0;
1175 continue;
1176 }
1177
Simon Kelley5aabfc72007-08-29 11:24:47 +01001178 if (!res->logged)
1179 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1180 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001181
1182 if (res->mtime != 0)
1183 {
1184 /* existing file evaporated, force selection of the latest
1185 file even if its mtime hasn't changed since we last looked */
1186 poll_resolv(1, do_reload, now);
1187 return;
1188 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001189 }
1190 else
1191 {
1192 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001193 if (force || (statbuf.st_mtime != res->mtime))
1194 {
1195 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001196 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1197 {
1198 last_change = statbuf.st_mtime;
1199 latest = res;
1200 }
1201 }
1202 }
1203
1204 if (latest)
1205 {
1206 static int warned = 0;
1207 if (reload_servers(latest->name))
1208 {
1209 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1210 warned = 0;
1211 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001212 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001213 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001214 }
1215 else
1216 {
1217 latest->mtime = 0;
1218 if (!warned)
1219 {
1220 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1221 warned = 1;
1222 }
1223 }
1224 }
1225}
1226
1227void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001228{
Simon Kelley824af852008-02-12 20:43:05 +00001229 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001230 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001231
Simon Kelley7622fc02009-06-04 20:32:05 +01001232#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001233 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001234 {
Simon Kelley28866e92011-02-14 20:19:14 +00001235 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001236 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001237 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001238 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001239 lease_update_from_configs();
1240 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001241 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001242 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001243#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001244 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001245 /* Not doing DHCP, so no lease system, manage
1246 alarms for ra only */
1247 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001248#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001249#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001250}
1251
Simon Kelley5aabfc72007-08-29 11:24:47 +01001252static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001253{
1254 struct serverfd *serverfdp;
1255 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001256 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001257
1258#ifdef HAVE_TFTP
1259 int tftp = 0;
1260 struct tftp_transfer *transfer;
1261 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1262 {
1263 tftp++;
1264 FD_SET(transfer->sockfd, set);
1265 bump_maxfd(transfer->sockfd, maxfdp);
1266 }
1267#endif
1268
Simon Kelley16972692006-10-16 20:04:18 +01001269 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001270 if (daemon->port != 0)
1271 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001272
Simon Kelley3be34542004-09-11 19:12:13 +01001273 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1274 {
1275 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001276 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001277 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001278
1279 if (daemon->port != 0 && !daemon->osport)
1280 for (i = 0; i < RANDOM_SOCKS; i++)
1281 if (daemon->randomsocks[i].refcount != 0)
1282 {
1283 FD_SET(daemon->randomsocks[i].fd, set);
1284 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1285 }
1286
Simon Kelley3be34542004-09-11 19:12:13 +01001287 for (listener = daemon->listeners; listener; listener = listener->next)
1288 {
Simon Kelley16972692006-10-16 20:04:18 +01001289 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001290 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001291 {
1292 FD_SET(listener->fd, set);
1293 bump_maxfd(listener->fd, maxfdp);
1294 }
1295
1296 /* death of a child goes through the select loop, so
1297 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001298 if (listener->tcpfd != -1)
1299 for (i = 0; i < MAX_PROCS; i++)
1300 if (daemon->tcp_pids[i] == 0)
1301 {
1302 FD_SET(listener->tcpfd, set);
1303 bump_maxfd(listener->tcpfd, maxfdp);
1304 break;
1305 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001306
Simon Kelley832af0b2007-01-21 20:01:28 +00001307#ifdef HAVE_TFTP
1308 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1309 {
1310 FD_SET(listener->tftpfd, set);
1311 bump_maxfd(listener->tftpfd, maxfdp);
1312 }
1313#endif
1314
1315 }
1316
Simon Kelley16972692006-10-16 20:04:18 +01001317 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001318}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001319
Simon Kelley5aabfc72007-08-29 11:24:47 +01001320static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001321{
1322 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001323 struct listener *listener;
1324 int i;
1325
Simon Kelley832af0b2007-01-21 20:01:28 +00001326 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1327 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001328 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1329
1330 if (daemon->port != 0 && !daemon->osport)
1331 for (i = 0; i < RANDOM_SOCKS; i++)
1332 if (daemon->randomsocks[i].refcount != 0 &&
1333 FD_ISSET(daemon->randomsocks[i].fd, set))
1334 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001335
1336 for (listener = daemon->listeners; listener; listener = listener->next)
1337 {
Simon Kelley824af852008-02-12 20:43:05 +00001338 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001339 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001340
Simon Kelley832af0b2007-01-21 20:01:28 +00001341#ifdef HAVE_TFTP
1342 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001343 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001344#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001345
Simon Kelley824af852008-02-12 20:43:05 +00001346 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001347 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001348 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001349 struct irec *iface = NULL;
1350 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001351 union mysockaddr tcp_addr;
1352 socklen_t tcp_len = sizeof(union mysockaddr);
1353
1354 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001355
Simon Kelley46b06652013-02-04 21:47:59 +00001356 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001357 continue;
Simon Kelley22ce5502013-01-22 13:53:04 +00001358
Simon Kelley46b06652013-02-04 21:47:59 +00001359 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1360 {
1361 close(confd);
1362 continue;
1363 }
1364
Simon Kelley22ce5502013-01-22 13:53:04 +00001365 if (option_bool(OPT_NOWILD))
Simon Kelley52d4abf2012-03-21 21:39:48 +00001366 iface = listener->iface; /* May be NULL */
Simon Kelley22ce5502013-01-22 13:53:04 +00001367 else
1368 {
1369 int if_index;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001370 char intr_name[IF_NAMESIZE];
1371
Simon Kelley22ce5502013-01-22 13:53:04 +00001372 /* In full wildcard mode, need to refresh interface list.
1373 This happens automagically in CLEVERBIND */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001374 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001375 enumerate_interfaces(0);
Simon Kelleye25db1f2013-01-29 22:10:26 +00001376
1377 /* if we can find the arrival interface, check it's one that's allowed */
1378 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1379 indextoname(listener->tcpfd, if_index, intr_name))
Simon Kelley22ce5502013-01-22 13:53:04 +00001380 {
Simon Kelleye25db1f2013-01-29 22:10:26 +00001381 struct all_addr addr;
1382 addr.addr.addr4 = tcp_addr.in.sin_addr;
1383#ifdef HAVE_IPV6
1384 if (tcp_addr.sa.sa_family == AF_INET6)
1385 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
1386#endif
1387
Simon Kelley22ce5502013-01-22 13:53:04 +00001388 for (iface = daemon->interfaces; iface; iface = iface->next)
1389 if (iface->index == if_index)
1390 break;
1391
Simon Kelleye25db1f2013-01-29 22:10:26 +00001392 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
Simon Kelley22ce5502013-01-22 13:53:04 +00001393 client_ok = 0;
1394 }
1395
1396 if (option_bool(OPT_CLEVERBIND))
1397 iface = listener->iface; /* May be NULL */
1398 else
1399 {
Simon Kelleye25db1f2013-01-29 22:10:26 +00001400 /* Check for allowed interfaces when binding the wildcard address:
1401 we do this by looking for an interface with the same address as
1402 the local address of the TCP connection, then looking to see if that's
1403 an allowed interface. As a side effect, we get the netmask of the
Simon Kelley22ce5502013-01-22 13:53:04 +00001404 interface too, for localisation. */
1405
1406 for (iface = daemon->interfaces; iface; iface = iface->next)
1407 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1408 break;
1409
1410 if (!iface)
1411 client_ok = 0;
1412 }
1413 }
1414
1415 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001416 {
1417 shutdown(confd, SHUT_RDWR);
1418 close(confd);
1419 }
1420#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001421 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001422 {
1423 if (p != -1)
1424 {
1425 int i;
1426 for (i = 0; i < MAX_PROCS; i++)
1427 if (daemon->tcp_pids[i] == 0)
1428 {
1429 daemon->tcp_pids[i] = p;
1430 break;
1431 }
1432 }
1433 close(confd);
1434 }
1435#endif
1436 else
1437 {
1438 unsigned char *buff;
1439 struct server *s;
1440 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001441 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001442 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001443
1444 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001445 {
1446 netmask = iface->netmask;
1447 auth_dns = iface->dns_auth;
1448 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001449 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001450 {
1451 netmask.s_addr = 0;
1452 auth_dns = 0;
1453 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001454
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001455#ifndef NO_FORK
1456 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1457 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001458 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001459 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001460#endif
1461
Simon Kelley832af0b2007-01-21 20:01:28 +00001462 /* start with no upstream connections. */
1463 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001464 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001465
1466 /* The connected socket inherits non-blocking
1467 attribute from the listening socket.
1468 Reset that here. */
1469 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1470 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1471
Simon Kelley4f7b3042012-11-28 21:27:02 +00001472 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001473
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 shutdown(confd, SHUT_RDWR);
1475 close(confd);
1476
1477 if (buff)
1478 free(buff);
1479
1480 for (s = daemon->servers; s; s = s->next)
1481 if (s->tcpfd != -1)
1482 {
1483 shutdown(s->tcpfd, SHUT_RDWR);
1484 close(s->tcpfd);
1485 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001486#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001487 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001488 {
1489 flush_log();
1490 _exit(0);
1491 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001492#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001493 }
1494 }
1495 }
Simon Kelley3be34542004-09-11 19:12:13 +01001496}
1497
Simon Kelley7622fc02009-06-04 20:32:05 +01001498#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001499int make_icmp_sock(void)
1500{
Simon Kelley7cebd202006-05-06 14:13:33 +01001501 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001502 int zeroopt = 0;
1503
1504 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1505 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001506 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001507 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1508 {
1509 close(fd);
1510 fd = -1;
1511 }
1512 }
1513
1514 return fd;
1515}
1516
Simon Kelley5aabfc72007-08-29 11:24:47 +01001517int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001518{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001519 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001520
1521 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001522 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001523 better not use any resources our caller has in use...)
1524 but we remain deaf to signals or further DHCP packets. */
1525
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001526 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001527 struct sockaddr_in saddr;
1528 struct {
1529 struct ip ip;
1530 struct icmp icmp;
1531 } packet;
1532 unsigned short id = rand16();
1533 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001534 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001535 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001536
Simon Kelley824af852008-02-12 20:43:05 +00001537#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001538 if ((fd = make_icmp_sock()) == -1)
1539 return 0;
1540#else
1541 int opt = 2000;
1542 fd = daemon->dhcp_icmp_fd;
1543 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1544#endif
1545
Simon Kelley3be34542004-09-11 19:12:13 +01001546 saddr.sin_family = AF_INET;
1547 saddr.sin_port = 0;
1548 saddr.sin_addr = addr;
1549#ifdef HAVE_SOCKADDR_SA_LEN
1550 saddr.sin_len = sizeof(struct sockaddr_in);
1551#endif
1552
1553 memset(&packet.icmp, 0, sizeof(packet.icmp));
1554 packet.icmp.icmp_type = ICMP_ECHO;
1555 packet.icmp.icmp_id = id;
1556 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1557 j += ((u16 *)&packet.icmp)[i];
1558 while (j>>16)
1559 j = (j & 0xffff) + (j >> 16);
1560 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1561
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001562 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001563 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1564 retry_send());
1565
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001566 for (now = start = dnsmasq_time();
1567 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001568 {
1569 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001570 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001571 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001572 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001573 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001574
1575 tv.tv_usec = 250000;
1576 tv.tv_sec = 0;
1577
1578 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001579 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001580 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001581 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001582 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001583
1584#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001585 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001586 {
1587 FD_SET(daemon->icmp6fd, &rset);
1588 bump_maxfd(daemon->icmp6fd, &maxfd);
1589 }
1590#endif
1591
Simon Kelleyf2621c72007-04-29 19:47:21 +01001592 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1593 {
1594 FD_ZERO(&rset);
1595 FD_ZERO(&wset);
1596 }
1597
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001598 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001599
1600 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001601 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001602
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001603#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001604 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1605 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001606#endif
1607
Simon Kelley832af0b2007-01-21 20:01:28 +00001608#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001609 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001610#endif
1611
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001612 if (FD_ISSET(fd, &rset) &&
1613 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001614 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1615 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1616 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1617 packet.icmp.icmp_seq == 0 &&
1618 packet.icmp.icmp_id == id)
1619 {
1620 gotreply = 1;
1621 break;
1622 }
1623 }
1624
Simon Kelley824af852008-02-12 20:43:05 +00001625#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001626 close(fd);
1627#else
Simon Kelley3be34542004-09-11 19:12:13 +01001628 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001629 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1630#endif
1631
Simon Kelley3be34542004-09-11 19:12:13 +01001632 return gotreply;
1633}
Simon Kelley7622fc02009-06-04 20:32:05 +01001634#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001635
1636