blob: 83d77d8d7ed38ab3ab0c84cd1cebf49186ee9150 [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;
Simon Kelley3b3f4412013-10-11 16:33:28 +010053 char *bound_device = NULL;
54 int did_bind = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010055#endif
Vladislav Grishenko408c3682013-09-24 16:18:49 +010056#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
Simon Kelley1f776932012-12-16 19:46:08 +000057 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +010058 struct dhcp_relay *relay;
Vladislav Grishenko408c3682013-09-24 16:18:49 +010059#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010060
Simon Kelley824af852008-02-12 20:43:05 +000061#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000062 setlocale(LC_ALL, "");
63 bindtextdomain("dnsmasq", LOCALEDIR);
64 textdomain("dnsmasq");
65#endif
66
Simon Kelley9e4abcb2004-01-22 19:47:41 +000067 sigact.sa_handler = sig_handler;
68 sigact.sa_flags = 0;
69 sigemptyset(&sigact.sa_mask);
70 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010071 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000072 sigaction(SIGHUP, &sigact, NULL);
73 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000074 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010075 sigaction(SIGCHLD, &sigact, NULL);
76
77 /* ignore SIGPIPE */
78 sigact.sa_handler = SIG_IGN;
79 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000080
Simon Kelley5aabfc72007-08-29 11:24:47 +010081 umask(022); /* known umask, create leases and pid files as 0644 */
82
83 read_opts(argc, argv, compile_opts);
84
Simon Kelley3be34542004-09-11 19:12:13 +010085 if (daemon->edns_pktsz < PACKETSZ)
86 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +000087 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
88 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
89 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +010090
Simon Kelleyc72daea2012-01-05 21:33:27 +000091 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
92
Simon Kelley4f7b3042012-11-28 21:27:02 +000093
Simon Kelley7622fc02009-06-04 20:32:05 +010094#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +010095 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000096 {
Simon Kelley52b92f42012-01-22 16:05:15 +000097 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +010098 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000099 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100100#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000101
Simon Kelleya2761752012-01-18 16:07:21 +0000102 /* Close any file descriptors we inherited apart from std{in|out|err}
103
104 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
105 otherwise file descriptors we create can end up being 0, 1, or 2
106 and then get accidentally closed later when we make 0, 1, and 2
107 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
108 but it's not guaranteed. By opening /dev/null three times, we
109 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110 for (i = 0; i < max_fd; i++)
111 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
112 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000113 else
114 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100115
Simon Kelley801ca9a2012-03-06 19:30:17 +0000116#ifndef HAVE_LINUX_NETWORK
117# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000118 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100119 {
120 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000121 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100122 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000123# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100124
125 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100126 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100127 {
128 bind_fallback = 1;
129 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100130 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100131 }
Simon Kelley309331f2006-04-22 15:05:01 +0100132#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100133
Simon Kelley832af0b2007-01-21 20:01:28 +0000134#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100135 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100136 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000137#endif
138
Simon Kelley7de060b2011-08-26 17:24:52 +0100139#ifdef HAVE_CONNTRACK
140 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
141 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
142#else
143 if (option_bool(OPT_CONNTRACK))
144 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
145#endif
146
Simon Kelley824af852008-02-12 20:43:05 +0000147#ifdef HAVE_SOLARIS_NETWORK
148 if (daemon->max_logs != 0)
149 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
150#endif
151
Simon Kelley572b41e2011-02-18 18:11:18 +0000152#ifdef __ANDROID__
153 if (daemon->max_logs != 0)
154 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
155#endif
156
Simon Kelley4820dce2012-12-18 18:30:30 +0000157#ifndef HAVE_AUTH
158 if (daemon->authserver)
159 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
160#endif
161
Simon Kelley1a6bca82008-07-11 11:11:42 +0100162 rand_init();
163
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100164 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000165
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000166 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000167 if (daemon->authinterface && daemon->soa_sn == 0)
168#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000169 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000170#else
171 daemon->soa_sn = now;
172#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173
Simon Kelleyff7eea22013-09-04 18:01:38 +0100174#ifdef HAVE_DHCP6
175 if (daemon->dhcp6)
176 {
177 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000178
Simon Kelleyff7eea22013-09-04 18:01:38 +0100179 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000180 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100181 if (context->flags & CONTEXT_DHCP)
182 daemon->doing_dhcp6 = 1;
183 if (context->flags & CONTEXT_RA)
184 daemon->doing_ra = 1;
Simon Kelleybb86e852012-12-17 22:00:53 +0000185#ifndef HAVE_LINUX_NETWORK
Simon Kelleyff7eea22013-09-04 18:01:38 +0100186 if (context->flags & CONTEXT_TEMPLATE)
187 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 }
Simon Kelley1f776932012-12-16 19:46:08 +0000190 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100191#endif
192
193#ifdef HAVE_DHCP
194 /* Note that order matters here, we must call lease_init before
195 creating any file descriptors which shouldn't be leaked
196 to the lease-script init process. We need to call common_init
197 before lease_init to allocate buffers it uses.*/
198 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
199 {
200 dhcp_common_init();
201 if (daemon->dhcp || daemon->doing_dhcp6)
202 lease_init(now);
203 }
204
205 if (daemon->dhcp || daemon->relay4)
206 dhcp_init();
207
208# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100209 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100210 ra_init(now);
211
212 if (daemon->doing_dhcp6 || daemon->relay6)
213 dhcp6_init();
214# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000215
Simon Kelley7622fc02009-06-04 20:32:05 +0100216#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100217
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000218#ifdef HAVE_IPSET
219 if (daemon->ipsets)
220 ipset_init();
221#endif
222
Simon Kelley801ca9a2012-03-06 19:30:17 +0000223#ifdef HAVE_LINUX_NETWORK
Simon Kelley801ca9a2012-03-06 19:30:17 +0000224 netlink_init();
Simon Kelley8445f5d2012-12-17 21:54:08 +0000225
Simon Kelley54dd3932012-06-20 11:23:38 +0100226 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
227 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000228#endif
229
Simon Kelley115ac3e2013-05-20 11:28:32 +0100230 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100231 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000232
Simon Kelley54dd3932012-06-20 11:23:38 +0100233 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100234 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100235 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100236
237 if (!option_bool(OPT_CLEVERBIND))
238 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
239 if (if_tmp->name && !if_tmp->used)
240 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100241
242#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
243 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100244 bound_device = whichdevice();
245
Simon Kelley10ae7b52013-09-05 20:08:01 +0100246 if (daemon->dhcp)
Simon Kelley9380ba72012-04-16 14:41:56 +0100247 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100248 if (!daemon->relay4 && bound_device)
249 {
250 bindtodevice(bound_device, daemon->dhcpfd);
251 did_bind = 1;
252 }
253 if (daemon->enable_pxe && bound_device)
254 {
255 bindtodevice(bound_device, daemon->pxefd);
256 did_bind = 1;
257 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100258 }
259#endif
260
261#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100262 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
263 {
264 bindtodevice(bound_device, daemon->dhcp6fd);
265 did_bind = 1;
266 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100267#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100268 }
Simon Kelley28866e92011-02-14 20:19:14 +0000269 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100270 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000271
272#ifdef HAVE_DHCP6
273 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100274 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000275 join_multicast(1);
276#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100277
Simon Kelley824af852008-02-12 20:43:05 +0000278 if (daemon->port != 0)
279 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100280
Simon Kelley28866e92011-02-14 20:19:14 +0000281 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100282#ifdef HAVE_DBUS
283 {
284 char *err;
285 daemon->dbus = NULL;
286 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100287 if ((err = dbus_init()))
288 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100289 }
290#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100291 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100292#endif
293
Simon Kelley824af852008-02-12 20:43:05 +0000294 if (daemon->port != 0)
295 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100296
Simon Kelleyc72daea2012-01-05 21:33:27 +0000297#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100298 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000299 if ((daemon->dhcp || daemon->dhcp6) &&
300 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000301 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100302 {
303 if ((ent_pw = getpwnam(daemon->scriptuser)))
304 {
305 script_uid = ent_pw->pw_uid;
306 script_gid = ent_pw->pw_gid;
307 }
308 else
309 baduser = daemon->scriptuser;
310 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100311#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000312
Simon Kelley1a6bca82008-07-11 11:11:42 +0100313 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
314 baduser = daemon->username;
315 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
316 baduser = daemon->groupname;
317
318 if (baduser)
319 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
320
321 /* implement group defaults, "dip" if available, or group associated with uid */
322 if (!daemon->group_set && !gp)
323 {
324 if (!(gp = getgrnam(CHGRP)) && ent_pw)
325 gp = getgrgid(ent_pw->pw_gid);
326
327 /* for error message */
328 if (gp)
329 daemon->groupname = gp->gr_name;
330 }
331
332#if defined(HAVE_LINUX_NETWORK)
333 /* determine capability API version here, while we can still
334 call safe_malloc */
335 if (ent_pw && ent_pw->pw_uid != 0)
336 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100337 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100338 hdr = safe_malloc(sizeof(*hdr));
339
Simon Kelley1a6bca82008-07-11 11:11:42 +0100340 /* find version supported by kernel */
341 memset(hdr, 0, sizeof(*hdr));
342 capget(hdr, NULL);
343
344 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
345 {
346 /* if unknown version, use largest supported version (3) */
347 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
348 hdr->version = LINUX_CAPABILITY_VERSION_3;
349 capsize = 2;
350 }
351
352 data = safe_malloc(sizeof(*data) * capsize);
353 memset(data, 0, sizeof(*data) * capsize);
354 }
355#endif
356
Simon Kelley5aabfc72007-08-29 11:24:47 +0100357 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 in a race-free manner and another to carry errors to daemon-invoking process */
359 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100360
361 piperead = pipefd[0];
362 pipewrite = pipefd[1];
363 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000364 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365
366 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100367
Simon Kelley28866e92011-02-14 20:19:14 +0000368 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000369 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000370 /* The following code "daemonizes" the process.
371 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100372
Simon Kelley9e038942008-05-30 20:06:34 +0100373 if (chdir("/") != 0)
374 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
375
Simon Kelley16972692006-10-16 20:04:18 +0100376#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000377 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100378 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100379 pid_t pid;
380
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381 /* pipe to carry errors back to original process.
382 When startup is complete we close this and the process terminates. */
383 safe_pipe(err_pipe, 0);
384
Simon Kelley7622fc02009-06-04 20:32:05 +0100385 if ((pid = fork()) == -1)
386 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000387 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100388
Simon Kelley5aabfc72007-08-29 11:24:47 +0100389 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390 {
391 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000392 char *msg;
393
Simon Kelley1a6bca82008-07-11 11:11:42 +0100394 /* close our copy of write-end */
395 close(err_pipe[1]);
396
397 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000398 if (read_event(err_pipe[0], &ev, &msg))
399 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100400
401 _exit(EC_GOOD);
402 }
403
404 close(err_pipe[0]);
405
406 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100407
408 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100409
410 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000411 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100412
413 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100414 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100415 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000416#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100417
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100419 if (daemon->runfile)
420 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100421 int fd, err = 0;
422
423 sprintf(daemon->namebuff, "%d\n", (int) getpid());
424
425 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
426 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
427 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
428 extent that an attacker running as the unprivileged user could replace the pidfile with a
429 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
430
431 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
432 ensuring that the open() fails should there be any existing file (because the unlink() failed,
433 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
434 attack can succeed.
435
436 Any compromise of the non-privileged user still theoretically allows the pid-file to be
437 replaced whilst dnsmasq is running. The worst that could allow is that the usual
438 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
439
440 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
441 failure to write the pid-file.
442 */
443
444 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445
Simon Kelley79cfefd2012-09-02 13:29:51 +0100446 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 +0100447 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100448 /* only complain if started as root */
449 if (getuid() == 0)
450 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100451 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100452 else
453 {
454 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
455 err = 1;
456
457 while (!err && close(fd) == -1)
458 if (!retry_send())
459 err = 1;
460 }
461
462 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000464 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100465 _exit(0);
466 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000467 }
Simon Kelley16972692006-10-16 20:04:18 +0100468 }
469
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100470 log_err = log_start(ent_pw, err_pipe[1]);
471
Simon Kelley28866e92011-02-14 20:19:14 +0000472 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100473 {
474 /* open stdout etc to /dev/null */
475 int nullfd = open("/dev/null", O_RDWR);
476 dup2(nullfd, STDOUT_FILENO);
477 dup2(nullfd, STDERR_FILENO);
478 dup2(nullfd, STDIN_FILENO);
479 close(nullfd);
480 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100481
Simon Kelley1a6bca82008-07-11 11:11:42 +0100482 /* if we are to run scripts, we need to fork a helper before dropping root. */
483 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000484#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000485 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100486 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
487#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100488
Simon Kelley28866e92011-02-14 20:19:14 +0000489 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100490 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100491 int bad_capabilities = 0;
492 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100493
Simon Kelley1a6bca82008-07-11 11:11:42 +0100494 /* remove all supplimentary groups */
495 if (gp &&
496 (setgroups(0, &dummy) == -1 ||
497 setgid(gp->gr_gid) == -1))
498 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000499 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100500 _exit(0);
501 }
502
Simon Kelley7cebd202006-05-06 14:13:33 +0100503 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100504 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100505#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100506 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100507 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100508 ports because of DAD, or we're doing it dynamically,
509 we need CAP_NET_BIND_SERVICE too. */
510 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100511 data->effective = data->permitted = data->inheritable =
512 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
513 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
514 else
515 data->effective = data->permitted = data->inheritable =
516 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100517
Simon Kelley16972692006-10-16 20:04:18 +0100518 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000519 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100520 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100521
Simon Kelley7622fc02009-06-04 20:32:05 +0100522#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000523 /* http://developers.sun.com/solaris/articles/program_privileges.html */
524 priv_set_t *priv_set;
525
526 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
527 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
528 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
529 bad_capabilities = errno;
530
531 if (priv_set && bad_capabilities == 0)
532 {
533 priv_inverse(priv_set);
534
535 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
536 bad_capabilities = errno;
537 }
538
539 if (priv_set)
540 priv_freeset(priv_set);
541
Simon Kelley824af852008-02-12 20:43:05 +0000542#endif
543
Simon Kelley1a6bca82008-07-11 11:11:42 +0100544 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100545 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000546 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100547 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100548 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100549
550 /* finally drop root */
551 if (setuid(ent_pw->pw_uid) == -1)
552 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000553 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100554 _exit(0);
555 }
556
557#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100558 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100559 data->effective = data->permitted =
560 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
561 else
562 data->effective = data->permitted =
563 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100564 data->inheritable = 0;
565
566 /* lose the setuid and setgid capbilities */
567 if (capset(hdr, data) == -1)
568 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000569 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100570 _exit(0);
571 }
572#endif
573
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574 }
Simon Kelley849a8352006-06-09 21:02:31 +0100575 }
Simon Kelley16972692006-10-16 20:04:18 +0100576
Simon Kelley16972692006-10-16 20:04:18 +0100577#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000578 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000579 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100580#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100581
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100582#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100583 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100584 {
585 DIR *dir;
586 struct tftp_prefix *p;
587
588 if (daemon->tftp_prefix)
589 {
590 if (!((dir = opendir(daemon->tftp_prefix))))
591 {
592 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
593 _exit(0);
594 }
595 closedir(dir);
596 }
597
598 for (p = daemon->if_prefix; p; p = p->next)
599 {
600 if (!((dir = opendir(p->prefix))))
601 {
602 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
603 _exit(0);
604 }
605 closedir(dir);
606 }
607 }
608#endif
609
Simon Kelley824af852008-02-12 20:43:05 +0000610 if (daemon->port == 0)
611 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
612 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100613 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100615 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100616
Simon Kelleyf2621c72007-04-29 19:47:21 +0100617 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100618
Simon Kelley3d8df262005-08-29 12:19:27 +0100619#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000620 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100621 {
622 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100623 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100624 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100625 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100626 }
627#endif
628
Simon Kelley1a6bca82008-07-11 11:11:42 +0100629 if (log_err != 0)
630 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
631 daemon->log_file, strerror(log_err));
632
Simon Kelleyde379512004-06-22 20:23:33 +0100633 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100634 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100635
Simon Kelley28866e92011-02-14 20:19:14 +0000636 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000637 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
638 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100639 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100640
Simon Kelley28866e92011-02-14 20:19:14 +0000641 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100642 {
643 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100644 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100645 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000646 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100647 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100648 }
649
Simon Kelleyf2621c72007-04-29 19:47:21 +0100650 if (daemon->max_logs != 0)
651 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000652
Simon Kelleyf2621c72007-04-29 19:47:21 +0100653
Simon Kelley7622fc02009-06-04 20:32:05 +0100654#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000655 for (context = daemon->dhcp; context; context = context->next)
656 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100657
Simon Kelleyff7eea22013-09-04 18:01:38 +0100658 for (relay = daemon->relay4; relay; relay = relay->next)
659 log_relay(AF_INET, relay);
660
Simon Kelley1f776932012-12-16 19:46:08 +0000661# ifdef HAVE_DHCP6
662 for (context = daemon->dhcp6; context; context = context->next)
663 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000664
Simon Kelleyff7eea22013-09-04 18:01:38 +0100665 for (relay = daemon->relay6; relay; relay = relay->next)
666 log_relay(AF_INET6, relay);
667
Simon Kelley1f776932012-12-16 19:46:08 +0000668 if (daemon->doing_dhcp6 || daemon->doing_ra)
669 dhcp_construct_contexts(now);
670
671 if (option_bool(OPT_RA))
672 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
673# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000674
Simon Kelley3b3f4412013-10-11 16:33:28 +0100675# ifdef HAVE_LINUX_NETWORK
676 if (did_bind)
677 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
678# endif
679
Simon Kelley8445f5d2012-12-17 21:54:08 +0000680 /* after dhcp_contruct_contexts */
681 if (daemon->dhcp || daemon->doing_dhcp6)
682 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000683#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000684
Simon Kelley832af0b2007-01-21 20:01:28 +0000685#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100686 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000687 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000688#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100689 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000690 max_fd = FD_SETSIZE;
691#endif
692
Simon Kelley7622fc02009-06-04 20:32:05 +0100693 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100694 daemon->tftp_prefix ? _("root is ") : _("enabled"),
695 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000696 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100697
Simon Kelley832af0b2007-01-21 20:01:28 +0000698 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100699 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000700 a single file will be sent to may clients (the file only needs
701 one fd). */
702
703 max_fd -= 30; /* use other than TFTP */
704
705 if (max_fd < 0)
706 max_fd = 5;
707 else if (max_fd < 100)
708 max_fd = max_fd/2;
709 else
710 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000711
712 /* if we have to use a limited range of ports,
713 that will limit the number of transfers */
714 if (daemon->start_tftp_port != 0 &&
715 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
716 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000717
718 if (daemon->tftp_max > max_fd)
719 {
720 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100721 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100722 _("restricting maximum simultaneous TFTP transfers to %d"),
723 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000724 }
725 }
726#endif
727
Simon Kelley1a6bca82008-07-11 11:11:42 +0100728 /* finished start-up - release original process */
729 if (err_pipe[1] != -1)
730 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000731
Simon Kelley824af852008-02-12 20:43:05 +0000732 if (daemon->port != 0)
733 check_servers();
734
Simon Kelley7cebd202006-05-06 14:13:33 +0100735 pid = getpid();
736
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100737 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000738 {
Simon Kelley16972692006-10-16 20:04:18 +0100739 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100740 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100741 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000742
743 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100744 FD_ZERO(&wset);
745 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000746
Simon Kelley16972692006-10-16 20:04:18 +0100747 /* if we are out of resources, find how long we have to wait
748 for some to come free, we'll loop around then and restart
749 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100750 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100751 {
752 t.tv_usec = 0;
753 tp = &t;
754 }
755
Simon Kelley832af0b2007-01-21 20:01:28 +0000756 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
757 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000758 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000759 {
Simon Kelley16972692006-10-16 20:04:18 +0100760 t.tv_sec = 0;
761 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100762 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000763 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100764 /* Wake every second whilst waiting for DAD to complete */
765 else if (is_dad_listeners())
766 {
767 t.tv_sec = 1;
768 t.tv_usec = 0;
769 tp = &t;
770 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100771
Simon Kelley832af0b2007-01-21 20:01:28 +0000772#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100773 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100774#endif
775
Simon Kelley7622fc02009-06-04 20:32:05 +0100776#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100777 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100778 {
779 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100780 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000781 if (daemon->pxefd != -1)
782 {
783 FD_SET(daemon->pxefd, &rset);
784 bump_maxfd(daemon->pxefd, &maxfd);
785 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100786 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100787#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100788
Simon Kelley52b92f42012-01-22 16:05:15 +0000789#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100790 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000791 {
792 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000793 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000794 }
795
Simon Kelley1f776932012-12-16 19:46:08 +0000796 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000797 {
798 FD_SET(daemon->icmp6fd, &rset);
799 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000800 }
801#endif
802
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100803#ifdef HAVE_LINUX_NETWORK
804 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100805 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100806#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100807
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100808 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100809 bump_maxfd(piperead, &maxfd);
810
Simon Kelley7622fc02009-06-04 20:32:05 +0100811#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100812# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100813 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100814
Simon Kelleya9530962012-03-20 22:07:35 +0000815# ifdef HAVE_TFTP
816 while (helper_buf_empty() && do_tftp_script_run());
817# endif
818
Simon Kelley16972692006-10-16 20:04:18 +0100819 if (!helper_buf_empty())
820 {
821 FD_SET(daemon->helperfd, &wset);
822 bump_maxfd(daemon->helperfd, &maxfd);
823 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100824# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100825 /* need this for other side-effects */
826 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000827
828# ifdef HAVE_TFTP
829 while (do_tftp_script_run());
830# endif
831
Simon Kelley7622fc02009-06-04 20:32:05 +0100832# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100833#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100834
Simon Kelleyf2621c72007-04-29 19:47:21 +0100835 /* must do this just before select(), when we know no
836 more calls to my_syslog() can occur */
837 set_log_writer(&wset, &maxfd);
838
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100839 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
840 {
841 /* otherwise undefined after error */
842 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
843 }
844
845 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000846
Simon Kelleyf2621c72007-04-29 19:47:21 +0100847 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100848
849 /* prime. */
850 enumerate_interfaces(1);
851
Simon Kelley74c95c22011-10-19 09:33:39 +0100852 /* Check the interfaces to see if any have exited DAD state
853 and if so, bind the address. */
854 if (is_dad_listeners())
855 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100856 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100857 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
858 create_bound_listeners(0);
859 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100860
Simon Kelleyc52e1892010-06-07 22:01:39 +0100861#ifdef HAVE_LINUX_NETWORK
862 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000863 netlink_multicast(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100864#endif
865
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000866 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100867 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000868 if (daemon->last_resolv == 0 ||
869 difftime(now, daemon->last_resolv) > 1.0 ||
870 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000871 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100872 /* poll_resolv doesn't need to reload first time through, since
873 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100874
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100875 poll_resolv(0, daemon->last_resolv != 0, now);
876 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100878
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100879 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100880 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100881
Simon Kelley3d8df262005-08-29 12:19:27 +0100882#ifdef HAVE_DBUS
883 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000884 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100885 {
886 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100887 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100888 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100889 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100890 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100891 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100892 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100893#endif
Simon Kelley824af852008-02-12 20:43:05 +0000894
Simon Kelley5aabfc72007-08-29 11:24:47 +0100895 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000896
897#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100898 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000899#endif
900
Simon Kelley7622fc02009-06-04 20:32:05 +0100901#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100902 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000903 {
904 if (FD_ISSET(daemon->dhcpfd, &rset))
905 dhcp_packet(now, 0);
906 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
907 dhcp_packet(now, 1);
908 }
Simon Kelley16972692006-10-16 20:04:18 +0100909
Simon Kelley52b92f42012-01-22 16:05:15 +0000910#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100911 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100912 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000913
Simon Kelley1f776932012-12-16 19:46:08 +0000914 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
915 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000916#endif
917
Simon Kelley1f15b812009-10-13 17:49:32 +0100918# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100919 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100920 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100921# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100922#endif
923
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000924 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000925}
926
Simon Kelley3be34542004-09-11 19:12:13 +0100927static void sig_handler(int sig)
928{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100929 if (pid == 0)
930 {
Simon Kelley16972692006-10-16 20:04:18 +0100931 /* ignore anything other than TERM during startup
932 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100933 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100934 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100935 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100936 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100937 {
Simon Kelley16972692006-10-16 20:04:18 +0100938 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100939 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100940 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100941 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100942 else
943 {
944 /* master process */
945 int event, errsave = errno;
946
947 if (sig == SIGHUP)
948 event = EVENT_RELOAD;
949 else if (sig == SIGCHLD)
950 event = EVENT_CHILD;
951 else if (sig == SIGALRM)
952 event = EVENT_ALARM;
953 else if (sig == SIGTERM)
954 event = EVENT_TERM;
955 else if (sig == SIGUSR1)
956 event = EVENT_DUMP;
957 else if (sig == SIGUSR2)
958 event = EVENT_REOPEN;
959 else
960 return;
961
Simon Kelleyc72daea2012-01-05 21:33:27 +0000962 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100963 errno = errsave;
964 }
Simon Kelley3be34542004-09-11 19:12:13 +0100965}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966
Simon Kelley353ae4d2012-03-19 20:07:51 +0000967/* now == 0 -> queue immediate callback */
968void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000969{
Simon Kelley884a6df2012-03-20 16:20:22 +0000970 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000971 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000972 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
973 if ((now == 0 || difftime(event, now) <= 0.0))
974 send_event(pipewrite, EVENT_ALARM, 0, NULL);
975 else
976 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000977 }
Simon Kelley741c2952012-02-25 13:09:18 +0000978}
979
Simon Kelleyc72daea2012-01-05 21:33:27 +0000980void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100981{
982 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000983 struct iovec iov[2];
984
Simon Kelley5aabfc72007-08-29 11:24:47 +0100985 ev.event = event;
986 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000987 ev.msg_sz = msg ? strlen(msg) : 0;
988
989 iov[0].iov_base = &ev;
990 iov[0].iov_len = sizeof(ev);
991 iov[1].iov_base = msg;
992 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100993
994 /* error pipe, debug mode. */
995 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000996 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100997 else
998 /* pipe is non-blocking and struct event_desc is smaller than
999 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001000 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001001}
Simon Kelley3d8df262005-08-29 12:19:27 +01001002
Simon Kelleyc72daea2012-01-05 21:33:27 +00001003/* NOTE: the memory used to return msg is leaked: use msgs in events only
1004 to describe fatal errors. */
1005static int read_event(int fd, struct event_desc *evp, char **msg)
1006{
1007 char *buf;
1008
1009 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1010 return 0;
1011
1012 *msg = NULL;
1013
1014 if (evp->msg_sz != 0 &&
1015 (buf = malloc(evp->msg_sz + 1)) &&
1016 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1017 {
1018 buf[evp->msg_sz] = 0;
1019 *msg = buf;
1020 }
1021
1022 return 1;
1023}
1024
1025static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001026{
1027 errno = ev->data;
1028
1029 switch (ev->event)
1030 {
1031 case EVENT_DIE:
1032 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001033
1034 case EVENT_FORK_ERR:
1035 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001036
1037 case EVENT_PIPE_ERR:
1038 die(_("failed to create helper: %s"), NULL, EC_MISC);
1039
1040 case EVENT_CAP_ERR:
1041 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1042
1043 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001044 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001045
1046 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001047 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001048
1049 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001050 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001051
1052 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001053 die(_("cannot open log %s: %s"), msg, EC_FILE);
1054
1055 case EVENT_LUA_ERR:
1056 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001057
1058 case EVENT_TFTP_ERR:
1059 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001060 }
1061}
1062
Simon Kelley5aabfc72007-08-29 11:24:47 +01001063static void async_event(int pipe, time_t now)
1064{
1065 pid_t p;
1066 struct event_desc ev;
1067 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001068 char *msg;
1069
1070 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1071 to describe fatal errors. */
1072
1073 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001074 switch (ev.event)
1075 {
1076 case EVENT_RELOAD:
1077 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001078 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001079 {
1080 reload_servers(daemon->resolv_files->name);
1081 check_servers();
1082 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001083#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001084 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001085#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001086 break;
1087
1088 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001089 if (daemon->port != 0)
1090 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001091 break;
1092
1093 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001094#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001095 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001096 {
1097 lease_prune(NULL, now);
1098 lease_update_file(now);
1099 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001100#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001101 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001102 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1103 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001104#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001105#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001106 break;
1107
1108 case EVENT_CHILD:
1109 /* See Stevens 5.10 */
1110 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1111 if (p == -1)
1112 {
1113 if (errno != EINTR)
1114 break;
1115 }
1116 else
1117 for (i = 0 ; i < MAX_PROCS; i++)
1118 if (daemon->tcp_pids[i] == p)
1119 daemon->tcp_pids[i] = 0;
1120 break;
1121
1122 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001123 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001124 break;
1125
1126 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001127 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001128 break;
1129
1130 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001131 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1132 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001133 break;
1134
Simon Kelley1a6bca82008-07-11 11:11:42 +01001135 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001136 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001137 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001138 case EVENT_LUA_ERR:
1139 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001140 break;
1141
Simon Kelley5aabfc72007-08-29 11:24:47 +01001142 case EVENT_REOPEN:
1143 /* Note: this may leave TCP-handling processes with the old file still open.
1144 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1145 we leave them logging to the old file. */
1146 if (daemon->log_file != NULL)
1147 log_reopen(daemon->log_file);
1148 break;
1149
1150 case EVENT_TERM:
1151 /* Knock all our children on the head. */
1152 for (i = 0; i < MAX_PROCS; i++)
1153 if (daemon->tcp_pids[i] != 0)
1154 kill(daemon->tcp_pids[i], SIGALRM);
1155
Simon Kelleyc72daea2012-01-05 21:33:27 +00001156#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001157 /* handle pending lease transitions */
1158 if (daemon->helperfd != -1)
1159 {
1160 /* block in writes until all done */
1161 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1162 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1163 do {
1164 helper_write();
1165 } while (!helper_buf_empty() || do_script_run(now));
1166 close(daemon->helperfd);
1167 }
1168#endif
1169
1170 if (daemon->lease_stream)
1171 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001172
1173 if (daemon->runfile)
1174 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001175
1176 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1177 flush_log();
1178 exit(EC_GOOD);
1179 }
1180}
1181
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001182void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001183{
1184 struct resolvc *res, *latest;
1185 struct stat statbuf;
1186 time_t last_change = 0;
1187 /* There may be more than one possible file.
1188 Go through and find the one which changed _last_.
1189 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001190
Simon Kelley28866e92011-02-14 20:19:14 +00001191 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001192 return;
1193
Simon Kelley5aabfc72007-08-29 11:24:47 +01001194 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1195 if (stat(res->name, &statbuf) == -1)
1196 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001197 if (force)
1198 {
1199 res->mtime = 0;
1200 continue;
1201 }
1202
Simon Kelley5aabfc72007-08-29 11:24:47 +01001203 if (!res->logged)
1204 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1205 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001206
1207 if (res->mtime != 0)
1208 {
1209 /* existing file evaporated, force selection of the latest
1210 file even if its mtime hasn't changed since we last looked */
1211 poll_resolv(1, do_reload, now);
1212 return;
1213 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001214 }
1215 else
1216 {
1217 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001218 if (force || (statbuf.st_mtime != res->mtime))
1219 {
1220 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001221 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1222 {
1223 last_change = statbuf.st_mtime;
1224 latest = res;
1225 }
1226 }
1227 }
1228
1229 if (latest)
1230 {
1231 static int warned = 0;
1232 if (reload_servers(latest->name))
1233 {
1234 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1235 warned = 0;
1236 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001237 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001238 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001239 }
1240 else
1241 {
1242 latest->mtime = 0;
1243 if (!warned)
1244 {
1245 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1246 warned = 1;
1247 }
1248 }
1249 }
1250}
1251
1252void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001253{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001254 (void)now;
1255
Simon Kelley824af852008-02-12 20:43:05 +00001256 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001257 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001258
Simon Kelley7622fc02009-06-04 20:32:05 +01001259#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001260 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001261 {
Simon Kelley28866e92011-02-14 20:19:14 +00001262 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001263 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001264 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001265 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001266 lease_update_from_configs();
1267 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001268 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001269 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001270#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001271 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001272 /* Not doing DHCP, so no lease system, manage
1273 alarms for ra only */
1274 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001275#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001276#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001277}
1278
Simon Kelley5aabfc72007-08-29 11:24:47 +01001279static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001280{
1281 struct serverfd *serverfdp;
1282 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001283 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001284
1285#ifdef HAVE_TFTP
1286 int tftp = 0;
1287 struct tftp_transfer *transfer;
1288 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1289 {
1290 tftp++;
1291 FD_SET(transfer->sockfd, set);
1292 bump_maxfd(transfer->sockfd, maxfdp);
1293 }
1294#endif
1295
Simon Kelley16972692006-10-16 20:04:18 +01001296 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001297 if (daemon->port != 0)
1298 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001299
Simon Kelley3be34542004-09-11 19:12:13 +01001300 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1301 {
1302 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001303 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001304 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001305
1306 if (daemon->port != 0 && !daemon->osport)
1307 for (i = 0; i < RANDOM_SOCKS; i++)
1308 if (daemon->randomsocks[i].refcount != 0)
1309 {
1310 FD_SET(daemon->randomsocks[i].fd, set);
1311 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1312 }
1313
Simon Kelley3be34542004-09-11 19:12:13 +01001314 for (listener = daemon->listeners; listener; listener = listener->next)
1315 {
Simon Kelley16972692006-10-16 20:04:18 +01001316 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001317 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001318 {
1319 FD_SET(listener->fd, set);
1320 bump_maxfd(listener->fd, maxfdp);
1321 }
1322
1323 /* death of a child goes through the select loop, so
1324 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001325 if (listener->tcpfd != -1)
1326 for (i = 0; i < MAX_PROCS; i++)
1327 if (daemon->tcp_pids[i] == 0)
1328 {
1329 FD_SET(listener->tcpfd, set);
1330 bump_maxfd(listener->tcpfd, maxfdp);
1331 break;
1332 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001333
Simon Kelley832af0b2007-01-21 20:01:28 +00001334#ifdef HAVE_TFTP
1335 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1336 {
1337 FD_SET(listener->tftpfd, set);
1338 bump_maxfd(listener->tftpfd, maxfdp);
1339 }
1340#endif
1341
1342 }
1343
Simon Kelley16972692006-10-16 20:04:18 +01001344 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001345}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001346
Simon Kelley5aabfc72007-08-29 11:24:47 +01001347static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001348{
1349 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001350 struct listener *listener;
1351 int i;
1352
Simon Kelley832af0b2007-01-21 20:01:28 +00001353 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1354 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001355 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1356
1357 if (daemon->port != 0 && !daemon->osport)
1358 for (i = 0; i < RANDOM_SOCKS; i++)
1359 if (daemon->randomsocks[i].refcount != 0 &&
1360 FD_ISSET(daemon->randomsocks[i].fd, set))
1361 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001362
1363 for (listener = daemon->listeners; listener; listener = listener->next)
1364 {
Simon Kelley824af852008-02-12 20:43:05 +00001365 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001366 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001367
Simon Kelley832af0b2007-01-21 20:01:28 +00001368#ifdef HAVE_TFTP
1369 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001370 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001371#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001372
Simon Kelley824af852008-02-12 20:43:05 +00001373 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001374 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001375 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001376 struct irec *iface = NULL;
1377 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001378 union mysockaddr tcp_addr;
1379 socklen_t tcp_len = sizeof(union mysockaddr);
1380
1381 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001382
Simon Kelley46b06652013-02-04 21:47:59 +00001383 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001384 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001385
Simon Kelley46b06652013-02-04 21:47:59 +00001386 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1387 {
1388 close(confd);
1389 continue;
1390 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001391
1392 /* Make sure that the interface list is up-to-date.
1393
1394 We do this here as we may need the results below, and
1395 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001396
Simon Kelley76dd75d2013-05-23 10:04:25 +01001397 Multiple calls to enumerate_interfaces() per select loop are
1398 inhibited, so calls to it in the child process (which doesn't select())
1399 have no effect. This avoids two processes reading from the same
1400 netlink fd and screwing the pooch entirely.
1401 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001402
Simon Kelley76dd75d2013-05-23 10:04:25 +01001403 enumerate_interfaces(0);
1404
1405 if (option_bool(OPT_NOWILD))
1406 iface = listener->iface; /* May be NULL */
1407 else
1408 {
1409 int if_index;
1410 char intr_name[IF_NAMESIZE];
1411
1412 /* if we can find the arrival interface, check it's one that's allowed */
1413 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1414 indextoname(listener->tcpfd, if_index, intr_name))
1415 {
1416 struct all_addr addr;
1417 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001418#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001419 if (tcp_addr.sa.sa_family == AF_INET6)
1420 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001421#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001422
1423 for (iface = daemon->interfaces; iface; iface = iface->next)
1424 if (iface->index == if_index)
1425 break;
1426
1427 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1428 client_ok = 0;
1429 }
1430
1431 if (option_bool(OPT_CLEVERBIND))
1432 iface = listener->iface; /* May be NULL */
1433 else
1434 {
1435 /* Check for allowed interfaces when binding the wildcard address:
1436 we do this by looking for an interface with the same address as
1437 the local address of the TCP connection, then looking to see if that's
1438 an allowed interface. As a side effect, we get the netmask of the
1439 interface too, for localisation. */
1440
1441 for (iface = daemon->interfaces; iface; iface = iface->next)
1442 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1443 break;
1444
1445 if (!iface)
1446 client_ok = 0;
1447 }
1448 }
1449
Simon Kelley22ce5502013-01-22 13:53:04 +00001450 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001451 {
1452 shutdown(confd, SHUT_RDWR);
1453 close(confd);
1454 }
1455#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001456 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001457 {
1458 if (p != -1)
1459 {
1460 int i;
1461 for (i = 0; i < MAX_PROCS; i++)
1462 if (daemon->tcp_pids[i] == 0)
1463 {
1464 daemon->tcp_pids[i] = p;
1465 break;
1466 }
1467 }
1468 close(confd);
1469 }
1470#endif
1471 else
1472 {
1473 unsigned char *buff;
1474 struct server *s;
1475 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001476 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001477 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001478
1479 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001480 {
1481 netmask = iface->netmask;
1482 auth_dns = iface->dns_auth;
1483 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001484 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001485 {
1486 netmask.s_addr = 0;
1487 auth_dns = 0;
1488 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001489
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001490#ifndef NO_FORK
1491 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1492 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001493 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001494 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001495#endif
1496
Simon Kelley832af0b2007-01-21 20:01:28 +00001497 /* start with no upstream connections. */
1498 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001499 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001500
1501 /* The connected socket inherits non-blocking
1502 attribute from the listening socket.
1503 Reset that here. */
1504 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1505 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1506
Simon Kelley4f7b3042012-11-28 21:27:02 +00001507 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001508
Simon Kelley832af0b2007-01-21 20:01:28 +00001509 shutdown(confd, SHUT_RDWR);
1510 close(confd);
1511
1512 if (buff)
1513 free(buff);
1514
1515 for (s = daemon->servers; s; s = s->next)
1516 if (s->tcpfd != -1)
1517 {
1518 shutdown(s->tcpfd, SHUT_RDWR);
1519 close(s->tcpfd);
1520 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001521#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001522 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001523 {
1524 flush_log();
1525 _exit(0);
1526 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001527#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001528 }
1529 }
1530 }
Simon Kelley3be34542004-09-11 19:12:13 +01001531}
1532
Simon Kelley7622fc02009-06-04 20:32:05 +01001533#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001534int make_icmp_sock(void)
1535{
Simon Kelley7cebd202006-05-06 14:13:33 +01001536 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001537 int zeroopt = 0;
1538
1539 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1540 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001541 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001542 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1543 {
1544 close(fd);
1545 fd = -1;
1546 }
1547 }
1548
1549 return fd;
1550}
1551
Simon Kelley5aabfc72007-08-29 11:24:47 +01001552int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001553{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001554 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001555
1556 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001557 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001558 better not use any resources our caller has in use...)
1559 but we remain deaf to signals or further DHCP packets. */
1560
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001561 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001562 struct sockaddr_in saddr;
1563 struct {
1564 struct ip ip;
1565 struct icmp icmp;
1566 } packet;
1567 unsigned short id = rand16();
1568 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001569 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001570 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001571
Simon Kelley824af852008-02-12 20:43:05 +00001572#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001573 if ((fd = make_icmp_sock()) == -1)
1574 return 0;
1575#else
1576 int opt = 2000;
1577 fd = daemon->dhcp_icmp_fd;
1578 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1579#endif
1580
Simon Kelley3be34542004-09-11 19:12:13 +01001581 saddr.sin_family = AF_INET;
1582 saddr.sin_port = 0;
1583 saddr.sin_addr = addr;
1584#ifdef HAVE_SOCKADDR_SA_LEN
1585 saddr.sin_len = sizeof(struct sockaddr_in);
1586#endif
1587
1588 memset(&packet.icmp, 0, sizeof(packet.icmp));
1589 packet.icmp.icmp_type = ICMP_ECHO;
1590 packet.icmp.icmp_id = id;
1591 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1592 j += ((u16 *)&packet.icmp)[i];
1593 while (j>>16)
1594 j = (j & 0xffff) + (j >> 16);
1595 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1596
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001597 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001598 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1599 retry_send());
1600
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001601 for (now = start = dnsmasq_time();
1602 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001603 {
1604 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001605 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001606 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001607 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001608 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001609
1610 tv.tv_usec = 250000;
1611 tv.tv_sec = 0;
1612
1613 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001614 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001615 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001616 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001617 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001618
1619#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001620 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001621 {
1622 FD_SET(daemon->icmp6fd, &rset);
1623 bump_maxfd(daemon->icmp6fd, &maxfd);
1624 }
1625#endif
1626
Simon Kelleyf2621c72007-04-29 19:47:21 +01001627 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1628 {
1629 FD_ZERO(&rset);
1630 FD_ZERO(&wset);
1631 }
1632
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001633 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001634
1635 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001636 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001637
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001638#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001639 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1640 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001641#endif
1642
Simon Kelley832af0b2007-01-21 20:01:28 +00001643#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001644 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001645#endif
1646
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001647 if (FD_ISSET(fd, &rset) &&
1648 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001649 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1650 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1651 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1652 packet.icmp.icmp_seq == 0 &&
1653 packet.icmp.icmp_id == id)
1654 {
1655 gotreply = 1;
1656 break;
1657 }
1658 }
1659
Simon Kelley824af852008-02-12 20:43:05 +00001660#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001661 close(fd);
1662#else
Simon Kelley3be34542004-09-11 19:12:13 +01001663 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001664 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1665#endif
1666
Simon Kelley3be34542004-09-11 19:12:13 +01001667 return gotreply;
1668}
Simon Kelley7622fc02009-06-04 20:32:05 +01001669#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001670
1671