blob: 82e4cad17acf7c5e8dd5f3b9a88f1be2d938220d [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 Kelley5e9e0ef2006-04-17 14:24:29 +0100109#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100111#elif !(defined(IP_RECVDSTADDR) && \
112 defined(IP_RECVIF) && \
113 defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000114 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100115 {
116 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000117 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100118 }
Simon Kelley309331f2006-04-22 15:05:01 +0100119#endif
120
Simon Kelley832af0b2007-01-21 20:01:28 +0000121#ifndef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100122 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100123 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000124#endif
125
Simon Kelley7de060b2011-08-26 17:24:52 +0100126#ifdef HAVE_CONNTRACK
127 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
128 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
129#else
130 if (option_bool(OPT_CONNTRACK))
131 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
132#endif
133
Simon Kelley824af852008-02-12 20:43:05 +0000134#ifdef HAVE_SOLARIS_NETWORK
135 if (daemon->max_logs != 0)
136 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
137#endif
138
Simon Kelley572b41e2011-02-18 18:11:18 +0000139#ifdef __ANDROID__
140 if (daemon->max_logs != 0)
141 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
142#endif
143
Simon Kelley1a6bca82008-07-11 11:11:42 +0100144 rand_init();
145
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100146 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000147
Simon Kelley7622fc02009-06-04 20:32:05 +0100148#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000149 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000150 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100151 /* Note that order matters here, we must call lease_init before
152 creating any file descriptors which shouldn't be leaked
Simon Kelley4cb1b322012-02-06 14:30:41 +0000153 to the lease-script init process. We need to call common_init
154 before lease_init to allocate buffers it uses.*/
155 dhcp_common_init();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100156 lease_init(now);
Simon Kelley843c96b2012-02-27 17:42:38 +0000157
Simon Kelley52b92f42012-01-22 16:05:15 +0000158 if (daemon->dhcp)
159 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000161
162# ifdef HAVE_DHCP6
163 /* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
164 if (daemon->ra_contexts || option_bool(OPT_RA))
165 {
166 /* link the DHCP6 contexts to the ra-only ones so we can traverse them all
167 from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
168 struct dhcp_context *context;
169
170 if (!daemon->ra_contexts)
171 daemon->ra_contexts = daemon->dhcp6;
172 else
173 {
174 for (context = daemon->ra_contexts; context->next; context = context->next);
175 context->next = daemon->dhcp6;
176 }
177 ra_init(now);
178 }
179
180 if (daemon->dhcp6)
181 dhcp6_init();
182
183 if (daemon->ra_contexts || daemon->dhcp6)
184 join_multicast();
185# endif
186
Simon Kelley7622fc02009-06-04 20:32:05 +0100187#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100188
Simon Kelley5aabfc72007-08-29 11:24:47 +0100189 if (!enumerate_interfaces())
190 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000191
Simon Kelley28866e92011-02-14 20:19:14 +0000192 if (option_bool(OPT_NOWILD))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100193 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100194 create_bound_listeners(1);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100195
196 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
197 if (if_tmp->name && !if_tmp->used)
198 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
199
200 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
201 if (!if_tmp->used)
202 {
203 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
204 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
205 }
206 }
Simon Kelley28866e92011-02-14 20:19:14 +0000207 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100208 create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100209
Simon Kelley824af852008-02-12 20:43:05 +0000210 if (daemon->port != 0)
211 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100212
Simon Kelley28866e92011-02-14 20:19:14 +0000213 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100214#ifdef HAVE_DBUS
215 {
216 char *err;
217 daemon->dbus = NULL;
218 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100219 if ((err = dbus_init()))
220 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100221 }
222#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100223 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100224#endif
225
Simon Kelley824af852008-02-12 20:43:05 +0000226 if (daemon->port != 0)
227 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100228
Simon Kelleyc72daea2012-01-05 21:33:27 +0000229#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100230 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000231 if ((daemon->dhcp || daemon->dhcp6) &&
232 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000233 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100234 {
235 if ((ent_pw = getpwnam(daemon->scriptuser)))
236 {
237 script_uid = ent_pw->pw_uid;
238 script_gid = ent_pw->pw_gid;
239 }
240 else
241 baduser = daemon->scriptuser;
242 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100243#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000244
Simon Kelley1a6bca82008-07-11 11:11:42 +0100245 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
246 baduser = daemon->username;
247 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
248 baduser = daemon->groupname;
249
250 if (baduser)
251 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
252
253 /* implement group defaults, "dip" if available, or group associated with uid */
254 if (!daemon->group_set && !gp)
255 {
256 if (!(gp = getgrnam(CHGRP)) && ent_pw)
257 gp = getgrgid(ent_pw->pw_gid);
258
259 /* for error message */
260 if (gp)
261 daemon->groupname = gp->gr_name;
262 }
263
264#if defined(HAVE_LINUX_NETWORK)
265 /* determine capability API version here, while we can still
266 call safe_malloc */
267 if (ent_pw && ent_pw->pw_uid != 0)
268 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100269 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100270 hdr = safe_malloc(sizeof(*hdr));
271
Simon Kelley1a6bca82008-07-11 11:11:42 +0100272 /* find version supported by kernel */
273 memset(hdr, 0, sizeof(*hdr));
274 capget(hdr, NULL);
275
276 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
277 {
278 /* if unknown version, use largest supported version (3) */
279 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
280 hdr->version = LINUX_CAPABILITY_VERSION_3;
281 capsize = 2;
282 }
283
284 data = safe_malloc(sizeof(*data) * capsize);
285 memset(data, 0, sizeof(*data) * capsize);
286 }
287#endif
288
Simon Kelley5aabfc72007-08-29 11:24:47 +0100289 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100290 in a race-free manner and another to carry errors to daemon-invoking process */
291 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100292
293 piperead = pipefd[0];
294 pipewrite = pipefd[1];
295 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000296 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100297
298 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100299
Simon Kelley28866e92011-02-14 20:19:14 +0000300 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000301 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000302 /* The following code "daemonizes" the process.
303 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100304
Simon Kelley9e038942008-05-30 20:06:34 +0100305 if (chdir("/") != 0)
306 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
307
Simon Kelley16972692006-10-16 20:04:18 +0100308#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000309 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100310 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311 pid_t pid;
312
Simon Kelley1a6bca82008-07-11 11:11:42 +0100313 /* pipe to carry errors back to original process.
314 When startup is complete we close this and the process terminates. */
315 safe_pipe(err_pipe, 0);
316
Simon Kelley7622fc02009-06-04 20:32:05 +0100317 if ((pid = fork()) == -1)
318 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000319 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100320
Simon Kelley5aabfc72007-08-29 11:24:47 +0100321 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100322 {
323 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000324 char *msg;
325
Simon Kelley1a6bca82008-07-11 11:11:42 +0100326 /* close our copy of write-end */
327 close(err_pipe[1]);
328
329 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000330 if (read_event(err_pipe[0], &ev, &msg))
331 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100332
333 _exit(EC_GOOD);
334 }
335
336 close(err_pipe[0]);
337
338 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100339
340 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100341
342 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000343 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100344
345 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100346 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100347 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100349
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000350 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100351 if (daemon->runfile)
352 {
353 FILE *pidfile;
354
355 /* only complain if started as root */
356 if ((pidfile = fopen(daemon->runfile, "w")))
357 {
358 fprintf(pidfile, "%d\n", (int) getpid());
359 fclose(pidfile);
360 }
361 else if (getuid() == 0)
362 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000363 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100364 _exit(0);
365 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000366 }
Simon Kelley16972692006-10-16 20:04:18 +0100367 }
368
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100369 log_err = log_start(ent_pw, err_pipe[1]);
370
Simon Kelley28866e92011-02-14 20:19:14 +0000371 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100372 {
373 /* open stdout etc to /dev/null */
374 int nullfd = open("/dev/null", O_RDWR);
375 dup2(nullfd, STDOUT_FILENO);
376 dup2(nullfd, STDERR_FILENO);
377 dup2(nullfd, STDIN_FILENO);
378 close(nullfd);
379 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100380
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381 /* if we are to run scripts, we need to fork a helper before dropping root. */
382 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000383#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000384 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
386#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100387
Simon Kelley28866e92011-02-14 20:19:14 +0000388 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100389 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390 int bad_capabilities = 0;
391 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100392
Simon Kelley1a6bca82008-07-11 11:11:42 +0100393 /* remove all supplimentary groups */
394 if (gp &&
395 (setgroups(0, &dummy) == -1 ||
396 setgid(gp->gr_gid) == -1))
397 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000398 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100399 _exit(0);
400 }
401
Simon Kelley7cebd202006-05-06 14:13:33 +0100402 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100403 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100404#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100405 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100406 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
407 ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
408 if (is_dad_listeners())
409 data->effective = data->permitted = data->inheritable =
410 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
411 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
412 else
413 data->effective = data->permitted = data->inheritable =
414 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100415
Simon Kelley16972692006-10-16 20:04:18 +0100416 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000417 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100418 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100419
Simon Kelley7622fc02009-06-04 20:32:05 +0100420#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000421 /* http://developers.sun.com/solaris/articles/program_privileges.html */
422 priv_set_t *priv_set;
423
424 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
425 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
426 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
427 bad_capabilities = errno;
428
429 if (priv_set && bad_capabilities == 0)
430 {
431 priv_inverse(priv_set);
432
433 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
434 bad_capabilities = errno;
435 }
436
437 if (priv_set)
438 priv_freeset(priv_set);
439
Simon Kelley824af852008-02-12 20:43:05 +0000440#endif
441
Simon Kelley1a6bca82008-07-11 11:11:42 +0100442 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100443 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000444 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100446 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100447
448 /* finally drop root */
449 if (setuid(ent_pw->pw_uid) == -1)
450 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000451 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100452 _exit(0);
453 }
454
455#ifdef HAVE_LINUX_NETWORK
Simon Kelley74c95c22011-10-19 09:33:39 +0100456 if (is_dad_listeners())
457 data->effective = data->permitted =
458 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
459 else
460 data->effective = data->permitted =
461 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100462 data->inheritable = 0;
463
464 /* lose the setuid and setgid capbilities */
465 if (capset(hdr, data) == -1)
466 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000467 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100468 _exit(0);
469 }
470#endif
471
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472 }
Simon Kelley849a8352006-06-09 21:02:31 +0100473 }
Simon Kelley16972692006-10-16 20:04:18 +0100474
Simon Kelley16972692006-10-16 20:04:18 +0100475#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000476 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000477 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100478#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100479
Simon Kelley824af852008-02-12 20:43:05 +0000480 if (daemon->port == 0)
481 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
482 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100483 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000484 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100485 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100486
Simon Kelleyf2621c72007-04-29 19:47:21 +0100487 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100488
Simon Kelley3d8df262005-08-29 12:19:27 +0100489#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000490 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100491 {
492 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100493 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100494 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100495 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100496 }
497#endif
498
Simon Kelley1a6bca82008-07-11 11:11:42 +0100499 if (log_err != 0)
500 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
501 daemon->log_file, strerror(log_err));
502
Simon Kelleyde379512004-06-22 20:23:33 +0100503 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100504 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100505
Simon Kelley28866e92011-02-14 20:19:14 +0000506 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000507 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
508 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100509 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100510
Simon Kelley28866e92011-02-14 20:19:14 +0000511 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100512 {
513 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100514 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100515 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000516 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100517 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100518 }
519
Simon Kelleyf2621c72007-04-29 19:47:21 +0100520 if (daemon->max_logs != 0)
521 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000522
Simon Kelley843c96b2012-02-27 17:42:38 +0000523 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000524 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100525
Simon Kelley7622fc02009-06-04 20:32:05 +0100526#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000527 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000528 {
Simon Kelley3be34542004-09-11 19:12:13 +0100529 struct dhcp_context *dhcp_tmp;
Simon Kelley52b92f42012-01-22 16:05:15 +0000530 int family = AF_INET;
531 dhcp_tmp = daemon->dhcp;
532
Simon Kelley3268e902012-01-22 16:15:02 +0000533#ifdef HAVE_DHCP6
Simon Kelley52b92f42012-01-22 16:05:15 +0000534 again:
Simon Kelley3268e902012-01-22 16:15:02 +0000535#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000536 for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100537 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000538 void *start = &dhcp_tmp->start;
539 void *end = &dhcp_tmp->end;
540
541#ifdef HAVE_DHCP6
542 if (family == AF_INET6)
543 {
544 start = &dhcp_tmp->start6;
545 end = &dhcp_tmp->end6;
546 }
547#endif
548
Simon Kelley0a852542005-03-23 20:28:59 +0000549 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley52b92f42012-01-22 16:05:15 +0000550 inet_ntop(family, start, daemon->dhcp_buff, 256);
551 inet_ntop(family, end, daemon->dhcp_buff3, 256);
Simon Kelley7622fc02009-06-04 20:32:05 +0100552 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100553 (dhcp_tmp->flags & CONTEXT_STATIC) ?
554 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000555 (dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
556 _("router advertisement only on %.0s%s, lifetime %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100557 (dhcp_tmp->flags & CONTEXT_PROXY) ?
558 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100559 _("DHCP, IP range %s -- %s, lease time %s"),
Simon Kelley52b92f42012-01-22 16:05:15 +0000560 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100561 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000562
563#ifdef HAVE_DHCP6
564 if (family == AF_INET)
565 {
566 family = AF_INET6;
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000567 if (daemon->ra_contexts)
568 dhcp_tmp = daemon->ra_contexts;
569 else
570 dhcp_tmp = daemon->dhcp6;
Simon Kelley52b92f42012-01-22 16:05:15 +0000571 goto again;
572 }
573#endif
574
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000575 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100576#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000577
Simon Kelley52b92f42012-01-22 16:05:15 +0000578
Simon Kelley832af0b2007-01-21 20:01:28 +0000579#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100580 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000581 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000582#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100583 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000584 max_fd = FD_SETSIZE;
585#endif
586
Simon Kelley7622fc02009-06-04 20:32:05 +0100587 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100588 daemon->tftp_prefix ? _("root is ") : _("enabled"),
589 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000590 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100591
Simon Kelley832af0b2007-01-21 20:01:28 +0000592 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100593 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000594 a single file will be sent to may clients (the file only needs
595 one fd). */
596
597 max_fd -= 30; /* use other than TFTP */
598
599 if (max_fd < 0)
600 max_fd = 5;
601 else if (max_fd < 100)
602 max_fd = max_fd/2;
603 else
604 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000605
606 /* if we have to use a limited range of ports,
607 that will limit the number of transfers */
608 if (daemon->start_tftp_port != 0 &&
609 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
610 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000611
612 if (daemon->tftp_max > max_fd)
613 {
614 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100615 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100616 _("restricting maximum simultaneous TFTP transfers to %d"),
617 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000618 }
619 }
620#endif
621
Simon Kelley1a6bca82008-07-11 11:11:42 +0100622 /* finished start-up - release original process */
623 if (err_pipe[1] != -1)
624 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625
Simon Kelley824af852008-02-12 20:43:05 +0000626 if (daemon->port != 0)
627 check_servers();
628
Simon Kelley7cebd202006-05-06 14:13:33 +0100629 pid = getpid();
630
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100631 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000632 {
Simon Kelley16972692006-10-16 20:04:18 +0100633 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100634 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100635 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000636
637 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100638 FD_ZERO(&wset);
639 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000640
Simon Kelley16972692006-10-16 20:04:18 +0100641 /* if we are out of resources, find how long we have to wait
642 for some to come free, we'll loop around then and restart
643 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100644 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100645 {
646 t.tv_usec = 0;
647 tp = &t;
648 }
649
Simon Kelley832af0b2007-01-21 20:01:28 +0000650 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
651 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000652 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000653 {
Simon Kelley16972692006-10-16 20:04:18 +0100654 t.tv_sec = 0;
655 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100656 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000657 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100658 /* Wake every second whilst waiting for DAD to complete */
659 else if (is_dad_listeners())
660 {
661 t.tv_sec = 1;
662 t.tv_usec = 0;
663 tp = &t;
664 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100665
Simon Kelley832af0b2007-01-21 20:01:28 +0000666#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100667 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100668#endif
669
Simon Kelley7622fc02009-06-04 20:32:05 +0100670#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100671 if (daemon->dhcp)
672 {
673 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100674 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000675 if (daemon->pxefd != -1)
676 {
677 FD_SET(daemon->pxefd, &rset);
678 bump_maxfd(daemon->pxefd, &maxfd);
679 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100680 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100681#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100682
Simon Kelley52b92f42012-01-22 16:05:15 +0000683#ifdef HAVE_DHCP6
684 if (daemon->dhcp6)
685 {
686 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000687 bump_maxfd(daemon->dhcp6fd, &maxfd);
688
Simon Kelley843c96b2012-02-27 17:42:38 +0000689 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000690 {
691 FD_SET(daemon->icmp6fd, &rset);
692 bump_maxfd(daemon->icmp6fd, &maxfd);
693 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000694 }
695#endif
696
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100697#ifdef HAVE_LINUX_NETWORK
698 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100699 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100700#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100701
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100702 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100703 bump_maxfd(piperead, &maxfd);
704
Simon Kelley7622fc02009-06-04 20:32:05 +0100705#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100706# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100707 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100708
709 if (!helper_buf_empty())
710 {
711 FD_SET(daemon->helperfd, &wset);
712 bump_maxfd(daemon->helperfd, &maxfd);
713 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100714# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100715 /* need this for other side-effects */
716 while (do_script_run(now));
Simon Kelley7622fc02009-06-04 20:32:05 +0100717# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100718#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100719
Simon Kelleyf2621c72007-04-29 19:47:21 +0100720 /* must do this just before select(), when we know no
721 more calls to my_syslog() can occur */
722 set_log_writer(&wset, &maxfd);
723
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100724 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
725 {
726 /* otherwise undefined after error */
727 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
728 }
729
730 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000731
Simon Kelleyf2621c72007-04-29 19:47:21 +0100732 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100733
734 /* Check the interfaces to see if any have exited DAD state
735 and if so, bind the address. */
736 if (is_dad_listeners())
737 {
738 enumerate_interfaces();
739 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
740 create_bound_listeners(0);
741 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100742
Simon Kelleyc52e1892010-06-07 22:01:39 +0100743#ifdef HAVE_LINUX_NETWORK
744 if (FD_ISSET(daemon->netlinkfd, &rset))
745 netlink_multicast();
746#endif
747
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000748 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100749 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000750 if (daemon->last_resolv == 0 ||
751 difftime(now, daemon->last_resolv) > 1.0 ||
752 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000753 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100754 /* poll_resolv doesn't need to reload first time through, since
755 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100756
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100757 poll_resolv(0, daemon->last_resolv != 0, now);
758 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000759 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100760
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100761 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100762 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100763
Simon Kelley3d8df262005-08-29 12:19:27 +0100764#ifdef HAVE_DBUS
765 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000766 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100767 {
768 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100769 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100770 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100771 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100772 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100773 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100774 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100775#endif
Simon Kelley824af852008-02-12 20:43:05 +0000776
Simon Kelley5aabfc72007-08-29 11:24:47 +0100777 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000778
779#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100780 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000781#endif
782
Simon Kelley7622fc02009-06-04 20:32:05 +0100783#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000784 if (daemon->dhcp)
785 {
786 if (FD_ISSET(daemon->dhcpfd, &rset))
787 dhcp_packet(now, 0);
788 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
789 dhcp_packet(now, 1);
790 }
Simon Kelley16972692006-10-16 20:04:18 +0100791
Simon Kelley52b92f42012-01-22 16:05:15 +0000792#ifdef HAVE_DHCP6
793 if (daemon->dhcp6)
794 {
795 if (FD_ISSET(daemon->dhcp6fd, &rset))
796 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000797
Simon Kelley843c96b2012-02-27 17:42:38 +0000798 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000799 icmp6_packet();
Simon Kelley52b92f42012-01-22 16:05:15 +0000800 }
801#endif
802
Simon Kelley1f15b812009-10-13 17:49:32 +0100803# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100804 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100805 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100806# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100807#endif
808
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000809 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000810}
811
Simon Kelley3be34542004-09-11 19:12:13 +0100812static void sig_handler(int sig)
813{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100814 if (pid == 0)
815 {
Simon Kelley16972692006-10-16 20:04:18 +0100816 /* ignore anything other than TERM during startup
817 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100818 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100819 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100820 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100821 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100822 {
Simon Kelley16972692006-10-16 20:04:18 +0100823 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100824 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100825 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100826 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100827 else
828 {
829 /* master process */
830 int event, errsave = errno;
831
832 if (sig == SIGHUP)
833 event = EVENT_RELOAD;
834 else if (sig == SIGCHLD)
835 event = EVENT_CHILD;
836 else if (sig == SIGALRM)
837 event = EVENT_ALARM;
838 else if (sig == SIGTERM)
839 event = EVENT_TERM;
840 else if (sig == SIGUSR1)
841 event = EVENT_DUMP;
842 else if (sig == SIGUSR2)
843 event = EVENT_REOPEN;
844 else
845 return;
846
Simon Kelleyc72daea2012-01-05 21:33:27 +0000847 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100848 errno = errsave;
849 }
Simon Kelley3be34542004-09-11 19:12:13 +0100850}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000851
Simon Kelley741c2952012-02-25 13:09:18 +0000852void send_alarm(void)
853{
854 send_event(pipewrite, EVENT_ALARM, 0, NULL);
855}
856
Simon Kelleyc72daea2012-01-05 21:33:27 +0000857void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100858{
859 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000860 struct iovec iov[2];
861
Simon Kelley5aabfc72007-08-29 11:24:47 +0100862 ev.event = event;
863 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000864 ev.msg_sz = msg ? strlen(msg) : 0;
865
866 iov[0].iov_base = &ev;
867 iov[0].iov_len = sizeof(ev);
868 iov[1].iov_base = msg;
869 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100870
871 /* error pipe, debug mode. */
872 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000873 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100874 else
875 /* pipe is non-blocking and struct event_desc is smaller than
876 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000877 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100878}
Simon Kelley3d8df262005-08-29 12:19:27 +0100879
Simon Kelleyc72daea2012-01-05 21:33:27 +0000880/* NOTE: the memory used to return msg is leaked: use msgs in events only
881 to describe fatal errors. */
882static int read_event(int fd, struct event_desc *evp, char **msg)
883{
884 char *buf;
885
886 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
887 return 0;
888
889 *msg = NULL;
890
891 if (evp->msg_sz != 0 &&
892 (buf = malloc(evp->msg_sz + 1)) &&
893 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
894 {
895 buf[evp->msg_sz] = 0;
896 *msg = buf;
897 }
898
899 return 1;
900}
901
902static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100903{
904 errno = ev->data;
905
906 switch (ev->event)
907 {
908 case EVENT_DIE:
909 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100910
911 case EVENT_FORK_ERR:
912 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100913
914 case EVENT_PIPE_ERR:
915 die(_("failed to create helper: %s"), NULL, EC_MISC);
916
917 case EVENT_CAP_ERR:
918 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
919
920 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000921 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100922
923 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000924 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100925
926 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000927 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100928
929 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000930 die(_("cannot open log %s: %s"), msg, EC_FILE);
931
932 case EVENT_LUA_ERR:
933 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100934 }
935}
936
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937static void async_event(int pipe, time_t now)
938{
939 pid_t p;
940 struct event_desc ev;
941 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000942 char *msg;
943
944 /* NOTE: the memory used to return msg is leaked: use msgs in events only
945 to describe fatal errors. */
946
947 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100948 switch (ev.event)
949 {
950 case EVENT_RELOAD:
951 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +0000952 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100953 {
954 reload_servers(daemon->resolv_files->name);
955 check_servers();
956 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100957#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100958 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100959#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100960 break;
961
962 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000963 if (daemon->port != 0)
964 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100965 break;
966
967 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +0100968#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000969 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100970 {
971 lease_prune(NULL, now);
972 lease_update_file(now);
973 }
Simon Kelley843c96b2012-02-27 17:42:38 +0000974#ifdef HAVE_DHCP6
975 else if (daemon->ra_contexts)
976 {
977 /* Not doing DHCP, so no lease system, manage
978 alarms for ra only */
979 time_t next_event = periodic_ra(now);
980 if (next_event != 0)
981 alarm((unsigned)difftime(next_event, now));
982 }
983#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100984#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100985 break;
986
987 case EVENT_CHILD:
988 /* See Stevens 5.10 */
989 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
990 if (p == -1)
991 {
992 if (errno != EINTR)
993 break;
994 }
995 else
996 for (i = 0 ; i < MAX_PROCS; i++)
997 if (daemon->tcp_pids[i] == p)
998 daemon->tcp_pids[i] = 0;
999 break;
1000
1001 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001002 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001003 break;
1004
1005 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001006 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001007 break;
1008
1009 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001010 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1011 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001012 break;
1013
Simon Kelley1a6bca82008-07-11 11:11:42 +01001014 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001015 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001016 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001017 case EVENT_LUA_ERR:
1018 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001019 break;
1020
Simon Kelley5aabfc72007-08-29 11:24:47 +01001021 case EVENT_REOPEN:
1022 /* Note: this may leave TCP-handling processes with the old file still open.
1023 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1024 we leave them logging to the old file. */
1025 if (daemon->log_file != NULL)
1026 log_reopen(daemon->log_file);
1027 break;
1028
1029 case EVENT_TERM:
1030 /* Knock all our children on the head. */
1031 for (i = 0; i < MAX_PROCS; i++)
1032 if (daemon->tcp_pids[i] != 0)
1033 kill(daemon->tcp_pids[i], SIGALRM);
1034
Simon Kelleyc72daea2012-01-05 21:33:27 +00001035#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001036 /* handle pending lease transitions */
1037 if (daemon->helperfd != -1)
1038 {
1039 /* block in writes until all done */
1040 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1041 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1042 do {
1043 helper_write();
1044 } while (!helper_buf_empty() || do_script_run(now));
1045 close(daemon->helperfd);
1046 }
1047#endif
1048
1049 if (daemon->lease_stream)
1050 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001051
1052 if (daemon->runfile)
1053 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001054
1055 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1056 flush_log();
1057 exit(EC_GOOD);
1058 }
1059}
1060
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001061void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001062{
1063 struct resolvc *res, *latest;
1064 struct stat statbuf;
1065 time_t last_change = 0;
1066 /* There may be more than one possible file.
1067 Go through and find the one which changed _last_.
1068 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001069
Simon Kelley28866e92011-02-14 20:19:14 +00001070 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001071 return;
1072
Simon Kelley5aabfc72007-08-29 11:24:47 +01001073 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1074 if (stat(res->name, &statbuf) == -1)
1075 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001076 if (force)
1077 {
1078 res->mtime = 0;
1079 continue;
1080 }
1081
Simon Kelley5aabfc72007-08-29 11:24:47 +01001082 if (!res->logged)
1083 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1084 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001085
1086 if (res->mtime != 0)
1087 {
1088 /* existing file evaporated, force selection of the latest
1089 file even if its mtime hasn't changed since we last looked */
1090 poll_resolv(1, do_reload, now);
1091 return;
1092 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001093 }
1094 else
1095 {
1096 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001097 if (force || (statbuf.st_mtime != res->mtime))
1098 {
1099 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001100 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1101 {
1102 last_change = statbuf.st_mtime;
1103 latest = res;
1104 }
1105 }
1106 }
1107
1108 if (latest)
1109 {
1110 static int warned = 0;
1111 if (reload_servers(latest->name))
1112 {
1113 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1114 warned = 0;
1115 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001116 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001117 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001118 }
1119 else
1120 {
1121 latest->mtime = 0;
1122 if (!warned)
1123 {
1124 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1125 warned = 1;
1126 }
1127 }
1128 }
1129}
1130
1131void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001132{
Simon Kelley824af852008-02-12 20:43:05 +00001133 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001134 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001135
Simon Kelley7622fc02009-06-04 20:32:05 +01001136#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001137 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001138 {
Simon Kelley28866e92011-02-14 20:19:14 +00001139 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001140 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001141 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001142 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +00001143 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001144 lease_update_from_configs();
1145 lease_update_file(now);
1146 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +01001147 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001148#ifdef HAVE_DHCP6
1149 else if (daemon->ra_contexts)
1150 {
1151 /* Not doing DHCP, so no lease system, manage
1152 alarms for ra only */
1153 time_t next_event = periodic_ra(now);
1154 if (next_event != 0)
1155 alarm((unsigned)difftime(next_event, now));
1156 }
1157#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001158#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001159}
1160
Simon Kelley5aabfc72007-08-29 11:24:47 +01001161static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001162{
1163 struct serverfd *serverfdp;
1164 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001165 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001166
1167#ifdef HAVE_TFTP
1168 int tftp = 0;
1169 struct tftp_transfer *transfer;
1170 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1171 {
1172 tftp++;
1173 FD_SET(transfer->sockfd, set);
1174 bump_maxfd(transfer->sockfd, maxfdp);
1175 }
1176#endif
1177
Simon Kelley16972692006-10-16 20:04:18 +01001178 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001179 if (daemon->port != 0)
1180 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001181
Simon Kelley3be34542004-09-11 19:12:13 +01001182 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1183 {
1184 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001185 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001186 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001187
1188 if (daemon->port != 0 && !daemon->osport)
1189 for (i = 0; i < RANDOM_SOCKS; i++)
1190 if (daemon->randomsocks[i].refcount != 0)
1191 {
1192 FD_SET(daemon->randomsocks[i].fd, set);
1193 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1194 }
1195
Simon Kelley3be34542004-09-11 19:12:13 +01001196 for (listener = daemon->listeners; listener; listener = listener->next)
1197 {
Simon Kelley16972692006-10-16 20:04:18 +01001198 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001199 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001200 {
1201 FD_SET(listener->fd, set);
1202 bump_maxfd(listener->fd, maxfdp);
1203 }
1204
1205 /* death of a child goes through the select loop, so
1206 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001207 if (listener->tcpfd != -1)
1208 for (i = 0; i < MAX_PROCS; i++)
1209 if (daemon->tcp_pids[i] == 0)
1210 {
1211 FD_SET(listener->tcpfd, set);
1212 bump_maxfd(listener->tcpfd, maxfdp);
1213 break;
1214 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001215
Simon Kelley832af0b2007-01-21 20:01:28 +00001216#ifdef HAVE_TFTP
1217 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1218 {
1219 FD_SET(listener->tftpfd, set);
1220 bump_maxfd(listener->tftpfd, maxfdp);
1221 }
1222#endif
1223
1224 }
1225
Simon Kelley16972692006-10-16 20:04:18 +01001226 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001227}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001228
Simon Kelley5aabfc72007-08-29 11:24:47 +01001229static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001230{
1231 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001232 struct listener *listener;
1233 int i;
1234
Simon Kelley832af0b2007-01-21 20:01:28 +00001235 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1236 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001237 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1238
1239 if (daemon->port != 0 && !daemon->osport)
1240 for (i = 0; i < RANDOM_SOCKS; i++)
1241 if (daemon->randomsocks[i].refcount != 0 &&
1242 FD_ISSET(daemon->randomsocks[i].fd, set))
1243 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001244
1245 for (listener = daemon->listeners; listener; listener = listener->next)
1246 {
Simon Kelley824af852008-02-12 20:43:05 +00001247 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001248 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001249
Simon Kelley832af0b2007-01-21 20:01:28 +00001250#ifdef HAVE_TFTP
1251 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001252 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001253#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001254
Simon Kelley824af852008-02-12 20:43:05 +00001255 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001256 {
1257 int confd;
1258 struct irec *iface = NULL;
1259 pid_t p;
1260
1261 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1262
1263 if (confd == -1)
1264 continue;
1265
Simon Kelley28866e92011-02-14 20:19:14 +00001266 if (option_bool(OPT_NOWILD))
Simon Kelley832af0b2007-01-21 20:01:28 +00001267 iface = listener->iface;
1268 else
1269 {
1270 union mysockaddr tcp_addr;
1271 socklen_t tcp_len = sizeof(union mysockaddr);
1272 /* Check for allowed interfaces when binding the wildcard address:
1273 we do this by looking for an interface with the same address as
1274 the local address of the TCP connection, then looking to see if that's
1275 an allowed interface. As a side effect, we get the netmask of the
1276 interface too, for localisation. */
1277
1278 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001279 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001280 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1281 for (iface = daemon->interfaces; iface; iface = iface->next)
1282 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1283 break;
1284 }
1285
1286 if (!iface)
1287 {
1288 shutdown(confd, SHUT_RDWR);
1289 close(confd);
1290 }
1291#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001292 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001293 {
1294 if (p != -1)
1295 {
1296 int i;
1297 for (i = 0; i < MAX_PROCS; i++)
1298 if (daemon->tcp_pids[i] == 0)
1299 {
1300 daemon->tcp_pids[i] = p;
1301 break;
1302 }
1303 }
1304 close(confd);
1305 }
1306#endif
1307 else
1308 {
1309 unsigned char *buff;
1310 struct server *s;
1311 int flags;
Simon Kelley832af0b2007-01-21 20:01:28 +00001312
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001313#ifndef NO_FORK
1314 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1315 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001316 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001317 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001318#endif
1319
Simon Kelley832af0b2007-01-21 20:01:28 +00001320 /* start with no upstream connections. */
1321 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001322 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001323
1324 /* The connected socket inherits non-blocking
1325 attribute from the listening socket.
1326 Reset that here. */
1327 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1328 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1329
Simon Kelley7de060b2011-08-26 17:24:52 +01001330 buff = tcp_request(confd, now, &iface->addr, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001331
Simon Kelley832af0b2007-01-21 20:01:28 +00001332 shutdown(confd, SHUT_RDWR);
1333 close(confd);
1334
1335 if (buff)
1336 free(buff);
1337
1338 for (s = daemon->servers; s; s = s->next)
1339 if (s->tcpfd != -1)
1340 {
1341 shutdown(s->tcpfd, SHUT_RDWR);
1342 close(s->tcpfd);
1343 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001344#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001345 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001346 {
1347 flush_log();
1348 _exit(0);
1349 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001350#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001351 }
1352 }
1353 }
Simon Kelley3be34542004-09-11 19:12:13 +01001354}
1355
Simon Kelley7622fc02009-06-04 20:32:05 +01001356#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001357int make_icmp_sock(void)
1358{
Simon Kelley7cebd202006-05-06 14:13:33 +01001359 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001360 int zeroopt = 0;
1361
1362 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1363 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001364 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001365 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1366 {
1367 close(fd);
1368 fd = -1;
1369 }
1370 }
1371
1372 return fd;
1373}
1374
Simon Kelley5aabfc72007-08-29 11:24:47 +01001375int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001376{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001377 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001378
1379 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001380 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001381 better not use any resources our caller has in use...)
1382 but we remain deaf to signals or further DHCP packets. */
1383
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001384 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001385 struct sockaddr_in saddr;
1386 struct {
1387 struct ip ip;
1388 struct icmp icmp;
1389 } packet;
1390 unsigned short id = rand16();
1391 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001392 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001393 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001394
Simon Kelley824af852008-02-12 20:43:05 +00001395#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001396 if ((fd = make_icmp_sock()) == -1)
1397 return 0;
1398#else
1399 int opt = 2000;
1400 fd = daemon->dhcp_icmp_fd;
1401 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1402#endif
1403
Simon Kelley3be34542004-09-11 19:12:13 +01001404 saddr.sin_family = AF_INET;
1405 saddr.sin_port = 0;
1406 saddr.sin_addr = addr;
1407#ifdef HAVE_SOCKADDR_SA_LEN
1408 saddr.sin_len = sizeof(struct sockaddr_in);
1409#endif
1410
1411 memset(&packet.icmp, 0, sizeof(packet.icmp));
1412 packet.icmp.icmp_type = ICMP_ECHO;
1413 packet.icmp.icmp_id = id;
1414 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1415 j += ((u16 *)&packet.icmp)[i];
1416 while (j>>16)
1417 j = (j & 0xffff) + (j >> 16);
1418 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1419
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001420 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001421 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1422 retry_send());
1423
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001424 for (now = start = dnsmasq_time();
1425 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001426 {
1427 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001428 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001429 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001430 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001431 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001432
1433 tv.tv_usec = 250000;
1434 tv.tv_sec = 0;
1435
1436 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001437 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001438 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001439 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001440 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001441
1442#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001443 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001444 {
1445 FD_SET(daemon->icmp6fd, &rset);
1446 bump_maxfd(daemon->icmp6fd, &maxfd);
1447 }
1448#endif
1449
Simon Kelleyf2621c72007-04-29 19:47:21 +01001450 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1451 {
1452 FD_ZERO(&rset);
1453 FD_ZERO(&wset);
1454 }
1455
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001456 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001457
1458 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001459 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001460
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001461#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001462 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001463 icmp6_packet();
1464#endif
1465
Simon Kelley832af0b2007-01-21 20:01:28 +00001466#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001467 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001468#endif
1469
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001470 if (FD_ISSET(fd, &rset) &&
1471 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001472 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1473 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1474 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1475 packet.icmp.icmp_seq == 0 &&
1476 packet.icmp.icmp_id == id)
1477 {
1478 gotreply = 1;
1479 break;
1480 }
1481 }
1482
Simon Kelley824af852008-02-12 20:43:05 +00001483#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001484 close(fd);
1485#else
Simon Kelley3be34542004-09-11 19:12:13 +01001486 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001487 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1488#endif
1489
Simon Kelley3be34542004-09-11 19:12:13 +01001490 return gotreply;
1491}
Simon Kelley7622fc02009-06-04 20:32:05 +01001492#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001493
1494