blob: d8686a7a4f3c9834fc2d33b637519f70b239dbaa [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);
Giovanni Bajofa164d42012-04-22 14:31:43 +020079 if (option_bool(OPT_DNSSEC_VALIDATE))
80 if (daemon->doctors) exit(1); /* TODO */
Simon Kelley3be34542004-09-11 19:12:13 +010081 if (daemon->edns_pktsz < PACKETSZ)
Giovanni Bajofa164d42012-04-22 14:31:43 +020082 daemon->edns_pktsz = option_bool(OPT_DNSSEC_VALIDATE) ? EDNS_PKTSZ : PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +000083 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
84 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
85 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +010086
Simon Kelleyc72daea2012-01-05 21:33:27 +000087 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
88
Simon Kelley4f7b3042012-11-28 21:27:02 +000089
Simon Kelley7622fc02009-06-04 20:32:05 +010090#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +010091 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000092 {
Simon Kelley52b92f42012-01-22 16:05:15 +000093 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +010094 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000095 }
Simon Kelley7622fc02009-06-04 20:32:05 +010096#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000097
Simon Kelleya2761752012-01-18 16:07:21 +000098 /* Close any file descriptors we inherited apart from std{in|out|err}
99
100 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
101 otherwise file descriptors we create can end up being 0, 1, or 2
102 and then get accidentally closed later when we make 0, 1, and 2
103 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
104 but it's not guaranteed. By opening /dev/null three times, we
105 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 for (i = 0; i < max_fd; i++)
107 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
108 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000109 else
110 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100111
Simon Kelley801ca9a2012-03-06 19:30:17 +0000112#ifndef HAVE_LINUX_NETWORK
113# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000114 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100115 {
116 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000117 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100118 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000119# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100120
121 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100122 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100123 {
124 bind_fallback = 1;
125 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100126 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100127 }
Simon Kelley309331f2006-04-22 15:05:01 +0100128#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100129
Simon Kelley832af0b2007-01-21 20:01:28 +0000130#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100131 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100132 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000133#endif
134
Simon Kelley7de060b2011-08-26 17:24:52 +0100135#ifdef HAVE_CONNTRACK
136 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
137 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
138#else
139 if (option_bool(OPT_CONNTRACK))
140 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
141#endif
142
Simon Kelley824af852008-02-12 20:43:05 +0000143#ifdef HAVE_SOLARIS_NETWORK
144 if (daemon->max_logs != 0)
145 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
146#endif
147
Simon Kelley572b41e2011-02-18 18:11:18 +0000148#ifdef __ANDROID__
149 if (daemon->max_logs != 0)
150 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
151#endif
152
Simon Kelley4820dce2012-12-18 18:30:30 +0000153#ifndef HAVE_AUTH
154 if (daemon->authserver)
155 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
156#endif
157
Simon Kelley1a6bca82008-07-11 11:11:42 +0100158 rand_init();
159
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100160 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000161
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000162 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000163 if (daemon->authinterface && daemon->soa_sn == 0)
164#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000165 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000166#else
167 daemon->soa_sn = now;
168#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000169
Simon Kelley7622fc02009-06-04 20:32:05 +0100170#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000171 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley1f776932012-12-16 19:46:08 +0000172 {
173
174# ifdef HAVE_DHCP6
175 if (daemon->dhcp6)
176 {
177 daemon->doing_ra = option_bool(OPT_RA);
178
179 for (context = daemon->dhcp6; context; context = context->next)
180 {
181 if (context->flags & CONTEXT_DHCP)
182 daemon->doing_dhcp6 = 1;
Simon Kelleybb86e852012-12-17 22:00:53 +0000183 if (context->flags & CONTEXT_RA)
Simon Kelley1f776932012-12-16 19:46:08 +0000184 daemon->doing_ra = 1;
Simon Kelleybb86e852012-12-17 22:00:53 +0000185#ifndef HAVE_LINUX_NETWORK
186 if (context->flags & CONTEXT_TEMPLATE)
Simon Kelley9d299492012-12-18 21:48:15 +0000187 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000188#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000189 }
190 }
191# endif
192
Simon Kelley5aabfc72007-08-29 11:24:47 +0100193 /* Note that order matters here, we must call lease_init before
194 creating any file descriptors which shouldn't be leaked
Simon Kelley4cb1b322012-02-06 14:30:41 +0000195 to the lease-script init process. We need to call common_init
196 before lease_init to allocate buffers it uses.*/
Simon Kelley1f776932012-12-16 19:46:08 +0000197 if (daemon->dhcp || daemon->doing_dhcp6)
198 {
199 dhcp_common_init();
200 lease_init(now);
201 }
202
Simon Kelley52b92f42012-01-22 16:05:15 +0000203 if (daemon->dhcp)
204 dhcp_init();
Simon Kelley1f776932012-12-16 19:46:08 +0000205
Simon Kelley843c96b2012-02-27 17:42:38 +0000206# ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000207 if (daemon->doing_ra)
208 ra_init(now);
Simon Kelley843c96b2012-02-27 17:42:38 +0000209
Simon Kelley1f776932012-12-16 19:46:08 +0000210 if (daemon->doing_dhcp6)
211 dhcp6_init();
Simon Kelley843c96b2012-02-27 17:42:38 +0000212# endif
Simon Kelley1f776932012-12-16 19:46:08 +0000213 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000214
Simon Kelley7622fc02009-06-04 20:32:05 +0100215#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100216
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000217#ifdef HAVE_IPSET
218 if (daemon->ipsets)
219 ipset_init();
220#endif
221
Simon Kelley801ca9a2012-03-06 19:30:17 +0000222#ifdef HAVE_LINUX_NETWORK
Simon Kelley801ca9a2012-03-06 19:30:17 +0000223 netlink_init();
Simon Kelley8445f5d2012-12-17 21:54:08 +0000224
Simon Kelley54dd3932012-06-20 11:23:38 +0100225 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
226 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000227#endif
228
Simon Kelley115ac3e2013-05-20 11:28:32 +0100229 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100230 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000231
Simon Kelley54dd3932012-06-20 11:23:38 +0100232 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100233 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100234 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100235
236 if (!option_bool(OPT_CLEVERBIND))
237 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
238 if (if_tmp->name && !if_tmp->used)
239 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100240
241#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
242 /* after enumerate_interfaces() */
243 if (daemon->dhcp)
244 {
245 bindtodevice(daemon->dhcpfd);
246 if (daemon->enable_pxe)
247 bindtodevice(daemon->pxefd);
248 }
249#endif
250
251#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelleycfcad422013-05-17 11:32:03 +0100252 if (daemon->doing_dhcp6)
Simon Kelley9380ba72012-04-16 14:41:56 +0100253 bindtodevice(daemon->dhcp6fd);
254#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100255 }
Simon Kelley28866e92011-02-14 20:19:14 +0000256 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100257 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000258
259#ifdef HAVE_DHCP6
260 /* after enumerate_interfaces() */
261 if (daemon->doing_dhcp6 || daemon->doing_ra)
262 join_multicast(1);
263#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100264
Simon Kelley824af852008-02-12 20:43:05 +0000265 if (daemon->port != 0)
266 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100267
Simon Kelley28866e92011-02-14 20:19:14 +0000268 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100269#ifdef HAVE_DBUS
270 {
271 char *err;
272 daemon->dbus = NULL;
273 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100274 if ((err = dbus_init()))
275 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100276 }
277#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100278 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100279#endif
280
Simon Kelley824af852008-02-12 20:43:05 +0000281 if (daemon->port != 0)
282 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100283
Simon Kelleyc72daea2012-01-05 21:33:27 +0000284#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100285 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000286 if ((daemon->dhcp || daemon->dhcp6) &&
287 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000288 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100289 {
290 if ((ent_pw = getpwnam(daemon->scriptuser)))
291 {
292 script_uid = ent_pw->pw_uid;
293 script_gid = ent_pw->pw_gid;
294 }
295 else
296 baduser = daemon->scriptuser;
297 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100298#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000299
Simon Kelley1a6bca82008-07-11 11:11:42 +0100300 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
301 baduser = daemon->username;
302 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
303 baduser = daemon->groupname;
304
305 if (baduser)
306 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
307
308 /* implement group defaults, "dip" if available, or group associated with uid */
309 if (!daemon->group_set && !gp)
310 {
311 if (!(gp = getgrnam(CHGRP)) && ent_pw)
312 gp = getgrgid(ent_pw->pw_gid);
313
314 /* for error message */
315 if (gp)
316 daemon->groupname = gp->gr_name;
317 }
318
319#if defined(HAVE_LINUX_NETWORK)
320 /* determine capability API version here, while we can still
321 call safe_malloc */
322 if (ent_pw && ent_pw->pw_uid != 0)
323 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100324 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100325 hdr = safe_malloc(sizeof(*hdr));
326
Simon Kelley1a6bca82008-07-11 11:11:42 +0100327 /* find version supported by kernel */
328 memset(hdr, 0, sizeof(*hdr));
329 capget(hdr, NULL);
330
331 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
332 {
333 /* if unknown version, use largest supported version (3) */
334 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
335 hdr->version = LINUX_CAPABILITY_VERSION_3;
336 capsize = 2;
337 }
338
339 data = safe_malloc(sizeof(*data) * capsize);
340 memset(data, 0, sizeof(*data) * capsize);
341 }
342#endif
343
Simon Kelley5aabfc72007-08-29 11:24:47 +0100344 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100345 in a race-free manner and another to carry errors to daemon-invoking process */
346 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100347
348 piperead = pipefd[0];
349 pipewrite = pipefd[1];
350 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000351 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100352
353 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100354
Simon Kelley28866e92011-02-14 20:19:14 +0000355 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000356 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000357 /* The following code "daemonizes" the process.
358 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100359
Simon Kelley9e038942008-05-30 20:06:34 +0100360 if (chdir("/") != 0)
361 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
362
Simon Kelley16972692006-10-16 20:04:18 +0100363#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000364 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100365 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100366 pid_t pid;
367
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 /* pipe to carry errors back to original process.
369 When startup is complete we close this and the process terminates. */
370 safe_pipe(err_pipe, 0);
371
Simon Kelley7622fc02009-06-04 20:32:05 +0100372 if ((pid = fork()) == -1)
373 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000374 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100375
Simon Kelley5aabfc72007-08-29 11:24:47 +0100376 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100377 {
378 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000379 char *msg;
380
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381 /* close our copy of write-end */
382 close(err_pipe[1]);
383
384 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000385 if (read_event(err_pipe[0], &ev, &msg))
386 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100387
388 _exit(EC_GOOD);
389 }
390
391 close(err_pipe[0]);
392
393 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100394
395 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100396
397 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000398 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100399
400 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100401 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100402 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000403#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100404
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000405 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100406 if (daemon->runfile)
407 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100408 int fd, err = 0;
409
410 sprintf(daemon->namebuff, "%d\n", (int) getpid());
411
412 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
413 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
414 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
415 extent that an attacker running as the unprivileged user could replace the pidfile with a
416 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
417
418 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
419 ensuring that the open() fails should there be any existing file (because the unlink() failed,
420 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
421 attack can succeed.
422
423 Any compromise of the non-privileged user still theoretically allows the pid-file to be
424 replaced whilst dnsmasq is running. The worst that could allow is that the usual
425 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
426
427 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
428 failure to write the pid-file.
429 */
430
431 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100432
Simon Kelley79cfefd2012-09-02 13:29:51 +0100433 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 +0100434 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100435 /* only complain if started as root */
436 if (getuid() == 0)
437 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100438 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100439 else
440 {
441 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
442 err = 1;
443
444 while (!err && close(fd) == -1)
445 if (!retry_send())
446 err = 1;
447 }
448
449 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100450 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000451 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100452 _exit(0);
453 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000454 }
Simon Kelley16972692006-10-16 20:04:18 +0100455 }
456
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100457 log_err = log_start(ent_pw, err_pipe[1]);
458
Simon Kelley28866e92011-02-14 20:19:14 +0000459 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100460 {
461 /* open stdout etc to /dev/null */
462 int nullfd = open("/dev/null", O_RDWR);
463 dup2(nullfd, STDOUT_FILENO);
464 dup2(nullfd, STDERR_FILENO);
465 dup2(nullfd, STDIN_FILENO);
466 close(nullfd);
467 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100468
Simon Kelley1a6bca82008-07-11 11:11:42 +0100469 /* if we are to run scripts, we need to fork a helper before dropping root. */
470 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000471#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000472 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100473 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
474#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100475
Simon Kelley28866e92011-02-14 20:19:14 +0000476 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100477 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100478 int bad_capabilities = 0;
479 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100480
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481 /* remove all supplimentary groups */
482 if (gp &&
483 (setgroups(0, &dummy) == -1 ||
484 setgid(gp->gr_gid) == -1))
485 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000486 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100487 _exit(0);
488 }
489
Simon Kelley7cebd202006-05-06 14:13:33 +0100490 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100491 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100492#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100493 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100494 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100495 ports because of DAD, or we're doing it dynamically,
496 we need CAP_NET_BIND_SERVICE too. */
497 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100498 data->effective = data->permitted = data->inheritable =
499 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
500 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
501 else
502 data->effective = data->permitted = data->inheritable =
503 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100504
Simon Kelley16972692006-10-16 20:04:18 +0100505 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000506 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100507 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100508
Simon Kelley7622fc02009-06-04 20:32:05 +0100509#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000510 /* http://developers.sun.com/solaris/articles/program_privileges.html */
511 priv_set_t *priv_set;
512
513 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
514 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
515 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
516 bad_capabilities = errno;
517
518 if (priv_set && bad_capabilities == 0)
519 {
520 priv_inverse(priv_set);
521
522 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
523 bad_capabilities = errno;
524 }
525
526 if (priv_set)
527 priv_freeset(priv_set);
528
Simon Kelley824af852008-02-12 20:43:05 +0000529#endif
530
Simon Kelley1a6bca82008-07-11 11:11:42 +0100531 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100532 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000533 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100534 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100535 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536
537 /* finally drop root */
538 if (setuid(ent_pw->pw_uid) == -1)
539 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000540 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100541 _exit(0);
542 }
543
544#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100545 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100546 data->effective = data->permitted =
547 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
548 else
549 data->effective = data->permitted =
550 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100551 data->inheritable = 0;
552
553 /* lose the setuid and setgid capbilities */
554 if (capset(hdr, data) == -1)
555 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000556 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100557 _exit(0);
558 }
559#endif
560
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000561 }
Simon Kelley849a8352006-06-09 21:02:31 +0100562 }
Simon Kelley16972692006-10-16 20:04:18 +0100563
Simon Kelley16972692006-10-16 20:04:18 +0100564#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000565 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000566 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100567#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100568
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100569#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100570 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100571 {
572 DIR *dir;
573 struct tftp_prefix *p;
574
575 if (daemon->tftp_prefix)
576 {
577 if (!((dir = opendir(daemon->tftp_prefix))))
578 {
579 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
580 _exit(0);
581 }
582 closedir(dir);
583 }
584
585 for (p = daemon->if_prefix; p; p = p->next)
586 {
587 if (!((dir = opendir(p->prefix))))
588 {
589 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
590 _exit(0);
591 }
592 closedir(dir);
593 }
594 }
595#endif
596
Simon Kelley824af852008-02-12 20:43:05 +0000597 if (daemon->port == 0)
598 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
599 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100600 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100602 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100603
Simon Kelleyf2621c72007-04-29 19:47:21 +0100604 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100605
Simon Kelley3d8df262005-08-29 12:19:27 +0100606#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000607 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100608 {
609 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100610 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100611 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100612 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100613 }
614#endif
615
Simon Kelley1a6bca82008-07-11 11:11:42 +0100616 if (log_err != 0)
617 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
618 daemon->log_file, strerror(log_err));
619
Simon Kelleyde379512004-06-22 20:23:33 +0100620 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100621 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100622
Simon Kelley28866e92011-02-14 20:19:14 +0000623 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000624 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
625 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100626 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100627
Simon Kelley28866e92011-02-14 20:19:14 +0000628 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100629 {
630 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100631 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100632 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000633 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100634 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100635 }
636
Simon Kelleyf2621c72007-04-29 19:47:21 +0100637 if (daemon->max_logs != 0)
638 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000639
Simon Kelleyf2621c72007-04-29 19:47:21 +0100640
Simon Kelley7622fc02009-06-04 20:32:05 +0100641#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000642 for (context = daemon->dhcp; context; context = context->next)
643 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100644
Simon Kelley1f776932012-12-16 19:46:08 +0000645# ifdef HAVE_DHCP6
646 for (context = daemon->dhcp6; context; context = context->next)
647 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000648
Simon Kelley1f776932012-12-16 19:46:08 +0000649 if (daemon->doing_dhcp6 || daemon->doing_ra)
650 dhcp_construct_contexts(now);
651
652 if (option_bool(OPT_RA))
653 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
654# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000655
Simon Kelley8445f5d2012-12-17 21:54:08 +0000656 /* after dhcp_contruct_contexts */
657 if (daemon->dhcp || daemon->doing_dhcp6)
658 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000659#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000660
Simon Kelley832af0b2007-01-21 20:01:28 +0000661#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100662 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000663 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000664#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100665 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000666 max_fd = FD_SETSIZE;
667#endif
668
Simon Kelley7622fc02009-06-04 20:32:05 +0100669 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100670 daemon->tftp_prefix ? _("root is ") : _("enabled"),
671 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000672 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100673
Simon Kelley832af0b2007-01-21 20:01:28 +0000674 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100675 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000676 a single file will be sent to may clients (the file only needs
677 one fd). */
678
679 max_fd -= 30; /* use other than TFTP */
680
681 if (max_fd < 0)
682 max_fd = 5;
683 else if (max_fd < 100)
684 max_fd = max_fd/2;
685 else
686 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000687
688 /* if we have to use a limited range of ports,
689 that will limit the number of transfers */
690 if (daemon->start_tftp_port != 0 &&
691 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
692 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000693
694 if (daemon->tftp_max > max_fd)
695 {
696 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100697 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100698 _("restricting maximum simultaneous TFTP transfers to %d"),
699 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000700 }
701 }
702#endif
703
Simon Kelley1a6bca82008-07-11 11:11:42 +0100704 /* finished start-up - release original process */
705 if (err_pipe[1] != -1)
706 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000707
Simon Kelley824af852008-02-12 20:43:05 +0000708 if (daemon->port != 0)
709 check_servers();
710
Simon Kelley7cebd202006-05-06 14:13:33 +0100711 pid = getpid();
712
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100713 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000714 {
Simon Kelley16972692006-10-16 20:04:18 +0100715 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100716 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100717 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000718
719 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100720 FD_ZERO(&wset);
721 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000722
Simon Kelley16972692006-10-16 20:04:18 +0100723 /* if we are out of resources, find how long we have to wait
724 for some to come free, we'll loop around then and restart
725 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100726 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100727 {
728 t.tv_usec = 0;
729 tp = &t;
730 }
731
Simon Kelley832af0b2007-01-21 20:01:28 +0000732 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
733 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000734 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000735 {
Simon Kelley16972692006-10-16 20:04:18 +0100736 t.tv_sec = 0;
737 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100738 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000739 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100740 /* Wake every second whilst waiting for DAD to complete */
741 else if (is_dad_listeners())
742 {
743 t.tv_sec = 1;
744 t.tv_usec = 0;
745 tp = &t;
746 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100747
Simon Kelley832af0b2007-01-21 20:01:28 +0000748#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100749 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100750#endif
751
Simon Kelley7622fc02009-06-04 20:32:05 +0100752#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100753 if (daemon->dhcp)
754 {
755 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100756 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000757 if (daemon->pxefd != -1)
758 {
759 FD_SET(daemon->pxefd, &rset);
760 bump_maxfd(daemon->pxefd, &maxfd);
761 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100762 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100763#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100764
Simon Kelley52b92f42012-01-22 16:05:15 +0000765#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000766 if (daemon->doing_dhcp6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000767 {
768 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000769 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000770 }
771
Simon Kelley1f776932012-12-16 19:46:08 +0000772 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000773 {
774 FD_SET(daemon->icmp6fd, &rset);
775 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000776 }
777#endif
778
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100779#ifdef HAVE_LINUX_NETWORK
780 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100781 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100782#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100783
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100784 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100785 bump_maxfd(piperead, &maxfd);
786
Simon Kelley7622fc02009-06-04 20:32:05 +0100787#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100788# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100789 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100790
Simon Kelleya9530962012-03-20 22:07:35 +0000791# ifdef HAVE_TFTP
792 while (helper_buf_empty() && do_tftp_script_run());
793# endif
794
Simon Kelley16972692006-10-16 20:04:18 +0100795 if (!helper_buf_empty())
796 {
797 FD_SET(daemon->helperfd, &wset);
798 bump_maxfd(daemon->helperfd, &maxfd);
799 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100800# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100801 /* need this for other side-effects */
802 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000803
804# ifdef HAVE_TFTP
805 while (do_tftp_script_run());
806# endif
807
Simon Kelley7622fc02009-06-04 20:32:05 +0100808# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100809#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100810
Simon Kelleyf2621c72007-04-29 19:47:21 +0100811 /* must do this just before select(), when we know no
812 more calls to my_syslog() can occur */
813 set_log_writer(&wset, &maxfd);
814
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100815 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
816 {
817 /* otherwise undefined after error */
818 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
819 }
820
821 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000822
Simon Kelleyf2621c72007-04-29 19:47:21 +0100823 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100824
825 /* prime. */
826 enumerate_interfaces(1);
827
Simon Kelley74c95c22011-10-19 09:33:39 +0100828 /* Check the interfaces to see if any have exited DAD state
829 and if so, bind the address. */
830 if (is_dad_listeners())
831 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100832 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100833 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
834 create_bound_listeners(0);
835 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100836
Simon Kelleyc52e1892010-06-07 22:01:39 +0100837#ifdef HAVE_LINUX_NETWORK
838 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000839 netlink_multicast(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100840#endif
841
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100843 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000844 if (daemon->last_resolv == 0 ||
845 difftime(now, daemon->last_resolv) > 1.0 ||
846 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000847 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100848 /* poll_resolv doesn't need to reload first time through, since
849 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100850
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100851 poll_resolv(0, daemon->last_resolv != 0, now);
852 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000853 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100854
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100855 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100856 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100857
Simon Kelley3d8df262005-08-29 12:19:27 +0100858#ifdef HAVE_DBUS
859 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000860 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100861 {
862 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100863 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100864 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100865 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100866 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100867 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100868 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100869#endif
Simon Kelley824af852008-02-12 20:43:05 +0000870
Simon Kelley5aabfc72007-08-29 11:24:47 +0100871 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000872
873#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100874 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000875#endif
876
Simon Kelley7622fc02009-06-04 20:32:05 +0100877#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000878 if (daemon->dhcp)
879 {
880 if (FD_ISSET(daemon->dhcpfd, &rset))
881 dhcp_packet(now, 0);
882 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
883 dhcp_packet(now, 1);
884 }
Simon Kelley16972692006-10-16 20:04:18 +0100885
Simon Kelley52b92f42012-01-22 16:05:15 +0000886#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000887 if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100888 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000889
Simon Kelley1f776932012-12-16 19:46:08 +0000890 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
891 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000892#endif
893
Simon Kelley1f15b812009-10-13 17:49:32 +0100894# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100895 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100896 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100897# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100898#endif
899
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000900 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000901}
902
Simon Kelley3be34542004-09-11 19:12:13 +0100903static void sig_handler(int sig)
904{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100905 if (pid == 0)
906 {
Simon Kelley16972692006-10-16 20:04:18 +0100907 /* ignore anything other than TERM during startup
908 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100909 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100910 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100911 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100912 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100913 {
Simon Kelley16972692006-10-16 20:04:18 +0100914 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100915 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100916 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100917 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100918 else
919 {
920 /* master process */
921 int event, errsave = errno;
922
923 if (sig == SIGHUP)
924 event = EVENT_RELOAD;
925 else if (sig == SIGCHLD)
926 event = EVENT_CHILD;
927 else if (sig == SIGALRM)
928 event = EVENT_ALARM;
929 else if (sig == SIGTERM)
930 event = EVENT_TERM;
931 else if (sig == SIGUSR1)
932 event = EVENT_DUMP;
933 else if (sig == SIGUSR2)
934 event = EVENT_REOPEN;
935 else
936 return;
937
Simon Kelleyc72daea2012-01-05 21:33:27 +0000938 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100939 errno = errsave;
940 }
Simon Kelley3be34542004-09-11 19:12:13 +0100941}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000942
Simon Kelley353ae4d2012-03-19 20:07:51 +0000943/* now == 0 -> queue immediate callback */
944void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000945{
Simon Kelley884a6df2012-03-20 16:20:22 +0000946 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000947 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000948 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
949 if ((now == 0 || difftime(event, now) <= 0.0))
950 send_event(pipewrite, EVENT_ALARM, 0, NULL);
951 else
952 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000953 }
Simon Kelley741c2952012-02-25 13:09:18 +0000954}
955
Simon Kelleyc72daea2012-01-05 21:33:27 +0000956void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100957{
958 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000959 struct iovec iov[2];
960
Simon Kelley5aabfc72007-08-29 11:24:47 +0100961 ev.event = event;
962 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000963 ev.msg_sz = msg ? strlen(msg) : 0;
964
965 iov[0].iov_base = &ev;
966 iov[0].iov_len = sizeof(ev);
967 iov[1].iov_base = msg;
968 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100969
970 /* error pipe, debug mode. */
971 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000972 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100973 else
974 /* pipe is non-blocking and struct event_desc is smaller than
975 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000976 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100977}
Simon Kelley3d8df262005-08-29 12:19:27 +0100978
Simon Kelleyc72daea2012-01-05 21:33:27 +0000979/* NOTE: the memory used to return msg is leaked: use msgs in events only
980 to describe fatal errors. */
981static int read_event(int fd, struct event_desc *evp, char **msg)
982{
983 char *buf;
984
985 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
986 return 0;
987
988 *msg = NULL;
989
990 if (evp->msg_sz != 0 &&
991 (buf = malloc(evp->msg_sz + 1)) &&
992 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
993 {
994 buf[evp->msg_sz] = 0;
995 *msg = buf;
996 }
997
998 return 1;
999}
1000
1001static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001002{
1003 errno = ev->data;
1004
1005 switch (ev->event)
1006 {
1007 case EVENT_DIE:
1008 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001009
1010 case EVENT_FORK_ERR:
1011 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001012
1013 case EVENT_PIPE_ERR:
1014 die(_("failed to create helper: %s"), NULL, EC_MISC);
1015
1016 case EVENT_CAP_ERR:
1017 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1018
1019 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001020 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001021
1022 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001023 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001024
1025 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001026 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001027
1028 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001029 die(_("cannot open log %s: %s"), msg, EC_FILE);
1030
1031 case EVENT_LUA_ERR:
1032 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001033
1034 case EVENT_TFTP_ERR:
1035 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001036 }
1037}
1038
Simon Kelley5aabfc72007-08-29 11:24:47 +01001039static void async_event(int pipe, time_t now)
1040{
1041 pid_t p;
1042 struct event_desc ev;
1043 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001044 char *msg;
1045
1046 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1047 to describe fatal errors. */
1048
1049 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001050 switch (ev.event)
1051 {
1052 case EVENT_RELOAD:
1053 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001054 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001055 {
1056 reload_servers(daemon->resolv_files->name);
1057 check_servers();
1058 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001059#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001060 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001061#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001062 break;
1063
1064 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001065 if (daemon->port != 0)
1066 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001067 break;
1068
1069 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001070#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001071 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001072 {
1073 lease_prune(NULL, now);
1074 lease_update_file(now);
1075 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001076#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001077 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001078 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1079 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001080#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001081#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001082 break;
1083
1084 case EVENT_CHILD:
1085 /* See Stevens 5.10 */
1086 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1087 if (p == -1)
1088 {
1089 if (errno != EINTR)
1090 break;
1091 }
1092 else
1093 for (i = 0 ; i < MAX_PROCS; i++)
1094 if (daemon->tcp_pids[i] == p)
1095 daemon->tcp_pids[i] = 0;
1096 break;
1097
1098 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001099 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001100 break;
1101
1102 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001103 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001104 break;
1105
1106 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001107 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1108 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001109 break;
1110
Simon Kelley1a6bca82008-07-11 11:11:42 +01001111 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001112 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001113 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001114 case EVENT_LUA_ERR:
1115 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001116 break;
1117
Simon Kelley5aabfc72007-08-29 11:24:47 +01001118 case EVENT_REOPEN:
1119 /* Note: this may leave TCP-handling processes with the old file still open.
1120 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1121 we leave them logging to the old file. */
1122 if (daemon->log_file != NULL)
1123 log_reopen(daemon->log_file);
1124 break;
1125
1126 case EVENT_TERM:
1127 /* Knock all our children on the head. */
1128 for (i = 0; i < MAX_PROCS; i++)
1129 if (daemon->tcp_pids[i] != 0)
1130 kill(daemon->tcp_pids[i], SIGALRM);
1131
Simon Kelleyc72daea2012-01-05 21:33:27 +00001132#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001133 /* handle pending lease transitions */
1134 if (daemon->helperfd != -1)
1135 {
1136 /* block in writes until all done */
1137 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1138 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1139 do {
1140 helper_write();
1141 } while (!helper_buf_empty() || do_script_run(now));
1142 close(daemon->helperfd);
1143 }
1144#endif
1145
1146 if (daemon->lease_stream)
1147 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001148
1149 if (daemon->runfile)
1150 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001151
1152 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1153 flush_log();
1154 exit(EC_GOOD);
1155 }
1156}
1157
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001158void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001159{
1160 struct resolvc *res, *latest;
1161 struct stat statbuf;
1162 time_t last_change = 0;
1163 /* There may be more than one possible file.
1164 Go through and find the one which changed _last_.
1165 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001166
Simon Kelley28866e92011-02-14 20:19:14 +00001167 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001168 return;
1169
Simon Kelley5aabfc72007-08-29 11:24:47 +01001170 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1171 if (stat(res->name, &statbuf) == -1)
1172 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001173 if (force)
1174 {
1175 res->mtime = 0;
1176 continue;
1177 }
1178
Simon Kelley5aabfc72007-08-29 11:24:47 +01001179 if (!res->logged)
1180 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1181 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001182
1183 if (res->mtime != 0)
1184 {
1185 /* existing file evaporated, force selection of the latest
1186 file even if its mtime hasn't changed since we last looked */
1187 poll_resolv(1, do_reload, now);
1188 return;
1189 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001190 }
1191 else
1192 {
1193 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001194 if (force || (statbuf.st_mtime != res->mtime))
1195 {
1196 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001197 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1198 {
1199 last_change = statbuf.st_mtime;
1200 latest = res;
1201 }
1202 }
1203 }
1204
1205 if (latest)
1206 {
1207 static int warned = 0;
1208 if (reload_servers(latest->name))
1209 {
1210 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1211 warned = 0;
1212 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001213 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001214 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001215 }
1216 else
1217 {
1218 latest->mtime = 0;
1219 if (!warned)
1220 {
1221 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1222 warned = 1;
1223 }
1224 }
1225 }
1226}
1227
1228void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001229{
Simon Kelley824af852008-02-12 20:43:05 +00001230 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001231 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001232
Simon Kelley7622fc02009-06-04 20:32:05 +01001233#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001234 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001235 {
Simon Kelley28866e92011-02-14 20:19:14 +00001236 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001237 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001238 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001239 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001240 lease_update_from_configs();
1241 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001242 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001243 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001244#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001245 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001246 /* Not doing DHCP, so no lease system, manage
1247 alarms for ra only */
1248 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001249#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001250#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001251}
1252
Simon Kelley5aabfc72007-08-29 11:24:47 +01001253static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001254{
1255 struct serverfd *serverfdp;
1256 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001257 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001258
1259#ifdef HAVE_TFTP
1260 int tftp = 0;
1261 struct tftp_transfer *transfer;
1262 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1263 {
1264 tftp++;
1265 FD_SET(transfer->sockfd, set);
1266 bump_maxfd(transfer->sockfd, maxfdp);
1267 }
1268#endif
1269
Simon Kelley16972692006-10-16 20:04:18 +01001270 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001271 if (daemon->port != 0)
1272 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001273
Simon Kelley3be34542004-09-11 19:12:13 +01001274 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1275 {
1276 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001277 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001278 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001279
1280 if (daemon->port != 0 && !daemon->osport)
1281 for (i = 0; i < RANDOM_SOCKS; i++)
1282 if (daemon->randomsocks[i].refcount != 0)
1283 {
1284 FD_SET(daemon->randomsocks[i].fd, set);
1285 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1286 }
1287
Simon Kelley3be34542004-09-11 19:12:13 +01001288 for (listener = daemon->listeners; listener; listener = listener->next)
1289 {
Simon Kelley16972692006-10-16 20:04:18 +01001290 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001291 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001292 {
1293 FD_SET(listener->fd, set);
1294 bump_maxfd(listener->fd, maxfdp);
1295 }
1296
1297 /* death of a child goes through the select loop, so
1298 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001299 if (listener->tcpfd != -1)
1300 for (i = 0; i < MAX_PROCS; i++)
1301 if (daemon->tcp_pids[i] == 0)
1302 {
1303 FD_SET(listener->tcpfd, set);
1304 bump_maxfd(listener->tcpfd, maxfdp);
1305 break;
1306 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001307
Simon Kelley832af0b2007-01-21 20:01:28 +00001308#ifdef HAVE_TFTP
1309 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1310 {
1311 FD_SET(listener->tftpfd, set);
1312 bump_maxfd(listener->tftpfd, maxfdp);
1313 }
1314#endif
1315
1316 }
1317
Simon Kelley16972692006-10-16 20:04:18 +01001318 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001319}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001320
Simon Kelley5aabfc72007-08-29 11:24:47 +01001321static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001322{
1323 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001324 struct listener *listener;
1325 int i;
1326
Simon Kelley832af0b2007-01-21 20:01:28 +00001327 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1328 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001329 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1330
1331 if (daemon->port != 0 && !daemon->osport)
1332 for (i = 0; i < RANDOM_SOCKS; i++)
1333 if (daemon->randomsocks[i].refcount != 0 &&
1334 FD_ISSET(daemon->randomsocks[i].fd, set))
1335 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001336
1337 for (listener = daemon->listeners; listener; listener = listener->next)
1338 {
Simon Kelley824af852008-02-12 20:43:05 +00001339 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001340 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001341
Simon Kelley832af0b2007-01-21 20:01:28 +00001342#ifdef HAVE_TFTP
1343 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001344 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001345#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001346
Simon Kelley824af852008-02-12 20:43:05 +00001347 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001348 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001349 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001350 struct irec *iface = NULL;
1351 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001352 union mysockaddr tcp_addr;
1353 socklen_t tcp_len = sizeof(union mysockaddr);
1354
1355 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001356
Simon Kelley46b06652013-02-04 21:47:59 +00001357 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001358 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001359
Simon Kelley46b06652013-02-04 21:47:59 +00001360 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1361 {
1362 close(confd);
1363 continue;
1364 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001365
1366 /* Make sure that the interface list is up-to-date.
1367
1368 We do this here as we may need the results below, and
1369 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001370
Simon Kelley76dd75d2013-05-23 10:04:25 +01001371 Multiple calls to enumerate_interfaces() per select loop are
1372 inhibited, so calls to it in the child process (which doesn't select())
1373 have no effect. This avoids two processes reading from the same
1374 netlink fd and screwing the pooch entirely.
1375 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001376
Simon Kelley76dd75d2013-05-23 10:04:25 +01001377 enumerate_interfaces(0);
1378
1379 if (option_bool(OPT_NOWILD))
1380 iface = listener->iface; /* May be NULL */
1381 else
1382 {
1383 int if_index;
1384 char intr_name[IF_NAMESIZE];
1385
1386 /* if we can find the arrival interface, check it's one that's allowed */
1387 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1388 indextoname(listener->tcpfd, if_index, intr_name))
1389 {
1390 struct all_addr addr;
1391 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001392#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001393 if (tcp_addr.sa.sa_family == AF_INET6)
1394 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001395#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001396
1397 for (iface = daemon->interfaces; iface; iface = iface->next)
1398 if (iface->index == if_index)
1399 break;
1400
1401 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1402 client_ok = 0;
1403 }
1404
1405 if (option_bool(OPT_CLEVERBIND))
1406 iface = listener->iface; /* May be NULL */
1407 else
1408 {
1409 /* Check for allowed interfaces when binding the wildcard address:
1410 we do this by looking for an interface with the same address as
1411 the local address of the TCP connection, then looking to see if that's
1412 an allowed interface. As a side effect, we get the netmask of the
1413 interface too, for localisation. */
1414
1415 for (iface = daemon->interfaces; iface; iface = iface->next)
1416 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1417 break;
1418
1419 if (!iface)
1420 client_ok = 0;
1421 }
1422 }
1423
Simon Kelley22ce5502013-01-22 13:53:04 +00001424 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001425 {
1426 shutdown(confd, SHUT_RDWR);
1427 close(confd);
1428 }
1429#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001430 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001431 {
1432 if (p != -1)
1433 {
1434 int i;
1435 for (i = 0; i < MAX_PROCS; i++)
1436 if (daemon->tcp_pids[i] == 0)
1437 {
1438 daemon->tcp_pids[i] = p;
1439 break;
1440 }
1441 }
1442 close(confd);
1443 }
1444#endif
1445 else
1446 {
1447 unsigned char *buff;
1448 struct server *s;
1449 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001450 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001451 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001452
1453 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001454 {
1455 netmask = iface->netmask;
1456 auth_dns = iface->dns_auth;
1457 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001458 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001459 {
1460 netmask.s_addr = 0;
1461 auth_dns = 0;
1462 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001463
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001464#ifndef NO_FORK
1465 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1466 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001467 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001468 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001469#endif
1470
Simon Kelley832af0b2007-01-21 20:01:28 +00001471 /* start with no upstream connections. */
1472 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001473 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001474
1475 /* The connected socket inherits non-blocking
1476 attribute from the listening socket.
1477 Reset that here. */
1478 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1479 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1480
Simon Kelley4f7b3042012-11-28 21:27:02 +00001481 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001482
Simon Kelley832af0b2007-01-21 20:01:28 +00001483 shutdown(confd, SHUT_RDWR);
1484 close(confd);
1485
1486 if (buff)
1487 free(buff);
1488
1489 for (s = daemon->servers; s; s = s->next)
1490 if (s->tcpfd != -1)
1491 {
1492 shutdown(s->tcpfd, SHUT_RDWR);
1493 close(s->tcpfd);
1494 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001495#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001496 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001497 {
1498 flush_log();
1499 _exit(0);
1500 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001501#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001502 }
1503 }
1504 }
Simon Kelley3be34542004-09-11 19:12:13 +01001505}
1506
Simon Kelley7622fc02009-06-04 20:32:05 +01001507#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001508int make_icmp_sock(void)
1509{
Simon Kelley7cebd202006-05-06 14:13:33 +01001510 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001511 int zeroopt = 0;
1512
1513 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1514 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001515 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001516 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1517 {
1518 close(fd);
1519 fd = -1;
1520 }
1521 }
1522
1523 return fd;
1524}
1525
Simon Kelley5aabfc72007-08-29 11:24:47 +01001526int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001527{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001528 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001529
1530 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001531 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001532 better not use any resources our caller has in use...)
1533 but we remain deaf to signals or further DHCP packets. */
1534
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001535 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001536 struct sockaddr_in saddr;
1537 struct {
1538 struct ip ip;
1539 struct icmp icmp;
1540 } packet;
1541 unsigned short id = rand16();
1542 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001543 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001544 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001545
Simon Kelley824af852008-02-12 20:43:05 +00001546#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001547 if ((fd = make_icmp_sock()) == -1)
1548 return 0;
1549#else
1550 int opt = 2000;
1551 fd = daemon->dhcp_icmp_fd;
1552 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1553#endif
1554
Simon Kelley3be34542004-09-11 19:12:13 +01001555 saddr.sin_family = AF_INET;
1556 saddr.sin_port = 0;
1557 saddr.sin_addr = addr;
1558#ifdef HAVE_SOCKADDR_SA_LEN
1559 saddr.sin_len = sizeof(struct sockaddr_in);
1560#endif
1561
1562 memset(&packet.icmp, 0, sizeof(packet.icmp));
1563 packet.icmp.icmp_type = ICMP_ECHO;
1564 packet.icmp.icmp_id = id;
1565 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1566 j += ((u16 *)&packet.icmp)[i];
1567 while (j>>16)
1568 j = (j & 0xffff) + (j >> 16);
1569 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1570
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001571 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001572 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1573 retry_send());
1574
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001575 for (now = start = dnsmasq_time();
1576 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001577 {
1578 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001579 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001580 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001581 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001582 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001583
1584 tv.tv_usec = 250000;
1585 tv.tv_sec = 0;
1586
1587 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001588 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001589 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001590 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001591 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001592
1593#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001594 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001595 {
1596 FD_SET(daemon->icmp6fd, &rset);
1597 bump_maxfd(daemon->icmp6fd, &maxfd);
1598 }
1599#endif
1600
Simon Kelleyf2621c72007-04-29 19:47:21 +01001601 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1602 {
1603 FD_ZERO(&rset);
1604 FD_ZERO(&wset);
1605 }
1606
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001607 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001608
1609 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001610 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001611
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001612#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001613 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1614 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001615#endif
1616
Simon Kelley832af0b2007-01-21 20:01:28 +00001617#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001618 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001619#endif
1620
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001621 if (FD_ISSET(fd, &rset) &&
1622 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001623 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1624 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1625 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1626 packet.icmp.icmp_seq == 0 &&
1627 packet.icmp.icmp_id == id)
1628 {
1629 gotreply = 1;
1630 break;
1631 }
1632 }
1633
Simon Kelley824af852008-02-12 20:43:05 +00001634#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001635 close(fd);
1636#else
Simon Kelley3be34542004-09-11 19:12:13 +01001637 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001638 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1639#endif
1640
Simon Kelley3be34542004-09-11 19:12:13 +01001641 return gotreply;
1642}
Simon Kelley7622fc02009-06-04 20:32:05 +01001643#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001644
1645