blob: 827b0dcdbca9d8f09bc529d3d5b2733449dcdb29 [file] [log] [blame]
Simon Kelley28866e92011-02-14 20:19:14 +00001/* dnsmasq is Copyright (c) 2000-2011 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 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 Kelley3d8df262005-08-29 12:19:27 +010036#ifndef HAVE_DBUS
37"no-"
38#endif
Simon Kelleyb8187c82005-11-26 21:46:27 +000039"DBus "
Simon Kelley824af852008-02-12 20:43:05 +000040#ifndef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000041"no-"
42#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000043"I18N "
Simon Kelley7622fc02009-06-04 20:32:05 +010044#ifndef HAVE_DHCP
45"no-"
46#endif
47"DHCP "
Simon Kelley1f15b812009-10-13 17:49:32 +010048#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
49"no-scripts "
50#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000051#ifndef HAVE_TFTP
52"no-"
53#endif
Simon Kelley572b41e2011-02-18 18:11:18 +000054"TFTP "
55#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
56"no-"
57#endif
58"IDN";
Simon Kelley1f15b812009-10-13 17:49:32 +010059
60
Simon Kelley5aabfc72007-08-29 11:24:47 +010061static volatile pid_t pid = 0;
62static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000063
Simon Kelley5aabfc72007-08-29 11:24:47 +010064static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
65static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010066static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010067static void async_event(int pipe, time_t now);
Simon Kelley1a6bca82008-07-11 11:11:42 +010068static void fatal_event(struct event_desc *ev);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000069
70int main (int argc, char **argv)
71{
Simon Kelleyde379512004-06-22 20:23:33 +010072 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000073 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000075 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010076 int piperead, pipefd[2], err_pipe[2];
77 struct passwd *ent_pw = NULL;
Simon Kelley1f15b812009-10-13 17:49:32 +010078#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010079 uid_t script_uid = 0;
80 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010081#endif
82 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010083 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010084 char *baduser = NULL;
85 int log_err;
86#if defined(HAVE_LINUX_NETWORK)
87 cap_user_header_t hdr = NULL;
88 cap_user_data_t data = NULL;
89#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010090
Simon Kelley824af852008-02-12 20:43:05 +000091#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000092 setlocale(LC_ALL, "");
93 bindtextdomain("dnsmasq", LOCALEDIR);
94 textdomain("dnsmasq");
95#endif
96
Simon Kelley9e4abcb2004-01-22 19:47:41 +000097 sigact.sa_handler = sig_handler;
98 sigact.sa_flags = 0;
99 sigemptyset(&sigact.sa_mask);
100 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100101 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000102 sigaction(SIGHUP, &sigact, NULL);
103 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +0000104 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100105 sigaction(SIGCHLD, &sigact, NULL);
106
107 /* ignore SIGPIPE */
108 sigact.sa_handler = SIG_IGN;
109 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000110
Simon Kelley5aabfc72007-08-29 11:24:47 +0100111 umask(022); /* known umask, create leases and pid files as 0644 */
112
113 read_opts(argc, argv, compile_opts);
114
Simon Kelley3be34542004-09-11 19:12:13 +0100115 if (daemon->edns_pktsz < PACKETSZ)
116 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +0000117 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
118 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
119 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100120
Simon Kelley7622fc02009-06-04 20:32:05 +0100121#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100122 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000123 {
Simon Kelley3be34542004-09-11 19:12:13 +0100124 if (daemon->dhcp)
125 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000126 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100127#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000128
Simon Kelley5aabfc72007-08-29 11:24:47 +0100129 /* Close any file descriptors we inherited apart from std{in|out|err} */
130 for (i = 0; i < max_fd; i++)
131 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
132 close(i);
133
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100134#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100135 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100136#elif !(defined(IP_RECVDSTADDR) && \
137 defined(IP_RECVIF) && \
138 defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000139 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100140 {
141 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000142 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100143 }
Simon Kelley309331f2006-04-22 15:05:01 +0100144#endif
145
Simon Kelley832af0b2007-01-21 20:01:28 +0000146#ifndef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100147 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100148 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000149#endif
150
Simon Kelley824af852008-02-12 20:43:05 +0000151#ifdef HAVE_SOLARIS_NETWORK
152 if (daemon->max_logs != 0)
153 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
154#endif
155
Simon Kelley572b41e2011-02-18 18:11:18 +0000156#ifdef __ANDROID__
157 if (daemon->max_logs != 0)
158 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
159#endif
160
Simon Kelley1a6bca82008-07-11 11:11:42 +0100161 rand_init();
162
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100163 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000164
Simon Kelley7622fc02009-06-04 20:32:05 +0100165#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100166 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000167 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100168 /* Note that order matters here, we must call lease_init before
169 creating any file descriptors which shouldn't be leaked
170 to the lease-script init process. */
171 lease_init(now);
172 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100174#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100175
Simon Kelley5aabfc72007-08-29 11:24:47 +0100176 if (!enumerate_interfaces())
177 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
178
Simon Kelley28866e92011-02-14 20:19:14 +0000179 if (option_bool(OPT_NOWILD))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100180 {
181 daemon->listeners = create_bound_listeners();
182
183 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
184 if (if_tmp->name && !if_tmp->used)
185 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
186
187 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
188 if (!if_tmp->used)
189 {
190 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
191 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
192 }
193 }
Simon Kelley28866e92011-02-14 20:19:14 +0000194 else
195 daemon->listeners = create_wildcard_listeners();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100196
Simon Kelley824af852008-02-12 20:43:05 +0000197 if (daemon->port != 0)
198 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100199
Simon Kelley28866e92011-02-14 20:19:14 +0000200 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100201#ifdef HAVE_DBUS
202 {
203 char *err;
204 daemon->dbus = NULL;
205 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100206 if ((err = dbus_init()))
207 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100208 }
209#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100210 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100211#endif
212
Simon Kelley824af852008-02-12 20:43:05 +0000213 if (daemon->port != 0)
214 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100215
Simon Kelley1f15b812009-10-13 17:49:32 +0100216#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100217 /* Note getpwnam returns static storage */
218 if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
219 {
220 if ((ent_pw = getpwnam(daemon->scriptuser)))
221 {
222 script_uid = ent_pw->pw_uid;
223 script_gid = ent_pw->pw_gid;
224 }
225 else
226 baduser = daemon->scriptuser;
227 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100228#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000229
Simon Kelley1a6bca82008-07-11 11:11:42 +0100230 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
231 baduser = daemon->username;
232 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
233 baduser = daemon->groupname;
234
235 if (baduser)
236 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
237
238 /* implement group defaults, "dip" if available, or group associated with uid */
239 if (!daemon->group_set && !gp)
240 {
241 if (!(gp = getgrnam(CHGRP)) && ent_pw)
242 gp = getgrgid(ent_pw->pw_gid);
243
244 /* for error message */
245 if (gp)
246 daemon->groupname = gp->gr_name;
247 }
248
249#if defined(HAVE_LINUX_NETWORK)
250 /* determine capability API version here, while we can still
251 call safe_malloc */
252 if (ent_pw && ent_pw->pw_uid != 0)
253 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100254 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100255 hdr = safe_malloc(sizeof(*hdr));
256
Simon Kelley1a6bca82008-07-11 11:11:42 +0100257 /* find version supported by kernel */
258 memset(hdr, 0, sizeof(*hdr));
259 capget(hdr, NULL);
260
261 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
262 {
263 /* if unknown version, use largest supported version (3) */
264 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
265 hdr->version = LINUX_CAPABILITY_VERSION_3;
266 capsize = 2;
267 }
268
269 data = safe_malloc(sizeof(*data) * capsize);
270 memset(data, 0, sizeof(*data) * capsize);
271 }
272#endif
273
Simon Kelley5aabfc72007-08-29 11:24:47 +0100274 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100275 in a race-free manner and another to carry errors to daemon-invoking process */
276 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100277
278 piperead = pipefd[0];
279 pipewrite = pipefd[1];
280 /* prime the pipe to load stuff first time. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100281 send_event(pipewrite, EVENT_RELOAD, 0);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100282
283 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100284
Simon Kelley28866e92011-02-14 20:19:14 +0000285 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000286 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000287 /* The following code "daemonizes" the process.
288 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100289
Simon Kelley9e038942008-05-30 20:06:34 +0100290 if (chdir("/") != 0)
291 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
292
Simon Kelley16972692006-10-16 20:04:18 +0100293#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000294 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100295 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100296 pid_t pid;
297
Simon Kelley1a6bca82008-07-11 11:11:42 +0100298 /* pipe to carry errors back to original process.
299 When startup is complete we close this and the process terminates. */
300 safe_pipe(err_pipe, 0);
301
Simon Kelley7622fc02009-06-04 20:32:05 +0100302 if ((pid = fork()) == -1)
303 /* fd == -1 since we've not forked, never returns. */
304 send_event(-1, EVENT_FORK_ERR, errno);
Simon Kelley9e038942008-05-30 20:06:34 +0100305
Simon Kelley5aabfc72007-08-29 11:24:47 +0100306 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100307 {
308 struct event_desc ev;
309
310 /* close our copy of write-end */
311 close(err_pipe[1]);
312
313 /* check for errors after the fork */
314 if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
315 fatal_event(&ev);
316
317 _exit(EC_GOOD);
318 }
319
320 close(err_pipe[0]);
321
322 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100323
324 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100325
326 if ((pid = fork()) == -1)
327 send_event(err_pipe[1], EVENT_FORK_ERR, errno);
328
329 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100330 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100331 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000332#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100333
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000334 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100335 if (daemon->runfile)
336 {
337 FILE *pidfile;
338
339 /* only complain if started as root */
340 if ((pidfile = fopen(daemon->runfile, "w")))
341 {
342 fprintf(pidfile, "%d\n", (int) getpid());
343 fclose(pidfile);
344 }
345 else if (getuid() == 0)
346 {
347 send_event(err_pipe[1], EVENT_PIDFILE, errno);
348 _exit(0);
349 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000350 }
Simon Kelley16972692006-10-16 20:04:18 +0100351 }
352
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100353 log_err = log_start(ent_pw, err_pipe[1]);
354
Simon Kelley28866e92011-02-14 20:19:14 +0000355 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100356 {
357 /* open stdout etc to /dev/null */
358 int nullfd = open("/dev/null", O_RDWR);
359 dup2(nullfd, STDOUT_FILENO);
360 dup2(nullfd, STDERR_FILENO);
361 dup2(nullfd, STDIN_FILENO);
362 close(nullfd);
363 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100364
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365 /* if we are to run scripts, we need to fork a helper before dropping root. */
366 daemon->helperfd = -1;
Simon Kelley1f15b812009-10-13 17:49:32 +0100367#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 if (daemon->dhcp && daemon->lease_change_command)
369 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
370#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100371
Simon Kelley28866e92011-02-14 20:19:14 +0000372 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100373 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100374 int bad_capabilities = 0;
375 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100376
Simon Kelley1a6bca82008-07-11 11:11:42 +0100377 /* remove all supplimentary groups */
378 if (gp &&
379 (setgroups(0, &dummy) == -1 ||
380 setgid(gp->gr_gid) == -1))
381 {
382 send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
383 _exit(0);
384 }
385
Simon Kelley7cebd202006-05-06 14:13:33 +0100386 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100387 {
Simon Kelley824af852008-02-12 20:43:05 +0000388#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100389 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
390 CAP_NET_RAW (for icmp) if we're doing dhcp */
Simon Kelley16972692006-10-16 20:04:18 +0100391 data->effective = data->permitted = data->inheritable =
Simon Kelley1a6bca82008-07-11 11:11:42 +0100392 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100393
Simon Kelley16972692006-10-16 20:04:18 +0100394 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000395 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100396 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100397
Simon Kelley7622fc02009-06-04 20:32:05 +0100398#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000399 /* http://developers.sun.com/solaris/articles/program_privileges.html */
400 priv_set_t *priv_set;
401
402 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
403 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
404 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
405 bad_capabilities = errno;
406
407 if (priv_set && bad_capabilities == 0)
408 {
409 priv_inverse(priv_set);
410
411 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
412 bad_capabilities = errno;
413 }
414
415 if (priv_set)
416 priv_freeset(priv_set);
417
Simon Kelley824af852008-02-12 20:43:05 +0000418#endif
419
Simon Kelley1a6bca82008-07-11 11:11:42 +0100420 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100421 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100422 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
423 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100424 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100425
426 /* finally drop root */
427 if (setuid(ent_pw->pw_uid) == -1)
428 {
429 send_event(err_pipe[1], EVENT_USER_ERR, errno);
430 _exit(0);
431 }
432
433#ifdef HAVE_LINUX_NETWORK
434 data->effective = data->permitted =
435 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
436 data->inheritable = 0;
437
438 /* lose the setuid and setgid capbilities */
439 if (capset(hdr, data) == -1)
440 {
441 send_event(err_pipe[1], EVENT_CAP_ERR, errno);
442 _exit(0);
443 }
444#endif
445
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446 }
Simon Kelley849a8352006-06-09 21:02:31 +0100447 }
Simon Kelley16972692006-10-16 20:04:18 +0100448
Simon Kelley16972692006-10-16 20:04:18 +0100449#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000450 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000451 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100452#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100453
Simon Kelley824af852008-02-12 20:43:05 +0000454 if (daemon->port == 0)
455 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
456 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100457 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000458 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100459 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100460
Simon Kelleyf2621c72007-04-29 19:47:21 +0100461 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100462
Simon Kelley3d8df262005-08-29 12:19:27 +0100463#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000464 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100465 {
466 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100467 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100468 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100469 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100470 }
471#endif
472
Simon Kelley1a6bca82008-07-11 11:11:42 +0100473 if (log_err != 0)
474 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
475 daemon->log_file, strerror(log_err));
476
Simon Kelleyde379512004-06-22 20:23:33 +0100477 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100478 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100479
Simon Kelley28866e92011-02-14 20:19:14 +0000480 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000481 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
482 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100483 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100484
Simon Kelley28866e92011-02-14 20:19:14 +0000485 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100486 {
487 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100488 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100489 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000490 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100491 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100492 }
493
Simon Kelleyf2621c72007-04-29 19:47:21 +0100494 if (daemon->max_logs != 0)
495 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
496
Simon Kelley7622fc02009-06-04 20:32:05 +0100497#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100498 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000499 {
Simon Kelley3be34542004-09-11 19:12:13 +0100500 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000501
Simon Kelley3be34542004-09-11 19:12:13 +0100502 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100503 {
Simon Kelley0a852542005-03-23 20:28:59 +0000504 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100505 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelley7622fc02009-06-04 20:32:05 +0100506 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100507 (dhcp_tmp->flags & CONTEXT_STATIC) ?
508 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100509 (dhcp_tmp->flags & CONTEXT_PROXY) ?
510 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100511 _("DHCP, IP range %s -- %s, lease time %s"),
512 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100513 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000514 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100515#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000516
Simon Kelley832af0b2007-01-21 20:01:28 +0000517#ifdef HAVE_TFTP
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100518 if (daemon->tftp_unlimited || daemon->tftp_interfaces)
Simon Kelley832af0b2007-01-21 20:01:28 +0000519 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000520#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100521 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000522 max_fd = FD_SETSIZE;
523#endif
524
Simon Kelley7622fc02009-06-04 20:32:05 +0100525 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100526 daemon->tftp_prefix ? _("root is ") : _("enabled"),
527 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000528 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100529
Simon Kelley832af0b2007-01-21 20:01:28 +0000530 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100531 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000532 a single file will be sent to may clients (the file only needs
533 one fd). */
534
535 max_fd -= 30; /* use other than TFTP */
536
537 if (max_fd < 0)
538 max_fd = 5;
539 else if (max_fd < 100)
540 max_fd = max_fd/2;
541 else
542 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000543
544 /* if we have to use a limited range of ports,
545 that will limit the number of transfers */
546 if (daemon->start_tftp_port != 0 &&
547 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
548 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000549
550 if (daemon->tftp_max > max_fd)
551 {
552 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100553 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100554 _("restricting maximum simultaneous TFTP transfers to %d"),
555 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000556 }
557 }
558#endif
559
Simon Kelley1a6bca82008-07-11 11:11:42 +0100560 /* finished start-up - release original process */
561 if (err_pipe[1] != -1)
562 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000563
Simon Kelley824af852008-02-12 20:43:05 +0000564 if (daemon->port != 0)
565 check_servers();
566
Simon Kelley7cebd202006-05-06 14:13:33 +0100567 pid = getpid();
568
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100569 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000570 {
Simon Kelley16972692006-10-16 20:04:18 +0100571 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100572 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100573 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574
575 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100576 FD_ZERO(&wset);
577 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000578
Simon Kelley16972692006-10-16 20:04:18 +0100579 /* if we are out of resources, find how long we have to wait
580 for some to come free, we'll loop around then and restart
581 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100582 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100583 {
584 t.tv_usec = 0;
585 tp = &t;
586 }
587
Simon Kelley832af0b2007-01-21 20:01:28 +0000588 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
589 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000590 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000591 {
Simon Kelley16972692006-10-16 20:04:18 +0100592 t.tv_sec = 0;
593 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100594 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100596
Simon Kelley832af0b2007-01-21 20:01:28 +0000597#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100598 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100599#endif
600
Simon Kelley7622fc02009-06-04 20:32:05 +0100601#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100602 if (daemon->dhcp)
603 {
604 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100605 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000606 if (daemon->pxefd != -1)
607 {
608 FD_SET(daemon->pxefd, &rset);
609 bump_maxfd(daemon->pxefd, &maxfd);
610 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100611 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100612#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100613
614#ifdef HAVE_LINUX_NETWORK
615 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100616 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100617#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100618
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100619 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100620 bump_maxfd(piperead, &maxfd);
621
Simon Kelley7622fc02009-06-04 20:32:05 +0100622#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100623# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100624 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100625
626 if (!helper_buf_empty())
627 {
628 FD_SET(daemon->helperfd, &wset);
629 bump_maxfd(daemon->helperfd, &maxfd);
630 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100631# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100632 /* need this for other side-effects */
633 while (do_script_run(now));
Simon Kelley7622fc02009-06-04 20:32:05 +0100634# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100635#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100636
Simon Kelleyf2621c72007-04-29 19:47:21 +0100637 /* must do this just before select(), when we know no
638 more calls to my_syslog() can occur */
639 set_log_writer(&wset, &maxfd);
640
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100641 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
642 {
643 /* otherwise undefined after error */
644 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
645 }
646
647 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000648
Simon Kelleyf2621c72007-04-29 19:47:21 +0100649 check_log_writer(&wset);
650
Simon Kelleyc52e1892010-06-07 22:01:39 +0100651#ifdef HAVE_LINUX_NETWORK
652 if (FD_ISSET(daemon->netlinkfd, &rset))
653 netlink_multicast();
654#endif
655
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000656 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100657 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000658 if (daemon->last_resolv == 0 ||
659 difftime(now, daemon->last_resolv) > 1.0 ||
660 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000661 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100662 /* poll_resolv doesn't need to reload first time through, since
663 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100664
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100665 poll_resolv(0, daemon->last_resolv != 0, now);
666 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000667 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100668
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100669 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100670 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100671
Simon Kelley3d8df262005-08-29 12:19:27 +0100672#ifdef HAVE_DBUS
673 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000674 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100675 {
676 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100677 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100678 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100679 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100680 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100681 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100682 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100683#endif
Simon Kelley824af852008-02-12 20:43:05 +0000684
Simon Kelley5aabfc72007-08-29 11:24:47 +0100685 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000686
687#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100688 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000689#endif
690
Simon Kelley7622fc02009-06-04 20:32:05 +0100691#ifdef HAVE_DHCP
Simon Kelley316e2732010-01-22 20:16:09 +0000692 if (daemon->dhcp)
693 {
694 if (FD_ISSET(daemon->dhcpfd, &rset))
695 dhcp_packet(now, 0);
696 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
697 dhcp_packet(now, 1);
698 }
Simon Kelley16972692006-10-16 20:04:18 +0100699
Simon Kelley1f15b812009-10-13 17:49:32 +0100700# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100701 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100702 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100703# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100704#endif
705
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000706 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000707}
708
Simon Kelley3be34542004-09-11 19:12:13 +0100709static void sig_handler(int sig)
710{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100711 if (pid == 0)
712 {
Simon Kelley16972692006-10-16 20:04:18 +0100713 /* ignore anything other than TERM during startup
714 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100715 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100716 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100717 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100718 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100719 {
Simon Kelley16972692006-10-16 20:04:18 +0100720 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100721 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100722 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100723 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100724 else
725 {
726 /* master process */
727 int event, errsave = errno;
728
729 if (sig == SIGHUP)
730 event = EVENT_RELOAD;
731 else if (sig == SIGCHLD)
732 event = EVENT_CHILD;
733 else if (sig == SIGALRM)
734 event = EVENT_ALARM;
735 else if (sig == SIGTERM)
736 event = EVENT_TERM;
737 else if (sig == SIGUSR1)
738 event = EVENT_DUMP;
739 else if (sig == SIGUSR2)
740 event = EVENT_REOPEN;
741 else
742 return;
743
744 send_event(pipewrite, event, 0);
745 errno = errsave;
746 }
Simon Kelley3be34542004-09-11 19:12:13 +0100747}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000748
Simon Kelley5aabfc72007-08-29 11:24:47 +0100749void send_event(int fd, int event, int data)
750{
751 struct event_desc ev;
752
753 ev.event = event;
754 ev.data = data;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100755
756 /* error pipe, debug mode. */
757 if (fd == -1)
758 fatal_event(&ev);
759 else
760 /* pipe is non-blocking and struct event_desc is smaller than
761 PIPE_BUF, so this either fails or writes everything */
762 while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100763}
Simon Kelley3d8df262005-08-29 12:19:27 +0100764
Simon Kelley1a6bca82008-07-11 11:11:42 +0100765static void fatal_event(struct event_desc *ev)
766{
767 errno = ev->data;
768
769 switch (ev->event)
770 {
771 case EVENT_DIE:
772 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100773
774 case EVENT_FORK_ERR:
775 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100776
777 case EVENT_PIPE_ERR:
778 die(_("failed to create helper: %s"), NULL, EC_MISC);
779
780 case EVENT_CAP_ERR:
781 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
782
783 case EVENT_USER_ERR:
784 case EVENT_HUSER_ERR:
785 die(_("failed to change user-id to %s: %s"),
786 ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
787 EC_MISC);
788
789 case EVENT_GROUP_ERR:
790 die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
791
792 case EVENT_PIDFILE:
793 die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
794
795 case EVENT_LOG_ERR:
796 die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
797 }
798}
799
Simon Kelley5aabfc72007-08-29 11:24:47 +0100800static void async_event(int pipe, time_t now)
801{
802 pid_t p;
803 struct event_desc ev;
804 int i;
805
806 if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
807 switch (ev.event)
808 {
809 case EVENT_RELOAD:
810 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +0000811 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100812 {
813 reload_servers(daemon->resolv_files->name);
814 check_servers();
815 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100816#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100817 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100818#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100819 break;
820
821 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000822 if (daemon->port != 0)
823 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100824 break;
825
826 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +0100827#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100828 if (daemon->dhcp)
829 {
830 lease_prune(NULL, now);
831 lease_update_file(now);
832 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100833#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100834 break;
835
836 case EVENT_CHILD:
837 /* See Stevens 5.10 */
838 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
839 if (p == -1)
840 {
841 if (errno != EINTR)
842 break;
843 }
844 else
845 for (i = 0 ; i < MAX_PROCS; i++)
846 if (daemon->tcp_pids[i] == p)
847 daemon->tcp_pids[i] = 0;
848 break;
849
850 case EVENT_KILLED:
851 my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
852 break;
853
854 case EVENT_EXITED:
855 my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
856 break;
857
858 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +0100859 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
860 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100861 break;
862
Simon Kelley1a6bca82008-07-11 11:11:42 +0100863 /* necessary for fatal errors in helper */
864 case EVENT_HUSER_ERR:
865 case EVENT_DIE:
866 fatal_event(&ev);
Simon Kelley9e038942008-05-30 20:06:34 +0100867 break;
868
Simon Kelley5aabfc72007-08-29 11:24:47 +0100869 case EVENT_REOPEN:
870 /* Note: this may leave TCP-handling processes with the old file still open.
871 Since any such process will die in CHILD_LIFETIME or probably much sooner,
872 we leave them logging to the old file. */
873 if (daemon->log_file != NULL)
874 log_reopen(daemon->log_file);
875 break;
876
877 case EVENT_TERM:
878 /* Knock all our children on the head. */
879 for (i = 0; i < MAX_PROCS; i++)
880 if (daemon->tcp_pids[i] != 0)
881 kill(daemon->tcp_pids[i], SIGALRM);
882
Simon Kelley1f15b812009-10-13 17:49:32 +0100883#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100884 /* handle pending lease transitions */
885 if (daemon->helperfd != -1)
886 {
887 /* block in writes until all done */
888 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
889 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
890 do {
891 helper_write();
892 } while (!helper_buf_empty() || do_script_run(now));
893 close(daemon->helperfd);
894 }
895#endif
896
897 if (daemon->lease_stream)
898 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +0000899
900 if (daemon->runfile)
901 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100902
903 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
904 flush_log();
905 exit(EC_GOOD);
906 }
907}
908
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100909void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100910{
911 struct resolvc *res, *latest;
912 struct stat statbuf;
913 time_t last_change = 0;
914 /* There may be more than one possible file.
915 Go through and find the one which changed _last_.
916 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100917
Simon Kelley28866e92011-02-14 20:19:14 +0000918 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100919 return;
920
Simon Kelley5aabfc72007-08-29 11:24:47 +0100921 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
922 if (stat(res->name, &statbuf) == -1)
923 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100924 if (force)
925 {
926 res->mtime = 0;
927 continue;
928 }
929
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 if (!res->logged)
931 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
932 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100933
934 if (res->mtime != 0)
935 {
936 /* existing file evaporated, force selection of the latest
937 file even if its mtime hasn't changed since we last looked */
938 poll_resolv(1, do_reload, now);
939 return;
940 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100941 }
942 else
943 {
944 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100945 if (force || (statbuf.st_mtime != res->mtime))
946 {
947 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100948 if (difftime(statbuf.st_mtime, last_change) > 0.0)
949 {
950 last_change = statbuf.st_mtime;
951 latest = res;
952 }
953 }
954 }
955
956 if (latest)
957 {
958 static int warned = 0;
959 if (reload_servers(latest->name))
960 {
961 my_syslog(LOG_INFO, _("reading %s"), latest->name);
962 warned = 0;
963 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +0000964 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100965 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100966 }
967 else
968 {
969 latest->mtime = 0;
970 if (!warned)
971 {
972 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
973 warned = 1;
974 }
975 }
976 }
977}
978
979void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +0100980{
Simon Kelley824af852008-02-12 20:43:05 +0000981 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +0100982 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +0000983
Simon Kelley7622fc02009-06-04 20:32:05 +0100984#ifdef HAVE_DHCP
Simon Kelley3d8df262005-08-29 12:19:27 +0100985 if (daemon->dhcp)
986 {
Simon Kelley28866e92011-02-14 20:19:14 +0000987 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100988 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +0000989 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +0100990 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +0000991 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100992 lease_update_from_configs();
993 lease_update_file(now);
994 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +0100995 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100996#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100997}
998
Simon Kelley5aabfc72007-08-29 11:24:47 +0100999static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001000{
1001 struct serverfd *serverfdp;
1002 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001003 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001004
1005#ifdef HAVE_TFTP
1006 int tftp = 0;
1007 struct tftp_transfer *transfer;
1008 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1009 {
1010 tftp++;
1011 FD_SET(transfer->sockfd, set);
1012 bump_maxfd(transfer->sockfd, maxfdp);
1013 }
1014#endif
1015
Simon Kelley16972692006-10-16 20:04:18 +01001016 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001017 if (daemon->port != 0)
1018 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +01001019
Simon Kelley3be34542004-09-11 19:12:13 +01001020 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1021 {
1022 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001023 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001024 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001025
1026 if (daemon->port != 0 && !daemon->osport)
1027 for (i = 0; i < RANDOM_SOCKS; i++)
1028 if (daemon->randomsocks[i].refcount != 0)
1029 {
1030 FD_SET(daemon->randomsocks[i].fd, set);
1031 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1032 }
1033
Simon Kelley3be34542004-09-11 19:12:13 +01001034 for (listener = daemon->listeners; listener; listener = listener->next)
1035 {
Simon Kelley16972692006-10-16 20:04:18 +01001036 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001037 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001038 {
1039 FD_SET(listener->fd, set);
1040 bump_maxfd(listener->fd, maxfdp);
1041 }
1042
1043 /* death of a child goes through the select loop, so
1044 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001045 if (listener->tcpfd != -1)
1046 for (i = 0; i < MAX_PROCS; i++)
1047 if (daemon->tcp_pids[i] == 0)
1048 {
1049 FD_SET(listener->tcpfd, set);
1050 bump_maxfd(listener->tcpfd, maxfdp);
1051 break;
1052 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001053
Simon Kelley832af0b2007-01-21 20:01:28 +00001054#ifdef HAVE_TFTP
1055 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1056 {
1057 FD_SET(listener->tftpfd, set);
1058 bump_maxfd(listener->tftpfd, maxfdp);
1059 }
1060#endif
1061
1062 }
1063
Simon Kelley16972692006-10-16 20:04:18 +01001064 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001065}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001066
Simon Kelley5aabfc72007-08-29 11:24:47 +01001067static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001068{
1069 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001070 struct listener *listener;
1071 int i;
1072
Simon Kelley832af0b2007-01-21 20:01:28 +00001073 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1074 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001075 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1076
1077 if (daemon->port != 0 && !daemon->osport)
1078 for (i = 0; i < RANDOM_SOCKS; i++)
1079 if (daemon->randomsocks[i].refcount != 0 &&
1080 FD_ISSET(daemon->randomsocks[i].fd, set))
1081 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001082
1083 for (listener = daemon->listeners; listener; listener = listener->next)
1084 {
Simon Kelley824af852008-02-12 20:43:05 +00001085 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001086 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001087
Simon Kelley832af0b2007-01-21 20:01:28 +00001088#ifdef HAVE_TFTP
1089 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001090 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001091#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001092
Simon Kelley824af852008-02-12 20:43:05 +00001093 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001094 {
1095 int confd;
1096 struct irec *iface = NULL;
1097 pid_t p;
1098
1099 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1100
1101 if (confd == -1)
1102 continue;
1103
Simon Kelley28866e92011-02-14 20:19:14 +00001104 if (option_bool(OPT_NOWILD))
Simon Kelley832af0b2007-01-21 20:01:28 +00001105 iface = listener->iface;
1106 else
1107 {
1108 union mysockaddr tcp_addr;
1109 socklen_t tcp_len = sizeof(union mysockaddr);
1110 /* Check for allowed interfaces when binding the wildcard address:
1111 we do this by looking for an interface with the same address as
1112 the local address of the TCP connection, then looking to see if that's
1113 an allowed interface. As a side effect, we get the netmask of the
1114 interface too, for localisation. */
1115
1116 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001117 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001118 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1119 for (iface = daemon->interfaces; iface; iface = iface->next)
1120 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1121 break;
1122 }
1123
1124 if (!iface)
1125 {
1126 shutdown(confd, SHUT_RDWR);
1127 close(confd);
1128 }
1129#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001130 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001131 {
1132 if (p != -1)
1133 {
1134 int i;
1135 for (i = 0; i < MAX_PROCS; i++)
1136 if (daemon->tcp_pids[i] == 0)
1137 {
1138 daemon->tcp_pids[i] = p;
1139 break;
1140 }
1141 }
1142 close(confd);
1143 }
1144#endif
1145 else
1146 {
1147 unsigned char *buff;
1148 struct server *s;
1149 int flags;
1150 struct in_addr dst_addr_4;
1151
1152 dst_addr_4.s_addr = 0;
1153
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001154#ifndef NO_FORK
1155 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1156 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001157 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001158 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001159#endif
1160
Simon Kelley832af0b2007-01-21 20:01:28 +00001161 /* start with no upstream connections. */
1162 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001163 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001164
1165 /* The connected socket inherits non-blocking
1166 attribute from the listening socket.
1167 Reset that here. */
1168 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1169 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1170
1171 if (listener->family == AF_INET)
1172 dst_addr_4 = iface->addr.in.sin_addr;
1173
Simon Kelley5aabfc72007-08-29 11:24:47 +01001174 buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001175
Simon Kelley832af0b2007-01-21 20:01:28 +00001176 shutdown(confd, SHUT_RDWR);
1177 close(confd);
1178
1179 if (buff)
1180 free(buff);
1181
1182 for (s = daemon->servers; s; s = s->next)
1183 if (s->tcpfd != -1)
1184 {
1185 shutdown(s->tcpfd, SHUT_RDWR);
1186 close(s->tcpfd);
1187 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001188#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001189 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001190 {
1191 flush_log();
1192 _exit(0);
1193 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001194#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001195 }
1196 }
1197 }
Simon Kelley3be34542004-09-11 19:12:13 +01001198}
1199
Simon Kelley7622fc02009-06-04 20:32:05 +01001200#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001201int make_icmp_sock(void)
1202{
Simon Kelley7cebd202006-05-06 14:13:33 +01001203 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001204 int zeroopt = 0;
1205
1206 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1207 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001208 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001209 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1210 {
1211 close(fd);
1212 fd = -1;
1213 }
1214 }
1215
1216 return fd;
1217}
1218
Simon Kelley5aabfc72007-08-29 11:24:47 +01001219int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001220{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001221 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001222
1223 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001224 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001225 better not use any resources our caller has in use...)
1226 but we remain deaf to signals or further DHCP packets. */
1227
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001228 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001229 struct sockaddr_in saddr;
1230 struct {
1231 struct ip ip;
1232 struct icmp icmp;
1233 } packet;
1234 unsigned short id = rand16();
1235 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001236 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001237 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001238
Simon Kelley824af852008-02-12 20:43:05 +00001239#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001240 if ((fd = make_icmp_sock()) == -1)
1241 return 0;
1242#else
1243 int opt = 2000;
1244 fd = daemon->dhcp_icmp_fd;
1245 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1246#endif
1247
Simon Kelley3be34542004-09-11 19:12:13 +01001248 saddr.sin_family = AF_INET;
1249 saddr.sin_port = 0;
1250 saddr.sin_addr = addr;
1251#ifdef HAVE_SOCKADDR_SA_LEN
1252 saddr.sin_len = sizeof(struct sockaddr_in);
1253#endif
1254
1255 memset(&packet.icmp, 0, sizeof(packet.icmp));
1256 packet.icmp.icmp_type = ICMP_ECHO;
1257 packet.icmp.icmp_id = id;
1258 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1259 j += ((u16 *)&packet.icmp)[i];
1260 while (j>>16)
1261 j = (j & 0xffff) + (j >> 16);
1262 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1263
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001264 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001265 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1266 retry_send());
1267
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001268 for (now = start = dnsmasq_time();
1269 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001270 {
1271 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001272 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001273 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001274 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001275 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001276
1277 tv.tv_usec = 250000;
1278 tv.tv_sec = 0;
1279
1280 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001281 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001282 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001283 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001284 set_log_writer(&wset, &maxfd);
1285
1286 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1287 {
1288 FD_ZERO(&rset);
1289 FD_ZERO(&wset);
1290 }
1291
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001292 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001293
1294 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001295 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001296
1297#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001298 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001299#endif
1300
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001301 if (FD_ISSET(fd, &rset) &&
1302 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001303 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1304 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1305 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1306 packet.icmp.icmp_seq == 0 &&
1307 packet.icmp.icmp_id == id)
1308 {
1309 gotreply = 1;
1310 break;
1311 }
1312 }
1313
Simon Kelley824af852008-02-12 20:43:05 +00001314#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001315 close(fd);
1316#else
Simon Kelley3be34542004-09-11 19:12:13 +01001317 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001318 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1319#endif
1320
Simon Kelley3be34542004-09-11 19:12:13 +01001321 return gotreply;
1322}
Simon Kelley7622fc02009-06-04 20:32:05 +01001323#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001324
1325