blob: efe63d131ee6a6d354419a925b48ba294d265d8c [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 Kelley309331f2006-04-22 15:05:01 +0100117#endif
118
Simon Kelley832af0b2007-01-21 20:01:28 +0000119#ifndef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100120 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100121 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000122#endif
123
Simon Kelley7de060b2011-08-26 17:24:52 +0100124#ifdef HAVE_CONNTRACK
125 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
126 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
127#else
128 if (option_bool(OPT_CONNTRACK))
129 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
130#endif
131
Simon Kelley824af852008-02-12 20:43:05 +0000132#ifdef HAVE_SOLARIS_NETWORK
133 if (daemon->max_logs != 0)
134 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
135#endif
136
Simon Kelley572b41e2011-02-18 18:11:18 +0000137#ifdef __ANDROID__
138 if (daemon->max_logs != 0)
139 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
140#endif
141
Simon Kelley1a6bca82008-07-11 11:11:42 +0100142 rand_init();
143
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100144 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000145
Simon Kelley7622fc02009-06-04 20:32:05 +0100146#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000147 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000148 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100149 /* Note that order matters here, we must call lease_init before
150 creating any file descriptors which shouldn't be leaked
Simon Kelley4cb1b322012-02-06 14:30:41 +0000151 to the lease-script init process. We need to call common_init
152 before lease_init to allocate buffers it uses.*/
153 dhcp_common_init();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100154 lease_init(now);
Simon Kelley843c96b2012-02-27 17:42:38 +0000155
Simon Kelley52b92f42012-01-22 16:05:15 +0000156 if (daemon->dhcp)
157 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000158 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000159
160# ifdef HAVE_DHCP6
161 /* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
162 if (daemon->ra_contexts || option_bool(OPT_RA))
163 {
164 /* link the DHCP6 contexts to the ra-only ones so we can traverse them all
165 from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
166 struct dhcp_context *context;
167
168 if (!daemon->ra_contexts)
169 daemon->ra_contexts = daemon->dhcp6;
170 else
171 {
172 for (context = daemon->ra_contexts; context->next; context = context->next);
173 context->next = daemon->dhcp6;
174 }
175 ra_init(now);
176 }
177
178 if (daemon->dhcp6)
179 dhcp6_init();
180
Simon Kelley843c96b2012-02-27 17:42:38 +0000181# endif
182
Simon Kelley7622fc02009-06-04 20:32:05 +0100183#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100184
Simon Kelley801ca9a2012-03-06 19:30:17 +0000185#ifdef HAVE_LINUX_NETWORK
186 /* After lease_init */
187 netlink_init();
188#endif
189
190#ifdef HAVE_DHCP6
191 /* after netlink_init */
192 if (daemon->ra_contexts || daemon->dhcp6)
193 join_multicast();
194#endif
195
196#ifdef HAVE_DHCP
197 /* after netlink_init */
198 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley8b372702012-03-09 17:45:10 +0000199 lease_find_interfaces(now);
Simon Kelley801ca9a2012-03-06 19:30:17 +0000200#endif
201
Simon Kelley5aabfc72007-08-29 11:24:47 +0100202 if (!enumerate_interfaces())
203 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000204
Simon Kelley28866e92011-02-14 20:19:14 +0000205 if (option_bool(OPT_NOWILD))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100206 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100207 create_bound_listeners(1);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100208
209 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
210 if (if_tmp->name && !if_tmp->used)
211 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
212
213 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
214 if (!if_tmp->used)
215 {
216 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
217 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
218 }
219 }
Simon Kelley28866e92011-02-14 20:19:14 +0000220 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100221 create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100222
Simon Kelley824af852008-02-12 20:43:05 +0000223 if (daemon->port != 0)
224 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100225
Simon Kelley28866e92011-02-14 20:19:14 +0000226 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100227#ifdef HAVE_DBUS
228 {
229 char *err;
230 daemon->dbus = NULL;
231 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100232 if ((err = dbus_init()))
233 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100234 }
235#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100236 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100237#endif
238
Simon Kelley824af852008-02-12 20:43:05 +0000239 if (daemon->port != 0)
240 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100241
Simon Kelleyc72daea2012-01-05 21:33:27 +0000242#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100243 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000244 if ((daemon->dhcp || daemon->dhcp6) &&
245 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000246 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100247 {
248 if ((ent_pw = getpwnam(daemon->scriptuser)))
249 {
250 script_uid = ent_pw->pw_uid;
251 script_gid = ent_pw->pw_gid;
252 }
253 else
254 baduser = daemon->scriptuser;
255 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100256#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000257
Simon Kelley1a6bca82008-07-11 11:11:42 +0100258 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
259 baduser = daemon->username;
260 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
261 baduser = daemon->groupname;
262
263 if (baduser)
264 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
265
266 /* implement group defaults, "dip" if available, or group associated with uid */
267 if (!daemon->group_set && !gp)
268 {
269 if (!(gp = getgrnam(CHGRP)) && ent_pw)
270 gp = getgrgid(ent_pw->pw_gid);
271
272 /* for error message */
273 if (gp)
274 daemon->groupname = gp->gr_name;
275 }
276
277#if defined(HAVE_LINUX_NETWORK)
278 /* determine capability API version here, while we can still
279 call safe_malloc */
280 if (ent_pw && ent_pw->pw_uid != 0)
281 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100282 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100283 hdr = safe_malloc(sizeof(*hdr));
284
Simon Kelley1a6bca82008-07-11 11:11:42 +0100285 /* find version supported by kernel */
286 memset(hdr, 0, sizeof(*hdr));
287 capget(hdr, NULL);
288
289 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
290 {
291 /* if unknown version, use largest supported version (3) */
292 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
293 hdr->version = LINUX_CAPABILITY_VERSION_3;
294 capsize = 2;
295 }
296
297 data = safe_malloc(sizeof(*data) * capsize);
298 memset(data, 0, sizeof(*data) * capsize);
299 }
300#endif
301
Simon Kelley5aabfc72007-08-29 11:24:47 +0100302 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100303 in a race-free manner and another to carry errors to daemon-invoking process */
304 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100305
306 piperead = pipefd[0];
307 pipewrite = pipefd[1];
308 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000309 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100310
311 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100312
Simon Kelley28866e92011-02-14 20:19:14 +0000313 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000314 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315 /* The following code "daemonizes" the process.
316 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100317
Simon Kelley9e038942008-05-30 20:06:34 +0100318 if (chdir("/") != 0)
319 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
320
Simon Kelley16972692006-10-16 20:04:18 +0100321#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000322 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100323 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100324 pid_t pid;
325
Simon Kelley1a6bca82008-07-11 11:11:42 +0100326 /* pipe to carry errors back to original process.
327 When startup is complete we close this and the process terminates. */
328 safe_pipe(err_pipe, 0);
329
Simon Kelley7622fc02009-06-04 20:32:05 +0100330 if ((pid = fork()) == -1)
331 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000332 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100333
Simon Kelley5aabfc72007-08-29 11:24:47 +0100334 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100335 {
336 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000337 char *msg;
338
Simon Kelley1a6bca82008-07-11 11:11:42 +0100339 /* close our copy of write-end */
340 close(err_pipe[1]);
341
342 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000343 if (read_event(err_pipe[0], &ev, &msg))
344 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100345
346 _exit(EC_GOOD);
347 }
348
349 close(err_pipe[0]);
350
351 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100352
353 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100354
355 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000356 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100357
358 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100359 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100360 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000361#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100362
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000363 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100364 if (daemon->runfile)
365 {
366 FILE *pidfile;
367
368 /* only complain if started as root */
369 if ((pidfile = fopen(daemon->runfile, "w")))
370 {
371 fprintf(pidfile, "%d\n", (int) getpid());
372 fclose(pidfile);
373 }
374 else if (getuid() == 0)
375 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000376 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100377 _exit(0);
378 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000379 }
Simon Kelley16972692006-10-16 20:04:18 +0100380 }
381
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100382 log_err = log_start(ent_pw, err_pipe[1]);
383
Simon Kelley28866e92011-02-14 20:19:14 +0000384 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100385 {
386 /* open stdout etc to /dev/null */
387 int nullfd = open("/dev/null", O_RDWR);
388 dup2(nullfd, STDOUT_FILENO);
389 dup2(nullfd, STDERR_FILENO);
390 dup2(nullfd, STDIN_FILENO);
391 close(nullfd);
392 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100393
Simon Kelley1a6bca82008-07-11 11:11:42 +0100394 /* if we are to run scripts, we need to fork a helper before dropping root. */
395 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000396#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000397 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100398 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
399#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100400
Simon Kelley28866e92011-02-14 20:19:14 +0000401 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100402 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100403 int bad_capabilities = 0;
404 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100405
Simon Kelley1a6bca82008-07-11 11:11:42 +0100406 /* remove all supplimentary groups */
407 if (gp &&
408 (setgroups(0, &dummy) == -1 ||
409 setgid(gp->gr_gid) == -1))
410 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000411 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100412 _exit(0);
413 }
414
Simon Kelley7cebd202006-05-06 14:13:33 +0100415 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100416 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100417#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100418 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100419 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
420 ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
421 if (is_dad_listeners())
422 data->effective = data->permitted = data->inheritable =
423 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
424 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
425 else
426 data->effective = data->permitted = data->inheritable =
427 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100428
Simon Kelley16972692006-10-16 20:04:18 +0100429 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000430 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100431 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100432
Simon Kelley7622fc02009-06-04 20:32:05 +0100433#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000434 /* http://developers.sun.com/solaris/articles/program_privileges.html */
435 priv_set_t *priv_set;
436
437 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
438 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
439 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
440 bad_capabilities = errno;
441
442 if (priv_set && bad_capabilities == 0)
443 {
444 priv_inverse(priv_set);
445
446 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
447 bad_capabilities = errno;
448 }
449
450 if (priv_set)
451 priv_freeset(priv_set);
452
Simon Kelley824af852008-02-12 20:43:05 +0000453#endif
454
Simon Kelley1a6bca82008-07-11 11:11:42 +0100455 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100456 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000457 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100458 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100459 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100460
461 /* finally drop root */
462 if (setuid(ent_pw->pw_uid) == -1)
463 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000464 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100465 _exit(0);
466 }
467
468#ifdef HAVE_LINUX_NETWORK
Simon Kelley74c95c22011-10-19 09:33:39 +0100469 if (is_dad_listeners())
470 data->effective = data->permitted =
471 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
472 else
473 data->effective = data->permitted =
474 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100475 data->inheritable = 0;
476
477 /* lose the setuid and setgid capbilities */
478 if (capset(hdr, data) == -1)
479 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000480 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481 _exit(0);
482 }
483#endif
484
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000485 }
Simon Kelley849a8352006-06-09 21:02:31 +0100486 }
Simon Kelley16972692006-10-16 20:04:18 +0100487
Simon Kelley16972692006-10-16 20:04:18 +0100488#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000489 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000490 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100491#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100492
Simon Kelley824af852008-02-12 20:43:05 +0000493 if (daemon->port == 0)
494 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
495 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100496 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000497 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100498 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100499
Simon Kelleyf2621c72007-04-29 19:47:21 +0100500 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100501
Simon Kelley3d8df262005-08-29 12:19:27 +0100502#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000503 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100504 {
505 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100506 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100507 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100508 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100509 }
510#endif
511
Simon Kelley1a6bca82008-07-11 11:11:42 +0100512 if (log_err != 0)
513 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
514 daemon->log_file, strerror(log_err));
515
Simon Kelleyde379512004-06-22 20:23:33 +0100516 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100517 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100518
Simon Kelley28866e92011-02-14 20:19:14 +0000519 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000520 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
521 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100522 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100523
Simon Kelley28866e92011-02-14 20:19:14 +0000524 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100525 {
526 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100527 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100528 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000529 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100530 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100531 }
532
Simon Kelleyf2621c72007-04-29 19:47:21 +0100533 if (daemon->max_logs != 0)
534 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000535
Simon Kelley843c96b2012-02-27 17:42:38 +0000536 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000537 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100538
Simon Kelley7622fc02009-06-04 20:32:05 +0100539#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000540 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000541 {
Simon Kelley3be34542004-09-11 19:12:13 +0100542 struct dhcp_context *dhcp_tmp;
Simon Kelley52b92f42012-01-22 16:05:15 +0000543 int family = AF_INET;
544 dhcp_tmp = daemon->dhcp;
545
Simon Kelley3268e902012-01-22 16:15:02 +0000546#ifdef HAVE_DHCP6
Simon Kelley52b92f42012-01-22 16:05:15 +0000547 again:
Simon Kelley3268e902012-01-22 16:15:02 +0000548#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000549 for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100550 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000551 void *start = &dhcp_tmp->start;
552 void *end = &dhcp_tmp->end;
553
554#ifdef HAVE_DHCP6
555 if (family == AF_INET6)
556 {
557 start = &dhcp_tmp->start6;
558 end = &dhcp_tmp->end6;
559 }
560#endif
561
Simon Kelley0a852542005-03-23 20:28:59 +0000562 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley52b92f42012-01-22 16:05:15 +0000563 inet_ntop(family, start, daemon->dhcp_buff, 256);
564 inet_ntop(family, end, daemon->dhcp_buff3, 256);
Simon Kelley7622fc02009-06-04 20:32:05 +0100565 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100566 (dhcp_tmp->flags & CONTEXT_STATIC) ?
567 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelley801ca9a2012-03-06 19:30:17 +0000568 (dhcp_tmp->flags & CONTEXT_RA_NAME) ?
569 _("router advertisement with DHCPv4-derived names on %.0s%s, lifetime %s") :
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000570 (dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
571 _("router advertisement only on %.0s%s, lifetime %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100572 (dhcp_tmp->flags & CONTEXT_PROXY) ?
573 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100574 _("DHCP, IP range %s -- %s, lease time %s"),
Simon Kelley52b92f42012-01-22 16:05:15 +0000575 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100576 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000577
578#ifdef HAVE_DHCP6
579 if (family == AF_INET)
580 {
581 family = AF_INET6;
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000582 if (daemon->ra_contexts)
583 dhcp_tmp = daemon->ra_contexts;
584 else
585 dhcp_tmp = daemon->dhcp6;
Simon Kelley52b92f42012-01-22 16:05:15 +0000586 goto again;
587 }
588#endif
589
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000590 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100591#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000592
Simon Kelley52b92f42012-01-22 16:05:15 +0000593
Simon Kelley832af0b2007-01-21 20:01:28 +0000594#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100595 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000596 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000597#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100598 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000599 max_fd = FD_SETSIZE;
600#endif
601
Simon Kelley7622fc02009-06-04 20:32:05 +0100602 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100603 daemon->tftp_prefix ? _("root is ") : _("enabled"),
604 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000605 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100606
Simon Kelley832af0b2007-01-21 20:01:28 +0000607 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100608 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000609 a single file will be sent to may clients (the file only needs
610 one fd). */
611
612 max_fd -= 30; /* use other than TFTP */
613
614 if (max_fd < 0)
615 max_fd = 5;
616 else if (max_fd < 100)
617 max_fd = max_fd/2;
618 else
619 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000620
621 /* if we have to use a limited range of ports,
622 that will limit the number of transfers */
623 if (daemon->start_tftp_port != 0 &&
624 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
625 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000626
627 if (daemon->tftp_max > max_fd)
628 {
629 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100630 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100631 _("restricting maximum simultaneous TFTP transfers to %d"),
632 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000633 }
634 }
635#endif
636
Simon Kelley1a6bca82008-07-11 11:11:42 +0100637 /* finished start-up - release original process */
638 if (err_pipe[1] != -1)
639 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000640
Simon Kelley824af852008-02-12 20:43:05 +0000641 if (daemon->port != 0)
642 check_servers();
643
Simon Kelley7cebd202006-05-06 14:13:33 +0100644 pid = getpid();
645
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100646 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000647 {
Simon Kelley16972692006-10-16 20:04:18 +0100648 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100649 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100650 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000651
652 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100653 FD_ZERO(&wset);
654 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000655
Simon Kelley16972692006-10-16 20:04:18 +0100656 /* if we are out of resources, find how long we have to wait
657 for some to come free, we'll loop around then and restart
658 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100659 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100660 {
661 t.tv_usec = 0;
662 tp = &t;
663 }
664
Simon Kelley832af0b2007-01-21 20:01:28 +0000665 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
666 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000667 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000668 {
Simon Kelley16972692006-10-16 20:04:18 +0100669 t.tv_sec = 0;
670 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100671 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000672 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100673 /* Wake every second whilst waiting for DAD to complete */
674 else if (is_dad_listeners())
675 {
676 t.tv_sec = 1;
677 t.tv_usec = 0;
678 tp = &t;
679 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100680
Simon Kelley832af0b2007-01-21 20:01:28 +0000681#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100682 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100683#endif
684
Simon Kelley7622fc02009-06-04 20:32:05 +0100685#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100686 if (daemon->dhcp)
687 {
688 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100689 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000690 if (daemon->pxefd != -1)
691 {
692 FD_SET(daemon->pxefd, &rset);
693 bump_maxfd(daemon->pxefd, &maxfd);
694 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100695 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100696#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100697
Simon Kelley52b92f42012-01-22 16:05:15 +0000698#ifdef HAVE_DHCP6
699 if (daemon->dhcp6)
700 {
701 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000702 bump_maxfd(daemon->dhcp6fd, &maxfd);
703
Simon Kelley843c96b2012-02-27 17:42:38 +0000704 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000705 {
706 FD_SET(daemon->icmp6fd, &rset);
707 bump_maxfd(daemon->icmp6fd, &maxfd);
708 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000709 }
710#endif
711
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100712#ifdef HAVE_LINUX_NETWORK
713 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100714 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100715#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100716
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100717 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100718 bump_maxfd(piperead, &maxfd);
719
Simon Kelley7622fc02009-06-04 20:32:05 +0100720#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100721# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100722 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100723
Simon Kelleya9530962012-03-20 22:07:35 +0000724# ifdef HAVE_TFTP
725 while (helper_buf_empty() && do_tftp_script_run());
726# endif
727
Simon Kelley16972692006-10-16 20:04:18 +0100728 if (!helper_buf_empty())
729 {
730 FD_SET(daemon->helperfd, &wset);
731 bump_maxfd(daemon->helperfd, &maxfd);
732 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100733# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100734 /* need this for other side-effects */
735 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000736
737# ifdef HAVE_TFTP
738 while (do_tftp_script_run());
739# endif
740
Simon Kelley7622fc02009-06-04 20:32:05 +0100741# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100742#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100743
Simon Kelleyf2621c72007-04-29 19:47:21 +0100744 /* must do this just before select(), when we know no
745 more calls to my_syslog() can occur */
746 set_log_writer(&wset, &maxfd);
747
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100748 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
749 {
750 /* otherwise undefined after error */
751 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
752 }
753
754 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000755
Simon Kelleyf2621c72007-04-29 19:47:21 +0100756 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100757
758 /* Check the interfaces to see if any have exited DAD state
759 and if so, bind the address. */
760 if (is_dad_listeners())
761 {
762 enumerate_interfaces();
763 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
764 create_bound_listeners(0);
765 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100766
Simon Kelleyc52e1892010-06-07 22:01:39 +0100767#ifdef HAVE_LINUX_NETWORK
768 if (FD_ISSET(daemon->netlinkfd, &rset))
769 netlink_multicast();
770#endif
771
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000772 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100773 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000774 if (daemon->last_resolv == 0 ||
775 difftime(now, daemon->last_resolv) > 1.0 ||
776 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000777 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100778 /* poll_resolv doesn't need to reload first time through, since
779 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100780
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100781 poll_resolv(0, daemon->last_resolv != 0, now);
782 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000783 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100784
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100785 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100786 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100787
Simon Kelley3d8df262005-08-29 12:19:27 +0100788#ifdef HAVE_DBUS
789 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000790 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100791 {
792 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100793 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100794 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100795 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100796 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100797 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100798 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100799#endif
Simon Kelley824af852008-02-12 20:43:05 +0000800
Simon Kelley5aabfc72007-08-29 11:24:47 +0100801 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000802
803#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100804 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000805#endif
806
Simon Kelley7622fc02009-06-04 20:32:05 +0100807#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000808 if (daemon->dhcp)
809 {
810 if (FD_ISSET(daemon->dhcpfd, &rset))
811 dhcp_packet(now, 0);
812 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
813 dhcp_packet(now, 1);
814 }
Simon Kelley16972692006-10-16 20:04:18 +0100815
Simon Kelley52b92f42012-01-22 16:05:15 +0000816#ifdef HAVE_DHCP6
817 if (daemon->dhcp6)
818 {
819 if (FD_ISSET(daemon->dhcp6fd, &rset))
820 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000821
Simon Kelley843c96b2012-02-27 17:42:38 +0000822 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000823 icmp6_packet();
Simon Kelley52b92f42012-01-22 16:05:15 +0000824 }
825#endif
826
Simon Kelley1f15b812009-10-13 17:49:32 +0100827# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100828 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100829 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100830# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100831#endif
832
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000834}
835
Simon Kelley3be34542004-09-11 19:12:13 +0100836static void sig_handler(int sig)
837{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100838 if (pid == 0)
839 {
Simon Kelley16972692006-10-16 20:04:18 +0100840 /* ignore anything other than TERM during startup
841 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100842 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100843 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100844 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100845 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100846 {
Simon Kelley16972692006-10-16 20:04:18 +0100847 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100848 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100849 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100850 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100851 else
852 {
853 /* master process */
854 int event, errsave = errno;
855
856 if (sig == SIGHUP)
857 event = EVENT_RELOAD;
858 else if (sig == SIGCHLD)
859 event = EVENT_CHILD;
860 else if (sig == SIGALRM)
861 event = EVENT_ALARM;
862 else if (sig == SIGTERM)
863 event = EVENT_TERM;
864 else if (sig == SIGUSR1)
865 event = EVENT_DUMP;
866 else if (sig == SIGUSR2)
867 event = EVENT_REOPEN;
868 else
869 return;
870
Simon Kelleyc72daea2012-01-05 21:33:27 +0000871 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100872 errno = errsave;
873 }
Simon Kelley3be34542004-09-11 19:12:13 +0100874}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000875
Simon Kelley353ae4d2012-03-19 20:07:51 +0000876/* now == 0 -> queue immediate callback */
877void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000878{
Simon Kelley884a6df2012-03-20 16:20:22 +0000879 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000880 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000881 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
882 if ((now == 0 || difftime(event, now) <= 0.0))
883 send_event(pipewrite, EVENT_ALARM, 0, NULL);
884 else
885 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000886 }
Simon Kelley741c2952012-02-25 13:09:18 +0000887}
888
Simon Kelleyc72daea2012-01-05 21:33:27 +0000889void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100890{
891 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000892 struct iovec iov[2];
893
Simon Kelley5aabfc72007-08-29 11:24:47 +0100894 ev.event = event;
895 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000896 ev.msg_sz = msg ? strlen(msg) : 0;
897
898 iov[0].iov_base = &ev;
899 iov[0].iov_len = sizeof(ev);
900 iov[1].iov_base = msg;
901 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100902
903 /* error pipe, debug mode. */
904 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000905 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100906 else
907 /* pipe is non-blocking and struct event_desc is smaller than
908 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000909 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100910}
Simon Kelley3d8df262005-08-29 12:19:27 +0100911
Simon Kelleyc72daea2012-01-05 21:33:27 +0000912/* NOTE: the memory used to return msg is leaked: use msgs in events only
913 to describe fatal errors. */
914static int read_event(int fd, struct event_desc *evp, char **msg)
915{
916 char *buf;
917
918 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
919 return 0;
920
921 *msg = NULL;
922
923 if (evp->msg_sz != 0 &&
924 (buf = malloc(evp->msg_sz + 1)) &&
925 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
926 {
927 buf[evp->msg_sz] = 0;
928 *msg = buf;
929 }
930
931 return 1;
932}
933
934static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100935{
936 errno = ev->data;
937
938 switch (ev->event)
939 {
940 case EVENT_DIE:
941 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100942
943 case EVENT_FORK_ERR:
944 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100945
946 case EVENT_PIPE_ERR:
947 die(_("failed to create helper: %s"), NULL, EC_MISC);
948
949 case EVENT_CAP_ERR:
950 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
951
952 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000953 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100954
955 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000956 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100957
958 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000959 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100960
961 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000962 die(_("cannot open log %s: %s"), msg, EC_FILE);
963
964 case EVENT_LUA_ERR:
965 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100966 }
967}
968
Simon Kelley5aabfc72007-08-29 11:24:47 +0100969static void async_event(int pipe, time_t now)
970{
971 pid_t p;
972 struct event_desc ev;
973 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000974 char *msg;
975
976 /* NOTE: the memory used to return msg is leaked: use msgs in events only
977 to describe fatal errors. */
978
979 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100980 switch (ev.event)
981 {
982 case EVENT_RELOAD:
983 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +0000984 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100985 {
986 reload_servers(daemon->resolv_files->name);
987 check_servers();
988 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100989#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100990 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100991#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100992 break;
993
994 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000995 if (daemon->port != 0)
996 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100997 break;
998
999 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001000#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001001 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001002 {
1003 lease_prune(NULL, now);
1004 lease_update_file(now);
1005 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001006#ifdef HAVE_DHCP6
1007 else if (daemon->ra_contexts)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001008 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1009 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001010#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001011#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001012 break;
1013
1014 case EVENT_CHILD:
1015 /* See Stevens 5.10 */
1016 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1017 if (p == -1)
1018 {
1019 if (errno != EINTR)
1020 break;
1021 }
1022 else
1023 for (i = 0 ; i < MAX_PROCS; i++)
1024 if (daemon->tcp_pids[i] == p)
1025 daemon->tcp_pids[i] = 0;
1026 break;
1027
1028 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001029 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001030 break;
1031
1032 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001033 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001034 break;
1035
1036 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001037 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1038 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001039 break;
1040
Simon Kelley1a6bca82008-07-11 11:11:42 +01001041 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001042 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001043 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001044 case EVENT_LUA_ERR:
1045 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001046 break;
1047
Simon Kelley5aabfc72007-08-29 11:24:47 +01001048 case EVENT_REOPEN:
1049 /* Note: this may leave TCP-handling processes with the old file still open.
1050 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1051 we leave them logging to the old file. */
1052 if (daemon->log_file != NULL)
1053 log_reopen(daemon->log_file);
1054 break;
1055
1056 case EVENT_TERM:
1057 /* Knock all our children on the head. */
1058 for (i = 0; i < MAX_PROCS; i++)
1059 if (daemon->tcp_pids[i] != 0)
1060 kill(daemon->tcp_pids[i], SIGALRM);
1061
Simon Kelleyc72daea2012-01-05 21:33:27 +00001062#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001063 /* handle pending lease transitions */
1064 if (daemon->helperfd != -1)
1065 {
1066 /* block in writes until all done */
1067 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1068 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1069 do {
1070 helper_write();
1071 } while (!helper_buf_empty() || do_script_run(now));
1072 close(daemon->helperfd);
1073 }
1074#endif
1075
1076 if (daemon->lease_stream)
1077 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001078
1079 if (daemon->runfile)
1080 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001081
1082 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1083 flush_log();
1084 exit(EC_GOOD);
1085 }
1086}
1087
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001088void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001089{
1090 struct resolvc *res, *latest;
1091 struct stat statbuf;
1092 time_t last_change = 0;
1093 /* There may be more than one possible file.
1094 Go through and find the one which changed _last_.
1095 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001096
Simon Kelley28866e92011-02-14 20:19:14 +00001097 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001098 return;
1099
Simon Kelley5aabfc72007-08-29 11:24:47 +01001100 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1101 if (stat(res->name, &statbuf) == -1)
1102 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001103 if (force)
1104 {
1105 res->mtime = 0;
1106 continue;
1107 }
1108
Simon Kelley5aabfc72007-08-29 11:24:47 +01001109 if (!res->logged)
1110 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1111 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001112
1113 if (res->mtime != 0)
1114 {
1115 /* existing file evaporated, force selection of the latest
1116 file even if its mtime hasn't changed since we last looked */
1117 poll_resolv(1, do_reload, now);
1118 return;
1119 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001120 }
1121 else
1122 {
1123 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001124 if (force || (statbuf.st_mtime != res->mtime))
1125 {
1126 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001127 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1128 {
1129 last_change = statbuf.st_mtime;
1130 latest = res;
1131 }
1132 }
1133 }
1134
1135 if (latest)
1136 {
1137 static int warned = 0;
1138 if (reload_servers(latest->name))
1139 {
1140 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1141 warned = 0;
1142 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001143 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001144 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001145 }
1146 else
1147 {
1148 latest->mtime = 0;
1149 if (!warned)
1150 {
1151 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1152 warned = 1;
1153 }
1154 }
1155 }
1156}
1157
1158void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001159{
Simon Kelley824af852008-02-12 20:43:05 +00001160 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001161 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001162
Simon Kelley7622fc02009-06-04 20:32:05 +01001163#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001164 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001165 {
Simon Kelley28866e92011-02-14 20:19:14 +00001166 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001167 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001168 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001169 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +00001170 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001171 lease_update_from_configs();
1172 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001173 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001174 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001175#ifdef HAVE_DHCP6
1176 else if (daemon->ra_contexts)
1177 {
1178 /* Not doing DHCP, so no lease system, manage
1179 alarms for ra only */
1180 time_t next_event = periodic_ra(now);
1181 if (next_event != 0)
1182 alarm((unsigned)difftime(next_event, now));
1183 }
1184#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001185#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001186}
1187
Simon Kelley5aabfc72007-08-29 11:24:47 +01001188static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001189{
1190 struct serverfd *serverfdp;
1191 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001192 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001193
1194#ifdef HAVE_TFTP
1195 int tftp = 0;
1196 struct tftp_transfer *transfer;
1197 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1198 {
1199 tftp++;
1200 FD_SET(transfer->sockfd, set);
1201 bump_maxfd(transfer->sockfd, maxfdp);
1202 }
1203#endif
1204
Simon Kelley16972692006-10-16 20:04:18 +01001205 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001206 if (daemon->port != 0)
1207 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001208
Simon Kelley3be34542004-09-11 19:12:13 +01001209 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1210 {
1211 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001212 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001213 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001214
1215 if (daemon->port != 0 && !daemon->osport)
1216 for (i = 0; i < RANDOM_SOCKS; i++)
1217 if (daemon->randomsocks[i].refcount != 0)
1218 {
1219 FD_SET(daemon->randomsocks[i].fd, set);
1220 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1221 }
1222
Simon Kelley3be34542004-09-11 19:12:13 +01001223 for (listener = daemon->listeners; listener; listener = listener->next)
1224 {
Simon Kelley16972692006-10-16 20:04:18 +01001225 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001226 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001227 {
1228 FD_SET(listener->fd, set);
1229 bump_maxfd(listener->fd, maxfdp);
1230 }
1231
1232 /* death of a child goes through the select loop, so
1233 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001234 if (listener->tcpfd != -1)
1235 for (i = 0; i < MAX_PROCS; i++)
1236 if (daemon->tcp_pids[i] == 0)
1237 {
1238 FD_SET(listener->tcpfd, set);
1239 bump_maxfd(listener->tcpfd, maxfdp);
1240 break;
1241 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001242
Simon Kelley832af0b2007-01-21 20:01:28 +00001243#ifdef HAVE_TFTP
1244 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1245 {
1246 FD_SET(listener->tftpfd, set);
1247 bump_maxfd(listener->tftpfd, maxfdp);
1248 }
1249#endif
1250
1251 }
1252
Simon Kelley16972692006-10-16 20:04:18 +01001253 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001254}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001255
Simon Kelley5aabfc72007-08-29 11:24:47 +01001256static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001257{
1258 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001259 struct listener *listener;
1260 int i;
1261
Simon Kelley832af0b2007-01-21 20:01:28 +00001262 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1263 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001264 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1265
1266 if (daemon->port != 0 && !daemon->osport)
1267 for (i = 0; i < RANDOM_SOCKS; i++)
1268 if (daemon->randomsocks[i].refcount != 0 &&
1269 FD_ISSET(daemon->randomsocks[i].fd, set))
1270 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001271
1272 for (listener = daemon->listeners; listener; listener = listener->next)
1273 {
Simon Kelley824af852008-02-12 20:43:05 +00001274 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001275 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001276
Simon Kelley832af0b2007-01-21 20:01:28 +00001277#ifdef HAVE_TFTP
1278 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001279 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001280#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001281
Simon Kelley824af852008-02-12 20:43:05 +00001282 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001283 {
1284 int confd;
1285 struct irec *iface = NULL;
1286 pid_t p;
1287
1288 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1289
1290 if (confd == -1)
1291 continue;
1292
Simon Kelley28866e92011-02-14 20:19:14 +00001293 if (option_bool(OPT_NOWILD))
Simon Kelley832af0b2007-01-21 20:01:28 +00001294 iface = listener->iface;
1295 else
1296 {
1297 union mysockaddr tcp_addr;
1298 socklen_t tcp_len = sizeof(union mysockaddr);
1299 /* Check for allowed interfaces when binding the wildcard address:
1300 we do this by looking for an interface with the same address as
1301 the local address of the TCP connection, then looking to see if that's
1302 an allowed interface. As a side effect, we get the netmask of the
1303 interface too, for localisation. */
1304
1305 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001306 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001307 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1308 for (iface = daemon->interfaces; iface; iface = iface->next)
1309 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1310 break;
1311 }
1312
1313 if (!iface)
1314 {
1315 shutdown(confd, SHUT_RDWR);
1316 close(confd);
1317 }
1318#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001319 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001320 {
1321 if (p != -1)
1322 {
1323 int i;
1324 for (i = 0; i < MAX_PROCS; i++)
1325 if (daemon->tcp_pids[i] == 0)
1326 {
1327 daemon->tcp_pids[i] = p;
1328 break;
1329 }
1330 }
1331 close(confd);
1332 }
1333#endif
1334 else
1335 {
1336 unsigned char *buff;
1337 struct server *s;
1338 int flags;
Simon Kelley832af0b2007-01-21 20:01:28 +00001339
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001340#ifndef NO_FORK
1341 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1342 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001343 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001344 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001345#endif
1346
Simon Kelley832af0b2007-01-21 20:01:28 +00001347 /* start with no upstream connections. */
1348 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001349 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001350
1351 /* The connected socket inherits non-blocking
1352 attribute from the listening socket.
1353 Reset that here. */
1354 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1355 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1356
Simon Kelley7de060b2011-08-26 17:24:52 +01001357 buff = tcp_request(confd, now, &iface->addr, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001358
Simon Kelley832af0b2007-01-21 20:01:28 +00001359 shutdown(confd, SHUT_RDWR);
1360 close(confd);
1361
1362 if (buff)
1363 free(buff);
1364
1365 for (s = daemon->servers; s; s = s->next)
1366 if (s->tcpfd != -1)
1367 {
1368 shutdown(s->tcpfd, SHUT_RDWR);
1369 close(s->tcpfd);
1370 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001371#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001372 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001373 {
1374 flush_log();
1375 _exit(0);
1376 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001377#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001378 }
1379 }
1380 }
Simon Kelley3be34542004-09-11 19:12:13 +01001381}
1382
Simon Kelley7622fc02009-06-04 20:32:05 +01001383#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001384int make_icmp_sock(void)
1385{
Simon Kelley7cebd202006-05-06 14:13:33 +01001386 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001387 int zeroopt = 0;
1388
1389 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1390 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001391 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001392 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1393 {
1394 close(fd);
1395 fd = -1;
1396 }
1397 }
1398
1399 return fd;
1400}
1401
Simon Kelley5aabfc72007-08-29 11:24:47 +01001402int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001403{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001404 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001405
1406 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001407 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001408 better not use any resources our caller has in use...)
1409 but we remain deaf to signals or further DHCP packets. */
1410
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001411 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001412 struct sockaddr_in saddr;
1413 struct {
1414 struct ip ip;
1415 struct icmp icmp;
1416 } packet;
1417 unsigned short id = rand16();
1418 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001419 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001420 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001421
Simon Kelley824af852008-02-12 20:43:05 +00001422#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001423 if ((fd = make_icmp_sock()) == -1)
1424 return 0;
1425#else
1426 int opt = 2000;
1427 fd = daemon->dhcp_icmp_fd;
1428 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1429#endif
1430
Simon Kelley3be34542004-09-11 19:12:13 +01001431 saddr.sin_family = AF_INET;
1432 saddr.sin_port = 0;
1433 saddr.sin_addr = addr;
1434#ifdef HAVE_SOCKADDR_SA_LEN
1435 saddr.sin_len = sizeof(struct sockaddr_in);
1436#endif
1437
1438 memset(&packet.icmp, 0, sizeof(packet.icmp));
1439 packet.icmp.icmp_type = ICMP_ECHO;
1440 packet.icmp.icmp_id = id;
1441 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1442 j += ((u16 *)&packet.icmp)[i];
1443 while (j>>16)
1444 j = (j & 0xffff) + (j >> 16);
1445 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1446
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001447 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001448 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1449 retry_send());
1450
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001451 for (now = start = dnsmasq_time();
1452 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001453 {
1454 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001455 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001456 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001457 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001458 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001459
1460 tv.tv_usec = 250000;
1461 tv.tv_sec = 0;
1462
1463 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001464 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001465 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001466 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001467 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001468
1469#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001470 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001471 {
1472 FD_SET(daemon->icmp6fd, &rset);
1473 bump_maxfd(daemon->icmp6fd, &maxfd);
1474 }
1475#endif
1476
Simon Kelleyf2621c72007-04-29 19:47:21 +01001477 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1478 {
1479 FD_ZERO(&rset);
1480 FD_ZERO(&wset);
1481 }
1482
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001483 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001484
1485 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001486 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001487
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001488#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001489 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001490 icmp6_packet();
1491#endif
1492
Simon Kelley832af0b2007-01-21 20:01:28 +00001493#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001494 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001495#endif
1496
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001497 if (FD_ISSET(fd, &rset) &&
1498 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001499 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1500 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1501 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1502 packet.icmp.icmp_seq == 0 &&
1503 packet.icmp.icmp_id == id)
1504 {
1505 gotreply = 1;
1506 break;
1507 }
1508 }
1509
Simon Kelley824af852008-02-12 20:43:05 +00001510#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001511 close(fd);
1512#else
Simon Kelley3be34542004-09-11 19:12:13 +01001513 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001514 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1515#endif
1516
Simon Kelley3be34542004-09-11 19:12:13 +01001517 return gotreply;
1518}
Simon Kelley7622fc02009-06-04 20:32:05 +01001519#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001520
1521