blob: cd59dd252171a3321de734fae6cd916523778c0b [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 Kelley52b92f42012-01-22 16:05:15 +0000157 if (daemon->dhcp)
158 dhcp_init();
159#ifdef HAVE_DHCP6
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000160 daemon->icmp6fd = -1;
Simon Kelley52b92f42012-01-22 16:05:15 +0000161 if (daemon->dhcp6)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000162 {
163 /* ra_init before dhcp6_init, so dhcp6_init can setup multicast listening */
164 if (option_bool(OPT_RA))
165 ra_init(now);
166 dhcp6_init();
167 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000168#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000169 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100170#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100171
Simon Kelley5aabfc72007-08-29 11:24:47 +0100172 if (!enumerate_interfaces())
173 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
174
Simon Kelley28866e92011-02-14 20:19:14 +0000175 if (option_bool(OPT_NOWILD))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100176 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100177 create_bound_listeners(1);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100178
179 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
180 if (if_tmp->name && !if_tmp->used)
181 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
182
183 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
184 if (!if_tmp->used)
185 {
186 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
187 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
188 }
189 }
Simon Kelley28866e92011-02-14 20:19:14 +0000190 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100191 create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100192
Simon Kelley824af852008-02-12 20:43:05 +0000193 if (daemon->port != 0)
194 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100195
Simon Kelley28866e92011-02-14 20:19:14 +0000196 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100197#ifdef HAVE_DBUS
198 {
199 char *err;
200 daemon->dbus = NULL;
201 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100202 if ((err = dbus_init()))
203 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100204 }
205#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100206 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100207#endif
208
Simon Kelley824af852008-02-12 20:43:05 +0000209 if (daemon->port != 0)
210 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100211
Simon Kelleyc72daea2012-01-05 21:33:27 +0000212#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100213 /* Note getpwnam returns static storage */
Simon Kelley52b92f42012-01-22 16:05:15 +0000214 if ((daemon->dhcp || daemon->dhcp6) && daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000215 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100216 {
217 if ((ent_pw = getpwnam(daemon->scriptuser)))
218 {
219 script_uid = ent_pw->pw_uid;
220 script_gid = ent_pw->pw_gid;
221 }
222 else
223 baduser = daemon->scriptuser;
224 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100225#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000226
Simon Kelley1a6bca82008-07-11 11:11:42 +0100227 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
228 baduser = daemon->username;
229 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
230 baduser = daemon->groupname;
231
232 if (baduser)
233 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
234
235 /* implement group defaults, "dip" if available, or group associated with uid */
236 if (!daemon->group_set && !gp)
237 {
238 if (!(gp = getgrnam(CHGRP)) && ent_pw)
239 gp = getgrgid(ent_pw->pw_gid);
240
241 /* for error message */
242 if (gp)
243 daemon->groupname = gp->gr_name;
244 }
245
246#if defined(HAVE_LINUX_NETWORK)
247 /* determine capability API version here, while we can still
248 call safe_malloc */
249 if (ent_pw && ent_pw->pw_uid != 0)
250 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100251 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100252 hdr = safe_malloc(sizeof(*hdr));
253
Simon Kelley1a6bca82008-07-11 11:11:42 +0100254 /* find version supported by kernel */
255 memset(hdr, 0, sizeof(*hdr));
256 capget(hdr, NULL);
257
258 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
259 {
260 /* if unknown version, use largest supported version (3) */
261 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
262 hdr->version = LINUX_CAPABILITY_VERSION_3;
263 capsize = 2;
264 }
265
266 data = safe_malloc(sizeof(*data) * capsize);
267 memset(data, 0, sizeof(*data) * capsize);
268 }
269#endif
270
Simon Kelley5aabfc72007-08-29 11:24:47 +0100271 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100272 in a race-free manner and another to carry errors to daemon-invoking process */
273 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100274
275 piperead = pipefd[0];
276 pipewrite = pipefd[1];
277 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000278 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100279
280 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100281
Simon Kelley28866e92011-02-14 20:19:14 +0000282 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000284 /* The following code "daemonizes" the process.
285 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100286
Simon Kelley9e038942008-05-30 20:06:34 +0100287 if (chdir("/") != 0)
288 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
289
Simon Kelley16972692006-10-16 20:04:18 +0100290#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000291 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100292 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100293 pid_t pid;
294
Simon Kelley1a6bca82008-07-11 11:11:42 +0100295 /* pipe to carry errors back to original process.
296 When startup is complete we close this and the process terminates. */
297 safe_pipe(err_pipe, 0);
298
Simon Kelley7622fc02009-06-04 20:32:05 +0100299 if ((pid = fork()) == -1)
300 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000301 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100302
Simon Kelley5aabfc72007-08-29 11:24:47 +0100303 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100304 {
305 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000306 char *msg;
307
Simon Kelley1a6bca82008-07-11 11:11:42 +0100308 /* close our copy of write-end */
309 close(err_pipe[1]);
310
311 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000312 if (read_event(err_pipe[0], &ev, &msg))
313 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100314
315 _exit(EC_GOOD);
316 }
317
318 close(err_pipe[0]);
319
320 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100321
322 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100323
324 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000325 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100326
327 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100328 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100329 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000330#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100331
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100333 if (daemon->runfile)
334 {
335 FILE *pidfile;
336
337 /* only complain if started as root */
338 if ((pidfile = fopen(daemon->runfile, "w")))
339 {
340 fprintf(pidfile, "%d\n", (int) getpid());
341 fclose(pidfile);
342 }
343 else if (getuid() == 0)
344 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000345 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100346 _exit(0);
347 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348 }
Simon Kelley16972692006-10-16 20:04:18 +0100349 }
350
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100351 log_err = log_start(ent_pw, err_pipe[1]);
352
Simon Kelley28866e92011-02-14 20:19:14 +0000353 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100354 {
355 /* open stdout etc to /dev/null */
356 int nullfd = open("/dev/null", O_RDWR);
357 dup2(nullfd, STDOUT_FILENO);
358 dup2(nullfd, STDERR_FILENO);
359 dup2(nullfd, STDIN_FILENO);
360 close(nullfd);
361 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100362
Simon Kelley1a6bca82008-07-11 11:11:42 +0100363 /* if we are to run scripts, we need to fork a helper before dropping root. */
364 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000365#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000366 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100367 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
368#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100369
Simon Kelley28866e92011-02-14 20:19:14 +0000370 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100371 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100372 int bad_capabilities = 0;
373 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100374
Simon Kelley1a6bca82008-07-11 11:11:42 +0100375 /* remove all supplimentary groups */
376 if (gp &&
377 (setgroups(0, &dummy) == -1 ||
378 setgid(gp->gr_gid) == -1))
379 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000380 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381 _exit(0);
382 }
383
Simon Kelley7cebd202006-05-06 14:13:33 +0100384 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100385 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100386#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100387 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100388 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
389 ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
390 if (is_dad_listeners())
391 data->effective = data->permitted = data->inheritable =
392 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
393 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
394 else
395 data->effective = data->permitted = data->inheritable =
396 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100397
Simon Kelley16972692006-10-16 20:04:18 +0100398 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000399 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100400 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100401
Simon Kelley7622fc02009-06-04 20:32:05 +0100402#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000403 /* http://developers.sun.com/solaris/articles/program_privileges.html */
404 priv_set_t *priv_set;
405
406 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
407 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
408 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
409 bad_capabilities = errno;
410
411 if (priv_set && bad_capabilities == 0)
412 {
413 priv_inverse(priv_set);
414
415 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
416 bad_capabilities = errno;
417 }
418
419 if (priv_set)
420 priv_freeset(priv_set);
421
Simon Kelley824af852008-02-12 20:43:05 +0000422#endif
423
Simon Kelley1a6bca82008-07-11 11:11:42 +0100424 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100425 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000426 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100427 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100428 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100429
430 /* finally drop root */
431 if (setuid(ent_pw->pw_uid) == -1)
432 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000433 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100434 _exit(0);
435 }
436
437#ifdef HAVE_LINUX_NETWORK
Simon Kelley74c95c22011-10-19 09:33:39 +0100438 if (is_dad_listeners())
439 data->effective = data->permitted =
440 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
441 else
442 data->effective = data->permitted =
443 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100444 data->inheritable = 0;
445
446 /* lose the setuid and setgid capbilities */
447 if (capset(hdr, data) == -1)
448 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000449 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100450 _exit(0);
451 }
452#endif
453
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000454 }
Simon Kelley849a8352006-06-09 21:02:31 +0100455 }
Simon Kelley16972692006-10-16 20:04:18 +0100456
Simon Kelley16972692006-10-16 20:04:18 +0100457#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000458 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000459 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100460#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100461
Simon Kelley824af852008-02-12 20:43:05 +0000462 if (daemon->port == 0)
463 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
464 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100465 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000466 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100467 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100468
Simon Kelleyf2621c72007-04-29 19:47:21 +0100469 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100470
Simon Kelley3d8df262005-08-29 12:19:27 +0100471#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000472 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100473 {
474 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100475 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100476 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100477 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100478 }
479#endif
480
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481 if (log_err != 0)
482 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
483 daemon->log_file, strerror(log_err));
484
Simon Kelleyde379512004-06-22 20:23:33 +0100485 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100486 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100487
Simon Kelley28866e92011-02-14 20:19:14 +0000488 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000489 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
490 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100491 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100492
Simon Kelley28866e92011-02-14 20:19:14 +0000493 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100494 {
495 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100496 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100497 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000498 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100499 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100500 }
501
Simon Kelleyf2621c72007-04-29 19:47:21 +0100502 if (daemon->max_logs != 0)
503 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000504
505 if (option_bool(OPT_RA))
506 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100507
Simon Kelley7622fc02009-06-04 20:32:05 +0100508#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000509 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000510 {
Simon Kelley3be34542004-09-11 19:12:13 +0100511 struct dhcp_context *dhcp_tmp;
Simon Kelley52b92f42012-01-22 16:05:15 +0000512 int family = AF_INET;
513 dhcp_tmp = daemon->dhcp;
514
Simon Kelley3268e902012-01-22 16:15:02 +0000515#ifdef HAVE_DHCP6
Simon Kelley52b92f42012-01-22 16:05:15 +0000516 again:
Simon Kelley3268e902012-01-22 16:15:02 +0000517#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000518 for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100519 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000520 void *start = &dhcp_tmp->start;
521 void *end = &dhcp_tmp->end;
522
523#ifdef HAVE_DHCP6
524 if (family == AF_INET6)
525 {
526 start = &dhcp_tmp->start6;
527 end = &dhcp_tmp->end6;
528 }
529#endif
530
Simon Kelley0a852542005-03-23 20:28:59 +0000531 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley52b92f42012-01-22 16:05:15 +0000532 inet_ntop(family, start, daemon->dhcp_buff, 256);
533 inet_ntop(family, end, daemon->dhcp_buff3, 256);
Simon Kelley7622fc02009-06-04 20:32:05 +0100534 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100535 (dhcp_tmp->flags & CONTEXT_STATIC) ?
536 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000537 (dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
538 _("router advertisement only on %.0s%s, lifetime %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100539 (dhcp_tmp->flags & CONTEXT_PROXY) ?
540 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100541 _("DHCP, IP range %s -- %s, lease time %s"),
Simon Kelley52b92f42012-01-22 16:05:15 +0000542 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100543 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000544
545#ifdef HAVE_DHCP6
546 if (family == AF_INET)
547 {
548 family = AF_INET6;
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000549 if (daemon->ra_contexts)
550 dhcp_tmp = daemon->ra_contexts;
551 else
552 dhcp_tmp = daemon->dhcp6;
Simon Kelley52b92f42012-01-22 16:05:15 +0000553 goto again;
554 }
555#endif
556
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000557 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100558#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000559
Simon Kelley52b92f42012-01-22 16:05:15 +0000560
Simon Kelley832af0b2007-01-21 20:01:28 +0000561#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100562 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000563 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000564#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100565 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000566 max_fd = FD_SETSIZE;
567#endif
568
Simon Kelley7622fc02009-06-04 20:32:05 +0100569 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100570 daemon->tftp_prefix ? _("root is ") : _("enabled"),
571 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000572 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100573
Simon Kelley832af0b2007-01-21 20:01:28 +0000574 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100575 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000576 a single file will be sent to may clients (the file only needs
577 one fd). */
578
579 max_fd -= 30; /* use other than TFTP */
580
581 if (max_fd < 0)
582 max_fd = 5;
583 else if (max_fd < 100)
584 max_fd = max_fd/2;
585 else
586 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000587
588 /* if we have to use a limited range of ports,
589 that will limit the number of transfers */
590 if (daemon->start_tftp_port != 0 &&
591 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
592 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000593
594 if (daemon->tftp_max > max_fd)
595 {
596 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100597 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100598 _("restricting maximum simultaneous TFTP transfers to %d"),
599 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000600 }
601 }
602#endif
603
Simon Kelley1a6bca82008-07-11 11:11:42 +0100604 /* finished start-up - release original process */
605 if (err_pipe[1] != -1)
606 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000607
Simon Kelley824af852008-02-12 20:43:05 +0000608 if (daemon->port != 0)
609 check_servers();
610
Simon Kelley7cebd202006-05-06 14:13:33 +0100611 pid = getpid();
612
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100613 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614 {
Simon Kelley16972692006-10-16 20:04:18 +0100615 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100616 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100617 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000618
619 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100620 FD_ZERO(&wset);
621 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000622
Simon Kelley16972692006-10-16 20:04:18 +0100623 /* if we are out of resources, find how long we have to wait
624 for some to come free, we'll loop around then and restart
625 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100626 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100627 {
628 t.tv_usec = 0;
629 tp = &t;
630 }
631
Simon Kelley832af0b2007-01-21 20:01:28 +0000632 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
633 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000634 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000635 {
Simon Kelley16972692006-10-16 20:04:18 +0100636 t.tv_sec = 0;
637 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100638 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000639 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100640 /* Wake every second whilst waiting for DAD to complete */
641 else if (is_dad_listeners())
642 {
643 t.tv_sec = 1;
644 t.tv_usec = 0;
645 tp = &t;
646 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100647
Simon Kelley832af0b2007-01-21 20:01:28 +0000648#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100649 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100650#endif
651
Simon Kelley7622fc02009-06-04 20:32:05 +0100652#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100653 if (daemon->dhcp)
654 {
655 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100656 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000657 if (daemon->pxefd != -1)
658 {
659 FD_SET(daemon->pxefd, &rset);
660 bump_maxfd(daemon->pxefd, &maxfd);
661 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100662 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100663#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100664
Simon Kelley52b92f42012-01-22 16:05:15 +0000665#ifdef HAVE_DHCP6
666 if (daemon->dhcp6)
667 {
668 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000669 bump_maxfd(daemon->dhcp6fd, &maxfd);
670
671 if (daemon->icmp6fd != -1)
672 {
673 FD_SET(daemon->icmp6fd, &rset);
674 bump_maxfd(daemon->icmp6fd, &maxfd);
675 }
Simon Kelley52b92f42012-01-22 16:05:15 +0000676 }
677#endif
678
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100679#ifdef HAVE_LINUX_NETWORK
680 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100681 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100682#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100683
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100684 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100685 bump_maxfd(piperead, &maxfd);
686
Simon Kelley7622fc02009-06-04 20:32:05 +0100687#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100688# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100689 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100690
691 if (!helper_buf_empty())
692 {
693 FD_SET(daemon->helperfd, &wset);
694 bump_maxfd(daemon->helperfd, &maxfd);
695 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100696# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100697 /* need this for other side-effects */
698 while (do_script_run(now));
Simon Kelley7622fc02009-06-04 20:32:05 +0100699# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100700#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100701
Simon Kelleyf2621c72007-04-29 19:47:21 +0100702 /* must do this just before select(), when we know no
703 more calls to my_syslog() can occur */
704 set_log_writer(&wset, &maxfd);
705
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100706 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
707 {
708 /* otherwise undefined after error */
709 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
710 }
711
712 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000713
Simon Kelleyf2621c72007-04-29 19:47:21 +0100714 check_log_writer(&wset);
Simon Kelley74c95c22011-10-19 09:33:39 +0100715
716 /* Check the interfaces to see if any have exited DAD state
717 and if so, bind the address. */
718 if (is_dad_listeners())
719 {
720 enumerate_interfaces();
721 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
722 create_bound_listeners(0);
723 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100724
Simon Kelleyc52e1892010-06-07 22:01:39 +0100725#ifdef HAVE_LINUX_NETWORK
726 if (FD_ISSET(daemon->netlinkfd, &rset))
727 netlink_multicast();
728#endif
729
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000730 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100731 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000732 if (daemon->last_resolv == 0 ||
733 difftime(now, daemon->last_resolv) > 1.0 ||
734 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000735 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100736 /* poll_resolv doesn't need to reload first time through, since
737 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100738
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100739 poll_resolv(0, daemon->last_resolv != 0, now);
740 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000741 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100742
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100743 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100744 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100745
Simon Kelley3d8df262005-08-29 12:19:27 +0100746#ifdef HAVE_DBUS
747 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000748 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100749 {
750 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100751 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100752 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100753 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100754 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100755 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100756 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100757#endif
Simon Kelley824af852008-02-12 20:43:05 +0000758
Simon Kelley5aabfc72007-08-29 11:24:47 +0100759 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000760
761#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100762 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000763#endif
764
Simon Kelley7622fc02009-06-04 20:32:05 +0100765#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000766 if (daemon->dhcp)
767 {
768 if (FD_ISSET(daemon->dhcpfd, &rset))
769 dhcp_packet(now, 0);
770 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
771 dhcp_packet(now, 1);
772 }
Simon Kelley16972692006-10-16 20:04:18 +0100773
Simon Kelley52b92f42012-01-22 16:05:15 +0000774#ifdef HAVE_DHCP6
775 if (daemon->dhcp6)
776 {
777 if (FD_ISSET(daemon->dhcp6fd, &rset))
778 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000779
780 if (daemon->icmp6fd != -1 && FD_ISSET(daemon->icmp6fd, &rset))
781 icmp6_packet();
Simon Kelley52b92f42012-01-22 16:05:15 +0000782 }
783#endif
784
Simon Kelley1f15b812009-10-13 17:49:32 +0100785# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100786 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100787 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100788# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100789#endif
790
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000791 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000792}
793
Simon Kelley3be34542004-09-11 19:12:13 +0100794static void sig_handler(int sig)
795{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100796 if (pid == 0)
797 {
Simon Kelley16972692006-10-16 20:04:18 +0100798 /* ignore anything other than TERM during startup
799 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100800 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100801 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100802 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100803 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100804 {
Simon Kelley16972692006-10-16 20:04:18 +0100805 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100806 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100807 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100808 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100809 else
810 {
811 /* master process */
812 int event, errsave = errno;
813
814 if (sig == SIGHUP)
815 event = EVENT_RELOAD;
816 else if (sig == SIGCHLD)
817 event = EVENT_CHILD;
818 else if (sig == SIGALRM)
819 event = EVENT_ALARM;
820 else if (sig == SIGTERM)
821 event = EVENT_TERM;
822 else if (sig == SIGUSR1)
823 event = EVENT_DUMP;
824 else if (sig == SIGUSR2)
825 event = EVENT_REOPEN;
826 else
827 return;
828
Simon Kelleyc72daea2012-01-05 21:33:27 +0000829 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100830 errno = errsave;
831 }
Simon Kelley3be34542004-09-11 19:12:13 +0100832}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833
Simon Kelley741c2952012-02-25 13:09:18 +0000834void send_alarm(void)
835{
836 send_event(pipewrite, EVENT_ALARM, 0, NULL);
837}
838
Simon Kelleyc72daea2012-01-05 21:33:27 +0000839void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100840{
841 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000842 struct iovec iov[2];
843
Simon Kelley5aabfc72007-08-29 11:24:47 +0100844 ev.event = event;
845 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000846 ev.msg_sz = msg ? strlen(msg) : 0;
847
848 iov[0].iov_base = &ev;
849 iov[0].iov_len = sizeof(ev);
850 iov[1].iov_base = msg;
851 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100852
853 /* error pipe, debug mode. */
854 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000855 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100856 else
857 /* pipe is non-blocking and struct event_desc is smaller than
858 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000859 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100860}
Simon Kelley3d8df262005-08-29 12:19:27 +0100861
Simon Kelleyc72daea2012-01-05 21:33:27 +0000862/* NOTE: the memory used to return msg is leaked: use msgs in events only
863 to describe fatal errors. */
864static int read_event(int fd, struct event_desc *evp, char **msg)
865{
866 char *buf;
867
868 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
869 return 0;
870
871 *msg = NULL;
872
873 if (evp->msg_sz != 0 &&
874 (buf = malloc(evp->msg_sz + 1)) &&
875 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
876 {
877 buf[evp->msg_sz] = 0;
878 *msg = buf;
879 }
880
881 return 1;
882}
883
884static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100885{
886 errno = ev->data;
887
888 switch (ev->event)
889 {
890 case EVENT_DIE:
891 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100892
893 case EVENT_FORK_ERR:
894 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100895
896 case EVENT_PIPE_ERR:
897 die(_("failed to create helper: %s"), NULL, EC_MISC);
898
899 case EVENT_CAP_ERR:
900 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
901
902 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000903 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100904
905 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000906 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100907
908 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000909 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100910
911 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000912 die(_("cannot open log %s: %s"), msg, EC_FILE);
913
914 case EVENT_LUA_ERR:
915 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100916 }
917}
918
Simon Kelley5aabfc72007-08-29 11:24:47 +0100919static void async_event(int pipe, time_t now)
920{
921 pid_t p;
922 struct event_desc ev;
923 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000924 char *msg;
925
926 /* NOTE: the memory used to return msg is leaked: use msgs in events only
927 to describe fatal errors. */
928
929 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 switch (ev.event)
931 {
932 case EVENT_RELOAD:
933 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +0000934 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100935 {
936 reload_servers(daemon->resolv_files->name);
937 check_servers();
938 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100939#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100940 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100941#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100942 break;
943
944 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000945 if (daemon->port != 0)
946 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100947 break;
948
949 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +0100950#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +0000951 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100952 {
953 lease_prune(NULL, now);
954 lease_update_file(now);
955 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100956#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100957 break;
958
959 case EVENT_CHILD:
960 /* See Stevens 5.10 */
961 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
962 if (p == -1)
963 {
964 if (errno != EINTR)
965 break;
966 }
967 else
968 for (i = 0 ; i < MAX_PROCS; i++)
969 if (daemon->tcp_pids[i] == p)
970 daemon->tcp_pids[i] = 0;
971 break;
972
973 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000974 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100975 break;
976
977 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000978 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100979 break;
980
981 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +0100982 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
983 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100984 break;
985
Simon Kelley1a6bca82008-07-11 11:11:42 +0100986 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000987 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +0100988 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +0000989 case EVENT_LUA_ERR:
990 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +0100991 break;
992
Simon Kelley5aabfc72007-08-29 11:24:47 +0100993 case EVENT_REOPEN:
994 /* Note: this may leave TCP-handling processes with the old file still open.
995 Since any such process will die in CHILD_LIFETIME or probably much sooner,
996 we leave them logging to the old file. */
997 if (daemon->log_file != NULL)
998 log_reopen(daemon->log_file);
999 break;
1000
1001 case EVENT_TERM:
1002 /* Knock all our children on the head. */
1003 for (i = 0; i < MAX_PROCS; i++)
1004 if (daemon->tcp_pids[i] != 0)
1005 kill(daemon->tcp_pids[i], SIGALRM);
1006
Simon Kelleyc72daea2012-01-05 21:33:27 +00001007#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001008 /* handle pending lease transitions */
1009 if (daemon->helperfd != -1)
1010 {
1011 /* block in writes until all done */
1012 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1013 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1014 do {
1015 helper_write();
1016 } while (!helper_buf_empty() || do_script_run(now));
1017 close(daemon->helperfd);
1018 }
1019#endif
1020
1021 if (daemon->lease_stream)
1022 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001023
1024 if (daemon->runfile)
1025 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001026
1027 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1028 flush_log();
1029 exit(EC_GOOD);
1030 }
1031}
1032
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001033void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001034{
1035 struct resolvc *res, *latest;
1036 struct stat statbuf;
1037 time_t last_change = 0;
1038 /* There may be more than one possible file.
1039 Go through and find the one which changed _last_.
1040 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001041
Simon Kelley28866e92011-02-14 20:19:14 +00001042 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001043 return;
1044
Simon Kelley5aabfc72007-08-29 11:24:47 +01001045 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1046 if (stat(res->name, &statbuf) == -1)
1047 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001048 if (force)
1049 {
1050 res->mtime = 0;
1051 continue;
1052 }
1053
Simon Kelley5aabfc72007-08-29 11:24:47 +01001054 if (!res->logged)
1055 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1056 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001057
1058 if (res->mtime != 0)
1059 {
1060 /* existing file evaporated, force selection of the latest
1061 file even if its mtime hasn't changed since we last looked */
1062 poll_resolv(1, do_reload, now);
1063 return;
1064 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001065 }
1066 else
1067 {
1068 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001069 if (force || (statbuf.st_mtime != res->mtime))
1070 {
1071 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001072 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1073 {
1074 last_change = statbuf.st_mtime;
1075 latest = res;
1076 }
1077 }
1078 }
1079
1080 if (latest)
1081 {
1082 static int warned = 0;
1083 if (reload_servers(latest->name))
1084 {
1085 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1086 warned = 0;
1087 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001088 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001089 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001090 }
1091 else
1092 {
1093 latest->mtime = 0;
1094 if (!warned)
1095 {
1096 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1097 warned = 1;
1098 }
1099 }
1100 }
1101}
1102
1103void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001104{
Simon Kelley824af852008-02-12 20:43:05 +00001105 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001106 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001107
Simon Kelley7622fc02009-06-04 20:32:05 +01001108#ifdef HAVE_DHCP
Simon Kelley52b92f42012-01-22 16:05:15 +00001109 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001110 {
Simon Kelley28866e92011-02-14 20:19:14 +00001111 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001112 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001113 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001114 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +00001115 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001116 lease_update_from_configs();
1117 lease_update_file(now);
1118 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +01001119 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001120#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001121}
1122
Simon Kelley5aabfc72007-08-29 11:24:47 +01001123static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001124{
1125 struct serverfd *serverfdp;
1126 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001127 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001128
1129#ifdef HAVE_TFTP
1130 int tftp = 0;
1131 struct tftp_transfer *transfer;
1132 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1133 {
1134 tftp++;
1135 FD_SET(transfer->sockfd, set);
1136 bump_maxfd(transfer->sockfd, maxfdp);
1137 }
1138#endif
1139
Simon Kelley16972692006-10-16 20:04:18 +01001140 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001141 if (daemon->port != 0)
1142 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001143
Simon Kelley3be34542004-09-11 19:12:13 +01001144 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1145 {
1146 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001147 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001148 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001149
1150 if (daemon->port != 0 && !daemon->osport)
1151 for (i = 0; i < RANDOM_SOCKS; i++)
1152 if (daemon->randomsocks[i].refcount != 0)
1153 {
1154 FD_SET(daemon->randomsocks[i].fd, set);
1155 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1156 }
1157
Simon Kelley3be34542004-09-11 19:12:13 +01001158 for (listener = daemon->listeners; listener; listener = listener->next)
1159 {
Simon Kelley16972692006-10-16 20:04:18 +01001160 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001161 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001162 {
1163 FD_SET(listener->fd, set);
1164 bump_maxfd(listener->fd, maxfdp);
1165 }
1166
1167 /* death of a child goes through the select loop, so
1168 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001169 if (listener->tcpfd != -1)
1170 for (i = 0; i < MAX_PROCS; i++)
1171 if (daemon->tcp_pids[i] == 0)
1172 {
1173 FD_SET(listener->tcpfd, set);
1174 bump_maxfd(listener->tcpfd, maxfdp);
1175 break;
1176 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001177
Simon Kelley832af0b2007-01-21 20:01:28 +00001178#ifdef HAVE_TFTP
1179 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1180 {
1181 FD_SET(listener->tftpfd, set);
1182 bump_maxfd(listener->tftpfd, maxfdp);
1183 }
1184#endif
1185
1186 }
1187
Simon Kelley16972692006-10-16 20:04:18 +01001188 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001189}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001190
Simon Kelley5aabfc72007-08-29 11:24:47 +01001191static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001192{
1193 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001194 struct listener *listener;
1195 int i;
1196
Simon Kelley832af0b2007-01-21 20:01:28 +00001197 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1198 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001199 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1200
1201 if (daemon->port != 0 && !daemon->osport)
1202 for (i = 0; i < RANDOM_SOCKS; i++)
1203 if (daemon->randomsocks[i].refcount != 0 &&
1204 FD_ISSET(daemon->randomsocks[i].fd, set))
1205 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001206
1207 for (listener = daemon->listeners; listener; listener = listener->next)
1208 {
Simon Kelley824af852008-02-12 20:43:05 +00001209 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001210 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001211
Simon Kelley832af0b2007-01-21 20:01:28 +00001212#ifdef HAVE_TFTP
1213 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001214 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001215#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001216
Simon Kelley824af852008-02-12 20:43:05 +00001217 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001218 {
1219 int confd;
1220 struct irec *iface = NULL;
1221 pid_t p;
1222
1223 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1224
1225 if (confd == -1)
1226 continue;
1227
Simon Kelley28866e92011-02-14 20:19:14 +00001228 if (option_bool(OPT_NOWILD))
Simon Kelley832af0b2007-01-21 20:01:28 +00001229 iface = listener->iface;
1230 else
1231 {
1232 union mysockaddr tcp_addr;
1233 socklen_t tcp_len = sizeof(union mysockaddr);
1234 /* Check for allowed interfaces when binding the wildcard address:
1235 we do this by looking for an interface with the same address as
1236 the local address of the TCP connection, then looking to see if that's
1237 an allowed interface. As a side effect, we get the netmask of the
1238 interface too, for localisation. */
1239
1240 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001241 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001242 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1243 for (iface = daemon->interfaces; iface; iface = iface->next)
1244 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1245 break;
1246 }
1247
1248 if (!iface)
1249 {
1250 shutdown(confd, SHUT_RDWR);
1251 close(confd);
1252 }
1253#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001254 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001255 {
1256 if (p != -1)
1257 {
1258 int i;
1259 for (i = 0; i < MAX_PROCS; i++)
1260 if (daemon->tcp_pids[i] == 0)
1261 {
1262 daemon->tcp_pids[i] = p;
1263 break;
1264 }
1265 }
1266 close(confd);
1267 }
1268#endif
1269 else
1270 {
1271 unsigned char *buff;
1272 struct server *s;
1273 int flags;
Simon Kelley832af0b2007-01-21 20:01:28 +00001274
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001275#ifndef NO_FORK
1276 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1277 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001278 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001279 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001280#endif
1281
Simon Kelley832af0b2007-01-21 20:01:28 +00001282 /* start with no upstream connections. */
1283 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001284 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001285
1286 /* The connected socket inherits non-blocking
1287 attribute from the listening socket.
1288 Reset that here. */
1289 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1290 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1291
Simon Kelley7de060b2011-08-26 17:24:52 +01001292 buff = tcp_request(confd, now, &iface->addr, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001293
Simon Kelley832af0b2007-01-21 20:01:28 +00001294 shutdown(confd, SHUT_RDWR);
1295 close(confd);
1296
1297 if (buff)
1298 free(buff);
1299
1300 for (s = daemon->servers; s; s = s->next)
1301 if (s->tcpfd != -1)
1302 {
1303 shutdown(s->tcpfd, SHUT_RDWR);
1304 close(s->tcpfd);
1305 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001306#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001307 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001308 {
1309 flush_log();
1310 _exit(0);
1311 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001312#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001313 }
1314 }
1315 }
Simon Kelley3be34542004-09-11 19:12:13 +01001316}
1317
Simon Kelley7622fc02009-06-04 20:32:05 +01001318#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001319int make_icmp_sock(void)
1320{
Simon Kelley7cebd202006-05-06 14:13:33 +01001321 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001322 int zeroopt = 0;
1323
1324 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1325 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001326 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001327 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1328 {
1329 close(fd);
1330 fd = -1;
1331 }
1332 }
1333
1334 return fd;
1335}
1336
Simon Kelley5aabfc72007-08-29 11:24:47 +01001337int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001338{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001339 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001340
1341 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001342 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001343 better not use any resources our caller has in use...)
1344 but we remain deaf to signals or further DHCP packets. */
1345
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001346 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001347 struct sockaddr_in saddr;
1348 struct {
1349 struct ip ip;
1350 struct icmp icmp;
1351 } packet;
1352 unsigned short id = rand16();
1353 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001354 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001355 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001356
Simon Kelley824af852008-02-12 20:43:05 +00001357#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001358 if ((fd = make_icmp_sock()) == -1)
1359 return 0;
1360#else
1361 int opt = 2000;
1362 fd = daemon->dhcp_icmp_fd;
1363 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1364#endif
1365
Simon Kelley3be34542004-09-11 19:12:13 +01001366 saddr.sin_family = AF_INET;
1367 saddr.sin_port = 0;
1368 saddr.sin_addr = addr;
1369#ifdef HAVE_SOCKADDR_SA_LEN
1370 saddr.sin_len = sizeof(struct sockaddr_in);
1371#endif
1372
1373 memset(&packet.icmp, 0, sizeof(packet.icmp));
1374 packet.icmp.icmp_type = ICMP_ECHO;
1375 packet.icmp.icmp_id = id;
1376 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1377 j += ((u16 *)&packet.icmp)[i];
1378 while (j>>16)
1379 j = (j & 0xffff) + (j >> 16);
1380 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1381
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001382 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001383 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1384 retry_send());
1385
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001386 for (now = start = dnsmasq_time();
1387 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001388 {
1389 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001390 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001391 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001392 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001393 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001394
1395 tv.tv_usec = 250000;
1396 tv.tv_sec = 0;
1397
1398 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001399 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001400 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001401 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001402 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001403
1404#ifdef HAVE_DHCP6
1405 if (daemon->icmp6fd != -1)
1406 {
1407 FD_SET(daemon->icmp6fd, &rset);
1408 bump_maxfd(daemon->icmp6fd, &maxfd);
1409 }
1410#endif
1411
Simon Kelleyf2621c72007-04-29 19:47:21 +01001412 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1413 {
1414 FD_ZERO(&rset);
1415 FD_ZERO(&wset);
1416 }
1417
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001418 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001419
1420 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001421 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001422
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001423#ifdef HAVE_DHCP6
1424 if (daemon->icmp6fd != -1 && FD_ISSET(daemon->icmp6fd, &rset))
1425 icmp6_packet();
1426#endif
1427
Simon Kelley832af0b2007-01-21 20:01:28 +00001428#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001429 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001430#endif
1431
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001432 if (FD_ISSET(fd, &rset) &&
1433 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001434 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1435 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1436 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1437 packet.icmp.icmp_seq == 0 &&
1438 packet.icmp.icmp_id == id)
1439 {
1440 gotreply = 1;
1441 break;
1442 }
1443 }
1444
Simon Kelley824af852008-02-12 20:43:05 +00001445#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001446 close(fd);
1447#else
Simon Kelley3be34542004-09-11 19:12:13 +01001448 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001449 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1450#endif
1451
Simon Kelley3be34542004-09-11 19:12:13 +01001452 return gotreply;
1453}
Simon Kelley7622fc02009-06-04 20:32:05 +01001454#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001455
1456