blob: 25943d7c2b0b108f1a11747061c710e9f355e384 [file] [log] [blame]
Simon Kelley59546082012-01-06 20:02:04 +00001/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelleyc72daea2012-01-05 21:33:27 +000017/* Declare static char *compiler_opts in config.h */
18#define DNSMASQ_COMPILE_OPTS
19
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020#include "dnsmasq.h"
21
Simon Kelley5aabfc72007-08-29 11:24:47 +010022struct daemon *daemon;
23
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static volatile pid_t pid = 0;
25static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley5aabfc72007-08-29 11:24:47 +010027static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
28static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010029static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010030static void async_event(int pipe, time_t now);
Simon Kelleyc72daea2012-01-05 21:33:27 +000031static void fatal_event(struct event_desc *ev, char *msg);
32static int read_event(int fd, struct event_desc *evp, char **msg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000033
34int main (int argc, char **argv)
35{
Simon Kelleyde379512004-06-22 20:23:33 +010036 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000037 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000038 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000039 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010040 int piperead, pipefd[2], err_pipe[2];
41 struct passwd *ent_pw = NULL;
Simon Kelleyc72daea2012-01-05 21:33:27 +000042#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010043 uid_t script_uid = 0;
44 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010045#endif
46 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010047 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010048 char *baduser = NULL;
49 int log_err;
50#if defined(HAVE_LINUX_NETWORK)
51 cap_user_header_t hdr = NULL;
52 cap_user_data_t data = NULL;
53#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010054
Simon Kelley824af852008-02-12 20:43:05 +000055#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000056 setlocale(LC_ALL, "");
57 bindtextdomain("dnsmasq", LOCALEDIR);
58 textdomain("dnsmasq");
59#endif
60
Simon Kelley9e4abcb2004-01-22 19:47:41 +000061 sigact.sa_handler = sig_handler;
62 sigact.sa_flags = 0;
63 sigemptyset(&sigact.sa_mask);
64 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010065 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000066 sigaction(SIGHUP, &sigact, NULL);
67 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000068 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010069 sigaction(SIGCHLD, &sigact, NULL);
70
71 /* ignore SIGPIPE */
72 sigact.sa_handler = SIG_IGN;
73 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074
Simon Kelley5aabfc72007-08-29 11:24:47 +010075 umask(022); /* known umask, create leases and pid files as 0644 */
76
77 read_opts(argc, argv, compile_opts);
78
Simon Kelley3be34542004-09-11 19:12:13 +010079 if (daemon->edns_pktsz < PACKETSZ)
80 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +000081 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
82 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
83 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +010084
Simon Kelleyc72daea2012-01-05 21:33:27 +000085 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
86
Simon Kelley7622fc02009-06-04 20:32:05 +010087#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +010088 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000089 {
Simon Kelley52b92f42012-01-22 16:05:15 +000090 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +010091 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000092 }
Simon Kelley7622fc02009-06-04 20:32:05 +010093#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000094
Simon Kelleya2761752012-01-18 16:07:21 +000095 /* Close any file descriptors we inherited apart from std{in|out|err}
96
97 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
98 otherwise file descriptors we create can end up being 0, 1, or 2
99 and then get accidentally closed later when we make 0, 1, and 2
100 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
101 but it's not guaranteed. By opening /dev/null three times, we
102 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100103 for (i = 0; i < max_fd; i++)
104 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
105 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000106 else
107 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100108
Simon Kelley801ca9a2012-03-06 19:30:17 +0000109#ifndef HAVE_LINUX_NETWORK
110# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000111 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100112 {
113 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000114 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100115 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000116# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100117
118 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100119 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100120 {
121 bind_fallback = 1;
122 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100123 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100124 }
Simon Kelley309331f2006-04-22 15:05:01 +0100125#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100126
Simon Kelley832af0b2007-01-21 20:01:28 +0000127#ifndef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100128 if (option_bool(OPT_TFTP)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100129 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000130#endif
131
Simon Kelley7de060b2011-08-26 17:24:52 +0100132#ifdef HAVE_CONNTRACK
133 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
134 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
135#else
136 if (option_bool(OPT_CONNTRACK))
137 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
138#endif
139
Simon Kelley824af852008-02-12 20:43:05 +0000140#ifdef HAVE_SOLARIS_NETWORK
141 if (daemon->max_logs != 0)
142 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
143#endif
144
Simon Kelley572b41e2011-02-18 18:11:18 +0000145#ifdef __ANDROID__
146 if (daemon->max_logs != 0)
147 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
148#endif
149
Simon Kelley1a6bca82008-07-11 11:11:42 +0100150 rand_init();
151
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100152 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000153
Simon Kelley7622fc02009-06-04 20:32:05 +0100154#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000155 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000156 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100157 /* Note that order matters here, we must call lease_init before
158 creating any file descriptors which shouldn't be leaked
Simon Kelley4cb1b322012-02-06 14:30:41 +0000159 to the lease-script init process. We need to call common_init
160 before lease_init to allocate buffers it uses.*/
161 dhcp_common_init();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100162 lease_init(now);
Simon Kelley843c96b2012-02-27 17:42:38 +0000163
Simon Kelley52b92f42012-01-22 16:05:15 +0000164 if (daemon->dhcp)
165 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000167
168# ifdef HAVE_DHCP6
169 /* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
170 if (daemon->ra_contexts || option_bool(OPT_RA))
171 {
172 /* link the DHCP6 contexts to the ra-only ones so we can traverse them all
173 from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
174 struct dhcp_context *context;
175
176 if (!daemon->ra_contexts)
177 daemon->ra_contexts = daemon->dhcp6;
178 else
179 {
180 for (context = daemon->ra_contexts; context->next; context = context->next);
181 context->next = daemon->dhcp6;
182 }
183 ra_init(now);
184 }
185
186 if (daemon->dhcp6)
187 dhcp6_init();
188
Simon Kelley843c96b2012-02-27 17:42:38 +0000189# endif
190
Simon Kelley7622fc02009-06-04 20:32:05 +0100191#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100192
Simon Kelley801ca9a2012-03-06 19:30:17 +0000193#ifdef HAVE_LINUX_NETWORK
194 /* After lease_init */
195 netlink_init();
Simon Kelley54dd3932012-06-20 11:23:38 +0100196
197 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
198 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000199#endif
200
201#ifdef HAVE_DHCP6
202 /* after netlink_init */
203 if (daemon->ra_contexts || daemon->dhcp6)
204 join_multicast();
205#endif
206
207#ifdef HAVE_DHCP
208 /* after netlink_init */
209 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley8b372702012-03-09 17:45:10 +0000210 lease_find_interfaces(now);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000211#endif
212
Simon Kelley5aabfc72007-08-29 11:24:47 +0100213 if (!enumerate_interfaces())
214 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000215
Simon Kelley54dd3932012-06-20 11:23:38 +0100216 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100217 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100218 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100219
220 if (!option_bool(OPT_CLEVERBIND))
221 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
222 if (if_tmp->name && !if_tmp->used)
223 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100224
225#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
226 /* after enumerate_interfaces() */
227 if (daemon->dhcp)
228 {
229 bindtodevice(daemon->dhcpfd);
230 if (daemon->enable_pxe)
231 bindtodevice(daemon->pxefd);
232 }
233#endif
234
235#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
236 if (daemon->dhcp6)
237 bindtodevice(daemon->dhcp6fd);
238#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100239 }
Simon Kelley28866e92011-02-14 20:19:14 +0000240 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100241 create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100242
Simon Kelley824af852008-02-12 20:43:05 +0000243 if (daemon->port != 0)
244 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100245
Simon Kelley28866e92011-02-14 20:19:14 +0000246 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100247#ifdef HAVE_DBUS
248 {
249 char *err;
250 daemon->dbus = NULL;
251 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100252 if ((err = dbus_init()))
253 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100254 }
255#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100256 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100257#endif
258
Simon Kelley824af852008-02-12 20:43:05 +0000259 if (daemon->port != 0)
260 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100261
Simon Kelleyc72daea2012-01-05 21:33:27 +0000262#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100263 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000264 if ((daemon->dhcp || daemon->dhcp6) &&
265 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000266 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100267 {
268 if ((ent_pw = getpwnam(daemon->scriptuser)))
269 {
270 script_uid = ent_pw->pw_uid;
271 script_gid = ent_pw->pw_gid;
272 }
273 else
274 baduser = daemon->scriptuser;
275 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100276#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000277
Simon Kelley1a6bca82008-07-11 11:11:42 +0100278 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
279 baduser = daemon->username;
280 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
281 baduser = daemon->groupname;
282
283 if (baduser)
284 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
285
286 /* implement group defaults, "dip" if available, or group associated with uid */
287 if (!daemon->group_set && !gp)
288 {
289 if (!(gp = getgrnam(CHGRP)) && ent_pw)
290 gp = getgrgid(ent_pw->pw_gid);
291
292 /* for error message */
293 if (gp)
294 daemon->groupname = gp->gr_name;
295 }
296
297#if defined(HAVE_LINUX_NETWORK)
298 /* determine capability API version here, while we can still
299 call safe_malloc */
300 if (ent_pw && ent_pw->pw_uid != 0)
301 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100302 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100303 hdr = safe_malloc(sizeof(*hdr));
304
Simon Kelley1a6bca82008-07-11 11:11:42 +0100305 /* find version supported by kernel */
306 memset(hdr, 0, sizeof(*hdr));
307 capget(hdr, NULL);
308
309 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
310 {
311 /* if unknown version, use largest supported version (3) */
312 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
313 hdr->version = LINUX_CAPABILITY_VERSION_3;
314 capsize = 2;
315 }
316
317 data = safe_malloc(sizeof(*data) * capsize);
318 memset(data, 0, sizeof(*data) * capsize);
319 }
320#endif
321
Simon Kelley5aabfc72007-08-29 11:24:47 +0100322 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100323 in a race-free manner and another to carry errors to daemon-invoking process */
324 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100325
326 piperead = pipefd[0];
327 pipewrite = pipefd[1];
328 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000329 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100330
331 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100332
Simon Kelley28866e92011-02-14 20:19:14 +0000333 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000334 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000335 /* The following code "daemonizes" the process.
336 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100337
Simon Kelley9e038942008-05-30 20:06:34 +0100338 if (chdir("/") != 0)
339 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
340
Simon Kelley16972692006-10-16 20:04:18 +0100341#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000342 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100343 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100344 pid_t pid;
345
Simon Kelley1a6bca82008-07-11 11:11:42 +0100346 /* pipe to carry errors back to original process.
347 When startup is complete we close this and the process terminates. */
348 safe_pipe(err_pipe, 0);
349
Simon Kelley7622fc02009-06-04 20:32:05 +0100350 if ((pid = fork()) == -1)
351 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000352 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100353
Simon Kelley5aabfc72007-08-29 11:24:47 +0100354 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100355 {
356 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000357 char *msg;
358
Simon Kelley1a6bca82008-07-11 11:11:42 +0100359 /* close our copy of write-end */
360 close(err_pipe[1]);
361
362 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000363 if (read_event(err_pipe[0], &ev, &msg))
364 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365
366 _exit(EC_GOOD);
367 }
368
369 close(err_pipe[0]);
370
371 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100372
373 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100374
375 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000376 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100377
378 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100379 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100380 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000381#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100382
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000383 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100384 if (daemon->runfile)
385 {
386 FILE *pidfile;
387
388 /* only complain if started as root */
389 if ((pidfile = fopen(daemon->runfile, "w")))
390 {
391 fprintf(pidfile, "%d\n", (int) getpid());
392 fclose(pidfile);
393 }
394 else if (getuid() == 0)
395 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000396 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100397 _exit(0);
398 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000399 }
Simon Kelley16972692006-10-16 20:04:18 +0100400 }
401
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100402 log_err = log_start(ent_pw, err_pipe[1]);
403
Simon Kelley28866e92011-02-14 20:19:14 +0000404 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100405 {
406 /* open stdout etc to /dev/null */
407 int nullfd = open("/dev/null", O_RDWR);
408 dup2(nullfd, STDOUT_FILENO);
409 dup2(nullfd, STDERR_FILENO);
410 dup2(nullfd, STDIN_FILENO);
411 close(nullfd);
412 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100413
Simon Kelley1a6bca82008-07-11 11:11:42 +0100414 /* if we are to run scripts, we need to fork a helper before dropping root. */
415 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000416#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000417 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
419#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100420
Simon Kelley28866e92011-02-14 20:19:14 +0000421 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100422 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100423 int bad_capabilities = 0;
424 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100425
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 /* remove all supplimentary groups */
427 if (gp &&
428 (setgroups(0, &dummy) == -1 ||
429 setgid(gp->gr_gid) == -1))
430 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000431 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100432 _exit(0);
433 }
434
Simon Kelley7cebd202006-05-06 14:13:33 +0100435 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100436 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100437#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100438 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100439 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100440 ports because of DAD, or we're doing it dynamically,
441 we need CAP_NET_BIND_SERVICE too. */
442 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100443 data->effective = data->permitted = data->inheritable =
444 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
445 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
446 else
447 data->effective = data->permitted = data->inheritable =
448 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100449
Simon Kelley16972692006-10-16 20:04:18 +0100450 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000451 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100452 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100453
Simon Kelley7622fc02009-06-04 20:32:05 +0100454#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000455 /* http://developers.sun.com/solaris/articles/program_privileges.html */
456 priv_set_t *priv_set;
457
458 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
459 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
460 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
461 bad_capabilities = errno;
462
463 if (priv_set && bad_capabilities == 0)
464 {
465 priv_inverse(priv_set);
466
467 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
468 bad_capabilities = errno;
469 }
470
471 if (priv_set)
472 priv_freeset(priv_set);
473
Simon Kelley824af852008-02-12 20:43:05 +0000474#endif
475
Simon Kelley1a6bca82008-07-11 11:11:42 +0100476 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100477 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000478 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100479 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100480 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481
482 /* finally drop root */
483 if (setuid(ent_pw->pw_uid) == -1)
484 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000485 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100486 _exit(0);
487 }
488
489#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100490 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100491 data->effective = data->permitted =
492 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
493 else
494 data->effective = data->permitted =
495 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100496 data->inheritable = 0;
497
498 /* lose the setuid and setgid capbilities */
499 if (capset(hdr, data) == -1)
500 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000501 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100502 _exit(0);
503 }
504#endif
505
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000506 }
Simon Kelley849a8352006-06-09 21:02:31 +0100507 }
Simon Kelley16972692006-10-16 20:04:18 +0100508
Simon Kelley16972692006-10-16 20:04:18 +0100509#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000510 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000511 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100512#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100513
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100514#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100515 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100516 {
517 DIR *dir;
518 struct tftp_prefix *p;
519
520 if (daemon->tftp_prefix)
521 {
522 if (!((dir = opendir(daemon->tftp_prefix))))
523 {
524 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
525 _exit(0);
526 }
527 closedir(dir);
528 }
529
530 for (p = daemon->if_prefix; p; p = p->next)
531 {
532 if (!((dir = opendir(p->prefix))))
533 {
534 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
535 _exit(0);
536 }
537 closedir(dir);
538 }
539 }
540#endif
541
Simon Kelley824af852008-02-12 20:43:05 +0000542 if (daemon->port == 0)
543 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
544 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100545 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000546 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100547 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100548
Simon Kelleyf2621c72007-04-29 19:47:21 +0100549 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100550
Simon Kelley3d8df262005-08-29 12:19:27 +0100551#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000552 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100553 {
554 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100555 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100556 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100557 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100558 }
559#endif
560
Simon Kelley1a6bca82008-07-11 11:11:42 +0100561 if (log_err != 0)
562 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
563 daemon->log_file, strerror(log_err));
564
Simon Kelleyde379512004-06-22 20:23:33 +0100565 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100566 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100567
Simon Kelley28866e92011-02-14 20:19:14 +0000568 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000569 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
570 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100571 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100572
Simon Kelley28866e92011-02-14 20:19:14 +0000573 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100574 {
575 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100576 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100577 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000578 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100579 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100580 }
581
Simon Kelleyf2621c72007-04-29 19:47:21 +0100582 if (daemon->max_logs != 0)
583 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000584
Simon Kelley843c96b2012-02-27 17:42:38 +0000585 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000586 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100587
Simon Kelley7622fc02009-06-04 20:32:05 +0100588#ifdef HAVE_DHCP
Simon Kelleyc8257542012-03-28 21:15:41 +0100589 if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000590 {
Simon Kelley3be34542004-09-11 19:12:13 +0100591 struct dhcp_context *dhcp_tmp;
Simon Kelley52b92f42012-01-22 16:05:15 +0000592 int family = AF_INET;
593 dhcp_tmp = daemon->dhcp;
594
Simon Kelley3268e902012-01-22 16:15:02 +0000595#ifdef HAVE_DHCP6
Simon Kelley52b92f42012-01-22 16:05:15 +0000596 again:
Simon Kelley3268e902012-01-22 16:15:02 +0000597#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000598 for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100599 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000600 void *start = &dhcp_tmp->start;
601 void *end = &dhcp_tmp->end;
Simon Kelleyc8257542012-03-28 21:15:41 +0100602
Simon Kelley52b92f42012-01-22 16:05:15 +0000603#ifdef HAVE_DHCP6
604 if (family == AF_INET6)
605 {
606 start = &dhcp_tmp->start6;
607 end = &dhcp_tmp->end6;
Simon Kelley30cd9662012-03-25 20:44:38 +0100608 struct in6_addr subnet = dhcp_tmp->start6;
609 setaddr6part(&subnet, 0);
Simon Kelleyc8257542012-03-28 21:15:41 +0100610 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
Simon Kelley52b92f42012-01-22 16:05:15 +0000611 }
612#endif
613
Simon Kelleyc8257542012-03-28 21:15:41 +0100614 if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
615 strcpy(daemon->namebuff, _("prefix deprecated"));
616 else
617 {
618 char *p = daemon->namebuff;
619 p += sprintf(p, _("lease time "));
620 prettyprint_time(p, dhcp_tmp->lease_time);
621 }
622
623 if (daemon->dhcp_buff)
624 inet_ntop(family, start, daemon->dhcp_buff, 256);
625 if (daemon->dhcp_buff3)
626 inet_ntop(family, end, daemon->dhcp_buff3, 256);
Simon Kelley30cd9662012-03-25 20:44:38 +0100627 if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
628 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelley30cd9662012-03-25 20:44:38 +0100629 (dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
Simon Kelleyc8257542012-03-28 21:15:41 +0100630 _("stateless DHCPv6 on %s%.0s%.0s") :
Simon Kelley22407042012-03-27 14:42:48 +0100631 (dhcp_tmp->flags & CONTEXT_STATIC) ?
Simon Kelleyc8257542012-03-28 21:15:41 +0100632 _("DHCP, static leases only on %.0s%s, %s") :
Simon Kelley30cd9662012-03-25 20:44:38 +0100633 (dhcp_tmp->flags & CONTEXT_PROXY) ?
634 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyc8257542012-03-28 21:15:41 +0100635 _("DHCP, IP range %s -- %s, %s"),
Simon Kelley30cd9662012-03-25 20:44:38 +0100636 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
Simon Kelleyc8257542012-03-28 21:15:41 +0100637
Simon Kelley30cd9662012-03-25 20:44:38 +0100638 if (dhcp_tmp->flags & CONTEXT_RA_NAME)
Simon Kelleyc8257542012-03-28 21:15:41 +0100639 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
640 daemon->addrbuff);
641 if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
642 {
643 if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
644 {
645 char *p = daemon->namebuff;
646 p += sprintf(p, _("prefix valid "));
647 prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
648 }
649 my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
650 daemon->addrbuff, daemon->namebuff);
651 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100652 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000653
654#ifdef HAVE_DHCP6
655 if (family == AF_INET)
656 {
657 family = AF_INET6;
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000658 if (daemon->ra_contexts)
659 dhcp_tmp = daemon->ra_contexts;
660 else
661 dhcp_tmp = daemon->dhcp6;
Simon Kelley52b92f42012-01-22 16:05:15 +0000662 goto again;
663 }
664#endif
665
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000666 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100667#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000668
Simon Kelley52b92f42012-01-22 16:05:15 +0000669
Simon Kelley832af0b2007-01-21 20:01:28 +0000670#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100671 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000672 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000673#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100674 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000675 max_fd = FD_SETSIZE;
676#endif
677
Simon Kelley7622fc02009-06-04 20:32:05 +0100678 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100679 daemon->tftp_prefix ? _("root is ") : _("enabled"),
680 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000681 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100682
Simon Kelley832af0b2007-01-21 20:01:28 +0000683 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100684 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000685 a single file will be sent to may clients (the file only needs
686 one fd). */
687
688 max_fd -= 30; /* use other than TFTP */
689
690 if (max_fd < 0)
691 max_fd = 5;
692 else if (max_fd < 100)
693 max_fd = max_fd/2;
694 else
695 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000696
697 /* if we have to use a limited range of ports,
698 that will limit the number of transfers */
699 if (daemon->start_tftp_port != 0 &&
700 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
701 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000702
703 if (daemon->tftp_max > max_fd)
704 {
705 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100706 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100707 _("restricting maximum simultaneous TFTP transfers to %d"),
708 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000709 }
710 }
711#endif
712
Simon Kelley1a6bca82008-07-11 11:11:42 +0100713 /* finished start-up - release original process */
714 if (err_pipe[1] != -1)
715 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000716
Simon Kelley824af852008-02-12 20:43:05 +0000717 if (daemon->port != 0)
718 check_servers();
719
Simon Kelley7cebd202006-05-06 14:13:33 +0100720 pid = getpid();
721
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100722 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000723 {
Simon Kelley16972692006-10-16 20:04:18 +0100724 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100725 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100726 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000727
728 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100729 FD_ZERO(&wset);
730 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000731
Simon Kelley16972692006-10-16 20:04:18 +0100732 /* if we are out of resources, find how long we have to wait
733 for some to come free, we'll loop around then and restart
734 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100735 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100736 {
737 t.tv_usec = 0;
738 tp = &t;
739 }
740
Simon Kelley832af0b2007-01-21 20:01:28 +0000741 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
742 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000743 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000744 {
Simon Kelley16972692006-10-16 20:04:18 +0100745 t.tv_sec = 0;
746 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100747 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000748 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100749 /* Wake every second whilst waiting for DAD to complete */
750 else if (is_dad_listeners())
751 {
752 t.tv_sec = 1;
753 t.tv_usec = 0;
754 tp = &t;
755 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100756
Simon Kelley832af0b2007-01-21 20:01:28 +0000757#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100758 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100759#endif
760
Simon Kelley7622fc02009-06-04 20:32:05 +0100761#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100762 if (daemon->dhcp)
763 {
764 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100765 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000766 if (daemon->pxefd != -1)
767 {
768 FD_SET(daemon->pxefd, &rset);
769 bump_maxfd(daemon->pxefd, &maxfd);
770 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100771 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100772#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100773
Simon Kelley52b92f42012-01-22 16:05:15 +0000774#ifdef HAVE_DHCP6
775 if (daemon->dhcp6)
776 {
777 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000778 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000779 }
780
781 if (daemon->ra_contexts)
782 {
783 FD_SET(daemon->icmp6fd, &rset);
784 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000785 }
786#endif
787
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100788#ifdef HAVE_LINUX_NETWORK
789 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100790 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100791#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100792
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100793 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100794 bump_maxfd(piperead, &maxfd);
795
Simon Kelley7622fc02009-06-04 20:32:05 +0100796#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100797# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100798 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100799
Simon Kelleya9530962012-03-20 22:07:35 +0000800# ifdef HAVE_TFTP
801 while (helper_buf_empty() && do_tftp_script_run());
802# endif
803
Simon Kelley16972692006-10-16 20:04:18 +0100804 if (!helper_buf_empty())
805 {
806 FD_SET(daemon->helperfd, &wset);
807 bump_maxfd(daemon->helperfd, &maxfd);
808 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100809# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100810 /* need this for other side-effects */
811 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000812
813# ifdef HAVE_TFTP
814 while (do_tftp_script_run());
815# endif
816
Simon Kelley7622fc02009-06-04 20:32:05 +0100817# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100818#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100819
Simon Kelleyf2621c72007-04-29 19:47:21 +0100820 /* must do this just before select(), when we know no
821 more calls to my_syslog() can occur */
822 set_log_writer(&wset, &maxfd);
823
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100824 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
825 {
826 /* otherwise undefined after error */
827 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
828 }
829
830 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000831
Simon Kelleyf2621c72007-04-29 19:47:21 +0100832 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100833
834 /* Check the interfaces to see if any have exited DAD state
835 and if so, bind the address. */
836 if (is_dad_listeners())
837 {
838 enumerate_interfaces();
839 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
840 create_bound_listeners(0);
841 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100842
Simon Kelleyc52e1892010-06-07 22:01:39 +0100843#ifdef HAVE_LINUX_NETWORK
844 if (FD_ISSET(daemon->netlinkfd, &rset))
845 netlink_multicast();
846#endif
847
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000848 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100849 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000850 if (daemon->last_resolv == 0 ||
851 difftime(now, daemon->last_resolv) > 1.0 ||
852 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000853 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100854 /* poll_resolv doesn't need to reload first time through, since
855 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100856
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100857 poll_resolv(0, daemon->last_resolv != 0, now);
858 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000859 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100860
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100861 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100862 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100863
Simon Kelley3d8df262005-08-29 12:19:27 +0100864#ifdef HAVE_DBUS
865 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000866 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100867 {
868 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100869 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100870 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100871 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100872 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100873 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100874 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100875#endif
Simon Kelley824af852008-02-12 20:43:05 +0000876
Simon Kelley5aabfc72007-08-29 11:24:47 +0100877 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000878
879#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100880 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000881#endif
882
Simon Kelley7622fc02009-06-04 20:32:05 +0100883#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000884 if (daemon->dhcp)
885 {
886 if (FD_ISSET(daemon->dhcpfd, &rset))
887 dhcp_packet(now, 0);
888 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
889 dhcp_packet(now, 1);
890 }
Simon Kelley16972692006-10-16 20:04:18 +0100891
Simon Kelley52b92f42012-01-22 16:05:15 +0000892#ifdef HAVE_DHCP6
Simon Kelley18c63ef2012-05-21 14:34:15 +0100893 if (daemon->dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
894 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000895
Simon Kelley18c63ef2012-05-21 14:34:15 +0100896 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
897 icmp6_packet();
Simon Kelley52b92f42012-01-22 16:05:15 +0000898#endif
899
Simon Kelley1f15b812009-10-13 17:49:32 +0100900# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100901 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100902 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100903# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100904#endif
905
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000906 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000907}
908
Simon Kelley3be34542004-09-11 19:12:13 +0100909static void sig_handler(int sig)
910{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100911 if (pid == 0)
912 {
Simon Kelley16972692006-10-16 20:04:18 +0100913 /* ignore anything other than TERM during startup
914 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100915 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100916 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100917 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100918 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100919 {
Simon Kelley16972692006-10-16 20:04:18 +0100920 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100921 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100922 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100923 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100924 else
925 {
926 /* master process */
927 int event, errsave = errno;
928
929 if (sig == SIGHUP)
930 event = EVENT_RELOAD;
931 else if (sig == SIGCHLD)
932 event = EVENT_CHILD;
933 else if (sig == SIGALRM)
934 event = EVENT_ALARM;
935 else if (sig == SIGTERM)
936 event = EVENT_TERM;
937 else if (sig == SIGUSR1)
938 event = EVENT_DUMP;
939 else if (sig == SIGUSR2)
940 event = EVENT_REOPEN;
941 else
942 return;
943
Simon Kelleyc72daea2012-01-05 21:33:27 +0000944 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100945 errno = errsave;
946 }
Simon Kelley3be34542004-09-11 19:12:13 +0100947}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000948
Simon Kelley353ae4d2012-03-19 20:07:51 +0000949/* now == 0 -> queue immediate callback */
950void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000951{
Simon Kelley884a6df2012-03-20 16:20:22 +0000952 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000953 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000954 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
955 if ((now == 0 || difftime(event, now) <= 0.0))
956 send_event(pipewrite, EVENT_ALARM, 0, NULL);
957 else
958 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000959 }
Simon Kelley741c2952012-02-25 13:09:18 +0000960}
961
Simon Kelleyc72daea2012-01-05 21:33:27 +0000962void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100963{
964 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000965 struct iovec iov[2];
966
Simon Kelley5aabfc72007-08-29 11:24:47 +0100967 ev.event = event;
968 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000969 ev.msg_sz = msg ? strlen(msg) : 0;
970
971 iov[0].iov_base = &ev;
972 iov[0].iov_len = sizeof(ev);
973 iov[1].iov_base = msg;
974 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100975
976 /* error pipe, debug mode. */
977 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000978 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100979 else
980 /* pipe is non-blocking and struct event_desc is smaller than
981 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000982 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100983}
Simon Kelley3d8df262005-08-29 12:19:27 +0100984
Simon Kelleyc72daea2012-01-05 21:33:27 +0000985/* NOTE: the memory used to return msg is leaked: use msgs in events only
986 to describe fatal errors. */
987static int read_event(int fd, struct event_desc *evp, char **msg)
988{
989 char *buf;
990
991 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
992 return 0;
993
994 *msg = NULL;
995
996 if (evp->msg_sz != 0 &&
997 (buf = malloc(evp->msg_sz + 1)) &&
998 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
999 {
1000 buf[evp->msg_sz] = 0;
1001 *msg = buf;
1002 }
1003
1004 return 1;
1005}
1006
1007static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001008{
1009 errno = ev->data;
1010
1011 switch (ev->event)
1012 {
1013 case EVENT_DIE:
1014 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001015
1016 case EVENT_FORK_ERR:
1017 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001018
1019 case EVENT_PIPE_ERR:
1020 die(_("failed to create helper: %s"), NULL, EC_MISC);
1021
1022 case EVENT_CAP_ERR:
1023 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1024
1025 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001026 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001027
1028 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001029 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001030
1031 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001032 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001033
1034 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001035 die(_("cannot open log %s: %s"), msg, EC_FILE);
1036
1037 case EVENT_LUA_ERR:
1038 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001039
1040 case EVENT_TFTP_ERR:
1041 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001042 }
1043}
1044
Simon Kelley5aabfc72007-08-29 11:24:47 +01001045static void async_event(int pipe, time_t now)
1046{
1047 pid_t p;
1048 struct event_desc ev;
1049 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001050 char *msg;
1051
1052 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1053 to describe fatal errors. */
1054
1055 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001056 switch (ev.event)
1057 {
1058 case EVENT_RELOAD:
1059 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001060 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001061 {
1062 reload_servers(daemon->resolv_files->name);
1063 check_servers();
1064 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001065#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001066 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001067#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001068 break;
1069
1070 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001071 if (daemon->port != 0)
1072 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001073 break;
1074
1075 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001076#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001077 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001078 {
1079 lease_prune(NULL, now);
1080 lease_update_file(now);
1081 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001082#ifdef HAVE_DHCP6
1083 else if (daemon->ra_contexts)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001084 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1085 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001086#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001087#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001088 break;
1089
1090 case EVENT_CHILD:
1091 /* See Stevens 5.10 */
1092 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1093 if (p == -1)
1094 {
1095 if (errno != EINTR)
1096 break;
1097 }
1098 else
1099 for (i = 0 ; i < MAX_PROCS; i++)
1100 if (daemon->tcp_pids[i] == p)
1101 daemon->tcp_pids[i] = 0;
1102 break;
1103
1104 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001105 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001106 break;
1107
1108 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001109 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001110 break;
1111
1112 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001113 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1114 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001115 break;
1116
Simon Kelley1a6bca82008-07-11 11:11:42 +01001117 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001118 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001119 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001120 case EVENT_LUA_ERR:
1121 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001122 break;
1123
Simon Kelley5aabfc72007-08-29 11:24:47 +01001124 case EVENT_REOPEN:
1125 /* Note: this may leave TCP-handling processes with the old file still open.
1126 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1127 we leave them logging to the old file. */
1128 if (daemon->log_file != NULL)
1129 log_reopen(daemon->log_file);
1130 break;
1131
1132 case EVENT_TERM:
1133 /* Knock all our children on the head. */
1134 for (i = 0; i < MAX_PROCS; i++)
1135 if (daemon->tcp_pids[i] != 0)
1136 kill(daemon->tcp_pids[i], SIGALRM);
1137
Simon Kelleyc72daea2012-01-05 21:33:27 +00001138#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001139 /* handle pending lease transitions */
1140 if (daemon->helperfd != -1)
1141 {
1142 /* block in writes until all done */
1143 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1144 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1145 do {
1146 helper_write();
1147 } while (!helper_buf_empty() || do_script_run(now));
1148 close(daemon->helperfd);
1149 }
1150#endif
1151
1152 if (daemon->lease_stream)
1153 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001154
1155 if (daemon->runfile)
1156 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001157
1158 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1159 flush_log();
1160 exit(EC_GOOD);
1161 }
1162}
1163
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001164void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001165{
1166 struct resolvc *res, *latest;
1167 struct stat statbuf;
1168 time_t last_change = 0;
1169 /* There may be more than one possible file.
1170 Go through and find the one which changed _last_.
1171 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001172
Simon Kelley28866e92011-02-14 20:19:14 +00001173 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001174 return;
1175
Simon Kelley5aabfc72007-08-29 11:24:47 +01001176 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1177 if (stat(res->name, &statbuf) == -1)
1178 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001179 if (force)
1180 {
1181 res->mtime = 0;
1182 continue;
1183 }
1184
Simon Kelley5aabfc72007-08-29 11:24:47 +01001185 if (!res->logged)
1186 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1187 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001188
1189 if (res->mtime != 0)
1190 {
1191 /* existing file evaporated, force selection of the latest
1192 file even if its mtime hasn't changed since we last looked */
1193 poll_resolv(1, do_reload, now);
1194 return;
1195 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001196 }
1197 else
1198 {
1199 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001200 if (force || (statbuf.st_mtime != res->mtime))
1201 {
1202 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001203 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1204 {
1205 last_change = statbuf.st_mtime;
1206 latest = res;
1207 }
1208 }
1209 }
1210
1211 if (latest)
1212 {
1213 static int warned = 0;
1214 if (reload_servers(latest->name))
1215 {
1216 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1217 warned = 0;
1218 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001219 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001220 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001221 }
1222 else
1223 {
1224 latest->mtime = 0;
1225 if (!warned)
1226 {
1227 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1228 warned = 1;
1229 }
1230 }
1231 }
1232}
1233
1234void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001235{
Simon Kelley824af852008-02-12 20:43:05 +00001236 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001237 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001238
Simon Kelley7622fc02009-06-04 20:32:05 +01001239#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001240 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001241 {
Simon Kelley28866e92011-02-14 20:19:14 +00001242 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001243 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001244 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001245 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +00001246 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001247 lease_update_from_configs();
1248 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001249 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001250 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001251#ifdef HAVE_DHCP6
1252 else if (daemon->ra_contexts)
Simon Kelley2021c662012-05-07 16:43:21 +01001253 /* Not doing DHCP, so no lease system, manage
1254 alarms for ra only */
1255 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001256#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001257#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001258}
1259
Simon Kelley5aabfc72007-08-29 11:24:47 +01001260static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001261{
1262 struct serverfd *serverfdp;
1263 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001264 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001265
1266#ifdef HAVE_TFTP
1267 int tftp = 0;
1268 struct tftp_transfer *transfer;
1269 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1270 {
1271 tftp++;
1272 FD_SET(transfer->sockfd, set);
1273 bump_maxfd(transfer->sockfd, maxfdp);
1274 }
1275#endif
1276
Simon Kelley16972692006-10-16 20:04:18 +01001277 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001278 if (daemon->port != 0)
1279 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001280
Simon Kelley3be34542004-09-11 19:12:13 +01001281 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1282 {
1283 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001284 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001285 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001286
1287 if (daemon->port != 0 && !daemon->osport)
1288 for (i = 0; i < RANDOM_SOCKS; i++)
1289 if (daemon->randomsocks[i].refcount != 0)
1290 {
1291 FD_SET(daemon->randomsocks[i].fd, set);
1292 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1293 }
1294
Simon Kelley3be34542004-09-11 19:12:13 +01001295 for (listener = daemon->listeners; listener; listener = listener->next)
1296 {
Simon Kelley16972692006-10-16 20:04:18 +01001297 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001298 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001299 {
1300 FD_SET(listener->fd, set);
1301 bump_maxfd(listener->fd, maxfdp);
1302 }
1303
1304 /* death of a child goes through the select loop, so
1305 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001306 if (listener->tcpfd != -1)
1307 for (i = 0; i < MAX_PROCS; i++)
1308 if (daemon->tcp_pids[i] == 0)
1309 {
1310 FD_SET(listener->tcpfd, set);
1311 bump_maxfd(listener->tcpfd, maxfdp);
1312 break;
1313 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001314
Simon Kelley832af0b2007-01-21 20:01:28 +00001315#ifdef HAVE_TFTP
1316 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1317 {
1318 FD_SET(listener->tftpfd, set);
1319 bump_maxfd(listener->tftpfd, maxfdp);
1320 }
1321#endif
1322
1323 }
1324
Simon Kelley16972692006-10-16 20:04:18 +01001325 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001326}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001327
Simon Kelley5aabfc72007-08-29 11:24:47 +01001328static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001329{
1330 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001331 struct listener *listener;
1332 int i;
1333
Simon Kelley832af0b2007-01-21 20:01:28 +00001334 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1335 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001336 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1337
1338 if (daemon->port != 0 && !daemon->osport)
1339 for (i = 0; i < RANDOM_SOCKS; i++)
1340 if (daemon->randomsocks[i].refcount != 0 &&
1341 FD_ISSET(daemon->randomsocks[i].fd, set))
1342 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001343
1344 for (listener = daemon->listeners; listener; listener = listener->next)
1345 {
Simon Kelley824af852008-02-12 20:43:05 +00001346 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001347 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001348
Simon Kelley832af0b2007-01-21 20:01:28 +00001349#ifdef HAVE_TFTP
1350 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001351 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001352#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001353
Simon Kelley824af852008-02-12 20:43:05 +00001354 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001355 {
1356 int confd;
1357 struct irec *iface = NULL;
1358 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001359 union mysockaddr tcp_addr;
1360 socklen_t tcp_len = sizeof(union mysockaddr);
1361
1362 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001363
Simon Kelley52d4abf2012-03-21 21:39:48 +00001364 if (confd == -1 ||
1365 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001366 continue;
1367
Simon Kelley54dd3932012-06-20 11:23:38 +01001368 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley52d4abf2012-03-21 21:39:48 +00001369 iface = listener->iface; /* May be NULL */
Simon Kelley832af0b2007-01-21 20:01:28 +00001370 else
1371 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001372 /* Check for allowed interfaces when binding the wildcard address:
1373 we do this by looking for an interface with the same address as
1374 the local address of the TCP connection, then looking to see if that's
1375 an allowed interface. As a side effect, we get the netmask of the
1376 interface too, for localisation. */
1377
1378 /* interface may be new since startup */
Simon Kelley52d4abf2012-03-21 21:39:48 +00001379 if (enumerate_interfaces())
Simon Kelley832af0b2007-01-21 20:01:28 +00001380 for (iface = daemon->interfaces; iface; iface = iface->next)
1381 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1382 break;
1383 }
1384
Simon Kelley54dd3932012-06-20 11:23:38 +01001385 if (!iface && !(option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001386 {
1387 shutdown(confd, SHUT_RDWR);
1388 close(confd);
1389 }
1390#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001391 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001392 {
1393 if (p != -1)
1394 {
1395 int i;
1396 for (i = 0; i < MAX_PROCS; i++)
1397 if (daemon->tcp_pids[i] == 0)
1398 {
1399 daemon->tcp_pids[i] = p;
1400 break;
1401 }
1402 }
1403 close(confd);
1404 }
1405#endif
1406 else
1407 {
1408 unsigned char *buff;
1409 struct server *s;
1410 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001411 struct in_addr netmask;
1412
1413 if (iface)
1414 netmask = iface->netmask;
1415 else
1416 netmask.s_addr = 0;
1417
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001418#ifndef NO_FORK
1419 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1420 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001421 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001422 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001423#endif
1424
Simon Kelley832af0b2007-01-21 20:01:28 +00001425 /* start with no upstream connections. */
1426 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001427 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001428
1429 /* The connected socket inherits non-blocking
1430 attribute from the listening socket.
1431 Reset that here. */
1432 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1433 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1434
Simon Kelley52d4abf2012-03-21 21:39:48 +00001435 buff = tcp_request(confd, now, &tcp_addr, netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001436
Simon Kelley832af0b2007-01-21 20:01:28 +00001437 shutdown(confd, SHUT_RDWR);
1438 close(confd);
1439
1440 if (buff)
1441 free(buff);
1442
1443 for (s = daemon->servers; s; s = s->next)
1444 if (s->tcpfd != -1)
1445 {
1446 shutdown(s->tcpfd, SHUT_RDWR);
1447 close(s->tcpfd);
1448 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001449#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001450 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001451 {
1452 flush_log();
1453 _exit(0);
1454 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001455#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001456 }
1457 }
1458 }
Simon Kelley3be34542004-09-11 19:12:13 +01001459}
1460
Simon Kelley7622fc02009-06-04 20:32:05 +01001461#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001462int make_icmp_sock(void)
1463{
Simon Kelley7cebd202006-05-06 14:13:33 +01001464 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001465 int zeroopt = 0;
1466
1467 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1468 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001469 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001470 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1471 {
1472 close(fd);
1473 fd = -1;
1474 }
1475 }
1476
1477 return fd;
1478}
1479
Simon Kelley5aabfc72007-08-29 11:24:47 +01001480int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001481{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001482 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001483
1484 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001485 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001486 better not use any resources our caller has in use...)
1487 but we remain deaf to signals or further DHCP packets. */
1488
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001489 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001490 struct sockaddr_in saddr;
1491 struct {
1492 struct ip ip;
1493 struct icmp icmp;
1494 } packet;
1495 unsigned short id = rand16();
1496 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001497 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001498 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001499
Simon Kelley824af852008-02-12 20:43:05 +00001500#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001501 if ((fd = make_icmp_sock()) == -1)
1502 return 0;
1503#else
1504 int opt = 2000;
1505 fd = daemon->dhcp_icmp_fd;
1506 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1507#endif
1508
Simon Kelley3be34542004-09-11 19:12:13 +01001509 saddr.sin_family = AF_INET;
1510 saddr.sin_port = 0;
1511 saddr.sin_addr = addr;
1512#ifdef HAVE_SOCKADDR_SA_LEN
1513 saddr.sin_len = sizeof(struct sockaddr_in);
1514#endif
1515
1516 memset(&packet.icmp, 0, sizeof(packet.icmp));
1517 packet.icmp.icmp_type = ICMP_ECHO;
1518 packet.icmp.icmp_id = id;
1519 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1520 j += ((u16 *)&packet.icmp)[i];
1521 while (j>>16)
1522 j = (j & 0xffff) + (j >> 16);
1523 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1524
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001525 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001526 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1527 retry_send());
1528
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001529 for (now = start = dnsmasq_time();
1530 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001531 {
1532 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001533 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001534 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001535 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001536 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001537
1538 tv.tv_usec = 250000;
1539 tv.tv_sec = 0;
1540
1541 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001542 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001543 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001544 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001545 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001546
1547#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001548 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001549 {
1550 FD_SET(daemon->icmp6fd, &rset);
1551 bump_maxfd(daemon->icmp6fd, &maxfd);
1552 }
1553#endif
1554
Simon Kelleyf2621c72007-04-29 19:47:21 +01001555 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1556 {
1557 FD_ZERO(&rset);
1558 FD_ZERO(&wset);
1559 }
1560
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001561 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001562
1563 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001564 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001565
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001566#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001567 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001568 icmp6_packet();
1569#endif
1570
Simon Kelley832af0b2007-01-21 20:01:28 +00001571#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001572 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001573#endif
1574
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001575 if (FD_ISSET(fd, &rset) &&
1576 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001577 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1578 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1579 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1580 packet.icmp.icmp_seq == 0 &&
1581 packet.icmp.icmp_id == id)
1582 {
1583 gotreply = 1;
1584 break;
1585 }
1586 }
1587
Simon Kelley824af852008-02-12 20:43:05 +00001588#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001589 close(fd);
1590#else
Simon Kelley3be34542004-09-11 19:12:13 +01001591 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001592 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1593#endif
1594
Simon Kelley3be34542004-09-11 19:12:13 +01001595 return gotreply;
1596}
Simon Kelley7622fc02009-06-04 20:32:05 +01001597#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001598
1599