blob: 34c979bcc1a9bdb158890f86ba9f1e51615b246d [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);
Simon Kelley9380ba72012-04-16 14:41:56 +0100212
213#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
214 /* after enumerate_interfaces() */
215 if (daemon->dhcp)
216 {
217 bindtodevice(daemon->dhcpfd);
218 if (daemon->enable_pxe)
219 bindtodevice(daemon->pxefd);
220 }
221#endif
222
223#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
224 if (daemon->dhcp6)
225 bindtodevice(daemon->dhcp6fd);
226#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100227 }
Simon Kelley28866e92011-02-14 20:19:14 +0000228 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100229 create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100230
Simon Kelley824af852008-02-12 20:43:05 +0000231 if (daemon->port != 0)
232 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100233
Simon Kelley28866e92011-02-14 20:19:14 +0000234 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100235#ifdef HAVE_DBUS
236 {
237 char *err;
238 daemon->dbus = NULL;
239 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100240 if ((err = dbus_init()))
241 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100242 }
243#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100244 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100245#endif
246
Simon Kelley824af852008-02-12 20:43:05 +0000247 if (daemon->port != 0)
248 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100249
Simon Kelleyc72daea2012-01-05 21:33:27 +0000250#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100251 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000252 if ((daemon->dhcp || daemon->dhcp6) &&
253 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000254 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100255 {
256 if ((ent_pw = getpwnam(daemon->scriptuser)))
257 {
258 script_uid = ent_pw->pw_uid;
259 script_gid = ent_pw->pw_gid;
260 }
261 else
262 baduser = daemon->scriptuser;
263 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100264#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000265
Simon Kelley1a6bca82008-07-11 11:11:42 +0100266 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
267 baduser = daemon->username;
268 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
269 baduser = daemon->groupname;
270
271 if (baduser)
272 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
273
274 /* implement group defaults, "dip" if available, or group associated with uid */
275 if (!daemon->group_set && !gp)
276 {
277 if (!(gp = getgrnam(CHGRP)) && ent_pw)
278 gp = getgrgid(ent_pw->pw_gid);
279
280 /* for error message */
281 if (gp)
282 daemon->groupname = gp->gr_name;
283 }
284
285#if defined(HAVE_LINUX_NETWORK)
286 /* determine capability API version here, while we can still
287 call safe_malloc */
288 if (ent_pw && ent_pw->pw_uid != 0)
289 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100290 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100291 hdr = safe_malloc(sizeof(*hdr));
292
Simon Kelley1a6bca82008-07-11 11:11:42 +0100293 /* find version supported by kernel */
294 memset(hdr, 0, sizeof(*hdr));
295 capget(hdr, NULL);
296
297 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
298 {
299 /* if unknown version, use largest supported version (3) */
300 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
301 hdr->version = LINUX_CAPABILITY_VERSION_3;
302 capsize = 2;
303 }
304
305 data = safe_malloc(sizeof(*data) * capsize);
306 memset(data, 0, sizeof(*data) * capsize);
307 }
308#endif
309
Simon Kelley5aabfc72007-08-29 11:24:47 +0100310 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100311 in a race-free manner and another to carry errors to daemon-invoking process */
312 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100313
314 piperead = pipefd[0];
315 pipewrite = pipefd[1];
316 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000317 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100318
319 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100320
Simon Kelley28866e92011-02-14 20:19:14 +0000321 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000322 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000323 /* The following code "daemonizes" the process.
324 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100325
Simon Kelley9e038942008-05-30 20:06:34 +0100326 if (chdir("/") != 0)
327 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
328
Simon Kelley16972692006-10-16 20:04:18 +0100329#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000330 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100331 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100332 pid_t pid;
333
Simon Kelley1a6bca82008-07-11 11:11:42 +0100334 /* pipe to carry errors back to original process.
335 When startup is complete we close this and the process terminates. */
336 safe_pipe(err_pipe, 0);
337
Simon Kelley7622fc02009-06-04 20:32:05 +0100338 if ((pid = fork()) == -1)
339 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000340 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100341
Simon Kelley5aabfc72007-08-29 11:24:47 +0100342 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100343 {
344 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000345 char *msg;
346
Simon Kelley1a6bca82008-07-11 11:11:42 +0100347 /* close our copy of write-end */
348 close(err_pipe[1]);
349
350 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000351 if (read_event(err_pipe[0], &ev, &msg))
352 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100353
354 _exit(EC_GOOD);
355 }
356
357 close(err_pipe[0]);
358
359 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100360
361 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100362
363 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000364 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100365
366 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100367 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100368 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000369#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100370
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000371 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100372 if (daemon->runfile)
373 {
374 FILE *pidfile;
375
376 /* only complain if started as root */
377 if ((pidfile = fopen(daemon->runfile, "w")))
378 {
379 fprintf(pidfile, "%d\n", (int) getpid());
380 fclose(pidfile);
381 }
382 else if (getuid() == 0)
383 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000384 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 _exit(0);
386 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000387 }
Simon Kelley16972692006-10-16 20:04:18 +0100388 }
389
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100390 log_err = log_start(ent_pw, err_pipe[1]);
391
Simon Kelley28866e92011-02-14 20:19:14 +0000392 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100393 {
394 /* open stdout etc to /dev/null */
395 int nullfd = open("/dev/null", O_RDWR);
396 dup2(nullfd, STDOUT_FILENO);
397 dup2(nullfd, STDERR_FILENO);
398 dup2(nullfd, STDIN_FILENO);
399 close(nullfd);
400 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100401
Simon Kelley1a6bca82008-07-11 11:11:42 +0100402 /* if we are to run scripts, we need to fork a helper before dropping root. */
403 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000404#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000405 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100406 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
407#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100408
Simon Kelley28866e92011-02-14 20:19:14 +0000409 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100410 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100411 int bad_capabilities = 0;
412 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100413
Simon Kelley1a6bca82008-07-11 11:11:42 +0100414 /* remove all supplimentary groups */
415 if (gp &&
416 (setgroups(0, &dummy) == -1 ||
417 setgid(gp->gr_gid) == -1))
418 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000419 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100420 _exit(0);
421 }
422
Simon Kelley7cebd202006-05-06 14:13:33 +0100423 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100424 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100425#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100426 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100427 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
428 ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
429 if (is_dad_listeners())
430 data->effective = data->permitted = data->inheritable =
431 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
432 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
433 else
434 data->effective = data->permitted = data->inheritable =
435 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100436
Simon Kelley16972692006-10-16 20:04:18 +0100437 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000438 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100439 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100440
Simon Kelley7622fc02009-06-04 20:32:05 +0100441#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000442 /* http://developers.sun.com/solaris/articles/program_privileges.html */
443 priv_set_t *priv_set;
444
445 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
446 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
447 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
448 bad_capabilities = errno;
449
450 if (priv_set && bad_capabilities == 0)
451 {
452 priv_inverse(priv_set);
453
454 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
455 bad_capabilities = errno;
456 }
457
458 if (priv_set)
459 priv_freeset(priv_set);
460
Simon Kelley824af852008-02-12 20:43:05 +0000461#endif
462
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100464 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000465 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100466 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100467 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100468
469 /* finally drop root */
470 if (setuid(ent_pw->pw_uid) == -1)
471 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000472 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100473 _exit(0);
474 }
475
476#ifdef HAVE_LINUX_NETWORK
Simon Kelley74c95c22011-10-19 09:33:39 +0100477 if (is_dad_listeners())
478 data->effective = data->permitted =
479 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
480 else
481 data->effective = data->permitted =
482 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100483 data->inheritable = 0;
484
485 /* lose the setuid and setgid capbilities */
486 if (capset(hdr, data) == -1)
487 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000488 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100489 _exit(0);
490 }
491#endif
492
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000493 }
Simon Kelley849a8352006-06-09 21:02:31 +0100494 }
Simon Kelley16972692006-10-16 20:04:18 +0100495
Simon Kelley16972692006-10-16 20:04:18 +0100496#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000497 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000498 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100499#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100500
Simon Kelley824af852008-02-12 20:43:05 +0000501 if (daemon->port == 0)
502 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
503 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100504 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000505 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100506 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100507
Simon Kelleyf2621c72007-04-29 19:47:21 +0100508 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100509
Simon Kelley3d8df262005-08-29 12:19:27 +0100510#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000511 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100512 {
513 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100514 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100515 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100516 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100517 }
518#endif
519
Simon Kelley1a6bca82008-07-11 11:11:42 +0100520 if (log_err != 0)
521 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
522 daemon->log_file, strerror(log_err));
523
Simon Kelleyde379512004-06-22 20:23:33 +0100524 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100525 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100526
Simon Kelley28866e92011-02-14 20:19:14 +0000527 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000528 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
529 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100530 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100531
Simon Kelley28866e92011-02-14 20:19:14 +0000532 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100533 {
534 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100535 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100536 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000537 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100538 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100539 }
540
Simon Kelleyf2621c72007-04-29 19:47:21 +0100541 if (daemon->max_logs != 0)
542 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000543
Simon Kelley843c96b2012-02-27 17:42:38 +0000544 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000545 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100546
Simon Kelley7622fc02009-06-04 20:32:05 +0100547#ifdef HAVE_DHCP
Simon Kelleyc8257542012-03-28 21:15:41 +0100548 if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000549 {
Simon Kelley3be34542004-09-11 19:12:13 +0100550 struct dhcp_context *dhcp_tmp;
Simon Kelley52b92f42012-01-22 16:05:15 +0000551 int family = AF_INET;
552 dhcp_tmp = daemon->dhcp;
553
Simon Kelley3268e902012-01-22 16:15:02 +0000554#ifdef HAVE_DHCP6
Simon Kelley52b92f42012-01-22 16:05:15 +0000555 again:
Simon Kelley3268e902012-01-22 16:15:02 +0000556#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000557 for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100558 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000559 void *start = &dhcp_tmp->start;
560 void *end = &dhcp_tmp->end;
Simon Kelleyc8257542012-03-28 21:15:41 +0100561
Simon Kelley52b92f42012-01-22 16:05:15 +0000562#ifdef HAVE_DHCP6
563 if (family == AF_INET6)
564 {
565 start = &dhcp_tmp->start6;
566 end = &dhcp_tmp->end6;
Simon Kelley30cd9662012-03-25 20:44:38 +0100567 struct in6_addr subnet = dhcp_tmp->start6;
568 setaddr6part(&subnet, 0);
Simon Kelleyc8257542012-03-28 21:15:41 +0100569 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
Simon Kelley52b92f42012-01-22 16:05:15 +0000570 }
571#endif
572
Simon Kelleyc8257542012-03-28 21:15:41 +0100573 if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
574 strcpy(daemon->namebuff, _("prefix deprecated"));
575 else
576 {
577 char *p = daemon->namebuff;
578 p += sprintf(p, _("lease time "));
579 prettyprint_time(p, dhcp_tmp->lease_time);
580 }
581
582 if (daemon->dhcp_buff)
583 inet_ntop(family, start, daemon->dhcp_buff, 256);
584 if (daemon->dhcp_buff3)
585 inet_ntop(family, end, daemon->dhcp_buff3, 256);
Simon Kelley30cd9662012-03-25 20:44:38 +0100586 if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
587 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelley30cd9662012-03-25 20:44:38 +0100588 (dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
Simon Kelleyc8257542012-03-28 21:15:41 +0100589 _("stateless DHCPv6 on %s%.0s%.0s") :
Simon Kelley22407042012-03-27 14:42:48 +0100590 (dhcp_tmp->flags & CONTEXT_STATIC) ?
Simon Kelleyc8257542012-03-28 21:15:41 +0100591 _("DHCP, static leases only on %.0s%s, %s") :
Simon Kelley30cd9662012-03-25 20:44:38 +0100592 (dhcp_tmp->flags & CONTEXT_PROXY) ?
593 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyc8257542012-03-28 21:15:41 +0100594 _("DHCP, IP range %s -- %s, %s"),
Simon Kelley30cd9662012-03-25 20:44:38 +0100595 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
Simon Kelleyc8257542012-03-28 21:15:41 +0100596
Simon Kelley30cd9662012-03-25 20:44:38 +0100597 if (dhcp_tmp->flags & CONTEXT_RA_NAME)
Simon Kelleyc8257542012-03-28 21:15:41 +0100598 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
599 daemon->addrbuff);
600 if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
601 {
602 if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
603 {
604 char *p = daemon->namebuff;
605 p += sprintf(p, _("prefix valid "));
606 prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
607 }
608 my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
609 daemon->addrbuff, daemon->namebuff);
610 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100611 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000612
613#ifdef HAVE_DHCP6
614 if (family == AF_INET)
615 {
616 family = AF_INET6;
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000617 if (daemon->ra_contexts)
618 dhcp_tmp = daemon->ra_contexts;
619 else
620 dhcp_tmp = daemon->dhcp6;
Simon Kelley52b92f42012-01-22 16:05:15 +0000621 goto again;
622 }
623#endif
624
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100626#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000627
Simon Kelley52b92f42012-01-22 16:05:15 +0000628
Simon Kelley832af0b2007-01-21 20:01:28 +0000629#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100630 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000631 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000632#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100633 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000634 max_fd = FD_SETSIZE;
635#endif
636
Simon Kelley7622fc02009-06-04 20:32:05 +0100637 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100638 daemon->tftp_prefix ? _("root is ") : _("enabled"),
639 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000640 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100641
Simon Kelley832af0b2007-01-21 20:01:28 +0000642 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100643 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000644 a single file will be sent to may clients (the file only needs
645 one fd). */
646
647 max_fd -= 30; /* use other than TFTP */
648
649 if (max_fd < 0)
650 max_fd = 5;
651 else if (max_fd < 100)
652 max_fd = max_fd/2;
653 else
654 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000655
656 /* if we have to use a limited range of ports,
657 that will limit the number of transfers */
658 if (daemon->start_tftp_port != 0 &&
659 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
660 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000661
662 if (daemon->tftp_max > max_fd)
663 {
664 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100665 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100666 _("restricting maximum simultaneous TFTP transfers to %d"),
667 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000668 }
669 }
670#endif
671
Simon Kelley1a6bca82008-07-11 11:11:42 +0100672 /* finished start-up - release original process */
673 if (err_pipe[1] != -1)
674 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000675
Simon Kelley824af852008-02-12 20:43:05 +0000676 if (daemon->port != 0)
677 check_servers();
678
Simon Kelley7cebd202006-05-06 14:13:33 +0100679 pid = getpid();
680
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100681 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000682 {
Simon Kelley16972692006-10-16 20:04:18 +0100683 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100684 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100685 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000686
687 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100688 FD_ZERO(&wset);
689 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000690
Simon Kelley16972692006-10-16 20:04:18 +0100691 /* if we are out of resources, find how long we have to wait
692 for some to come free, we'll loop around then and restart
693 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100694 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100695 {
696 t.tv_usec = 0;
697 tp = &t;
698 }
699
Simon Kelley832af0b2007-01-21 20:01:28 +0000700 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
701 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000702 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000703 {
Simon Kelley16972692006-10-16 20:04:18 +0100704 t.tv_sec = 0;
705 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100706 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000707 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100708 /* Wake every second whilst waiting for DAD to complete */
709 else if (is_dad_listeners())
710 {
711 t.tv_sec = 1;
712 t.tv_usec = 0;
713 tp = &t;
714 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100715
Simon Kelley832af0b2007-01-21 20:01:28 +0000716#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100717 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100718#endif
719
Simon Kelley7622fc02009-06-04 20:32:05 +0100720#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100721 if (daemon->dhcp)
722 {
723 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100724 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000725 if (daemon->pxefd != -1)
726 {
727 FD_SET(daemon->pxefd, &rset);
728 bump_maxfd(daemon->pxefd, &maxfd);
729 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100730 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100731#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100732
Simon Kelley52b92f42012-01-22 16:05:15 +0000733#ifdef HAVE_DHCP6
734 if (daemon->dhcp6)
735 {
736 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000737 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000738 }
739
740 if (daemon->ra_contexts)
741 {
742 FD_SET(daemon->icmp6fd, &rset);
743 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000744 }
745#endif
746
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100747#ifdef HAVE_LINUX_NETWORK
748 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100749 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100750#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100751
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100752 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100753 bump_maxfd(piperead, &maxfd);
754
Simon Kelley7622fc02009-06-04 20:32:05 +0100755#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100756# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100757 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100758
Simon Kelleya9530962012-03-20 22:07:35 +0000759# ifdef HAVE_TFTP
760 while (helper_buf_empty() && do_tftp_script_run());
761# endif
762
Simon Kelley16972692006-10-16 20:04:18 +0100763 if (!helper_buf_empty())
764 {
765 FD_SET(daemon->helperfd, &wset);
766 bump_maxfd(daemon->helperfd, &maxfd);
767 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100768# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100769 /* need this for other side-effects */
770 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000771
772# ifdef HAVE_TFTP
773 while (do_tftp_script_run());
774# endif
775
Simon Kelley7622fc02009-06-04 20:32:05 +0100776# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100777#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100778
Simon Kelleyf2621c72007-04-29 19:47:21 +0100779 /* must do this just before select(), when we know no
780 more calls to my_syslog() can occur */
781 set_log_writer(&wset, &maxfd);
782
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100783 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
784 {
785 /* otherwise undefined after error */
786 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
787 }
788
789 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000790
Simon Kelleyf2621c72007-04-29 19:47:21 +0100791 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100792
793 /* Check the interfaces to see if any have exited DAD state
794 and if so, bind the address. */
795 if (is_dad_listeners())
796 {
797 enumerate_interfaces();
798 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
799 create_bound_listeners(0);
800 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100801
Simon Kelleyc52e1892010-06-07 22:01:39 +0100802#ifdef HAVE_LINUX_NETWORK
803 if (FD_ISSET(daemon->netlinkfd, &rset))
804 netlink_multicast();
805#endif
806
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000807 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100808 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000809 if (daemon->last_resolv == 0 ||
810 difftime(now, daemon->last_resolv) > 1.0 ||
811 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000812 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100813 /* poll_resolv doesn't need to reload first time through, since
814 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100815
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100816 poll_resolv(0, daemon->last_resolv != 0, now);
817 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100819
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100820 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100821 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100822
Simon Kelley3d8df262005-08-29 12:19:27 +0100823#ifdef HAVE_DBUS
824 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000825 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100826 {
827 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100828 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100829 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100830 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100831 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100832 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100833 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100834#endif
Simon Kelley824af852008-02-12 20:43:05 +0000835
Simon Kelley5aabfc72007-08-29 11:24:47 +0100836 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000837
838#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100839 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000840#endif
841
Simon Kelley7622fc02009-06-04 20:32:05 +0100842#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000843 if (daemon->dhcp)
844 {
845 if (FD_ISSET(daemon->dhcpfd, &rset))
846 dhcp_packet(now, 0);
847 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
848 dhcp_packet(now, 1);
849 }
Simon Kelley16972692006-10-16 20:04:18 +0100850
Simon Kelley52b92f42012-01-22 16:05:15 +0000851#ifdef HAVE_DHCP6
852 if (daemon->dhcp6)
853 {
854 if (FD_ISSET(daemon->dhcp6fd, &rset))
855 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000856
Simon Kelley843c96b2012-02-27 17:42:38 +0000857 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000858 icmp6_packet();
Simon Kelley52b92f42012-01-22 16:05:15 +0000859 }
860#endif
861
Simon Kelley1f15b812009-10-13 17:49:32 +0100862# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100863 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100864 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100865# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100866#endif
867
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000868 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869}
870
Simon Kelley3be34542004-09-11 19:12:13 +0100871static void sig_handler(int sig)
872{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100873 if (pid == 0)
874 {
Simon Kelley16972692006-10-16 20:04:18 +0100875 /* ignore anything other than TERM during startup
876 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100877 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100878 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100879 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100880 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100881 {
Simon Kelley16972692006-10-16 20:04:18 +0100882 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100883 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100884 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100885 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100886 else
887 {
888 /* master process */
889 int event, errsave = errno;
890
891 if (sig == SIGHUP)
892 event = EVENT_RELOAD;
893 else if (sig == SIGCHLD)
894 event = EVENT_CHILD;
895 else if (sig == SIGALRM)
896 event = EVENT_ALARM;
897 else if (sig == SIGTERM)
898 event = EVENT_TERM;
899 else if (sig == SIGUSR1)
900 event = EVENT_DUMP;
901 else if (sig == SIGUSR2)
902 event = EVENT_REOPEN;
903 else
904 return;
905
Simon Kelleyc72daea2012-01-05 21:33:27 +0000906 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100907 errno = errsave;
908 }
Simon Kelley3be34542004-09-11 19:12:13 +0100909}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000910
Simon Kelley353ae4d2012-03-19 20:07:51 +0000911/* now == 0 -> queue immediate callback */
912void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +0000913{
Simon Kelley884a6df2012-03-20 16:20:22 +0000914 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +0000915 {
Simon Kelley884a6df2012-03-20 16:20:22 +0000916 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
917 if ((now == 0 || difftime(event, now) <= 0.0))
918 send_event(pipewrite, EVENT_ALARM, 0, NULL);
919 else
920 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +0000921 }
Simon Kelley741c2952012-02-25 13:09:18 +0000922}
923
Simon Kelleyc72daea2012-01-05 21:33:27 +0000924void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100925{
926 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000927 struct iovec iov[2];
928
Simon Kelley5aabfc72007-08-29 11:24:47 +0100929 ev.event = event;
930 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000931 ev.msg_sz = msg ? strlen(msg) : 0;
932
933 iov[0].iov_base = &ev;
934 iov[0].iov_len = sizeof(ev);
935 iov[1].iov_base = msg;
936 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100937
938 /* error pipe, debug mode. */
939 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000940 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100941 else
942 /* pipe is non-blocking and struct event_desc is smaller than
943 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000944 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100945}
Simon Kelley3d8df262005-08-29 12:19:27 +0100946
Simon Kelleyc72daea2012-01-05 21:33:27 +0000947/* NOTE: the memory used to return msg is leaked: use msgs in events only
948 to describe fatal errors. */
949static int read_event(int fd, struct event_desc *evp, char **msg)
950{
951 char *buf;
952
953 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
954 return 0;
955
956 *msg = NULL;
957
958 if (evp->msg_sz != 0 &&
959 (buf = malloc(evp->msg_sz + 1)) &&
960 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
961 {
962 buf[evp->msg_sz] = 0;
963 *msg = buf;
964 }
965
966 return 1;
967}
968
969static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100970{
971 errno = ev->data;
972
973 switch (ev->event)
974 {
975 case EVENT_DIE:
976 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100977
978 case EVENT_FORK_ERR:
979 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100980
981 case EVENT_PIPE_ERR:
982 die(_("failed to create helper: %s"), NULL, EC_MISC);
983
984 case EVENT_CAP_ERR:
985 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
986
987 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000988 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100989
990 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000991 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100992
993 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000994 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100995
996 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000997 die(_("cannot open log %s: %s"), msg, EC_FILE);
998
999 case EVENT_LUA_ERR:
1000 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001001 }
1002}
1003
Simon Kelley5aabfc72007-08-29 11:24:47 +01001004static void async_event(int pipe, time_t now)
1005{
1006 pid_t p;
1007 struct event_desc ev;
1008 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001009 char *msg;
1010
1011 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1012 to describe fatal errors. */
1013
1014 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001015 switch (ev.event)
1016 {
1017 case EVENT_RELOAD:
1018 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001019 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001020 {
1021 reload_servers(daemon->resolv_files->name);
1022 check_servers();
1023 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001024#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001025 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001026#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001027 break;
1028
1029 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001030 if (daemon->port != 0)
1031 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001032 break;
1033
1034 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001035#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001036 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001037 {
1038 lease_prune(NULL, now);
1039 lease_update_file(now);
1040 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001041#ifdef HAVE_DHCP6
1042 else if (daemon->ra_contexts)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001043 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1044 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001045#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001046#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001047 break;
1048
1049 case EVENT_CHILD:
1050 /* See Stevens 5.10 */
1051 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1052 if (p == -1)
1053 {
1054 if (errno != EINTR)
1055 break;
1056 }
1057 else
1058 for (i = 0 ; i < MAX_PROCS; i++)
1059 if (daemon->tcp_pids[i] == p)
1060 daemon->tcp_pids[i] = 0;
1061 break;
1062
1063 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001064 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001065 break;
1066
1067 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001068 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001069 break;
1070
1071 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001072 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1073 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001074 break;
1075
Simon Kelley1a6bca82008-07-11 11:11:42 +01001076 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001077 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001078 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001079 case EVENT_LUA_ERR:
1080 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001081 break;
1082
Simon Kelley5aabfc72007-08-29 11:24:47 +01001083 case EVENT_REOPEN:
1084 /* Note: this may leave TCP-handling processes with the old file still open.
1085 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1086 we leave them logging to the old file. */
1087 if (daemon->log_file != NULL)
1088 log_reopen(daemon->log_file);
1089 break;
1090
1091 case EVENT_TERM:
1092 /* Knock all our children on the head. */
1093 for (i = 0; i < MAX_PROCS; i++)
1094 if (daemon->tcp_pids[i] != 0)
1095 kill(daemon->tcp_pids[i], SIGALRM);
1096
Simon Kelleyc72daea2012-01-05 21:33:27 +00001097#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001098 /* handle pending lease transitions */
1099 if (daemon->helperfd != -1)
1100 {
1101 /* block in writes until all done */
1102 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1103 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1104 do {
1105 helper_write();
1106 } while (!helper_buf_empty() || do_script_run(now));
1107 close(daemon->helperfd);
1108 }
1109#endif
1110
1111 if (daemon->lease_stream)
1112 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001113
1114 if (daemon->runfile)
1115 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001116
1117 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1118 flush_log();
1119 exit(EC_GOOD);
1120 }
1121}
1122
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001123void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001124{
1125 struct resolvc *res, *latest;
1126 struct stat statbuf;
1127 time_t last_change = 0;
1128 /* There may be more than one possible file.
1129 Go through and find the one which changed _last_.
1130 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001131
Simon Kelley28866e92011-02-14 20:19:14 +00001132 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001133 return;
1134
Simon Kelley5aabfc72007-08-29 11:24:47 +01001135 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1136 if (stat(res->name, &statbuf) == -1)
1137 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001138 if (force)
1139 {
1140 res->mtime = 0;
1141 continue;
1142 }
1143
Simon Kelley5aabfc72007-08-29 11:24:47 +01001144 if (!res->logged)
1145 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1146 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001147
1148 if (res->mtime != 0)
1149 {
1150 /* existing file evaporated, force selection of the latest
1151 file even if its mtime hasn't changed since we last looked */
1152 poll_resolv(1, do_reload, now);
1153 return;
1154 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001155 }
1156 else
1157 {
1158 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001159 if (force || (statbuf.st_mtime != res->mtime))
1160 {
1161 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001162 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1163 {
1164 last_change = statbuf.st_mtime;
1165 latest = res;
1166 }
1167 }
1168 }
1169
1170 if (latest)
1171 {
1172 static int warned = 0;
1173 if (reload_servers(latest->name))
1174 {
1175 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1176 warned = 0;
1177 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001178 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001179 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001180 }
1181 else
1182 {
1183 latest->mtime = 0;
1184 if (!warned)
1185 {
1186 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1187 warned = 1;
1188 }
1189 }
1190 }
1191}
1192
1193void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001194{
Simon Kelley824af852008-02-12 20:43:05 +00001195 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001196 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001197
Simon Kelley7622fc02009-06-04 20:32:05 +01001198#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001199 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001200 {
Simon Kelley28866e92011-02-14 20:19:14 +00001201 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001202 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001203 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001204 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +00001205 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001206 lease_update_from_configs();
1207 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001208 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001209 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001210#ifdef HAVE_DHCP6
1211 else if (daemon->ra_contexts)
1212 {
1213 /* Not doing DHCP, so no lease system, manage
1214 alarms for ra only */
1215 time_t next_event = periodic_ra(now);
1216 if (next_event != 0)
1217 alarm((unsigned)difftime(next_event, now));
1218 }
1219#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001220#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001221}
1222
Simon Kelley5aabfc72007-08-29 11:24:47 +01001223static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001224{
1225 struct serverfd *serverfdp;
1226 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001227 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001228
1229#ifdef HAVE_TFTP
1230 int tftp = 0;
1231 struct tftp_transfer *transfer;
1232 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1233 {
1234 tftp++;
1235 FD_SET(transfer->sockfd, set);
1236 bump_maxfd(transfer->sockfd, maxfdp);
1237 }
1238#endif
1239
Simon Kelley16972692006-10-16 20:04:18 +01001240 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001241 if (daemon->port != 0)
1242 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001243
Simon Kelley3be34542004-09-11 19:12:13 +01001244 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1245 {
1246 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001247 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001248 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001249
1250 if (daemon->port != 0 && !daemon->osport)
1251 for (i = 0; i < RANDOM_SOCKS; i++)
1252 if (daemon->randomsocks[i].refcount != 0)
1253 {
1254 FD_SET(daemon->randomsocks[i].fd, set);
1255 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1256 }
1257
Simon Kelley3be34542004-09-11 19:12:13 +01001258 for (listener = daemon->listeners; listener; listener = listener->next)
1259 {
Simon Kelley16972692006-10-16 20:04:18 +01001260 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001261 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001262 {
1263 FD_SET(listener->fd, set);
1264 bump_maxfd(listener->fd, maxfdp);
1265 }
1266
1267 /* death of a child goes through the select loop, so
1268 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001269 if (listener->tcpfd != -1)
1270 for (i = 0; i < MAX_PROCS; i++)
1271 if (daemon->tcp_pids[i] == 0)
1272 {
1273 FD_SET(listener->tcpfd, set);
1274 bump_maxfd(listener->tcpfd, maxfdp);
1275 break;
1276 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001277
Simon Kelley832af0b2007-01-21 20:01:28 +00001278#ifdef HAVE_TFTP
1279 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1280 {
1281 FD_SET(listener->tftpfd, set);
1282 bump_maxfd(listener->tftpfd, maxfdp);
1283 }
1284#endif
1285
1286 }
1287
Simon Kelley16972692006-10-16 20:04:18 +01001288 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001289}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001290
Simon Kelley5aabfc72007-08-29 11:24:47 +01001291static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001292{
1293 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001294 struct listener *listener;
1295 int i;
1296
Simon Kelley832af0b2007-01-21 20:01:28 +00001297 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1298 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001299 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1300
1301 if (daemon->port != 0 && !daemon->osport)
1302 for (i = 0; i < RANDOM_SOCKS; i++)
1303 if (daemon->randomsocks[i].refcount != 0 &&
1304 FD_ISSET(daemon->randomsocks[i].fd, set))
1305 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001306
1307 for (listener = daemon->listeners; listener; listener = listener->next)
1308 {
Simon Kelley824af852008-02-12 20:43:05 +00001309 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001310 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001311
Simon Kelley832af0b2007-01-21 20:01:28 +00001312#ifdef HAVE_TFTP
1313 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001314 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001315#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001316
Simon Kelley824af852008-02-12 20:43:05 +00001317 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001318 {
1319 int confd;
1320 struct irec *iface = NULL;
1321 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001322 union mysockaddr tcp_addr;
1323 socklen_t tcp_len = sizeof(union mysockaddr);
1324
1325 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001326
Simon Kelley52d4abf2012-03-21 21:39:48 +00001327 if (confd == -1 ||
1328 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001329 continue;
1330
Simon Kelley28866e92011-02-14 20:19:14 +00001331 if (option_bool(OPT_NOWILD))
Simon Kelley52d4abf2012-03-21 21:39:48 +00001332 iface = listener->iface; /* May be NULL */
Simon Kelley832af0b2007-01-21 20:01:28 +00001333 else
1334 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001335 /* Check for allowed interfaces when binding the wildcard address:
1336 we do this by looking for an interface with the same address as
1337 the local address of the TCP connection, then looking to see if that's
1338 an allowed interface. As a side effect, we get the netmask of the
1339 interface too, for localisation. */
1340
1341 /* interface may be new since startup */
Simon Kelley52d4abf2012-03-21 21:39:48 +00001342 if (enumerate_interfaces())
Simon Kelley832af0b2007-01-21 20:01:28 +00001343 for (iface = daemon->interfaces; iface; iface = iface->next)
1344 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1345 break;
1346 }
1347
Simon Kelley52d4abf2012-03-21 21:39:48 +00001348 if (!iface && !option_bool(OPT_NOWILD))
Simon Kelley832af0b2007-01-21 20:01:28 +00001349 {
1350 shutdown(confd, SHUT_RDWR);
1351 close(confd);
1352 }
1353#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001354 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001355 {
1356 if (p != -1)
1357 {
1358 int i;
1359 for (i = 0; i < MAX_PROCS; i++)
1360 if (daemon->tcp_pids[i] == 0)
1361 {
1362 daemon->tcp_pids[i] = p;
1363 break;
1364 }
1365 }
1366 close(confd);
1367 }
1368#endif
1369 else
1370 {
1371 unsigned char *buff;
1372 struct server *s;
1373 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001374 struct in_addr netmask;
1375
1376 if (iface)
1377 netmask = iface->netmask;
1378 else
1379 netmask.s_addr = 0;
1380
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001381#ifndef NO_FORK
1382 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1383 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001384 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001385 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001386#endif
1387
Simon Kelley832af0b2007-01-21 20:01:28 +00001388 /* start with no upstream connections. */
1389 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001390 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001391
1392 /* The connected socket inherits non-blocking
1393 attribute from the listening socket.
1394 Reset that here. */
1395 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1396 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1397
Simon Kelley52d4abf2012-03-21 21:39:48 +00001398 buff = tcp_request(confd, now, &tcp_addr, netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001399
Simon Kelley832af0b2007-01-21 20:01:28 +00001400 shutdown(confd, SHUT_RDWR);
1401 close(confd);
1402
1403 if (buff)
1404 free(buff);
1405
1406 for (s = daemon->servers; s; s = s->next)
1407 if (s->tcpfd != -1)
1408 {
1409 shutdown(s->tcpfd, SHUT_RDWR);
1410 close(s->tcpfd);
1411 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001412#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001413 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001414 {
1415 flush_log();
1416 _exit(0);
1417 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001418#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001419 }
1420 }
1421 }
Simon Kelley3be34542004-09-11 19:12:13 +01001422}
1423
Simon Kelley7622fc02009-06-04 20:32:05 +01001424#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001425int make_icmp_sock(void)
1426{
Simon Kelley7cebd202006-05-06 14:13:33 +01001427 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001428 int zeroopt = 0;
1429
1430 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1431 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001432 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001433 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1434 {
1435 close(fd);
1436 fd = -1;
1437 }
1438 }
1439
1440 return fd;
1441}
1442
Simon Kelley5aabfc72007-08-29 11:24:47 +01001443int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001444{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001445 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001446
1447 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001448 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001449 better not use any resources our caller has in use...)
1450 but we remain deaf to signals or further DHCP packets. */
1451
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001452 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001453 struct sockaddr_in saddr;
1454 struct {
1455 struct ip ip;
1456 struct icmp icmp;
1457 } packet;
1458 unsigned short id = rand16();
1459 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001460 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001461 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001462
Simon Kelley824af852008-02-12 20:43:05 +00001463#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001464 if ((fd = make_icmp_sock()) == -1)
1465 return 0;
1466#else
1467 int opt = 2000;
1468 fd = daemon->dhcp_icmp_fd;
1469 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1470#endif
1471
Simon Kelley3be34542004-09-11 19:12:13 +01001472 saddr.sin_family = AF_INET;
1473 saddr.sin_port = 0;
1474 saddr.sin_addr = addr;
1475#ifdef HAVE_SOCKADDR_SA_LEN
1476 saddr.sin_len = sizeof(struct sockaddr_in);
1477#endif
1478
1479 memset(&packet.icmp, 0, sizeof(packet.icmp));
1480 packet.icmp.icmp_type = ICMP_ECHO;
1481 packet.icmp.icmp_id = id;
1482 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1483 j += ((u16 *)&packet.icmp)[i];
1484 while (j>>16)
1485 j = (j & 0xffff) + (j >> 16);
1486 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1487
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001488 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001489 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1490 retry_send());
1491
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001492 for (now = start = dnsmasq_time();
1493 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001494 {
1495 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001496 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001497 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001498 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001499 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001500
1501 tv.tv_usec = 250000;
1502 tv.tv_sec = 0;
1503
1504 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001505 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001506 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001507 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001508 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001509
1510#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001511 if (daemon->ra_contexts)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001512 {
1513 FD_SET(daemon->icmp6fd, &rset);
1514 bump_maxfd(daemon->icmp6fd, &maxfd);
1515 }
1516#endif
1517
Simon Kelleyf2621c72007-04-29 19:47:21 +01001518 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1519 {
1520 FD_ZERO(&rset);
1521 FD_ZERO(&wset);
1522 }
1523
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001524 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001525
1526 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001527 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001528
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001529#ifdef HAVE_DHCP6
Simon Kelley843c96b2012-02-27 17:42:38 +00001530 if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001531 icmp6_packet();
1532#endif
1533
Simon Kelley832af0b2007-01-21 20:01:28 +00001534#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001535 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001536#endif
1537
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001538 if (FD_ISSET(fd, &rset) &&
1539 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001540 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1541 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1542 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1543 packet.icmp.icmp_seq == 0 &&
1544 packet.icmp.icmp_id == id)
1545 {
1546 gotreply = 1;
1547 break;
1548 }
1549 }
1550
Simon Kelley824af852008-02-12 20:43:05 +00001551#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001552 close(fd);
1553#else
Simon Kelley3be34542004-09-11 19:12:13 +01001554 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001555 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1556#endif
1557
Simon Kelley3be34542004-09-11 19:12:13 +01001558 return gotreply;
1559}
Simon Kelley7622fc02009-06-04 20:32:05 +01001560#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001561
1562