blob: 57ae0f3f92b9645e1c06146fb69c651418f37631 [file] [log] [blame]
Simon Kelley824af852008-02-12 20:43:05 +00001/* dnsmasq is Copyright (c) 2000-2007 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
13 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 Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Simon Kelley5aabfc72007-08-29 11:24:47 +010019struct daemon *daemon;
20
Simon Kelley3d8df262005-08-29 12:19:27 +010021static char *compile_opts =
22#ifndef HAVE_IPV6
23"no-"
24#endif
25"IPv6 "
26#ifndef HAVE_GETOPT_LONG
27"no-"
28#endif
29"GNU-getopt "
30#ifdef HAVE_BROKEN_RTC
31"no-RTC "
32#endif
Simon Kelley16972692006-10-16 20:04:18 +010033#ifdef NO_FORK
34"no-MMU "
35#endif
Simon Kelley9e038942008-05-30 20:06:34 +010036#ifdef HAVE_BSD_BRIDGE
37"BSD-bridge "
38#endif
Simon Kelley3d8df262005-08-29 12:19:27 +010039#ifndef HAVE_ISC_READER
40"no-"
41#endif
42"ISC-leasefile "
43#ifndef HAVE_DBUS
44"no-"
45#endif
Simon Kelleyb8187c82005-11-26 21:46:27 +000046"DBus "
Simon Kelley824af852008-02-12 20:43:05 +000047#ifndef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000048"no-"
49#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000050"I18N "
51#ifndef HAVE_TFTP
52"no-"
53#endif
54"TFTP";
Simon Kelley3d8df262005-08-29 12:19:27 +010055
Simon Kelley5aabfc72007-08-29 11:24:47 +010056static volatile pid_t pid = 0;
57static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000058
Simon Kelley5aabfc72007-08-29 11:24:47 +010059static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
60static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010061static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010062static void async_event(int pipe, time_t now);
Simon Kelley1a6bca82008-07-11 11:11:42 +010063static void fatal_event(struct event_desc *ev);
Simon Kelley5aabfc72007-08-29 11:24:47 +010064static void poll_resolv(void);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065
66int main (int argc, char **argv)
67{
Simon Kelleyde379512004-06-22 20:23:33 +010068 int bind_fallback = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000069 time_t now, last = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000071 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010072 int piperead, pipefd[2], err_pipe[2];
73 struct passwd *ent_pw = NULL;
74 uid_t script_uid = 0;
75 gid_t script_gid = 0;
76 struct group *gp= NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010077 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010078 char *baduser = NULL;
79 int log_err;
80#if defined(HAVE_LINUX_NETWORK)
81 cap_user_header_t hdr = NULL;
82 cap_user_data_t data = NULL;
83#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010084
Simon Kelley824af852008-02-12 20:43:05 +000085#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000086 setlocale(LC_ALL, "");
87 bindtextdomain("dnsmasq", LOCALEDIR);
88 textdomain("dnsmasq");
89#endif
90
Simon Kelley9e4abcb2004-01-22 19:47:41 +000091 sigact.sa_handler = sig_handler;
92 sigact.sa_flags = 0;
93 sigemptyset(&sigact.sa_mask);
94 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010095 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000096 sigaction(SIGHUP, &sigact, NULL);
97 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000098 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010099 sigaction(SIGCHLD, &sigact, NULL);
100
101 /* ignore SIGPIPE */
102 sigact.sa_handler = SIG_IGN;
103 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000104
Simon Kelley5aabfc72007-08-29 11:24:47 +0100105 umask(022); /* known umask, create leases and pid files as 0644 */
106
107 read_opts(argc, argv, compile_opts);
108
Simon Kelley3be34542004-09-11 19:12:13 +0100109 if (daemon->edns_pktsz < PACKETSZ)
110 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +0000111 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
112 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
113 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100114
Simon Kelley3be34542004-09-11 19:12:13 +0100115 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000116 {
Simon Kelley3be34542004-09-11 19:12:13 +0100117 if (daemon->dhcp)
118 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000119 }
Simon Kelley33820b72004-04-03 21:10:00 +0100120#ifndef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100121 else if (!daemon->dhcp)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100122 die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
Simon Kelley33820b72004-04-03 21:10:00 +0100123#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000124
Simon Kelley5aabfc72007-08-29 11:24:47 +0100125 /* Close any file descriptors we inherited apart from std{in|out|err} */
126 for (i = 0; i < max_fd; i++)
127 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
128 close(i);
129
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100130#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100131 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100132#elif !(defined(IP_RECVDSTADDR) && \
133 defined(IP_RECVIF) && \
134 defined(IP_SENDSRCADDR))
135 if (!(daemon->options & OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100136 {
137 bind_fallback = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100138 daemon->options |= OPT_NOWILD;
Simon Kelleyde379512004-06-22 20:23:33 +0100139 }
Simon Kelley309331f2006-04-22 15:05:01 +0100140#endif
141
Simon Kelley832af0b2007-01-21 20:01:28 +0000142#ifndef HAVE_TFTP
143 if (daemon->options & OPT_TFTP)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100144 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000145#endif
146
Simon Kelley824af852008-02-12 20:43:05 +0000147#ifdef HAVE_SOLARIS_NETWORK
148 if (daemon->max_logs != 0)
149 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
150#endif
151
Simon Kelley1a6bca82008-07-11 11:11:42 +0100152 rand_init();
153
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100154 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000155
Simon Kelley3be34542004-09-11 19:12:13 +0100156 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000157 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100158#if !defined(HAVE_LINUX_NETWORK) && !defined(IP_RECVIF)
Simon Kelleyde379512004-06-22 20:23:33 +0100159 int c;
160 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100161 for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100162 if (!tmp->isloop)
163 c++;
164 if (c != 1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100165 die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +0100166#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100167 /* Note that order matters here, we must call lease_init before
168 creating any file descriptors which shouldn't be leaked
169 to the lease-script init process. */
170 lease_init(now);
171 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000172 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100173
Simon Kelley5aabfc72007-08-29 11:24:47 +0100174 if (!enumerate_interfaces())
175 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
176
177 if (daemon->options & OPT_NOWILD)
178 {
179 daemon->listeners = create_bound_listeners();
180
181 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
182 if (if_tmp->name && !if_tmp->used)
183 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
184
185 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
186 if (!if_tmp->used)
187 {
188 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
189 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
190 }
191 }
Simon Kelley824af852008-02-12 20:43:05 +0000192 else if ((daemon->port != 0 || (daemon->options & OPT_TFTP)) &&
193 !(daemon->listeners = create_wildcard_listeners()))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100194 die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
195
Simon Kelley824af852008-02-12 20:43:05 +0000196 if (daemon->port != 0)
197 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100198
Simon Kelley3d8df262005-08-29 12:19:27 +0100199 if (daemon->options & OPT_DBUS)
200#ifdef HAVE_DBUS
201 {
202 char *err;
203 daemon->dbus = NULL;
204 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100205 if ((err = dbus_init()))
206 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100207 }
208#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100209 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100210#endif
211
Simon Kelley824af852008-02-12 20:43:05 +0000212 if (daemon->port != 0)
213 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100214
215 /* Note getpwnam returns static storage */
216 if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
217 {
218 if ((ent_pw = getpwnam(daemon->scriptuser)))
219 {
220 script_uid = ent_pw->pw_uid;
221 script_gid = ent_pw->pw_gid;
222 }
223 else
224 baduser = daemon->scriptuser;
225 }
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 {
251 hdr = safe_malloc(sizeof(*hdr));
252 int capsize = 1; /* for header version 1 */
253
254 /* 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 Kelley5aabfc72007-08-29 11:24:47 +0100278 send_event(pipewrite, EVENT_RELOAD, 0);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100279
280 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100281
282 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100284 int nullfd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100285
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000286 /* The following code "daemonizes" the process.
287 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100288
Simon Kelley9e038942008-05-30 20:06:34 +0100289 if (chdir("/") != 0)
290 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
291
Simon Kelley16972692006-10-16 20:04:18 +0100292#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100293 if (!(daemon->options & OPT_NO_FORK))
294 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100295 pid_t pid;
296
Simon Kelley1a6bca82008-07-11 11:11:42 +0100297 /* pipe to carry errors back to original process.
298 When startup is complete we close this and the process terminates. */
299 safe_pipe(err_pipe, 0);
300
Simon Kelley5aabfc72007-08-29 11:24:47 +0100301 if ((pid = fork()) == -1 )
302 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley9e038942008-05-30 20:06:34 +0100303
Simon Kelley5aabfc72007-08-29 11:24:47 +0100304 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100305 {
306 struct event_desc ev;
307
308 /* close our copy of write-end */
309 close(err_pipe[1]);
310
311 /* check for errors after the fork */
312 if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
313 fatal_event(&ev);
314
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 Kelley5aabfc72007-08-29 11:24:47 +0100323 pid = fork();
324
325 if (pid != 0 && pid != -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100326 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100327 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000328#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100329
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000330 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100331 if (daemon->runfile)
332 {
333 FILE *pidfile;
334
335 /* only complain if started as root */
336 if ((pidfile = fopen(daemon->runfile, "w")))
337 {
338 fprintf(pidfile, "%d\n", (int) getpid());
339 fclose(pidfile);
340 }
341 else if (getuid() == 0)
342 {
343 send_event(err_pipe[1], EVENT_PIDFILE, errno);
344 _exit(0);
345 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000346 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100347
Simon Kelley5aabfc72007-08-29 11:24:47 +0100348 /* open stdout etc to /dev/null */
349 nullfd = open("/dev/null", O_RDWR);
350 dup2(nullfd, STDOUT_FILENO);
351 dup2(nullfd, STDERR_FILENO);
352 dup2(nullfd, STDIN_FILENO);
353 close(nullfd);
Simon Kelley16972692006-10-16 20:04:18 +0100354 }
355
Simon Kelley1a6bca82008-07-11 11:11:42 +0100356 log_err = log_start(ent_pw, err_pipe[1]);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100357
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 /* if we are to run scripts, we need to fork a helper before dropping root. */
359 daemon->helperfd = -1;
360#ifndef NO_FORK
361 if (daemon->dhcp && daemon->lease_change_command)
362 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
363#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100364
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365 if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100366 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100367 int bad_capabilities = 0;
368 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100369
Simon Kelley1a6bca82008-07-11 11:11:42 +0100370 /* remove all supplimentary groups */
371 if (gp &&
372 (setgroups(0, &dummy) == -1 ||
373 setgid(gp->gr_gid) == -1))
374 {
375 send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
376 _exit(0);
377 }
378
Simon Kelley7cebd202006-05-06 14:13:33 +0100379 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100380 {
Simon Kelley824af852008-02-12 20:43:05 +0000381#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100382 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
383 CAP_NET_RAW (for icmp) if we're doing dhcp */
Simon Kelley16972692006-10-16 20:04:18 +0100384 data->effective = data->permitted = data->inheritable =
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100386
Simon Kelley16972692006-10-16 20:04:18 +0100387 /* Tell kernel to not clear capabilities when dropping root */
388 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
389 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390
Simon Kelley824af852008-02-12 20:43:05 +0000391#elif defined(HAVE_SOLARIS_PRIVS)
392 /* http://developers.sun.com/solaris/articles/program_privileges.html */
393 priv_set_t *priv_set;
394
395 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
396 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
397 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
398 bad_capabilities = errno;
399
400 if (priv_set && bad_capabilities == 0)
401 {
402 priv_inverse(priv_set);
403
404 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
405 bad_capabilities = errno;
406 }
407
408 if (priv_set)
409 priv_freeset(priv_set);
410
411#elif defined(HAVE_SOLARIS_NETWORK)
412
413 bad_capabilities = ENOTSUP;
414#endif
415
Simon Kelley1a6bca82008-07-11 11:11:42 +0100416 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100417 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
419 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100420 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100421
422 /* finally drop root */
423 if (setuid(ent_pw->pw_uid) == -1)
424 {
425 send_event(err_pipe[1], EVENT_USER_ERR, errno);
426 _exit(0);
427 }
428
429#ifdef HAVE_LINUX_NETWORK
430 data->effective = data->permitted =
431 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
432 data->inheritable = 0;
433
434 /* lose the setuid and setgid capbilities */
435 if (capset(hdr, data) == -1)
436 {
437 send_event(err_pipe[1], EVENT_CAP_ERR, errno);
438 _exit(0);
439 }
440#endif
441
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442 }
Simon Kelley849a8352006-06-09 21:02:31 +0100443 }
Simon Kelley16972692006-10-16 20:04:18 +0100444
Simon Kelley16972692006-10-16 20:04:18 +0100445#ifdef HAVE_LINUX_NETWORK
446 if (daemon->options & OPT_DEBUG)
447 prctl(PR_SET_DUMPABLE, 1);
448#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100449
Simon Kelley824af852008-02-12 20:43:05 +0000450 if (daemon->port == 0)
451 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
452 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100453 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000454 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100455 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100456
Simon Kelleyf2621c72007-04-29 19:47:21 +0100457 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100458
Simon Kelley3d8df262005-08-29 12:19:27 +0100459#ifdef HAVE_DBUS
460 if (daemon->options & OPT_DBUS)
461 {
462 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100463 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100464 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100465 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100466 }
467#endif
468
Simon Kelley1a6bca82008-07-11 11:11:42 +0100469 if (log_err != 0)
470 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
471 daemon->log_file, strerror(log_err));
472
Simon Kelleyde379512004-06-22 20:23:33 +0100473 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100474 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100475
Simon Kelley26128d22004-11-14 16:43:54 +0000476 if (!(daemon->options & OPT_NOWILD))
477 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
478 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100479 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100480
Simon Kelley824af852008-02-12 20:43:05 +0000481 if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100482 {
483 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100484 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100485 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000486 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100487 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100488 }
489
Simon Kelleyf2621c72007-04-29 19:47:21 +0100490 if (daemon->max_logs != 0)
491 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
492
Simon Kelley3be34542004-09-11 19:12:13 +0100493 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000494 {
Simon Kelley3be34542004-09-11 19:12:13 +0100495 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000496
Simon Kelley3be34542004-09-11 19:12:13 +0100497 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100498 {
Simon Kelley0a852542005-03-23 20:28:59 +0000499 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100500 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100501 my_syslog(LOG_INFO,
502 (dhcp_tmp->flags & CONTEXT_STATIC) ?
503 _("DHCP, static leases only on %.0s%s, lease time %s") :
504 _("DHCP, IP range %s -- %s, lease time %s"),
505 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100506 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000507 }
508
Simon Kelley832af0b2007-01-21 20:01:28 +0000509#ifdef HAVE_TFTP
510 if (daemon->options & OPT_TFTP)
511 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000512#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100513 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000514 max_fd = FD_SETSIZE;
515#endif
516
Simon Kelleyf2621c72007-04-29 19:47:21 +0100517 my_syslog(LOG_INFO, "TFTP %s%s %s",
518 daemon->tftp_prefix ? _("root is ") : _("enabled"),
519 daemon->tftp_prefix ? daemon->tftp_prefix: "",
520 daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
521
Simon Kelley832af0b2007-01-21 20:01:28 +0000522 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100523 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000524 a single file will be sent to may clients (the file only needs
525 one fd). */
526
527 max_fd -= 30; /* use other than TFTP */
528
529 if (max_fd < 0)
530 max_fd = 5;
531 else if (max_fd < 100)
532 max_fd = max_fd/2;
533 else
534 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000535
536 /* if we have to use a limited range of ports,
537 that will limit the number of transfers */
538 if (daemon->start_tftp_port != 0 &&
539 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
540 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000541
542 if (daemon->tftp_max > max_fd)
543 {
544 daemon->tftp_max = max_fd;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100545 my_syslog(LOG_WARNING,
546 _("restricting maximum simultaneous TFTP transfers to %d"),
547 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000548 }
549 }
550#endif
551
Simon Kelley1a6bca82008-07-11 11:11:42 +0100552 /* finished start-up - release original process */
553 if (err_pipe[1] != -1)
554 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000555
Simon Kelley824af852008-02-12 20:43:05 +0000556 if (daemon->port != 0)
557 check_servers();
558
Simon Kelley7cebd202006-05-06 14:13:33 +0100559 pid = getpid();
560
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100561 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000562 {
Simon Kelley16972692006-10-16 20:04:18 +0100563 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100564 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100565 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000566
567 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100568 FD_ZERO(&wset);
569 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000570
Simon Kelley16972692006-10-16 20:04:18 +0100571 /* if we are out of resources, find how long we have to wait
572 for some to come free, we'll loop around then and restart
573 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100574 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100575 {
576 t.tv_usec = 0;
577 tp = &t;
578 }
579
Simon Kelley832af0b2007-01-21 20:01:28 +0000580 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
581 if (daemon->tftp_trans ||
582 ((daemon->options & OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000583 {
Simon Kelley16972692006-10-16 20:04:18 +0100584 t.tv_sec = 0;
585 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100586 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000587 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100588
Simon Kelley832af0b2007-01-21 20:01:28 +0000589#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100590 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100591#endif
592
593 if (daemon->dhcp)
594 {
595 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100596 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100597 }
598
599#ifdef HAVE_LINUX_NETWORK
600 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100601 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100602#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100603
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100604 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100605 bump_maxfd(piperead, &maxfd);
606
Simon Kelley5aabfc72007-08-29 11:24:47 +0100607#ifndef NO_FORK
608 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100609
610 if (!helper_buf_empty())
611 {
612 FD_SET(daemon->helperfd, &wset);
613 bump_maxfd(daemon->helperfd, &maxfd);
614 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100615#else
616 /* need this for other side-effects */
617 while (do_script_run(now));
618#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +0100619
620 /* must do this just before select(), when we know no
621 more calls to my_syslog() can occur */
622 set_log_writer(&wset, &maxfd);
623
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100624 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
625 {
626 /* otherwise undefined after error */
627 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
628 }
629
630 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631
Simon Kelleyf2621c72007-04-29 19:47:21 +0100632 check_log_writer(&wset);
633
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000634 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100635 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley849a8352006-06-09 21:02:31 +0100636 if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000637 {
638 last = now;
Simon Kelley33820b72004-04-03 21:10:00 +0100639
640#ifdef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100641 if (daemon->lease_file && !daemon->dhcp)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100642 load_dhcp(now);
Simon Kelley33820b72004-04-03 21:10:00 +0100643#endif
644
Simon Kelley824af852008-02-12 20:43:05 +0000645 if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100646 poll_resolv();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000647 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100648
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100649 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100650 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100651
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100652#ifdef HAVE_LINUX_NETWORK
653 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100654 netlink_multicast();
Simon Kelleycdeda282006-03-16 20:16:06 +0000655#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100656
657#ifdef HAVE_DBUS
658 /* if we didn't create a DBus connection, retry now. */
Simon Kelley7cebd202006-05-06 14:13:33 +0100659 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100660 {
661 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100662 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100663 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100664 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100665 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100666 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100667 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100668#endif
Simon Kelley824af852008-02-12 20:43:05 +0000669
Simon Kelley5aabfc72007-08-29 11:24:47 +0100670 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000671
672#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100673 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000674#endif
675
Simon Kelley3be34542004-09-11 19:12:13 +0100676 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100677 dhcp_packet(now);
Simon Kelley16972692006-10-16 20:04:18 +0100678
Simon Kelley5aabfc72007-08-29 11:24:47 +0100679#ifndef NO_FORK
Simon Kelley16972692006-10-16 20:04:18 +0100680 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100681 helper_write();
682#endif
683
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000684 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000685}
686
Simon Kelley3be34542004-09-11 19:12:13 +0100687static void sig_handler(int sig)
688{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100689 if (pid == 0)
690 {
Simon Kelley16972692006-10-16 20:04:18 +0100691 /* ignore anything other than TERM during startup
692 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100693 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100694 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100695 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100696 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100697 {
Simon Kelley16972692006-10-16 20:04:18 +0100698 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100699 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100700 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100701 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100702 else
703 {
704 /* master process */
705 int event, errsave = errno;
706
707 if (sig == SIGHUP)
708 event = EVENT_RELOAD;
709 else if (sig == SIGCHLD)
710 event = EVENT_CHILD;
711 else if (sig == SIGALRM)
712 event = EVENT_ALARM;
713 else if (sig == SIGTERM)
714 event = EVENT_TERM;
715 else if (sig == SIGUSR1)
716 event = EVENT_DUMP;
717 else if (sig == SIGUSR2)
718 event = EVENT_REOPEN;
719 else
720 return;
721
722 send_event(pipewrite, event, 0);
723 errno = errsave;
724 }
Simon Kelley3be34542004-09-11 19:12:13 +0100725}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000726
Simon Kelley5aabfc72007-08-29 11:24:47 +0100727void send_event(int fd, int event, int data)
728{
729 struct event_desc ev;
730
731 ev.event = event;
732 ev.data = data;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100733
734 /* error pipe, debug mode. */
735 if (fd == -1)
736 fatal_event(&ev);
737 else
738 /* pipe is non-blocking and struct event_desc is smaller than
739 PIPE_BUF, so this either fails or writes everything */
740 while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100741}
Simon Kelley3d8df262005-08-29 12:19:27 +0100742
Simon Kelley1a6bca82008-07-11 11:11:42 +0100743static void fatal_event(struct event_desc *ev)
744{
745 errno = ev->data;
746
747 switch (ev->event)
748 {
749 case EVENT_DIE:
750 exit(0);
751
752 case EVENT_PIPE_ERR:
753 die(_("failed to create helper: %s"), NULL, EC_MISC);
754
755 case EVENT_CAP_ERR:
756 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
757
758 case EVENT_USER_ERR:
759 case EVENT_HUSER_ERR:
760 die(_("failed to change user-id to %s: %s"),
761 ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
762 EC_MISC);
763
764 case EVENT_GROUP_ERR:
765 die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
766
767 case EVENT_PIDFILE:
768 die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
769
770 case EVENT_LOG_ERR:
771 die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
772 }
773}
774
Simon Kelley5aabfc72007-08-29 11:24:47 +0100775static void async_event(int pipe, time_t now)
776{
777 pid_t p;
778 struct event_desc ev;
779 int i;
780
781 if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
782 switch (ev.event)
783 {
784 case EVENT_RELOAD:
785 clear_cache_and_reload(now);
Simon Kelley824af852008-02-12 20:43:05 +0000786 if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100787 {
788 reload_servers(daemon->resolv_files->name);
789 check_servers();
790 }
791 rerun_scripts();
792 break;
793
794 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000795 if (daemon->port != 0)
796 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100797 break;
798
799 case EVENT_ALARM:
800 if (daemon->dhcp)
801 {
802 lease_prune(NULL, now);
803 lease_update_file(now);
804 }
805 break;
806
807 case EVENT_CHILD:
808 /* See Stevens 5.10 */
809 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
810 if (p == -1)
811 {
812 if (errno != EINTR)
813 break;
814 }
815 else
816 for (i = 0 ; i < MAX_PROCS; i++)
817 if (daemon->tcp_pids[i] == p)
818 daemon->tcp_pids[i] = 0;
819 break;
820
821 case EVENT_KILLED:
822 my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
823 break;
824
825 case EVENT_EXITED:
826 my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
827 break;
828
829 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +0100830 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
831 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100832 break;
833
Simon Kelley1a6bca82008-07-11 11:11:42 +0100834 /* necessary for fatal errors in helper */
835 case EVENT_HUSER_ERR:
836 case EVENT_DIE:
837 fatal_event(&ev);
Simon Kelley9e038942008-05-30 20:06:34 +0100838 break;
839
Simon Kelley5aabfc72007-08-29 11:24:47 +0100840 case EVENT_REOPEN:
841 /* Note: this may leave TCP-handling processes with the old file still open.
842 Since any such process will die in CHILD_LIFETIME or probably much sooner,
843 we leave them logging to the old file. */
844 if (daemon->log_file != NULL)
845 log_reopen(daemon->log_file);
846 break;
847
848 case EVENT_TERM:
849 /* Knock all our children on the head. */
850 for (i = 0; i < MAX_PROCS; i++)
851 if (daemon->tcp_pids[i] != 0)
852 kill(daemon->tcp_pids[i], SIGALRM);
853
854#ifndef NO_FORK
855 /* handle pending lease transitions */
856 if (daemon->helperfd != -1)
857 {
858 /* block in writes until all done */
859 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
860 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
861 do {
862 helper_write();
863 } while (!helper_buf_empty() || do_script_run(now));
864 close(daemon->helperfd);
865 }
866#endif
867
868 if (daemon->lease_stream)
869 fclose(daemon->lease_stream);
870
871 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
872 flush_log();
873 exit(EC_GOOD);
874 }
875}
876
877static void poll_resolv()
878{
879 struct resolvc *res, *latest;
880 struct stat statbuf;
881 time_t last_change = 0;
882 /* There may be more than one possible file.
883 Go through and find the one which changed _last_.
884 Warn of any which can't be read. */
885 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
886 if (stat(res->name, &statbuf) == -1)
887 {
888 if (!res->logged)
889 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
890 res->logged = 1;
891 }
892 else
893 {
894 res->logged = 0;
895 if (statbuf.st_mtime != res->mtime)
896 {
897 res->mtime = statbuf.st_mtime;
898 if (difftime(statbuf.st_mtime, last_change) > 0.0)
899 {
900 last_change = statbuf.st_mtime;
901 latest = res;
902 }
903 }
904 }
905
906 if (latest)
907 {
908 static int warned = 0;
909 if (reload_servers(latest->name))
910 {
911 my_syslog(LOG_INFO, _("reading %s"), latest->name);
912 warned = 0;
913 check_servers();
914 if (daemon->options & OPT_RELOAD)
915 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
916 }
917 else
918 {
919 latest->mtime = 0;
920 if (!warned)
921 {
922 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
923 warned = 1;
924 }
925 }
926 }
927}
928
929void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +0100930{
Simon Kelley824af852008-02-12 20:43:05 +0000931 if (daemon->port != 0)
932 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
933
Simon Kelley3d8df262005-08-29 12:19:27 +0100934 if (daemon->dhcp)
935 {
936 if (daemon->options & OPT_ETHERS)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +0000938 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +0100939 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +0000940 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100941 lease_update_from_configs();
942 lease_update_file(now);
943 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +0100944 }
945}
946
Simon Kelley5aabfc72007-08-29 11:24:47 +0100947static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +0100948{
949 struct serverfd *serverfdp;
950 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +0000951 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +0000952
953#ifdef HAVE_TFTP
954 int tftp = 0;
955 struct tftp_transfer *transfer;
956 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
957 {
958 tftp++;
959 FD_SET(transfer->sockfd, set);
960 bump_maxfd(transfer->sockfd, maxfdp);
961 }
962#endif
963
Simon Kelley16972692006-10-16 20:04:18 +0100964 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +0000965 if (daemon->port != 0)
966 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +0100967
Simon Kelley3be34542004-09-11 19:12:13 +0100968 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
969 {
970 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +0100971 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +0100972 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100973
974 if (daemon->port != 0 && !daemon->osport)
975 for (i = 0; i < RANDOM_SOCKS; i++)
976 if (daemon->randomsocks[i].refcount != 0)
977 {
978 FD_SET(daemon->randomsocks[i].fd, set);
979 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
980 }
981
Simon Kelley3be34542004-09-11 19:12:13 +0100982 for (listener = daemon->listeners; listener; listener = listener->next)
983 {
Simon Kelley16972692006-10-16 20:04:18 +0100984 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +0000985 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100986 {
987 FD_SET(listener->fd, set);
988 bump_maxfd(listener->fd, maxfdp);
989 }
990
991 /* death of a child goes through the select loop, so
992 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +0000993 if (listener->tcpfd != -1)
994 for (i = 0; i < MAX_PROCS; i++)
995 if (daemon->tcp_pids[i] == 0)
996 {
997 FD_SET(listener->tcpfd, set);
998 bump_maxfd(listener->tcpfd, maxfdp);
999 break;
1000 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001001
Simon Kelley832af0b2007-01-21 20:01:28 +00001002#ifdef HAVE_TFTP
1003 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1004 {
1005 FD_SET(listener->tftpfd, set);
1006 bump_maxfd(listener->tftpfd, maxfdp);
1007 }
1008#endif
1009
1010 }
1011
Simon Kelley16972692006-10-16 20:04:18 +01001012 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001013}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001014
Simon Kelley5aabfc72007-08-29 11:24:47 +01001015static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001016{
1017 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001018 struct listener *listener;
1019 int i;
1020
Simon Kelley832af0b2007-01-21 20:01:28 +00001021 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1022 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001023 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1024
1025 if (daemon->port != 0 && !daemon->osport)
1026 for (i = 0; i < RANDOM_SOCKS; i++)
1027 if (daemon->randomsocks[i].refcount != 0 &&
1028 FD_ISSET(daemon->randomsocks[i].fd, set))
1029 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001030
1031 for (listener = daemon->listeners; listener; listener = listener->next)
1032 {
Simon Kelley824af852008-02-12 20:43:05 +00001033 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001034 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001035
Simon Kelley832af0b2007-01-21 20:01:28 +00001036#ifdef HAVE_TFTP
1037 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001038 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001039#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001040
Simon Kelley824af852008-02-12 20:43:05 +00001041 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001042 {
1043 int confd;
1044 struct irec *iface = NULL;
1045 pid_t p;
1046
1047 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1048
1049 if (confd == -1)
1050 continue;
1051
1052 if (daemon->options & OPT_NOWILD)
1053 iface = listener->iface;
1054 else
1055 {
1056 union mysockaddr tcp_addr;
1057 socklen_t tcp_len = sizeof(union mysockaddr);
1058 /* Check for allowed interfaces when binding the wildcard address:
1059 we do this by looking for an interface with the same address as
1060 the local address of the TCP connection, then looking to see if that's
1061 an allowed interface. As a side effect, we get the netmask of the
1062 interface too, for localisation. */
1063
1064 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001065 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001066 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1067 for (iface = daemon->interfaces; iface; iface = iface->next)
1068 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1069 break;
1070 }
1071
1072 if (!iface)
1073 {
1074 shutdown(confd, SHUT_RDWR);
1075 close(confd);
1076 }
1077#ifndef NO_FORK
1078 else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
1079 {
1080 if (p != -1)
1081 {
1082 int i;
1083 for (i = 0; i < MAX_PROCS; i++)
1084 if (daemon->tcp_pids[i] == 0)
1085 {
1086 daemon->tcp_pids[i] = p;
1087 break;
1088 }
1089 }
1090 close(confd);
1091 }
1092#endif
1093 else
1094 {
1095 unsigned char *buff;
1096 struct server *s;
1097 int flags;
1098 struct in_addr dst_addr_4;
1099
1100 dst_addr_4.s_addr = 0;
1101
Simon Kelley7cebd202006-05-06 14:13:33 +01001102 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1103 terminate the process. */
Simon Kelley832af0b2007-01-21 20:01:28 +00001104 if (!(daemon->options & OPT_DEBUG))
1105 alarm(CHILD_LIFETIME);
1106
1107 /* start with no upstream connections. */
1108 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001109 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001110
1111 /* The connected socket inherits non-blocking
1112 attribute from the listening socket.
1113 Reset that here. */
1114 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1115 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1116
1117 if (listener->family == AF_INET)
1118 dst_addr_4 = iface->addr.in.sin_addr;
1119
Simon Kelley5aabfc72007-08-29 11:24:47 +01001120 buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001121
Simon Kelley832af0b2007-01-21 20:01:28 +00001122 shutdown(confd, SHUT_RDWR);
1123 close(confd);
1124
1125 if (buff)
1126 free(buff);
1127
1128 for (s = daemon->servers; s; s = s->next)
1129 if (s->tcpfd != -1)
1130 {
1131 shutdown(s->tcpfd, SHUT_RDWR);
1132 close(s->tcpfd);
1133 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001134#ifndef NO_FORK
Simon Kelley832af0b2007-01-21 20:01:28 +00001135 if (!(daemon->options & OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001136 {
1137 flush_log();
1138 _exit(0);
1139 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001140#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001141 }
1142 }
1143 }
Simon Kelley3be34542004-09-11 19:12:13 +01001144}
1145
Simon Kelley7cebd202006-05-06 14:13:33 +01001146
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001147int make_icmp_sock(void)
1148{
Simon Kelley7cebd202006-05-06 14:13:33 +01001149 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001150 int zeroopt = 0;
1151
1152 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1153 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001154 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001155 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1156 {
1157 close(fd);
1158 fd = -1;
1159 }
1160 }
1161
1162 return fd;
1163}
1164
Simon Kelley5aabfc72007-08-29 11:24:47 +01001165int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001166{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001167 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001168
1169 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001170 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001171 better not use any resources our caller has in use...)
1172 but we remain deaf to signals or further DHCP packets. */
1173
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001174 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001175 struct sockaddr_in saddr;
1176 struct {
1177 struct ip ip;
1178 struct icmp icmp;
1179 } packet;
1180 unsigned short id = rand16();
1181 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001182 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001183 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001184
Simon Kelley824af852008-02-12 20:43:05 +00001185#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001186 if ((fd = make_icmp_sock()) == -1)
1187 return 0;
1188#else
1189 int opt = 2000;
1190 fd = daemon->dhcp_icmp_fd;
1191 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1192#endif
1193
Simon Kelley3be34542004-09-11 19:12:13 +01001194 saddr.sin_family = AF_INET;
1195 saddr.sin_port = 0;
1196 saddr.sin_addr = addr;
1197#ifdef HAVE_SOCKADDR_SA_LEN
1198 saddr.sin_len = sizeof(struct sockaddr_in);
1199#endif
1200
1201 memset(&packet.icmp, 0, sizeof(packet.icmp));
1202 packet.icmp.icmp_type = ICMP_ECHO;
1203 packet.icmp.icmp_id = id;
1204 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1205 j += ((u16 *)&packet.icmp)[i];
1206 while (j>>16)
1207 j = (j & 0xffff) + (j >> 16);
1208 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1209
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001210 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001211 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1212 retry_send());
1213
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001214 for (now = start = dnsmasq_time();
1215 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001216 {
1217 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001218 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001219 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001220 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001221 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001222
1223 tv.tv_usec = 250000;
1224 tv.tv_sec = 0;
1225
1226 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001227 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001228 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001229 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001230 set_log_writer(&wset, &maxfd);
1231
1232 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1233 {
1234 FD_ZERO(&rset);
1235 FD_ZERO(&wset);
1236 }
1237
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001238 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001239
1240 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001241 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001242
1243#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001244 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001245#endif
1246
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001247 if (FD_ISSET(fd, &rset) &&
1248 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001249 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1250 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1251 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1252 packet.icmp.icmp_seq == 0 &&
1253 packet.icmp.icmp_id == id)
1254 {
1255 gotreply = 1;
1256 break;
1257 }
1258 }
1259
Simon Kelley824af852008-02-12 20:43:05 +00001260#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001261 close(fd);
1262#else
Simon Kelley3be34542004-09-11 19:12:13 +01001263 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001264 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1265#endif
1266
Simon Kelley3be34542004-09-11 19:12:13 +01001267 return gotreply;
1268}
Simon Kelley0a852542005-03-23 20:28:59 +00001269
1270