blob: 48e3ecfc53a3976c4f0075a8669afda58726017b [file] [log] [blame]
Simon Kelley73a08a22009-02-05 20:28:08 +00001/* dnsmasq is Copyright (c) 2000-2009 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
54"TFTP";
Simon Kelley3d8df262005-08-29 12:19:27 +010055
Simon Kelley1f15b812009-10-13 17:49:32 +010056
57
Simon Kelley5aabfc72007-08-29 11:24:47 +010058static volatile pid_t pid = 0;
59static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000060
Simon Kelley5aabfc72007-08-29 11:24:47 +010061static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
62static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010063static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010064static void async_event(int pipe, time_t now);
Simon Kelley1a6bca82008-07-11 11:11:42 +010065static void fatal_event(struct event_desc *ev);
Simon Kelley5aabfc72007-08-29 11:24:47 +010066static void poll_resolv(void);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000067
68int main (int argc, char **argv)
69{
Simon Kelleyde379512004-06-22 20:23:33 +010070 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000071 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000072 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000073 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010074 int piperead, pipefd[2], err_pipe[2];
75 struct passwd *ent_pw = NULL;
Simon Kelley1f15b812009-10-13 17:49:32 +010076#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010077 uid_t script_uid = 0;
78 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010079#endif
80 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010081 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010082 char *baduser = NULL;
83 int log_err;
84#if defined(HAVE_LINUX_NETWORK)
85 cap_user_header_t hdr = NULL;
86 cap_user_data_t data = NULL;
87#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010088
Simon Kelley824af852008-02-12 20:43:05 +000089#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000090 setlocale(LC_ALL, "");
91 bindtextdomain("dnsmasq", LOCALEDIR);
92 textdomain("dnsmasq");
93#endif
94
Simon Kelley9e4abcb2004-01-22 19:47:41 +000095 sigact.sa_handler = sig_handler;
96 sigact.sa_flags = 0;
97 sigemptyset(&sigact.sa_mask);
98 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010099 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000100 sigaction(SIGHUP, &sigact, NULL);
101 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +0000102 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100103 sigaction(SIGCHLD, &sigact, NULL);
104
105 /* ignore SIGPIPE */
106 sigact.sa_handler = SIG_IGN;
107 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000108
Simon Kelley5aabfc72007-08-29 11:24:47 +0100109 umask(022); /* known umask, create leases and pid files as 0644 */
110
111 read_opts(argc, argv, compile_opts);
112
Simon Kelley3be34542004-09-11 19:12:13 +0100113 if (daemon->edns_pktsz < PACKETSZ)
114 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +0000115 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
116 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
117 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100118
Simon Kelley7622fc02009-06-04 20:32:05 +0100119#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100120 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000121 {
Simon Kelley3be34542004-09-11 19:12:13 +0100122 if (daemon->dhcp)
123 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000124 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100125#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000126
Simon Kelley5aabfc72007-08-29 11:24:47 +0100127 /* Close any file descriptors we inherited apart from std{in|out|err} */
128 for (i = 0; i < max_fd; i++)
129 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
130 close(i);
131
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100132#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100133 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100134#elif !(defined(IP_RECVDSTADDR) && \
135 defined(IP_RECVIF) && \
136 defined(IP_SENDSRCADDR))
137 if (!(daemon->options & OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100138 {
139 bind_fallback = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100140 daemon->options |= OPT_NOWILD;
Simon Kelleyde379512004-06-22 20:23:33 +0100141 }
Simon Kelley309331f2006-04-22 15:05:01 +0100142#endif
143
Simon Kelley832af0b2007-01-21 20:01:28 +0000144#ifndef HAVE_TFTP
145 if (daemon->options & OPT_TFTP)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100146 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000147#endif
148
Simon Kelley824af852008-02-12 20:43:05 +0000149#ifdef HAVE_SOLARIS_NETWORK
150 if (daemon->max_logs != 0)
151 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
152#endif
153
Simon Kelley1a6bca82008-07-11 11:11:42 +0100154 rand_init();
155
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100156 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000157
Simon Kelley7622fc02009-06-04 20:32:05 +0100158#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100159 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100161 /* Note that order matters here, we must call lease_init before
162 creating any file descriptors which shouldn't be leaked
163 to the lease-script init process. */
164 lease_init(now);
165 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100167#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100168
Simon Kelley5aabfc72007-08-29 11:24:47 +0100169 if (!enumerate_interfaces())
170 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
171
172 if (daemon->options & OPT_NOWILD)
173 {
174 daemon->listeners = create_bound_listeners();
175
176 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
177 if (if_tmp->name && !if_tmp->used)
178 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
179
180 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
181 if (!if_tmp->used)
182 {
183 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
184 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
185 }
186 }
Simon Kelley824af852008-02-12 20:43:05 +0000187 else if ((daemon->port != 0 || (daemon->options & OPT_TFTP)) &&
188 !(daemon->listeners = create_wildcard_listeners()))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100189 die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
190
Simon Kelley824af852008-02-12 20:43:05 +0000191 if (daemon->port != 0)
192 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100193
Simon Kelley3d8df262005-08-29 12:19:27 +0100194 if (daemon->options & OPT_DBUS)
195#ifdef HAVE_DBUS
196 {
197 char *err;
198 daemon->dbus = NULL;
199 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100200 if ((err = dbus_init()))
201 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100202 }
203#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100204 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100205#endif
206
Simon Kelley824af852008-02-12 20:43:05 +0000207 if (daemon->port != 0)
208 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100209
Simon Kelley1f15b812009-10-13 17:49:32 +0100210#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100211 /* Note getpwnam returns static storage */
212 if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
213 {
214 if ((ent_pw = getpwnam(daemon->scriptuser)))
215 {
216 script_uid = ent_pw->pw_uid;
217 script_gid = ent_pw->pw_gid;
218 }
219 else
220 baduser = daemon->scriptuser;
221 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100222#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000223
Simon Kelley1a6bca82008-07-11 11:11:42 +0100224 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
225 baduser = daemon->username;
226 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
227 baduser = daemon->groupname;
228
229 if (baduser)
230 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
231
232 /* implement group defaults, "dip" if available, or group associated with uid */
233 if (!daemon->group_set && !gp)
234 {
235 if (!(gp = getgrnam(CHGRP)) && ent_pw)
236 gp = getgrgid(ent_pw->pw_gid);
237
238 /* for error message */
239 if (gp)
240 daemon->groupname = gp->gr_name;
241 }
242
243#if defined(HAVE_LINUX_NETWORK)
244 /* determine capability API version here, while we can still
245 call safe_malloc */
246 if (ent_pw && ent_pw->pw_uid != 0)
247 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100248 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100249 hdr = safe_malloc(sizeof(*hdr));
250
Simon Kelley1a6bca82008-07-11 11:11:42 +0100251 /* find version supported by kernel */
252 memset(hdr, 0, sizeof(*hdr));
253 capget(hdr, NULL);
254
255 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
256 {
257 /* if unknown version, use largest supported version (3) */
258 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
259 hdr->version = LINUX_CAPABILITY_VERSION_3;
260 capsize = 2;
261 }
262
263 data = safe_malloc(sizeof(*data) * capsize);
264 memset(data, 0, sizeof(*data) * capsize);
265 }
266#endif
267
Simon Kelley5aabfc72007-08-29 11:24:47 +0100268 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100269 in a race-free manner and another to carry errors to daemon-invoking process */
270 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100271
272 piperead = pipefd[0];
273 pipewrite = pipefd[1];
274 /* prime the pipe to load stuff first time. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100275 send_event(pipewrite, EVENT_RELOAD, 0);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100276
277 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100278
279 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000280 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100281 int nullfd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100282
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000283 /* The following code "daemonizes" the process.
284 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100285
Simon Kelley9e038942008-05-30 20:06:34 +0100286 if (chdir("/") != 0)
287 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
288
Simon Kelley16972692006-10-16 20:04:18 +0100289#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100290 if (!(daemon->options & OPT_NO_FORK))
291 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100292 pid_t pid;
293
Simon Kelley1a6bca82008-07-11 11:11:42 +0100294 /* pipe to carry errors back to original process.
295 When startup is complete we close this and the process terminates. */
296 safe_pipe(err_pipe, 0);
297
Simon Kelley7622fc02009-06-04 20:32:05 +0100298 if ((pid = fork()) == -1)
299 /* fd == -1 since we've not forked, never returns. */
300 send_event(-1, EVENT_FORK_ERR, errno);
Simon Kelley9e038942008-05-30 20:06:34 +0100301
Simon Kelley5aabfc72007-08-29 11:24:47 +0100302 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100303 {
304 struct event_desc ev;
305
306 /* close our copy of write-end */
307 close(err_pipe[1]);
308
309 /* check for errors after the fork */
310 if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
311 fatal_event(&ev);
312
313 _exit(EC_GOOD);
314 }
315
316 close(err_pipe[0]);
317
318 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100319
320 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100321
322 if ((pid = fork()) == -1)
323 send_event(err_pipe[1], EVENT_FORK_ERR, errno);
324
325 if (pid != 0)
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;
Simon Kelley1f15b812009-10-13 17:49:32 +0100360#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100361 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 Kelley7622fc02009-06-04 20:32:05 +0100391#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000392 /* 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
Simon Kelley824af852008-02-12 20:43:05 +0000411#endif
412
Simon Kelley1a6bca82008-07-11 11:11:42 +0100413 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100414 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100415 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
416 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100417 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418
419 /* finally drop root */
420 if (setuid(ent_pw->pw_uid) == -1)
421 {
422 send_event(err_pipe[1], EVENT_USER_ERR, errno);
423 _exit(0);
424 }
425
426#ifdef HAVE_LINUX_NETWORK
427 data->effective = data->permitted =
428 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
429 data->inheritable = 0;
430
431 /* lose the setuid and setgid capbilities */
432 if (capset(hdr, data) == -1)
433 {
434 send_event(err_pipe[1], EVENT_CAP_ERR, errno);
435 _exit(0);
436 }
437#endif
438
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000439 }
Simon Kelley849a8352006-06-09 21:02:31 +0100440 }
Simon Kelley16972692006-10-16 20:04:18 +0100441
Simon Kelley16972692006-10-16 20:04:18 +0100442#ifdef HAVE_LINUX_NETWORK
443 if (daemon->options & OPT_DEBUG)
444 prctl(PR_SET_DUMPABLE, 1);
445#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100446
Simon Kelley824af852008-02-12 20:43:05 +0000447 if (daemon->port == 0)
448 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
449 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100450 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000451 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100452 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100453
Simon Kelleyf2621c72007-04-29 19:47:21 +0100454 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100455
Simon Kelley3d8df262005-08-29 12:19:27 +0100456#ifdef HAVE_DBUS
457 if (daemon->options & OPT_DBUS)
458 {
459 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100460 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100461 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100462 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100463 }
464#endif
465
Simon Kelley1a6bca82008-07-11 11:11:42 +0100466 if (log_err != 0)
467 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
468 daemon->log_file, strerror(log_err));
469
Simon Kelleyde379512004-06-22 20:23:33 +0100470 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100471 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100472
Simon Kelley26128d22004-11-14 16:43:54 +0000473 if (!(daemon->options & OPT_NOWILD))
474 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
475 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100476 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100477
Simon Kelley824af852008-02-12 20:43:05 +0000478 if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100479 {
480 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100481 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100482 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000483 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100484 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100485 }
486
Simon Kelleyf2621c72007-04-29 19:47:21 +0100487 if (daemon->max_logs != 0)
488 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
489
Simon Kelley7622fc02009-06-04 20:32:05 +0100490#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100491 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000492 {
Simon Kelley3be34542004-09-11 19:12:13 +0100493 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000494
Simon Kelley3be34542004-09-11 19:12:13 +0100495 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100496 {
Simon Kelley0a852542005-03-23 20:28:59 +0000497 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100498 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelley7622fc02009-06-04 20:32:05 +0100499 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100500 (dhcp_tmp->flags & CONTEXT_STATIC) ?
501 _("DHCP, static leases only on %.0s%s, lease time %s") :
Simon Kelley7622fc02009-06-04 20:32:05 +0100502 (dhcp_tmp->flags & CONTEXT_PROXY) ?
503 _("DHCP, proxy on subnet %.0s%s%.0s") :
Simon Kelleyf2621c72007-04-29 19:47:21 +0100504 _("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 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100508#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000509
Simon Kelley832af0b2007-01-21 20:01:28 +0000510#ifdef HAVE_TFTP
511 if (daemon->options & OPT_TFTP)
512 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000513#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100514 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000515 max_fd = FD_SETSIZE;
516#endif
517
Simon Kelley7622fc02009-06-04 20:32:05 +0100518 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100519 daemon->tftp_prefix ? _("root is ") : _("enabled"),
520 daemon->tftp_prefix ? daemon->tftp_prefix: "",
521 daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
522
Simon Kelley832af0b2007-01-21 20:01:28 +0000523 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100524 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000525 a single file will be sent to may clients (the file only needs
526 one fd). */
527
528 max_fd -= 30; /* use other than TFTP */
529
530 if (max_fd < 0)
531 max_fd = 5;
532 else if (max_fd < 100)
533 max_fd = max_fd/2;
534 else
535 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000536
537 /* if we have to use a limited range of ports,
538 that will limit the number of transfers */
539 if (daemon->start_tftp_port != 0 &&
540 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
541 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000542
543 if (daemon->tftp_max > max_fd)
544 {
545 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100546 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100547 _("restricting maximum simultaneous TFTP transfers to %d"),
548 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000549 }
550 }
551#endif
552
Simon Kelley1a6bca82008-07-11 11:11:42 +0100553 /* finished start-up - release original process */
554 if (err_pipe[1] != -1)
555 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000556
Simon Kelley824af852008-02-12 20:43:05 +0000557 if (daemon->port != 0)
558 check_servers();
559
Simon Kelley7cebd202006-05-06 14:13:33 +0100560 pid = getpid();
561
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100562 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000563 {
Simon Kelley16972692006-10-16 20:04:18 +0100564 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100565 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100566 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000567
568 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100569 FD_ZERO(&wset);
570 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000571
Simon Kelley16972692006-10-16 20:04:18 +0100572 /* if we are out of resources, find how long we have to wait
573 for some to come free, we'll loop around then and restart
574 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100575 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100576 {
577 t.tv_usec = 0;
578 tp = &t;
579 }
580
Simon Kelley832af0b2007-01-21 20:01:28 +0000581 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
582 if (daemon->tftp_trans ||
583 ((daemon->options & OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000584 {
Simon Kelley16972692006-10-16 20:04:18 +0100585 t.tv_sec = 0;
586 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100587 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000588 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100589
Simon Kelley832af0b2007-01-21 20:01:28 +0000590#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100591 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100592#endif
593
Simon Kelley7622fc02009-06-04 20:32:05 +0100594#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100595 if (daemon->dhcp)
596 {
597 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100598 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100599 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100600#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100601
602#ifdef HAVE_LINUX_NETWORK
603 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100604 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100605#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100606
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100607 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100608 bump_maxfd(piperead, &maxfd);
609
Simon Kelley7622fc02009-06-04 20:32:05 +0100610#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100611# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100612 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100613
614 if (!helper_buf_empty())
615 {
616 FD_SET(daemon->helperfd, &wset);
617 bump_maxfd(daemon->helperfd, &maxfd);
618 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100619# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100620 /* need this for other side-effects */
621 while (do_script_run(now));
Simon Kelley7622fc02009-06-04 20:32:05 +0100622# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100623#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100624
Simon Kelleyf2621c72007-04-29 19:47:21 +0100625 /* must do this just before select(), when we know no
626 more calls to my_syslog() can occur */
627 set_log_writer(&wset, &maxfd);
628
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100629 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
630 {
631 /* otherwise undefined after error */
632 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
633 }
634
635 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000636
Simon Kelleyf2621c72007-04-29 19:47:21 +0100637 check_log_writer(&wset);
638
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000639 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100640 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000641 if (daemon->last_resolv == 0 ||
642 difftime(now, daemon->last_resolv) > 1.0 ||
643 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000644 {
Simon Kelley9009d742008-11-14 20:04:27 +0000645 daemon->last_resolv = now;
Simon Kelley33820b72004-04-03 21:10:00 +0100646
Simon Kelley824af852008-02-12 20:43:05 +0000647 if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100648 poll_resolv();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100650
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100651 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100652 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100653
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100654#ifdef HAVE_LINUX_NETWORK
655 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100656 netlink_multicast();
Simon Kelleycdeda282006-03-16 20:16:06 +0000657#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100658
659#ifdef HAVE_DBUS
660 /* if we didn't create a DBus connection, retry now. */
Simon Kelley7cebd202006-05-06 14:13:33 +0100661 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100662 {
663 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100664 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100665 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100666 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100667 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100668 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100669 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100670#endif
Simon Kelley824af852008-02-12 20:43:05 +0000671
Simon Kelley5aabfc72007-08-29 11:24:47 +0100672 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000673
674#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100675 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000676#endif
677
Simon Kelley7622fc02009-06-04 20:32:05 +0100678#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100679 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100680 dhcp_packet(now);
Simon Kelley16972692006-10-16 20:04:18 +0100681
Simon Kelley1f15b812009-10-13 17:49:32 +0100682# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100683 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100684 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100685# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100686#endif
687
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000688 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000689}
690
Simon Kelley3be34542004-09-11 19:12:13 +0100691static void sig_handler(int sig)
692{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100693 if (pid == 0)
694 {
Simon Kelley16972692006-10-16 20:04:18 +0100695 /* ignore anything other than TERM during startup
696 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100697 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100698 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100699 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100700 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100701 {
Simon Kelley16972692006-10-16 20:04:18 +0100702 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100703 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100704 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100705 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100706 else
707 {
708 /* master process */
709 int event, errsave = errno;
710
711 if (sig == SIGHUP)
712 event = EVENT_RELOAD;
713 else if (sig == SIGCHLD)
714 event = EVENT_CHILD;
715 else if (sig == SIGALRM)
716 event = EVENT_ALARM;
717 else if (sig == SIGTERM)
718 event = EVENT_TERM;
719 else if (sig == SIGUSR1)
720 event = EVENT_DUMP;
721 else if (sig == SIGUSR2)
722 event = EVENT_REOPEN;
723 else
724 return;
725
726 send_event(pipewrite, event, 0);
727 errno = errsave;
728 }
Simon Kelley3be34542004-09-11 19:12:13 +0100729}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000730
Simon Kelley5aabfc72007-08-29 11:24:47 +0100731void send_event(int fd, int event, int data)
732{
733 struct event_desc ev;
734
735 ev.event = event;
736 ev.data = data;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100737
738 /* error pipe, debug mode. */
739 if (fd == -1)
740 fatal_event(&ev);
741 else
742 /* pipe is non-blocking and struct event_desc is smaller than
743 PIPE_BUF, so this either fails or writes everything */
744 while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100745}
Simon Kelley3d8df262005-08-29 12:19:27 +0100746
Simon Kelley1a6bca82008-07-11 11:11:42 +0100747static void fatal_event(struct event_desc *ev)
748{
749 errno = ev->data;
750
751 switch (ev->event)
752 {
753 case EVENT_DIE:
754 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +0100755
756 case EVENT_FORK_ERR:
757 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100758
759 case EVENT_PIPE_ERR:
760 die(_("failed to create helper: %s"), NULL, EC_MISC);
761
762 case EVENT_CAP_ERR:
763 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
764
765 case EVENT_USER_ERR:
766 case EVENT_HUSER_ERR:
767 die(_("failed to change user-id to %s: %s"),
768 ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
769 EC_MISC);
770
771 case EVENT_GROUP_ERR:
772 die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
773
774 case EVENT_PIDFILE:
775 die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
776
777 case EVENT_LOG_ERR:
778 die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
779 }
780}
781
Simon Kelley5aabfc72007-08-29 11:24:47 +0100782static void async_event(int pipe, time_t now)
783{
784 pid_t p;
785 struct event_desc ev;
786 int i;
787
788 if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
789 switch (ev.event)
790 {
791 case EVENT_RELOAD:
792 clear_cache_and_reload(now);
Simon Kelley824af852008-02-12 20:43:05 +0000793 if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100794 {
795 reload_servers(daemon->resolv_files->name);
796 check_servers();
797 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100798#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100799 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +0100800#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100801 break;
802
803 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +0000804 if (daemon->port != 0)
805 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100806 break;
807
808 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +0100809#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100810 if (daemon->dhcp)
811 {
812 lease_prune(NULL, now);
813 lease_update_file(now);
814 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100815#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100816 break;
817
818 case EVENT_CHILD:
819 /* See Stevens 5.10 */
820 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
821 if (p == -1)
822 {
823 if (errno != EINTR)
824 break;
825 }
826 else
827 for (i = 0 ; i < MAX_PROCS; i++)
828 if (daemon->tcp_pids[i] == p)
829 daemon->tcp_pids[i] = 0;
830 break;
831
832 case EVENT_KILLED:
833 my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
834 break;
835
836 case EVENT_EXITED:
837 my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
838 break;
839
840 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +0100841 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
842 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100843 break;
844
Simon Kelley1a6bca82008-07-11 11:11:42 +0100845 /* necessary for fatal errors in helper */
846 case EVENT_HUSER_ERR:
847 case EVENT_DIE:
848 fatal_event(&ev);
Simon Kelley9e038942008-05-30 20:06:34 +0100849 break;
850
Simon Kelley5aabfc72007-08-29 11:24:47 +0100851 case EVENT_REOPEN:
852 /* Note: this may leave TCP-handling processes with the old file still open.
853 Since any such process will die in CHILD_LIFETIME or probably much sooner,
854 we leave them logging to the old file. */
855 if (daemon->log_file != NULL)
856 log_reopen(daemon->log_file);
857 break;
858
859 case EVENT_TERM:
860 /* Knock all our children on the head. */
861 for (i = 0; i < MAX_PROCS; i++)
862 if (daemon->tcp_pids[i] != 0)
863 kill(daemon->tcp_pids[i], SIGALRM);
864
Simon Kelley1f15b812009-10-13 17:49:32 +0100865#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100866 /* handle pending lease transitions */
867 if (daemon->helperfd != -1)
868 {
869 /* block in writes until all done */
870 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
871 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
872 do {
873 helper_write();
874 } while (!helper_buf_empty() || do_script_run(now));
875 close(daemon->helperfd);
876 }
877#endif
878
879 if (daemon->lease_stream)
880 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +0000881
882 if (daemon->runfile)
883 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100884
885 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
886 flush_log();
887 exit(EC_GOOD);
888 }
889}
890
891static void poll_resolv()
892{
893 struct resolvc *res, *latest;
894 struct stat statbuf;
895 time_t last_change = 0;
896 /* There may be more than one possible file.
897 Go through and find the one which changed _last_.
898 Warn of any which can't be read. */
899 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
900 if (stat(res->name, &statbuf) == -1)
901 {
902 if (!res->logged)
903 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
904 res->logged = 1;
905 }
906 else
907 {
908 res->logged = 0;
909 if (statbuf.st_mtime != res->mtime)
910 {
911 res->mtime = statbuf.st_mtime;
912 if (difftime(statbuf.st_mtime, last_change) > 0.0)
913 {
914 last_change = statbuf.st_mtime;
915 latest = res;
916 }
917 }
918 }
919
920 if (latest)
921 {
922 static int warned = 0;
923 if (reload_servers(latest->name))
924 {
925 my_syslog(LOG_INFO, _("reading %s"), latest->name);
926 warned = 0;
927 check_servers();
928 if (daemon->options & OPT_RELOAD)
Simon Kelley7622fc02009-06-04 20:32:05 +0100929 cache_reload();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 }
931 else
932 {
933 latest->mtime = 0;
934 if (!warned)
935 {
936 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
937 warned = 1;
938 }
939 }
940 }
941}
942
943void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +0100944{
Simon Kelley824af852008-02-12 20:43:05 +0000945 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +0100946 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +0000947
Simon Kelley7622fc02009-06-04 20:32:05 +0100948#ifdef HAVE_DHCP
Simon Kelley3d8df262005-08-29 12:19:27 +0100949 if (daemon->dhcp)
950 {
951 if (daemon->options & OPT_ETHERS)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100952 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +0000953 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +0100954 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley824af852008-02-12 20:43:05 +0000955 check_dhcp_hosts(0);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100956 lease_update_from_configs();
957 lease_update_file(now);
958 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +0100959 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100960#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100961}
962
Simon Kelley5aabfc72007-08-29 11:24:47 +0100963static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +0100964{
965 struct serverfd *serverfdp;
966 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +0000967 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +0000968
969#ifdef HAVE_TFTP
970 int tftp = 0;
971 struct tftp_transfer *transfer;
972 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
973 {
974 tftp++;
975 FD_SET(transfer->sockfd, set);
976 bump_maxfd(transfer->sockfd, maxfdp);
977 }
978#endif
979
Simon Kelley16972692006-10-16 20:04:18 +0100980 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +0000981 if (daemon->port != 0)
982 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +0100983
Simon Kelley3be34542004-09-11 19:12:13 +0100984 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
985 {
986 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +0100987 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +0100988 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100989
990 if (daemon->port != 0 && !daemon->osport)
991 for (i = 0; i < RANDOM_SOCKS; i++)
992 if (daemon->randomsocks[i].refcount != 0)
993 {
994 FD_SET(daemon->randomsocks[i].fd, set);
995 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
996 }
997
Simon Kelley3be34542004-09-11 19:12:13 +0100998 for (listener = daemon->listeners; listener; listener = listener->next)
999 {
Simon Kelley16972692006-10-16 20:04:18 +01001000 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001001 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001002 {
1003 FD_SET(listener->fd, set);
1004 bump_maxfd(listener->fd, maxfdp);
1005 }
1006
1007 /* death of a child goes through the select loop, so
1008 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001009 if (listener->tcpfd != -1)
1010 for (i = 0; i < MAX_PROCS; i++)
1011 if (daemon->tcp_pids[i] == 0)
1012 {
1013 FD_SET(listener->tcpfd, set);
1014 bump_maxfd(listener->tcpfd, maxfdp);
1015 break;
1016 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001017
Simon Kelley832af0b2007-01-21 20:01:28 +00001018#ifdef HAVE_TFTP
1019 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1020 {
1021 FD_SET(listener->tftpfd, set);
1022 bump_maxfd(listener->tftpfd, maxfdp);
1023 }
1024#endif
1025
1026 }
1027
Simon Kelley16972692006-10-16 20:04:18 +01001028 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001029}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001030
Simon Kelley5aabfc72007-08-29 11:24:47 +01001031static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001032{
1033 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001034 struct listener *listener;
1035 int i;
1036
Simon Kelley832af0b2007-01-21 20:01:28 +00001037 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1038 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001039 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1040
1041 if (daemon->port != 0 && !daemon->osport)
1042 for (i = 0; i < RANDOM_SOCKS; i++)
1043 if (daemon->randomsocks[i].refcount != 0 &&
1044 FD_ISSET(daemon->randomsocks[i].fd, set))
1045 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001046
1047 for (listener = daemon->listeners; listener; listener = listener->next)
1048 {
Simon Kelley824af852008-02-12 20:43:05 +00001049 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001050 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001051
Simon Kelley832af0b2007-01-21 20:01:28 +00001052#ifdef HAVE_TFTP
1053 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001054 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001055#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001056
Simon Kelley824af852008-02-12 20:43:05 +00001057 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001058 {
1059 int confd;
1060 struct irec *iface = NULL;
1061 pid_t p;
1062
1063 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
1064
1065 if (confd == -1)
1066 continue;
1067
1068 if (daemon->options & OPT_NOWILD)
1069 iface = listener->iface;
1070 else
1071 {
1072 union mysockaddr tcp_addr;
1073 socklen_t tcp_len = sizeof(union mysockaddr);
1074 /* Check for allowed interfaces when binding the wildcard address:
1075 we do this by looking for an interface with the same address as
1076 the local address of the TCP connection, then looking to see if that's
1077 an allowed interface. As a side effect, we get the netmask of the
1078 interface too, for localisation. */
1079
1080 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001081 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +00001082 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
1083 for (iface = daemon->interfaces; iface; iface = iface->next)
1084 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1085 break;
1086 }
1087
1088 if (!iface)
1089 {
1090 shutdown(confd, SHUT_RDWR);
1091 close(confd);
1092 }
1093#ifndef NO_FORK
1094 else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
1095 {
1096 if (p != -1)
1097 {
1098 int i;
1099 for (i = 0; i < MAX_PROCS; i++)
1100 if (daemon->tcp_pids[i] == 0)
1101 {
1102 daemon->tcp_pids[i] = p;
1103 break;
1104 }
1105 }
1106 close(confd);
1107 }
1108#endif
1109 else
1110 {
1111 unsigned char *buff;
1112 struct server *s;
1113 int flags;
1114 struct in_addr dst_addr_4;
1115
1116 dst_addr_4.s_addr = 0;
1117
Simon Kelley7cebd202006-05-06 14:13:33 +01001118 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1119 terminate the process. */
Simon Kelley832af0b2007-01-21 20:01:28 +00001120 if (!(daemon->options & OPT_DEBUG))
1121 alarm(CHILD_LIFETIME);
1122
1123 /* start with no upstream connections. */
1124 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001125 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001126
1127 /* The connected socket inherits non-blocking
1128 attribute from the listening socket.
1129 Reset that here. */
1130 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1131 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1132
1133 if (listener->family == AF_INET)
1134 dst_addr_4 = iface->addr.in.sin_addr;
1135
Simon Kelley5aabfc72007-08-29 11:24:47 +01001136 buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +01001137
Simon Kelley832af0b2007-01-21 20:01:28 +00001138 shutdown(confd, SHUT_RDWR);
1139 close(confd);
1140
1141 if (buff)
1142 free(buff);
1143
1144 for (s = daemon->servers; s; s = s->next)
1145 if (s->tcpfd != -1)
1146 {
1147 shutdown(s->tcpfd, SHUT_RDWR);
1148 close(s->tcpfd);
1149 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001150#ifndef NO_FORK
Simon Kelley832af0b2007-01-21 20:01:28 +00001151 if (!(daemon->options & OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001152 {
1153 flush_log();
1154 _exit(0);
1155 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001156#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001157 }
1158 }
1159 }
Simon Kelley3be34542004-09-11 19:12:13 +01001160}
1161
Simon Kelley7622fc02009-06-04 20:32:05 +01001162#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001163int make_icmp_sock(void)
1164{
Simon Kelley7cebd202006-05-06 14:13:33 +01001165 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001166 int zeroopt = 0;
1167
1168 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1169 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001170 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001171 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1172 {
1173 close(fd);
1174 fd = -1;
1175 }
1176 }
1177
1178 return fd;
1179}
1180
Simon Kelley5aabfc72007-08-29 11:24:47 +01001181int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001182{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001183 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001184
1185 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001186 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001187 better not use any resources our caller has in use...)
1188 but we remain deaf to signals or further DHCP packets. */
1189
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001190 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001191 struct sockaddr_in saddr;
1192 struct {
1193 struct ip ip;
1194 struct icmp icmp;
1195 } packet;
1196 unsigned short id = rand16();
1197 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001198 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001199 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001200
Simon Kelley824af852008-02-12 20:43:05 +00001201#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001202 if ((fd = make_icmp_sock()) == -1)
1203 return 0;
1204#else
1205 int opt = 2000;
1206 fd = daemon->dhcp_icmp_fd;
1207 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1208#endif
1209
Simon Kelley3be34542004-09-11 19:12:13 +01001210 saddr.sin_family = AF_INET;
1211 saddr.sin_port = 0;
1212 saddr.sin_addr = addr;
1213#ifdef HAVE_SOCKADDR_SA_LEN
1214 saddr.sin_len = sizeof(struct sockaddr_in);
1215#endif
1216
1217 memset(&packet.icmp, 0, sizeof(packet.icmp));
1218 packet.icmp.icmp_type = ICMP_ECHO;
1219 packet.icmp.icmp_id = id;
1220 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1221 j += ((u16 *)&packet.icmp)[i];
1222 while (j>>16)
1223 j = (j & 0xffff) + (j >> 16);
1224 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1225
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001226 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001227 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1228 retry_send());
1229
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001230 for (now = start = dnsmasq_time();
1231 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001232 {
1233 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001234 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001235 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001236 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001237 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001238
1239 tv.tv_usec = 250000;
1240 tv.tv_sec = 0;
1241
1242 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001243 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001244 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001245 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001246 set_log_writer(&wset, &maxfd);
1247
1248 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1249 {
1250 FD_ZERO(&rset);
1251 FD_ZERO(&wset);
1252 }
1253
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001254 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001255
1256 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001257 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001258
1259#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001260 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001261#endif
1262
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001263 if (FD_ISSET(fd, &rset) &&
1264 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001265 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1266 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1267 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1268 packet.icmp.icmp_seq == 0 &&
1269 packet.icmp.icmp_id == id)
1270 {
1271 gotreply = 1;
1272 break;
1273 }
1274 }
1275
Simon Kelley824af852008-02-12 20:43:05 +00001276#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001277 close(fd);
1278#else
Simon Kelley3be34542004-09-11 19:12:13 +01001279 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001280 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1281#endif
1282
Simon Kelley3be34542004-09-11 19:12:13 +01001283 return gotreply;
1284}
Simon Kelley7622fc02009-06-04 20:32:05 +01001285#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001286
1287