blob: a264f77b2e1e0f11f5f75cd921343e32f39651d6 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 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);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000084
Simon Kelley3be34542004-09-11 19:12:13 +010085 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000086 daemon->edns_pktsz = PACKETSZ;
87#ifdef HAVE_DNSSEC
88 /* Enforce min packet big enough for DNSSEC */
89 if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
90 daemon->edns_pktsz = EDNS_PKTSZ;
91#endif
Simon Kelley3ddacb82014-01-08 14:32:03 +000092
Simon Kelley0a852542005-03-23 20:28:59 +000093 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
94 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
95 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000096
Simon Kelleyc72daea2012-01-05 21:33:27 +000097 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +000098
99#ifdef HAVE_DNSSEC
100 if (option_bool(OPT_DNSSEC_VALID))
101 daemon->keyname = safe_malloc(MAXDNAME);
102#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000103
Simon Kelley7622fc02009-06-04 20:32:05 +0100104#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100105 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000106 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000107 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100108 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100110#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111
Simon Kelleya2761752012-01-18 16:07:21 +0000112 /* Close any file descriptors we inherited apart from std{in|out|err}
113
114 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
115 otherwise file descriptors we create can end up being 0, 1, or 2
116 and then get accidentally closed later when we make 0, 1, and 2
117 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
118 but it's not guaranteed. By opening /dev/null three times, we
119 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100120 for (i = 0; i < max_fd; i++)
121 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
122 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000123 else
124 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100125
Simon Kelley801ca9a2012-03-06 19:30:17 +0000126#ifndef HAVE_LINUX_NETWORK
127# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000128 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100129 {
130 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000131 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100132 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000133# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100134
135 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100136 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100137 {
138 bind_fallback = 1;
139 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100140 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100141 }
Simon Kelley309331f2006-04-22 15:05:01 +0100142#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100143
Simon Kelley3ddacb82014-01-08 14:32:03 +0000144#ifdef HAVE_DNSSEC
145 if (daemon->cachesize <CACHESIZ && option_bool(OPT_DNSSEC_VALID))
146 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
147#endif
148
Simon Kelley832af0b2007-01-21 20:01:28 +0000149#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100150 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100151 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000152#endif
153
Simon Kelley7de060b2011-08-26 17:24:52 +0100154#ifdef HAVE_CONNTRACK
155 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
156 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
157#else
158 if (option_bool(OPT_CONNTRACK))
159 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
160#endif
161
Simon Kelley824af852008-02-12 20:43:05 +0000162#ifdef HAVE_SOLARIS_NETWORK
163 if (daemon->max_logs != 0)
164 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
165#endif
166
Simon Kelley572b41e2011-02-18 18:11:18 +0000167#ifdef __ANDROID__
168 if (daemon->max_logs != 0)
169 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
170#endif
171
Simon Kelley4820dce2012-12-18 18:30:30 +0000172#ifndef HAVE_AUTH
173 if (daemon->authserver)
174 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
175#endif
176
Simon Kelley1a6bca82008-07-11 11:11:42 +0100177 rand_init();
178
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100179 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000180
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000181 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000182 if (daemon->authinterface && daemon->soa_sn == 0)
183#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000184 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000185#else
186 daemon->soa_sn = now;
187#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000188
Simon Kelleyff7eea22013-09-04 18:01:38 +0100189#ifdef HAVE_DHCP6
190 if (daemon->dhcp6)
191 {
192 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000193
Simon Kelleyff7eea22013-09-04 18:01:38 +0100194 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000195 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100196 if (context->flags & CONTEXT_DHCP)
197 daemon->doing_dhcp6 = 1;
198 if (context->flags & CONTEXT_RA)
199 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000200#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100201 if (context->flags & CONTEXT_TEMPLATE)
202 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000203#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000204 }
Simon Kelley1f776932012-12-16 19:46:08 +0000205 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100206#endif
207
208#ifdef HAVE_DHCP
209 /* Note that order matters here, we must call lease_init before
210 creating any file descriptors which shouldn't be leaked
211 to the lease-script init process. We need to call common_init
212 before lease_init to allocate buffers it uses.*/
213 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
214 {
215 dhcp_common_init();
216 if (daemon->dhcp || daemon->doing_dhcp6)
217 lease_init(now);
218 }
219
220 if (daemon->dhcp || daemon->relay4)
221 dhcp_init();
222
223# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100224 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100225 ra_init(now);
226
227 if (daemon->doing_dhcp6 || daemon->relay6)
228 dhcp6_init();
229# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000230
Simon Kelley7622fc02009-06-04 20:32:05 +0100231#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100232
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000233#ifdef HAVE_IPSET
234 if (daemon->ipsets)
235 ipset_init();
236#endif
237
Simon Kelley1ee9be42013-12-09 16:50:19 +0000238#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000239 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000240#elif defined(HAVE_BSD_NETWORK)
241 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000242#endif
243
Simon Kelley1ee9be42013-12-09 16:50:19 +0000244 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
245 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
246
Simon Kelley115ac3e2013-05-20 11:28:32 +0100247 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100248 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000249
Simon Kelley54dd3932012-06-20 11:23:38 +0100250 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100251 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100252 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100253
254 if (!option_bool(OPT_CLEVERBIND))
255 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
256 if (if_tmp->name && !if_tmp->used)
257 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100258
259#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
260 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100261 bound_device = whichdevice();
262
Simon Kelley9380ba72012-04-16 14:41:56 +0100263 if (daemon->dhcp)
264 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100265 if (!daemon->relay4 && bound_device)
266 {
267 bindtodevice(bound_device, daemon->dhcpfd);
268 did_bind = 1;
269 }
270 if (daemon->enable_pxe && bound_device)
271 {
272 bindtodevice(bound_device, daemon->pxefd);
273 did_bind = 1;
274 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100275 }
276#endif
277
278#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100279 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
280 {
281 bindtodevice(bound_device, daemon->dhcp6fd);
282 did_bind = 1;
283 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100284#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100285 }
Simon Kelley28866e92011-02-14 20:19:14 +0000286 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100287 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000288
289#ifdef HAVE_DHCP6
290 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100291 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000292 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000293
294 /* After netlink_init() and before create_helper() */
295 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000296#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100297
Simon Kelley824af852008-02-12 20:43:05 +0000298 if (daemon->port != 0)
299 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100300
Simon Kelley28866e92011-02-14 20:19:14 +0000301 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100302#ifdef HAVE_DBUS
303 {
304 char *err;
305 daemon->dbus = NULL;
306 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100307 if ((err = dbus_init()))
308 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100309 }
310#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100312#endif
313
Simon Kelley824af852008-02-12 20:43:05 +0000314 if (daemon->port != 0)
315 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100316
Simon Kelleyc72daea2012-01-05 21:33:27 +0000317#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100318 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000319 if ((daemon->dhcp || daemon->dhcp6) &&
320 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000321 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100322 {
323 if ((ent_pw = getpwnam(daemon->scriptuser)))
324 {
325 script_uid = ent_pw->pw_uid;
326 script_gid = ent_pw->pw_gid;
327 }
328 else
329 baduser = daemon->scriptuser;
330 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100331#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332
Simon Kelley1a6bca82008-07-11 11:11:42 +0100333 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
334 baduser = daemon->username;
335 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
336 baduser = daemon->groupname;
337
338 if (baduser)
339 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
340
341 /* implement group defaults, "dip" if available, or group associated with uid */
342 if (!daemon->group_set && !gp)
343 {
344 if (!(gp = getgrnam(CHGRP)) && ent_pw)
345 gp = getgrgid(ent_pw->pw_gid);
346
347 /* for error message */
348 if (gp)
349 daemon->groupname = gp->gr_name;
350 }
351
352#if defined(HAVE_LINUX_NETWORK)
353 /* determine capability API version here, while we can still
354 call safe_malloc */
355 if (ent_pw && ent_pw->pw_uid != 0)
356 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100357 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100358 hdr = safe_malloc(sizeof(*hdr));
359
Simon Kelley1a6bca82008-07-11 11:11:42 +0100360 /* find version supported by kernel */
361 memset(hdr, 0, sizeof(*hdr));
362 capget(hdr, NULL);
363
364 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
365 {
366 /* if unknown version, use largest supported version (3) */
367 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
368 hdr->version = LINUX_CAPABILITY_VERSION_3;
369 capsize = 2;
370 }
371
372 data = safe_malloc(sizeof(*data) * capsize);
373 memset(data, 0, sizeof(*data) * capsize);
374 }
375#endif
376
Simon Kelley5aabfc72007-08-29 11:24:47 +0100377 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100378 in a race-free manner and another to carry errors to daemon-invoking process */
379 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100380
381 piperead = pipefd[0];
382 pipewrite = pipefd[1];
383 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000384 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385
386 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100387
Simon Kelley28866e92011-02-14 20:19:14 +0000388 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000389 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000390 /* The following code "daemonizes" the process.
391 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100392
Simon Kelley9e038942008-05-30 20:06:34 +0100393 if (chdir("/") != 0)
394 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
395
Simon Kelley16972692006-10-16 20:04:18 +0100396#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000397 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100398 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100399 pid_t pid;
400
Simon Kelley1a6bca82008-07-11 11:11:42 +0100401 /* pipe to carry errors back to original process.
402 When startup is complete we close this and the process terminates. */
403 safe_pipe(err_pipe, 0);
404
Simon Kelley7622fc02009-06-04 20:32:05 +0100405 if ((pid = fork()) == -1)
406 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000407 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100408
Simon Kelley5aabfc72007-08-29 11:24:47 +0100409 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100410 {
411 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000412 char *msg;
413
Simon Kelley1a6bca82008-07-11 11:11:42 +0100414 /* close our copy of write-end */
415 close(err_pipe[1]);
416
417 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000418 if (read_event(err_pipe[0], &ev, &msg))
419 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100420
421 _exit(EC_GOOD);
422 }
423
424 close(err_pipe[0]);
425
426 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100427
428 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100429
430 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000431 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100432
433 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100434 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100435 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000436#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100437
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000438 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100439 if (daemon->runfile)
440 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100441 int fd, err = 0;
442
443 sprintf(daemon->namebuff, "%d\n", (int) getpid());
444
445 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
446 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
447 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
448 extent that an attacker running as the unprivileged user could replace the pidfile with a
449 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
450
451 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
452 ensuring that the open() fails should there be any existing file (because the unlink() failed,
453 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
454 attack can succeed.
455
456 Any compromise of the non-privileged user still theoretically allows the pid-file to be
457 replaced whilst dnsmasq is running. The worst that could allow is that the usual
458 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
459
460 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
461 failure to write the pid-file.
462 */
463
464 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100465
Simon Kelley79cfefd2012-09-02 13:29:51 +0100466 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 +0100467 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100468 /* only complain if started as root */
469 if (getuid() == 0)
470 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100471 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100472 else
473 {
474 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
475 err = 1;
476
477 while (!err && close(fd) == -1)
478 if (!retry_send())
479 err = 1;
480 }
481
482 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100483 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000484 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100485 _exit(0);
486 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487 }
Simon Kelley16972692006-10-16 20:04:18 +0100488 }
489
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100490 log_err = log_start(ent_pw, err_pipe[1]);
491
Simon Kelley28866e92011-02-14 20:19:14 +0000492 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100493 {
494 /* open stdout etc to /dev/null */
495 int nullfd = open("/dev/null", O_RDWR);
496 dup2(nullfd, STDOUT_FILENO);
497 dup2(nullfd, STDERR_FILENO);
498 dup2(nullfd, STDIN_FILENO);
499 close(nullfd);
500 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100501
Simon Kelley1a6bca82008-07-11 11:11:42 +0100502 /* if we are to run scripts, we need to fork a helper before dropping root. */
503 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000504#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000505 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100506 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
507#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100508
Simon Kelley28866e92011-02-14 20:19:14 +0000509 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100510 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100511 int bad_capabilities = 0;
512 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100513
Simon Kelley1a6bca82008-07-11 11:11:42 +0100514 /* remove all supplimentary groups */
515 if (gp &&
516 (setgroups(0, &dummy) == -1 ||
517 setgid(gp->gr_gid) == -1))
518 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000519 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100520 _exit(0);
521 }
522
Simon Kelley7cebd202006-05-06 14:13:33 +0100523 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100524 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100525#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100526 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100527 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100528 ports because of DAD, or we're doing it dynamically,
529 we need CAP_NET_BIND_SERVICE too. */
530 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100531 data->effective = data->permitted = data->inheritable =
532 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
533 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
534 else
535 data->effective = data->permitted = data->inheritable =
536 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100537
Simon Kelley16972692006-10-16 20:04:18 +0100538 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000539 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100540 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100541
Simon Kelley7622fc02009-06-04 20:32:05 +0100542#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000543 /* http://developers.sun.com/solaris/articles/program_privileges.html */
544 priv_set_t *priv_set;
545
546 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
547 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
548 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
549 bad_capabilities = errno;
550
551 if (priv_set && bad_capabilities == 0)
552 {
553 priv_inverse(priv_set);
554
555 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
556 bad_capabilities = errno;
557 }
558
559 if (priv_set)
560 priv_freeset(priv_set);
561
Simon Kelley824af852008-02-12 20:43:05 +0000562#endif
563
Simon Kelley1a6bca82008-07-11 11:11:42 +0100564 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100565 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000566 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100567 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100568 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100569
570 /* finally drop root */
571 if (setuid(ent_pw->pw_uid) == -1)
572 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000573 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100574 _exit(0);
575 }
576
577#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100578 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100579 data->effective = data->permitted =
580 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
581 else
582 data->effective = data->permitted =
583 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100584 data->inheritable = 0;
585
586 /* lose the setuid and setgid capbilities */
587 if (capset(hdr, data) == -1)
588 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000589 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100590 _exit(0);
591 }
592#endif
593
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594 }
Simon Kelley849a8352006-06-09 21:02:31 +0100595 }
Simon Kelley16972692006-10-16 20:04:18 +0100596
Simon Kelley16972692006-10-16 20:04:18 +0100597#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000598 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000599 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100600#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100601
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100602#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100603 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100604 {
605 DIR *dir;
606 struct tftp_prefix *p;
607
608 if (daemon->tftp_prefix)
609 {
610 if (!((dir = opendir(daemon->tftp_prefix))))
611 {
612 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
613 _exit(0);
614 }
615 closedir(dir);
616 }
617
618 for (p = daemon->if_prefix; p; p = p->next)
619 {
620 if (!((dir = opendir(p->prefix))))
621 {
622 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
623 _exit(0);
624 }
625 closedir(dir);
626 }
627 }
628#endif
629
Simon Kelley824af852008-02-12 20:43:05 +0000630 if (daemon->port == 0)
631 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
632 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100633 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000634 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100635 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100636
Simon Kelleyf2621c72007-04-29 19:47:21 +0100637 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100638
Simon Kelley3d8df262005-08-29 12:19:27 +0100639#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000640 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100641 {
642 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100643 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100644 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100645 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100646 }
647#endif
648
Simon Kelley1a6bca82008-07-11 11:11:42 +0100649 if (log_err != 0)
650 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
651 daemon->log_file, strerror(log_err));
652
Simon Kelleyde379512004-06-22 20:23:33 +0100653 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100654 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100655
Simon Kelleyf7029f52013-11-21 15:09:09 +0000656 if (option_bool(OPT_NOWILD))
657 warn_bound_listeners();
658
659 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100660
Simon Kelley28866e92011-02-14 20:19:14 +0000661 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000662 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
663 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100664 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100665
Simon Kelley28866e92011-02-14 20:19:14 +0000666 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100667 {
668 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100669 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100670 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000671 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100672 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100673 }
674
Simon Kelleyf2621c72007-04-29 19:47:21 +0100675 if (daemon->max_logs != 0)
676 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000677
Simon Kelleyf2621c72007-04-29 19:47:21 +0100678
Simon Kelley7622fc02009-06-04 20:32:05 +0100679#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000680 for (context = daemon->dhcp; context; context = context->next)
681 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100682
Simon Kelleyff7eea22013-09-04 18:01:38 +0100683 for (relay = daemon->relay4; relay; relay = relay->next)
684 log_relay(AF_INET, relay);
685
Simon Kelley1f776932012-12-16 19:46:08 +0000686# ifdef HAVE_DHCP6
687 for (context = daemon->dhcp6; context; context = context->next)
688 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000689
Simon Kelleyff7eea22013-09-04 18:01:38 +0100690 for (relay = daemon->relay6; relay; relay = relay->next)
691 log_relay(AF_INET6, relay);
692
Simon Kelley1f776932012-12-16 19:46:08 +0000693 if (daemon->doing_dhcp6 || daemon->doing_ra)
694 dhcp_construct_contexts(now);
695
696 if (option_bool(OPT_RA))
697 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
698# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000699
Simon Kelley3b3f4412013-10-11 16:33:28 +0100700# ifdef HAVE_LINUX_NETWORK
701 if (did_bind)
702 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
703# endif
704
Simon Kelley8445f5d2012-12-17 21:54:08 +0000705 /* after dhcp_contruct_contexts */
706 if (daemon->dhcp || daemon->doing_dhcp6)
707 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000708#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000709
Simon Kelley832af0b2007-01-21 20:01:28 +0000710#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100711 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000712 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000713#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100714 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000715 max_fd = FD_SETSIZE;
716#endif
717
Simon Kelley7622fc02009-06-04 20:32:05 +0100718 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100719 daemon->tftp_prefix ? _("root is ") : _("enabled"),
720 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000721 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100722
Simon Kelley832af0b2007-01-21 20:01:28 +0000723 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100724 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000725 a single file will be sent to may clients (the file only needs
726 one fd). */
727
728 max_fd -= 30; /* use other than TFTP */
729
730 if (max_fd < 0)
731 max_fd = 5;
732 else if (max_fd < 100)
733 max_fd = max_fd/2;
734 else
735 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000736
737 /* if we have to use a limited range of ports,
738 that will limit the number of transfers */
739 if (daemon->start_tftp_port != 0 &&
740 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
741 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000742
743 if (daemon->tftp_max > max_fd)
744 {
745 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100746 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100747 _("restricting maximum simultaneous TFTP transfers to %d"),
748 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000749 }
750 }
751#endif
752
Simon Kelley1a6bca82008-07-11 11:11:42 +0100753 /* finished start-up - release original process */
754 if (err_pipe[1] != -1)
755 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000756
Simon Kelley824af852008-02-12 20:43:05 +0000757 if (daemon->port != 0)
758 check_servers();
759
Simon Kelley7cebd202006-05-06 14:13:33 +0100760 pid = getpid();
761
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100762 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000763 {
Simon Kelley16972692006-10-16 20:04:18 +0100764 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100765 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100766 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000767
768 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100769 FD_ZERO(&wset);
770 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000771
Simon Kelley16972692006-10-16 20:04:18 +0100772 /* if we are out of resources, find how long we have to wait
773 for some to come free, we'll loop around then and restart
774 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100775 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100776 {
777 t.tv_usec = 0;
778 tp = &t;
779 }
780
Simon Kelley832af0b2007-01-21 20:01:28 +0000781 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
782 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000783 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784 {
Simon Kelley16972692006-10-16 20:04:18 +0100785 t.tv_sec = 0;
786 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100787 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000788 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100789 /* Wake every second whilst waiting for DAD to complete */
790 else if (is_dad_listeners())
791 {
792 t.tv_sec = 1;
793 t.tv_usec = 0;
794 tp = &t;
795 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100796
Simon Kelley832af0b2007-01-21 20:01:28 +0000797#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100798 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100799#endif
800
Simon Kelley7622fc02009-06-04 20:32:05 +0100801#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100802 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100803 {
804 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100805 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000806 if (daemon->pxefd != -1)
807 {
808 FD_SET(daemon->pxefd, &rset);
809 bump_maxfd(daemon->pxefd, &maxfd);
810 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100811 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100812#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100813
Simon Kelley52b92f42012-01-22 16:05:15 +0000814#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100815 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000816 {
817 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000818 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000819 }
820
Simon Kelley1f776932012-12-16 19:46:08 +0000821 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000822 {
823 FD_SET(daemon->icmp6fd, &rset);
824 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000825 }
826#endif
827
Simon Kelley1ee9be42013-12-09 16:50:19 +0000828#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100829 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100830 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000831#elif defined(HAVE_BSD_NETWORK)
832 FD_SET(daemon->routefd, &rset);
833 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100834#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000835
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100836 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100837 bump_maxfd(piperead, &maxfd);
838
Simon Kelley7622fc02009-06-04 20:32:05 +0100839#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100840# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100841 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100842
Simon Kelleya9530962012-03-20 22:07:35 +0000843# ifdef HAVE_TFTP
844 while (helper_buf_empty() && do_tftp_script_run());
845# endif
846
Simon Kelley16972692006-10-16 20:04:18 +0100847 if (!helper_buf_empty())
848 {
849 FD_SET(daemon->helperfd, &wset);
850 bump_maxfd(daemon->helperfd, &maxfd);
851 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100852# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853 /* need this for other side-effects */
854 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000855
856# ifdef HAVE_TFTP
857 while (do_tftp_script_run());
858# endif
859
Simon Kelley7622fc02009-06-04 20:32:05 +0100860# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100861#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100862
Simon Kelleyf2621c72007-04-29 19:47:21 +0100863 /* must do this just before select(), when we know no
864 more calls to my_syslog() can occur */
865 set_log_writer(&wset, &maxfd);
866
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100867 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
868 {
869 /* otherwise undefined after error */
870 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
871 }
872
873 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000874
Simon Kelleyf2621c72007-04-29 19:47:21 +0100875 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100876
877 /* prime. */
878 enumerate_interfaces(1);
879
Simon Kelley74c95c22011-10-19 09:33:39 +0100880 /* Check the interfaces to see if any have exited DAD state
881 and if so, bind the address. */
882 if (is_dad_listeners())
883 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100884 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100885 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
886 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100887 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100888 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100889
Simon Kelley1ee9be42013-12-09 16:50:19 +0000890#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100891 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000892 netlink_multicast(now);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000893#elif defined(HAVE_BSD_NETWORK)
894 if (FD_ISSET(daemon->routefd, &rset))
895 route_sock(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100896#endif
897
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100899 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000900 if (daemon->last_resolv == 0 ||
901 difftime(now, daemon->last_resolv) > 1.0 ||
902 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000903 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100904 /* poll_resolv doesn't need to reload first time through, since
905 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100906
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100907 poll_resolv(0, daemon->last_resolv != 0, now);
908 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100910
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100911 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100912 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100913
Simon Kelley3d8df262005-08-29 12:19:27 +0100914#ifdef HAVE_DBUS
915 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000916 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100917 {
918 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100919 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100920 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100921 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100922 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100923 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100924 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100925#endif
Simon Kelley824af852008-02-12 20:43:05 +0000926
Simon Kelley5aabfc72007-08-29 11:24:47 +0100927 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000928
929#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000931#endif
932
Simon Kelley7622fc02009-06-04 20:32:05 +0100933#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100934 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000935 {
936 if (FD_ISSET(daemon->dhcpfd, &rset))
937 dhcp_packet(now, 0);
938 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
939 dhcp_packet(now, 1);
940 }
Simon Kelley16972692006-10-16 20:04:18 +0100941
Simon Kelley52b92f42012-01-22 16:05:15 +0000942#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100943 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100944 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000945
Simon Kelley1f776932012-12-16 19:46:08 +0000946 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
947 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000948#endif
949
Simon Kelley1f15b812009-10-13 17:49:32 +0100950# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100951 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100952 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100953# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100954#endif
955
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000956 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000957}
958
Simon Kelley3be34542004-09-11 19:12:13 +0100959static void sig_handler(int sig)
960{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100961 if (pid == 0)
962 {
Simon Kelley16972692006-10-16 20:04:18 +0100963 /* ignore anything other than TERM during startup
964 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100965 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100966 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100967 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100968 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100969 {
Simon Kelley16972692006-10-16 20:04:18 +0100970 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100971 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100972 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100973 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100974 else
975 {
976 /* master process */
977 int event, errsave = errno;
978
979 if (sig == SIGHUP)
980 event = EVENT_RELOAD;
981 else if (sig == SIGCHLD)
982 event = EVENT_CHILD;
983 else if (sig == SIGALRM)
984 event = EVENT_ALARM;
985 else if (sig == SIGTERM)
986 event = EVENT_TERM;
987 else if (sig == SIGUSR1)
988 event = EVENT_DUMP;
989 else if (sig == SIGUSR2)
990 event = EVENT_REOPEN;
991 else
992 return;
993
Simon Kelleyc72daea2012-01-05 21:33:27 +0000994 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100995 errno = errsave;
996 }
Simon Kelley3be34542004-09-11 19:12:13 +0100997}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000998
Simon Kelley353ae4d2012-03-19 20:07:51 +0000999/* now == 0 -> queue immediate callback */
1000void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001001{
Simon Kelley884a6df2012-03-20 16:20:22 +00001002 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001003 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001004 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1005 if ((now == 0 || difftime(event, now) <= 0.0))
1006 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1007 else
1008 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001009 }
Simon Kelley741c2952012-02-25 13:09:18 +00001010}
1011
Simon Kelleyc72daea2012-01-05 21:33:27 +00001012void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001013{
1014 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001015 struct iovec iov[2];
1016
Simon Kelley5aabfc72007-08-29 11:24:47 +01001017 ev.event = event;
1018 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001019 ev.msg_sz = msg ? strlen(msg) : 0;
1020
1021 iov[0].iov_base = &ev;
1022 iov[0].iov_len = sizeof(ev);
1023 iov[1].iov_base = msg;
1024 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001025
1026 /* error pipe, debug mode. */
1027 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001028 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001029 else
1030 /* pipe is non-blocking and struct event_desc is smaller than
1031 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001032 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001033}
Simon Kelley3d8df262005-08-29 12:19:27 +01001034
Simon Kelleyc72daea2012-01-05 21:33:27 +00001035/* NOTE: the memory used to return msg is leaked: use msgs in events only
1036 to describe fatal errors. */
1037static int read_event(int fd, struct event_desc *evp, char **msg)
1038{
1039 char *buf;
1040
1041 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1042 return 0;
1043
1044 *msg = NULL;
1045
1046 if (evp->msg_sz != 0 &&
1047 (buf = malloc(evp->msg_sz + 1)) &&
1048 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1049 {
1050 buf[evp->msg_sz] = 0;
1051 *msg = buf;
1052 }
1053
1054 return 1;
1055}
1056
1057static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001058{
1059 errno = ev->data;
1060
1061 switch (ev->event)
1062 {
1063 case EVENT_DIE:
1064 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001065
1066 case EVENT_FORK_ERR:
1067 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001068
1069 case EVENT_PIPE_ERR:
1070 die(_("failed to create helper: %s"), NULL, EC_MISC);
1071
1072 case EVENT_CAP_ERR:
1073 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1074
1075 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001076 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001077
1078 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001079 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001080
1081 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001082 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001083
1084 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001085 die(_("cannot open log %s: %s"), msg, EC_FILE);
1086
1087 case EVENT_LUA_ERR:
1088 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001089
1090 case EVENT_TFTP_ERR:
1091 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001092 }
1093}
1094
Simon Kelley5aabfc72007-08-29 11:24:47 +01001095static void async_event(int pipe, time_t now)
1096{
1097 pid_t p;
1098 struct event_desc ev;
1099 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001100 char *msg;
1101
1102 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1103 to describe fatal errors. */
1104
1105 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001106 switch (ev.event)
1107 {
1108 case EVENT_RELOAD:
1109 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001110 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001111 {
1112 reload_servers(daemon->resolv_files->name);
1113 check_servers();
1114 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001115#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001116 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001117#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001118 break;
1119
1120 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001121 if (daemon->port != 0)
1122 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001123 break;
1124
1125 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001126#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001127 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001128 {
1129 lease_prune(NULL, now);
1130 lease_update_file(now);
1131 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001132#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001133 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001134 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1135 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001136#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001137#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001138 break;
1139
1140 case EVENT_CHILD:
1141 /* See Stevens 5.10 */
1142 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1143 if (p == -1)
1144 {
1145 if (errno != EINTR)
1146 break;
1147 }
1148 else
1149 for (i = 0 ; i < MAX_PROCS; i++)
1150 if (daemon->tcp_pids[i] == p)
1151 daemon->tcp_pids[i] = 0;
1152 break;
1153
1154 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001155 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001156 break;
1157
1158 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001159 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001160 break;
1161
1162 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001163 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1164 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001165 break;
1166
Simon Kelley1a6bca82008-07-11 11:11:42 +01001167 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001168 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001169 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001170 case EVENT_LUA_ERR:
1171 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001172 break;
1173
Simon Kelley5aabfc72007-08-29 11:24:47 +01001174 case EVENT_REOPEN:
1175 /* Note: this may leave TCP-handling processes with the old file still open.
1176 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1177 we leave them logging to the old file. */
1178 if (daemon->log_file != NULL)
1179 log_reopen(daemon->log_file);
1180 break;
1181
1182 case EVENT_TERM:
1183 /* Knock all our children on the head. */
1184 for (i = 0; i < MAX_PROCS; i++)
1185 if (daemon->tcp_pids[i] != 0)
1186 kill(daemon->tcp_pids[i], SIGALRM);
1187
Simon Kelleyc72daea2012-01-05 21:33:27 +00001188#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001189 /* handle pending lease transitions */
1190 if (daemon->helperfd != -1)
1191 {
1192 /* block in writes until all done */
1193 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1194 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1195 do {
1196 helper_write();
1197 } while (!helper_buf_empty() || do_script_run(now));
1198 close(daemon->helperfd);
1199 }
1200#endif
1201
1202 if (daemon->lease_stream)
1203 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001204
1205 if (daemon->runfile)
1206 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001207
1208 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1209 flush_log();
1210 exit(EC_GOOD);
1211 }
1212}
1213
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001214void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001215{
1216 struct resolvc *res, *latest;
1217 struct stat statbuf;
1218 time_t last_change = 0;
1219 /* There may be more than one possible file.
1220 Go through and find the one which changed _last_.
1221 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001222
Simon Kelley28866e92011-02-14 20:19:14 +00001223 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001224 return;
1225
Simon Kelley5aabfc72007-08-29 11:24:47 +01001226 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1227 if (stat(res->name, &statbuf) == -1)
1228 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001229 if (force)
1230 {
1231 res->mtime = 0;
1232 continue;
1233 }
1234
Simon Kelley5aabfc72007-08-29 11:24:47 +01001235 if (!res->logged)
1236 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1237 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001238
1239 if (res->mtime != 0)
1240 {
1241 /* existing file evaporated, force selection of the latest
1242 file even if its mtime hasn't changed since we last looked */
1243 poll_resolv(1, do_reload, now);
1244 return;
1245 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001246 }
1247 else
1248 {
1249 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001250 if (force || (statbuf.st_mtime != res->mtime))
1251 {
1252 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001253 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1254 {
1255 last_change = statbuf.st_mtime;
1256 latest = res;
1257 }
1258 }
1259 }
1260
1261 if (latest)
1262 {
1263 static int warned = 0;
1264 if (reload_servers(latest->name))
1265 {
1266 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1267 warned = 0;
1268 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001269 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001270 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001271 }
1272 else
1273 {
1274 latest->mtime = 0;
1275 if (!warned)
1276 {
1277 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1278 warned = 1;
1279 }
1280 }
1281 }
1282}
1283
1284void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001285{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001286 (void)now;
1287
Simon Kelley824af852008-02-12 20:43:05 +00001288 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001289 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001290
Simon Kelley7622fc02009-06-04 20:32:05 +01001291#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001292 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001293 {
Simon Kelley28866e92011-02-14 20:19:14 +00001294 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001295 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001296 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001297 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001298 lease_update_from_configs();
1299 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001300 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001301 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001302#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001303 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001304 /* Not doing DHCP, so no lease system, manage
1305 alarms for ra only */
1306 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001307#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001308#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001309}
1310
Simon Kelley5aabfc72007-08-29 11:24:47 +01001311static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001312{
1313 struct serverfd *serverfdp;
1314 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001315 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001316
1317#ifdef HAVE_TFTP
1318 int tftp = 0;
1319 struct tftp_transfer *transfer;
1320 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1321 {
1322 tftp++;
1323 FD_SET(transfer->sockfd, set);
1324 bump_maxfd(transfer->sockfd, maxfdp);
1325 }
1326#endif
1327
Simon Kelley16972692006-10-16 20:04:18 +01001328 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001329 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001330 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001331
Simon Kelley3be34542004-09-11 19:12:13 +01001332 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1333 {
1334 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001335 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001336 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001337
1338 if (daemon->port != 0 && !daemon->osport)
1339 for (i = 0; i < RANDOM_SOCKS; i++)
1340 if (daemon->randomsocks[i].refcount != 0)
1341 {
1342 FD_SET(daemon->randomsocks[i].fd, set);
1343 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1344 }
1345
Simon Kelley3be34542004-09-11 19:12:13 +01001346 for (listener = daemon->listeners; listener; listener = listener->next)
1347 {
Simon Kelley16972692006-10-16 20:04:18 +01001348 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001349 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001350 {
1351 FD_SET(listener->fd, set);
1352 bump_maxfd(listener->fd, maxfdp);
1353 }
1354
1355 /* death of a child goes through the select loop, so
1356 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001357 if (listener->tcpfd != -1)
1358 for (i = 0; i < MAX_PROCS; i++)
1359 if (daemon->tcp_pids[i] == 0)
1360 {
1361 FD_SET(listener->tcpfd, set);
1362 bump_maxfd(listener->tcpfd, maxfdp);
1363 break;
1364 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001365
Simon Kelley832af0b2007-01-21 20:01:28 +00001366#ifdef HAVE_TFTP
1367 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1368 {
1369 FD_SET(listener->tftpfd, set);
1370 bump_maxfd(listener->tftpfd, maxfdp);
1371 }
1372#endif
1373
1374 }
1375
Simon Kelley16972692006-10-16 20:04:18 +01001376 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001377}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001378
Simon Kelley5aabfc72007-08-29 11:24:47 +01001379static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001380{
1381 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001382 struct listener *listener;
1383 int i;
1384
Simon Kelley832af0b2007-01-21 20:01:28 +00001385 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1386 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001387 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1388
1389 if (daemon->port != 0 && !daemon->osport)
1390 for (i = 0; i < RANDOM_SOCKS; i++)
1391 if (daemon->randomsocks[i].refcount != 0 &&
1392 FD_ISSET(daemon->randomsocks[i].fd, set))
1393 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001394
1395 for (listener = daemon->listeners; listener; listener = listener->next)
1396 {
Simon Kelley824af852008-02-12 20:43:05 +00001397 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001398 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001399
Simon Kelley832af0b2007-01-21 20:01:28 +00001400#ifdef HAVE_TFTP
1401 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001402 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001403#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001404
Simon Kelley824af852008-02-12 20:43:05 +00001405 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001406 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001407 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001408 struct irec *iface = NULL;
1409 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001410 union mysockaddr tcp_addr;
1411 socklen_t tcp_len = sizeof(union mysockaddr);
1412
1413 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001414
Simon Kelley46b06652013-02-04 21:47:59 +00001415 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001416 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001417
Simon Kelley46b06652013-02-04 21:47:59 +00001418 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1419 {
1420 close(confd);
1421 continue;
1422 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001423
1424 /* Make sure that the interface list is up-to-date.
1425
1426 We do this here as we may need the results below, and
1427 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001428
Simon Kelley76dd75d2013-05-23 10:04:25 +01001429 Multiple calls to enumerate_interfaces() per select loop are
1430 inhibited, so calls to it in the child process (which doesn't select())
1431 have no effect. This avoids two processes reading from the same
1432 netlink fd and screwing the pooch entirely.
1433 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001434
Simon Kelley76dd75d2013-05-23 10:04:25 +01001435 enumerate_interfaces(0);
1436
1437 if (option_bool(OPT_NOWILD))
1438 iface = listener->iface; /* May be NULL */
1439 else
1440 {
1441 int if_index;
1442 char intr_name[IF_NAMESIZE];
1443
1444 /* if we can find the arrival interface, check it's one that's allowed */
1445 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1446 indextoname(listener->tcpfd, if_index, intr_name))
1447 {
1448 struct all_addr addr;
1449 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001450#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001451 if (tcp_addr.sa.sa_family == AF_INET6)
1452 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001453#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001454
1455 for (iface = daemon->interfaces; iface; iface = iface->next)
1456 if (iface->index == if_index)
1457 break;
1458
1459 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1460 client_ok = 0;
1461 }
1462
1463 if (option_bool(OPT_CLEVERBIND))
1464 iface = listener->iface; /* May be NULL */
1465 else
1466 {
1467 /* Check for allowed interfaces when binding the wildcard address:
1468 we do this by looking for an interface with the same address as
1469 the local address of the TCP connection, then looking to see if that's
1470 an allowed interface. As a side effect, we get the netmask of the
1471 interface too, for localisation. */
1472
1473 for (iface = daemon->interfaces; iface; iface = iface->next)
1474 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1475 break;
1476
1477 if (!iface)
1478 client_ok = 0;
1479 }
1480 }
1481
Simon Kelley22ce5502013-01-22 13:53:04 +00001482 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001483 {
1484 shutdown(confd, SHUT_RDWR);
1485 close(confd);
1486 }
1487#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001488 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001489 {
1490 if (p != -1)
1491 {
1492 int i;
1493 for (i = 0; i < MAX_PROCS; i++)
1494 if (daemon->tcp_pids[i] == 0)
1495 {
1496 daemon->tcp_pids[i] = p;
1497 break;
1498 }
1499 }
1500 close(confd);
1501 }
1502#endif
1503 else
1504 {
1505 unsigned char *buff;
1506 struct server *s;
1507 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001508 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001509 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001510
1511 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001512 {
1513 netmask = iface->netmask;
1514 auth_dns = iface->dns_auth;
1515 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001516 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001517 {
1518 netmask.s_addr = 0;
1519 auth_dns = 0;
1520 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001521
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001522#ifndef NO_FORK
1523 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1524 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001525 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001526 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001527#endif
1528
Simon Kelley832af0b2007-01-21 20:01:28 +00001529 /* start with no upstream connections. */
1530 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001531 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001532
1533 /* The connected socket inherits non-blocking
1534 attribute from the listening socket.
1535 Reset that here. */
1536 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1537 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1538
Simon Kelley4f7b3042012-11-28 21:27:02 +00001539 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001540
Simon Kelley832af0b2007-01-21 20:01:28 +00001541 shutdown(confd, SHUT_RDWR);
1542 close(confd);
1543
1544 if (buff)
1545 free(buff);
1546
1547 for (s = daemon->servers; s; s = s->next)
1548 if (s->tcpfd != -1)
1549 {
1550 shutdown(s->tcpfd, SHUT_RDWR);
1551 close(s->tcpfd);
1552 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001553#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001554 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001555 {
1556 flush_log();
1557 _exit(0);
1558 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001559#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001560 }
1561 }
1562 }
Simon Kelley3be34542004-09-11 19:12:13 +01001563}
1564
Simon Kelley7622fc02009-06-04 20:32:05 +01001565#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001566int make_icmp_sock(void)
1567{
Simon Kelley7cebd202006-05-06 14:13:33 +01001568 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001569 int zeroopt = 0;
1570
1571 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1572 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001573 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001574 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1575 {
1576 close(fd);
1577 fd = -1;
1578 }
1579 }
1580
1581 return fd;
1582}
1583
Simon Kelley5aabfc72007-08-29 11:24:47 +01001584int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001585{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001586 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001587
1588 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001589 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001590 better not use any resources our caller has in use...)
1591 but we remain deaf to signals or further DHCP packets. */
1592
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001593 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001594 struct sockaddr_in saddr;
1595 struct {
1596 struct ip ip;
1597 struct icmp icmp;
1598 } packet;
1599 unsigned short id = rand16();
1600 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001601 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001602 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001603
Simon Kelley824af852008-02-12 20:43:05 +00001604#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001605 if ((fd = make_icmp_sock()) == -1)
1606 return 0;
1607#else
1608 int opt = 2000;
1609 fd = daemon->dhcp_icmp_fd;
1610 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1611#endif
1612
Simon Kelley3be34542004-09-11 19:12:13 +01001613 saddr.sin_family = AF_INET;
1614 saddr.sin_port = 0;
1615 saddr.sin_addr = addr;
1616#ifdef HAVE_SOCKADDR_SA_LEN
1617 saddr.sin_len = sizeof(struct sockaddr_in);
1618#endif
1619
1620 memset(&packet.icmp, 0, sizeof(packet.icmp));
1621 packet.icmp.icmp_type = ICMP_ECHO;
1622 packet.icmp.icmp_id = id;
1623 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1624 j += ((u16 *)&packet.icmp)[i];
1625 while (j>>16)
1626 j = (j & 0xffff) + (j >> 16);
1627 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1628
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001629 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001630 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1631 retry_send());
1632
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001633 for (now = start = dnsmasq_time();
1634 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001635 {
1636 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001637 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001638 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001639 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001640 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001641
1642 tv.tv_usec = 250000;
1643 tv.tv_sec = 0;
1644
1645 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001646 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001647 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001648 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001649 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001650
1651#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001652 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001653 {
1654 FD_SET(daemon->icmp6fd, &rset);
1655 bump_maxfd(daemon->icmp6fd, &maxfd);
1656 }
1657#endif
1658
Simon Kelleyf2621c72007-04-29 19:47:21 +01001659 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1660 {
1661 FD_ZERO(&rset);
1662 FD_ZERO(&wset);
1663 }
1664
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001665 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001666
1667 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001668 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001669
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001670#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001671 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1672 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001673#endif
1674
Simon Kelley832af0b2007-01-21 20:01:28 +00001675#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001676 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001677#endif
1678
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001679 if (FD_ISSET(fd, &rset) &&
1680 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001681 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1682 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1683 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1684 packet.icmp.icmp_seq == 0 &&
1685 packet.icmp.icmp_id == id)
1686 {
1687 gotreply = 1;
1688 break;
1689 }
1690 }
1691
Simon Kelley824af852008-02-12 20:43:05 +00001692#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001693 close(fd);
1694#else
Simon Kelley3be34542004-09-11 19:12:13 +01001695 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001696 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1697#endif
1698
Simon Kelley3be34542004-09-11 19:12:13 +01001699 return gotreply;
1700}
Simon Kelley7622fc02009-06-04 20:32:05 +01001701#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001702
1703