blob: e50ed1c36bbeb76a9d66352c6f31d85b6c8d0f91 [file] [log] [blame]
Simon Kelleycdeda282006-03-16 20:16:06 +00001/* dnsmasq is Copyright (c) 2000-2006 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
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
Simon Kelley9e4abcb2004-01-22 19:47:41 +000013#include "dnsmasq.h"
14
Simon Kelley5aabfc72007-08-29 11:24:47 +010015struct daemon *daemon;
16
Simon Kelley3d8df262005-08-29 12:19:27 +010017static char *compile_opts =
18#ifndef HAVE_IPV6
19"no-"
20#endif
21"IPv6 "
22#ifndef HAVE_GETOPT_LONG
23"no-"
24#endif
25"GNU-getopt "
26#ifdef HAVE_BROKEN_RTC
27"no-RTC "
28#endif
Simon Kelley16972692006-10-16 20:04:18 +010029#ifdef NO_FORK
30"no-MMU "
31#endif
Simon Kelley3d8df262005-08-29 12:19:27 +010032#ifndef HAVE_ISC_READER
33"no-"
34#endif
35"ISC-leasefile "
36#ifndef HAVE_DBUS
37"no-"
38#endif
Simon Kelleyb8187c82005-11-26 21:46:27 +000039"DBus "
40#ifdef NO_GETTEXT
41"no-"
42#endif
Simon Kelley1b7ecd12007-02-05 14:57:57 +000043"I18N "
44#ifndef HAVE_TFTP
45"no-"
46#endif
47"TFTP";
Simon Kelley3d8df262005-08-29 12:19:27 +010048
Simon Kelley5aabfc72007-08-29 11:24:47 +010049static volatile pid_t pid = 0;
50static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000051
Simon Kelley5aabfc72007-08-29 11:24:47 +010052static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
53static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010054static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010055static void async_event(int pipe, time_t now);
56static void poll_resolv(void);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000057
58int main (int argc, char **argv)
59{
Simon Kelleyde379512004-06-22 20:23:33 +010060 int bind_fallback = 0;
Simon Kelley309331f2006-04-22 15:05:01 +010061 int bad_capabilities = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 time_t now, last = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000063 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000064 struct iname *if_tmp;
Simon Kelley5aabfc72007-08-29 11:24:47 +010065 int piperead, pipefd[2];
66 struct passwd *ent_pw;
67 long i, max_fd = sysconf(_SC_OPEN_MAX);
68
Simon Kelleyb8187c82005-11-26 21:46:27 +000069#ifndef NO_GETTEXT
70 setlocale(LC_ALL, "");
71 bindtextdomain("dnsmasq", LOCALEDIR);
72 textdomain("dnsmasq");
73#endif
74
Simon Kelley9e4abcb2004-01-22 19:47:41 +000075 sigact.sa_handler = sig_handler;
76 sigact.sa_flags = 0;
77 sigemptyset(&sigact.sa_mask);
78 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010079 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000080 sigaction(SIGHUP, &sigact, NULL);
81 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000082 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010083 sigaction(SIGCHLD, &sigact, NULL);
84
85 /* ignore SIGPIPE */
86 sigact.sa_handler = SIG_IGN;
87 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088
Simon Kelley5aabfc72007-08-29 11:24:47 +010089 umask(022); /* known umask, create leases and pid files as 0644 */
90
91 read_opts(argc, argv, compile_opts);
92
Simon Kelley3be34542004-09-11 19:12:13 +010093 if (daemon->edns_pktsz < PACKETSZ)
94 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +000095 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
96 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
97 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3be34542004-09-11 19:12:13 +010098
99 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000100 {
Simon Kelley3be34542004-09-11 19:12:13 +0100101 if (daemon->dhcp)
102 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000103 }
Simon Kelley33820b72004-04-03 21:10:00 +0100104#ifndef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100105 else if (!daemon->dhcp)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
Simon Kelley33820b72004-04-03 21:10:00 +0100107#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000108
Simon Kelley5aabfc72007-08-29 11:24:47 +0100109 /* Close any file descriptors we inherited apart from std{in|out|err} */
110 for (i = 0; i < max_fd; i++)
111 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
112 close(i);
113
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100114#ifdef HAVE_LINUX_NETWORK
Simon Kelley5aabfc72007-08-29 11:24:47 +0100115 netlink_init();
Simon Kelley309331f2006-04-22 15:05:01 +0100116#elif !(defined(IP_RECVDSTADDR) && \
117 defined(IP_RECVIF) && \
118 defined(IP_SENDSRCADDR))
119 if (!(daemon->options & OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100120 {
121 bind_fallback = 1;
Simon Kelley3be34542004-09-11 19:12:13 +0100122 daemon->options |= OPT_NOWILD;
Simon Kelleyde379512004-06-22 20:23:33 +0100123 }
Simon Kelley309331f2006-04-22 15:05:01 +0100124#endif
125
Simon Kelley832af0b2007-01-21 20:01:28 +0000126#ifndef HAVE_TFTP
127 if (daemon->options & OPT_TFTP)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100128 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000129#endif
130
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100131 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000132
Simon Kelley3be34542004-09-11 19:12:13 +0100133 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100135#if !defined(HAVE_LINUX_NETWORK) && !defined(IP_RECVIF)
Simon Kelleyde379512004-06-22 20:23:33 +0100136 int c;
137 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100138 for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100139 if (!tmp->isloop)
140 c++;
141 if (c != 1)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100142 die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +0100143#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100144 /* Note that order matters here, we must call lease_init before
145 creating any file descriptors which shouldn't be leaked
146 to the lease-script init process. */
147 lease_init(now);
148 dhcp_init();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000149 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100150
Simon Kelley5aabfc72007-08-29 11:24:47 +0100151 if (!enumerate_interfaces())
152 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
153
154 if (daemon->options & OPT_NOWILD)
155 {
156 daemon->listeners = create_bound_listeners();
157
158 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
159 if (if_tmp->name && !if_tmp->used)
160 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
161
162 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
163 if (!if_tmp->used)
164 {
165 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
166 die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
167 }
168 }
169 else if (!(daemon->listeners = create_wildcard_listeners()))
170 die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
171
172 cache_init();
173
Simon Kelley3d8df262005-08-29 12:19:27 +0100174 if (daemon->options & OPT_DBUS)
175#ifdef HAVE_DBUS
176 {
177 char *err;
178 daemon->dbus = NULL;
179 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100180 if ((err = dbus_init()))
181 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100182 }
183#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100184 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100185#endif
186
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100187 /* If query_port is set then create a socket now, before dumping root
188 for use to access nameservers without more specific source addresses.
189 This allows query_port to be a low port */
Simon Kelley3be34542004-09-11 19:12:13 +0100190 if (daemon->query_port)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100191 {
192 union mysockaddr addr;
Simon Kelley849a8352006-06-09 21:02:31 +0100193 memset(&addr, 0, sizeof(addr));
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100194 addr.in.sin_family = AF_INET;
195 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +0100196 addr.in.sin_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100197#ifdef HAVE_SOCKADDR_SA_LEN
198 addr.in.sin_len = sizeof(struct sockaddr_in);
199#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100200 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100201#ifdef HAVE_IPV6
Simon Kelley849a8352006-06-09 21:02:31 +0100202 memset(&addr, 0, sizeof(addr));
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100203 addr.in6.sin6_family = AF_INET6;
204 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3be34542004-09-11 19:12:13 +0100205 addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100206#ifdef HAVE_SOCKADDR_SA_LEN
207 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
208#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100209 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100210#endif
211 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000212
Simon Kelley5aabfc72007-08-29 11:24:47 +0100213 /* Use a pipe to carry signals and other events back to the event loop
214 in a race-free manner */
Simon Kelley7cebd202006-05-06 14:13:33 +0100215 if (pipe(pipefd) == -1 || !fix_fd(pipefd[0]) || !fix_fd(pipefd[1]))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100216 die(_("cannot create pipe: %s"), NULL, EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100217
218 piperead = pipefd[0];
219 pipewrite = pipefd[1];
220 /* prime the pipe to load stuff first time. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100221 send_event(pipewrite, EVENT_RELOAD, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100222
223 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000224 {
225 FILE *pidfile;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100226 int nullfd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100227
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000228 /* The following code "daemonizes" the process.
229 See Stevens section 12.4 */
Simon Kelley16972692006-10-16 20:04:18 +0100230
231#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100232 if (!(daemon->options & OPT_NO_FORK))
233 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100234 pid_t pid;
235
236 if ((pid = fork()) == -1 )
237 die(_("cannot fork into background: %s"), NULL, EC_MISC);
238
239 if (pid != 0)
240 _exit(EC_GOOD);
Simon Kelley3be34542004-09-11 19:12:13 +0100241
242 setsid();
Simon Kelley5aabfc72007-08-29 11:24:47 +0100243 pid = fork();
244
245 if (pid != 0 && pid != -1)
Simon Kelley7cebd202006-05-06 14:13:33 +0100246 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100247 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000248#endif
249
250 chdir("/");
Simon Kelley5aabfc72007-08-29 11:24:47 +0100251
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000252 /* write pidfile _after_ forking ! */
Simon Kelley3be34542004-09-11 19:12:13 +0100253 if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000254 {
255 fprintf(pidfile, "%d\n", (int) getpid());
256 fclose(pidfile);
257 }
258
Simon Kelley5aabfc72007-08-29 11:24:47 +0100259 /* open stdout etc to /dev/null */
260 nullfd = open("/dev/null", O_RDWR);
261 dup2(nullfd, STDOUT_FILENO);
262 dup2(nullfd, STDERR_FILENO);
263 dup2(nullfd, STDIN_FILENO);
264 close(nullfd);
Simon Kelley16972692006-10-16 20:04:18 +0100265 }
266
267 /* if we are to run scripts, we need to fork a helper before dropping root. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100268#ifndef NO_FORK
269 daemon->helperfd = create_helper(pipewrite, max_fd);
270#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +0100271
Simon Kelley5aabfc72007-08-29 11:24:47 +0100272 ent_pw = daemon->username ? getpwnam(daemon->username) : NULL;
273
274 /* before here, we should only call die(), after here, only call syslog() */
275 log_start(ent_pw);
276
Simon Kelley16972692006-10-16 20:04:18 +0100277 if (!(daemon->options & OPT_DEBUG))
278 {
279 /* UID changing, etc */
Simon Kelley7cebd202006-05-06 14:13:33 +0100280 if (daemon->groupname || ent_pw)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000281 {
282 gid_t dummy;
283 struct group *gp;
Simon Kelley7cebd202006-05-06 14:13:33 +0100284
285 /* change group for /etc/ppp/resolv.conf otherwise get the group for "nobody" */
Simon Kelley3be34542004-09-11 19:12:13 +0100286 if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
Simon Kelley7cebd202006-05-06 14:13:33 +0100287 (ent_pw && (gp = getgrgid(ent_pw->pw_gid))))
288 {
289 /* remove all supplimentary groups */
290 setgroups(0, &dummy);
291 setgid(gp->gr_gid);
292 }
293 }
Simon Kelley16972692006-10-16 20:04:18 +0100294
Simon Kelley7cebd202006-05-06 14:13:33 +0100295 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100296 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100297#ifdef HAVE_LINUX_NETWORK
Simon Kelley16972692006-10-16 20:04:18 +0100298 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
299 CAP_NET_RAW (for icmp) if we're doing dhcp */
300 cap_user_header_t hdr = safe_malloc(sizeof(*hdr));
301 cap_user_data_t data = safe_malloc(sizeof(*data));
302 hdr->version = _LINUX_CAPABILITY_VERSION;
303 hdr->pid = 0; /* this process */
304 data->effective = data->permitted = data->inheritable =
305 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
306 (1 << CAP_SETGID) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100307
Simon Kelley16972692006-10-16 20:04:18 +0100308 /* Tell kernel to not clear capabilities when dropping root */
309 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
310 bad_capabilities = errno;
311 else
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100312#endif
Simon Kelley16972692006-10-16 20:04:18 +0100313 {
314 /* finally drop root */
315 setuid(ent_pw->pw_uid);
316
317#ifdef HAVE_LINUX_NETWORK
318 data->effective = data->permitted =
319 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
320 data->inheritable = 0;
321
322 /* lose the setuid and setgid capbilities */
323 capset(hdr, data);
324#endif
325 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326 }
Simon Kelley849a8352006-06-09 21:02:31 +0100327 }
Simon Kelley16972692006-10-16 20:04:18 +0100328
Simon Kelley16972692006-10-16 20:04:18 +0100329#ifdef HAVE_LINUX_NETWORK
330 if (daemon->options & OPT_DEBUG)
331 prctl(PR_SET_DUMPABLE, 1);
332#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100333
Simon Kelley3be34542004-09-11 19:12:13 +0100334 if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100335 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000336 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100337 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100338
Simon Kelleyf2621c72007-04-29 19:47:21 +0100339 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100340
Simon Kelley3d8df262005-08-29 12:19:27 +0100341#ifdef HAVE_DBUS
342 if (daemon->options & OPT_DBUS)
343 {
344 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100345 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100346 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100347 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100348 }
349#endif
350
Simon Kelleyde379512004-06-22 20:23:33 +0100351 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100352 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100353
Simon Kelley26128d22004-11-14 16:43:54 +0000354 if (!(daemon->options & OPT_NOWILD))
355 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
356 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100357 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100358
Simon Kelley208b65c2006-08-05 21:41:37 +0100359 if (daemon->options & OPT_NO_RESOLV)
360 {
361 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100362 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100363 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000364 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100365 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100366 }
367
Simon Kelleyf2621c72007-04-29 19:47:21 +0100368 if (daemon->max_logs != 0)
369 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
370
Simon Kelley3be34542004-09-11 19:12:13 +0100371 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000372 {
Simon Kelley3be34542004-09-11 19:12:13 +0100373 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000374
Simon Kelley3be34542004-09-11 19:12:13 +0100375 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100376 {
Simon Kelley0a852542005-03-23 20:28:59 +0000377 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100378 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100379 my_syslog(LOG_INFO,
380 (dhcp_tmp->flags & CONTEXT_STATIC) ?
381 _("DHCP, static leases only on %.0s%s, lease time %s") :
382 _("DHCP, IP range %s -- %s, lease time %s"),
383 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100384 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000385 }
386
Simon Kelley832af0b2007-01-21 20:01:28 +0000387#ifdef HAVE_TFTP
388 if (daemon->options & OPT_TFTP)
389 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000390#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100391 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000392 max_fd = FD_SETSIZE;
393#endif
394
Simon Kelleyf2621c72007-04-29 19:47:21 +0100395 my_syslog(LOG_INFO, "TFTP %s%s %s",
396 daemon->tftp_prefix ? _("root is ") : _("enabled"),
397 daemon->tftp_prefix ? daemon->tftp_prefix: "",
398 daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
399
Simon Kelley832af0b2007-01-21 20:01:28 +0000400 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100401 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000402 a single file will be sent to may clients (the file only needs
403 one fd). */
404
405 max_fd -= 30; /* use other than TFTP */
406
407 if (max_fd < 0)
408 max_fd = 5;
409 else if (max_fd < 100)
410 max_fd = max_fd/2;
411 else
412 max_fd = max_fd - 20;
413
414 if (daemon->tftp_max > max_fd)
415 {
416 daemon->tftp_max = max_fd;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100417 my_syslog(LOG_WARNING,
418 _("restricting maximum simultaneous TFTP transfers to %d"),
419 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000420 }
421 }
422#endif
423
Simon Kelley3be34542004-09-11 19:12:13 +0100424 if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
Simon Kelley309331f2006-04-22 15:05:01 +0100425 {
426 if (bad_capabilities)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100427 my_syslog(LOG_WARNING, _("warning: setting capabilities failed: %s"), strerror(bad_capabilities));
428
429 my_syslog(LOG_WARNING, _("running as root"));
Simon Kelley309331f2006-04-22 15:05:01 +0100430 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000431
Simon Kelley5aabfc72007-08-29 11:24:47 +0100432 check_servers();
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100433
Simon Kelley7cebd202006-05-06 14:13:33 +0100434 pid = getpid();
435
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100436 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000437 {
Simon Kelley16972692006-10-16 20:04:18 +0100438 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100439 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100440 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441
442 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100443 FD_ZERO(&wset);
444 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445
Simon Kelley16972692006-10-16 20:04:18 +0100446 /* if we are out of resources, find how long we have to wait
447 for some to come free, we'll loop around then and restart
448 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100449 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100450 {
451 t.tv_usec = 0;
452 tp = &t;
453 }
454
Simon Kelley832af0b2007-01-21 20:01:28 +0000455 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
456 if (daemon->tftp_trans ||
457 ((daemon->options & OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000458 {
Simon Kelley16972692006-10-16 20:04:18 +0100459 t.tv_sec = 0;
460 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100461 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000462 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100463
Simon Kelley832af0b2007-01-21 20:01:28 +0000464#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100465 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100466#endif
467
468 if (daemon->dhcp)
469 {
470 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100471 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100472 }
473
474#ifdef HAVE_LINUX_NETWORK
475 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100476 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100477#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100478
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100479 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100480 bump_maxfd(piperead, &maxfd);
481
Simon Kelley5aabfc72007-08-29 11:24:47 +0100482#ifndef NO_FORK
483 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100484
485 if (!helper_buf_empty())
486 {
487 FD_SET(daemon->helperfd, &wset);
488 bump_maxfd(daemon->helperfd, &maxfd);
489 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100490#else
491 /* need this for other side-effects */
492 while (do_script_run(now));
493#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +0100494
495 /* must do this just before select(), when we know no
496 more calls to my_syslog() can occur */
497 set_log_writer(&wset, &maxfd);
498
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100499 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
500 {
501 /* otherwise undefined after error */
502 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
503 }
504
505 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000506
Simon Kelleyf2621c72007-04-29 19:47:21 +0100507 check_log_writer(&wset);
508
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000509 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100510 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley849a8352006-06-09 21:02:31 +0100511 if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000512 {
513 last = now;
Simon Kelley33820b72004-04-03 21:10:00 +0100514
515#ifdef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100516 if (daemon->lease_file && !daemon->dhcp)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100517 load_dhcp(now);
Simon Kelley33820b72004-04-03 21:10:00 +0100518#endif
519
Simon Kelley3be34542004-09-11 19:12:13 +0100520 if (!(daemon->options & OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100521 poll_resolv();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000522 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100523
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100524 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100525 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100526
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100527#ifdef HAVE_LINUX_NETWORK
528 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100529 netlink_multicast();
Simon Kelleycdeda282006-03-16 20:16:06 +0000530#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100531
532#ifdef HAVE_DBUS
533 /* if we didn't create a DBus connection, retry now. */
Simon Kelley7cebd202006-05-06 14:13:33 +0100534 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100535 {
536 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100537 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100538 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100539 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100540 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100541 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100542 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100543#endif
544
Simon Kelley5aabfc72007-08-29 11:24:47 +0100545 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000546
547#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100548 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000549#endif
550
Simon Kelley3be34542004-09-11 19:12:13 +0100551 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100552 dhcp_packet(now);
Simon Kelley16972692006-10-16 20:04:18 +0100553
Simon Kelley5aabfc72007-08-29 11:24:47 +0100554#ifndef NO_FORK
Simon Kelley16972692006-10-16 20:04:18 +0100555 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100556 helper_write();
557#endif
558
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000559 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000560}
561
Simon Kelley3be34542004-09-11 19:12:13 +0100562static void sig_handler(int sig)
563{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100564 if (pid == 0)
565 {
Simon Kelley16972692006-10-16 20:04:18 +0100566 /* ignore anything other than TERM during startup
567 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100568 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100569 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100570 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100571 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100572 {
Simon Kelley16972692006-10-16 20:04:18 +0100573 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100574 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100575 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100576 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100577 else
578 {
579 /* master process */
580 int event, errsave = errno;
581
582 if (sig == SIGHUP)
583 event = EVENT_RELOAD;
584 else if (sig == SIGCHLD)
585 event = EVENT_CHILD;
586 else if (sig == SIGALRM)
587 event = EVENT_ALARM;
588 else if (sig == SIGTERM)
589 event = EVENT_TERM;
590 else if (sig == SIGUSR1)
591 event = EVENT_DUMP;
592 else if (sig == SIGUSR2)
593 event = EVENT_REOPEN;
594 else
595 return;
596
597 send_event(pipewrite, event, 0);
598 errno = errsave;
599 }
Simon Kelley3be34542004-09-11 19:12:13 +0100600}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601
Simon Kelley5aabfc72007-08-29 11:24:47 +0100602void send_event(int fd, int event, int data)
603{
604 struct event_desc ev;
605
606 ev.event = event;
607 ev.data = data;
608 /* pipe is non-blocking and struct event_desc is smaller than
609 PIPE_BUF, so this either fails or writes everything */
610 while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
611}
Simon Kelley3d8df262005-08-29 12:19:27 +0100612
Simon Kelley5aabfc72007-08-29 11:24:47 +0100613static void async_event(int pipe, time_t now)
614{
615 pid_t p;
616 struct event_desc ev;
617 int i;
618
619 if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
620 switch (ev.event)
621 {
622 case EVENT_RELOAD:
623 clear_cache_and_reload(now);
624 if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
625 {
626 reload_servers(daemon->resolv_files->name);
627 check_servers();
628 }
629 rerun_scripts();
630 break;
631
632 case EVENT_DUMP:
633 dump_cache(now);
634 break;
635
636 case EVENT_ALARM:
637 if (daemon->dhcp)
638 {
639 lease_prune(NULL, now);
640 lease_update_file(now);
641 }
642 break;
643
644 case EVENT_CHILD:
645 /* See Stevens 5.10 */
646 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
647 if (p == -1)
648 {
649 if (errno != EINTR)
650 break;
651 }
652 else
653 for (i = 0 ; i < MAX_PROCS; i++)
654 if (daemon->tcp_pids[i] == p)
655 daemon->tcp_pids[i] = 0;
656 break;
657
658 case EVENT_KILLED:
659 my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
660 break;
661
662 case EVENT_EXITED:
663 my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
664 break;
665
666 case EVENT_EXEC_ERR:
667 my_syslog(LOG_ERR, _("failed to execute %s: %s"), daemon->lease_change_command, strerror(ev.data));
668 break;
669
670 case EVENT_PIPE_ERR:
671 my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
672 break;
673
674 case EVENT_REOPEN:
675 /* Note: this may leave TCP-handling processes with the old file still open.
676 Since any such process will die in CHILD_LIFETIME or probably much sooner,
677 we leave them logging to the old file. */
678 if (daemon->log_file != NULL)
679 log_reopen(daemon->log_file);
680 break;
681
682 case EVENT_TERM:
683 /* Knock all our children on the head. */
684 for (i = 0; i < MAX_PROCS; i++)
685 if (daemon->tcp_pids[i] != 0)
686 kill(daemon->tcp_pids[i], SIGALRM);
687
688#ifndef NO_FORK
689 /* handle pending lease transitions */
690 if (daemon->helperfd != -1)
691 {
692 /* block in writes until all done */
693 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
694 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
695 do {
696 helper_write();
697 } while (!helper_buf_empty() || do_script_run(now));
698 close(daemon->helperfd);
699 }
700#endif
701
702 if (daemon->lease_stream)
703 fclose(daemon->lease_stream);
704
705 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
706 flush_log();
707 exit(EC_GOOD);
708 }
709}
710
711static void poll_resolv()
712{
713 struct resolvc *res, *latest;
714 struct stat statbuf;
715 time_t last_change = 0;
716 /* There may be more than one possible file.
717 Go through and find the one which changed _last_.
718 Warn of any which can't be read. */
719 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
720 if (stat(res->name, &statbuf) == -1)
721 {
722 if (!res->logged)
723 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
724 res->logged = 1;
725 }
726 else
727 {
728 res->logged = 0;
729 if (statbuf.st_mtime != res->mtime)
730 {
731 res->mtime = statbuf.st_mtime;
732 if (difftime(statbuf.st_mtime, last_change) > 0.0)
733 {
734 last_change = statbuf.st_mtime;
735 latest = res;
736 }
737 }
738 }
739
740 if (latest)
741 {
742 static int warned = 0;
743 if (reload_servers(latest->name))
744 {
745 my_syslog(LOG_INFO, _("reading %s"), latest->name);
746 warned = 0;
747 check_servers();
748 if (daemon->options & OPT_RELOAD)
749 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
750 }
751 else
752 {
753 latest->mtime = 0;
754 if (!warned)
755 {
756 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
757 warned = 1;
758 }
759 }
760 }
761}
762
763void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +0100764{
765 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
766 if (daemon->dhcp)
767 {
768 if (daemon->options & OPT_ETHERS)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100769 dhcp_read_ethers();
770 if (daemon->dhcp_hosts_file)
771 dhcp_read_hosts();
Simon Kelley3d8df262005-08-29 12:19:27 +0100772 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100773 lease_update_from_configs();
774 lease_update_file(now);
775 lease_update_dns();
Simon Kelley3d8df262005-08-29 12:19:27 +0100776 }
777}
778
Simon Kelley5aabfc72007-08-29 11:24:47 +0100779static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +0100780{
781 struct serverfd *serverfdp;
782 struct listener *listener;
Simon Kelley16972692006-10-16 20:04:18 +0100783 int wait, i;
Simon Kelley832af0b2007-01-21 20:01:28 +0000784
785#ifdef HAVE_TFTP
786 int tftp = 0;
787 struct tftp_transfer *transfer;
788 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
789 {
790 tftp++;
791 FD_SET(transfer->sockfd, set);
792 bump_maxfd(transfer->sockfd, maxfdp);
793 }
794#endif
795
Simon Kelley16972692006-10-16 20:04:18 +0100796 /* will we be able to get memory? */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100797 get_new_frec(now, &wait);
Simon Kelley16972692006-10-16 20:04:18 +0100798
Simon Kelley3be34542004-09-11 19:12:13 +0100799 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
800 {
801 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +0100802 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +0100803 }
804
805 for (listener = daemon->listeners; listener; listener = listener->next)
806 {
Simon Kelley16972692006-10-16 20:04:18 +0100807 /* only listen for queries if we have resources */
808 if (wait == 0)
809 {
810 FD_SET(listener->fd, set);
811 bump_maxfd(listener->fd, maxfdp);
812 }
813
814 /* death of a child goes through the select loop, so
815 we don't need to explicitly arrange to wake up here */
816 for (i = 0; i < MAX_PROCS; i++)
817 if (daemon->tcp_pids[i] == 0)
818 {
819 FD_SET(listener->tcpfd, set);
820 bump_maxfd(listener->tcpfd, maxfdp);
821 break;
822 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823
Simon Kelley832af0b2007-01-21 20:01:28 +0000824#ifdef HAVE_TFTP
825 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
826 {
827 FD_SET(listener->tftpfd, set);
828 bump_maxfd(listener->tftpfd, maxfdp);
829 }
830#endif
831
832 }
833
Simon Kelley16972692006-10-16 20:04:18 +0100834 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +0100835}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000836
Simon Kelley5aabfc72007-08-29 11:24:47 +0100837static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +0100838{
839 struct serverfd *serverfdp;
840 struct listener *listener;
Simon Kelley832af0b2007-01-21 20:01:28 +0000841
842 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
843 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100844 reply_query(serverfdp, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000845
846 for (listener = daemon->listeners; listener; listener = listener->next)
847 {
848 if (FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100849 receive_query(listener, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000850
851#ifdef HAVE_TFTP
852 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +0000854#endif
Simon Kelley832af0b2007-01-21 20:01:28 +0000855
856 if (FD_ISSET(listener->tcpfd, set))
857 {
858 int confd;
859 struct irec *iface = NULL;
860 pid_t p;
861
862 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
863
864 if (confd == -1)
865 continue;
866
867 if (daemon->options & OPT_NOWILD)
868 iface = listener->iface;
869 else
870 {
871 union mysockaddr tcp_addr;
872 socklen_t tcp_len = sizeof(union mysockaddr);
873 /* Check for allowed interfaces when binding the wildcard address:
874 we do this by looking for an interface with the same address as
875 the local address of the TCP connection, then looking to see if that's
876 an allowed interface. As a side effect, we get the netmask of the
877 interface too, for localisation. */
878
879 /* interface may be new since startup */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100880 if (enumerate_interfaces() &&
Simon Kelley832af0b2007-01-21 20:01:28 +0000881 getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
882 for (iface = daemon->interfaces; iface; iface = iface->next)
883 if (sockaddr_isequal(&iface->addr, &tcp_addr))
884 break;
885 }
886
887 if (!iface)
888 {
889 shutdown(confd, SHUT_RDWR);
890 close(confd);
891 }
892#ifndef NO_FORK
893 else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
894 {
895 if (p != -1)
896 {
897 int i;
898 for (i = 0; i < MAX_PROCS; i++)
899 if (daemon->tcp_pids[i] == 0)
900 {
901 daemon->tcp_pids[i] = p;
902 break;
903 }
904 }
905 close(confd);
906 }
907#endif
908 else
909 {
910 unsigned char *buff;
911 struct server *s;
912 int flags;
913 struct in_addr dst_addr_4;
914
915 dst_addr_4.s_addr = 0;
916
Simon Kelley7cebd202006-05-06 14:13:33 +0100917 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
918 terminate the process. */
Simon Kelley832af0b2007-01-21 20:01:28 +0000919 if (!(daemon->options & OPT_DEBUG))
920 alarm(CHILD_LIFETIME);
921
922 /* start with no upstream connections. */
923 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +0100924 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000925
926 /* The connected socket inherits non-blocking
927 attribute from the listening socket.
928 Reset that here. */
929 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
930 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
931
932 if (listener->family == AF_INET)
933 dst_addr_4 = iface->addr.in.sin_addr;
934
Simon Kelley5aabfc72007-08-29 11:24:47 +0100935 buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
Simon Kelley7cebd202006-05-06 14:13:33 +0100936
Simon Kelley832af0b2007-01-21 20:01:28 +0000937 shutdown(confd, SHUT_RDWR);
938 close(confd);
939
940 if (buff)
941 free(buff);
942
943 for (s = daemon->servers; s; s = s->next)
944 if (s->tcpfd != -1)
945 {
946 shutdown(s->tcpfd, SHUT_RDWR);
947 close(s->tcpfd);
948 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100949#ifndef NO_FORK
Simon Kelley832af0b2007-01-21 20:01:28 +0000950 if (!(daemon->options & OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100951 {
952 flush_log();
953 _exit(0);
954 }
Simon Kelley7cebd202006-05-06 14:13:33 +0100955#endif
Simon Kelley832af0b2007-01-21 20:01:28 +0000956 }
957 }
958 }
Simon Kelley3be34542004-09-11 19:12:13 +0100959}
960
Simon Kelley7cebd202006-05-06 14:13:33 +0100961
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100962int make_icmp_sock(void)
963{
Simon Kelley7cebd202006-05-06 14:13:33 +0100964 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100965 int zeroopt = 0;
966
967 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
968 {
Simon Kelley7cebd202006-05-06 14:13:33 +0100969 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100970 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
971 {
972 close(fd);
973 fd = -1;
974 }
975 }
976
977 return fd;
978}
979
Simon Kelley5aabfc72007-08-29 11:24:47 +0100980int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +0100981{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100982 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +0100983
984 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +0000985 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +0100986 better not use any resources our caller has in use...)
987 but we remain deaf to signals or further DHCP packets. */
988
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100989 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +0100990 struct sockaddr_in saddr;
991 struct {
992 struct ip ip;
993 struct icmp icmp;
994 } packet;
995 unsigned short id = rand16();
996 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100997 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100998 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100999
1000#ifdef HAVE_LINUX_NETWORK
1001 if ((fd = make_icmp_sock()) == -1)
1002 return 0;
1003#else
1004 int opt = 2000;
1005 fd = daemon->dhcp_icmp_fd;
1006 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1007#endif
1008
Simon Kelley3be34542004-09-11 19:12:13 +01001009 saddr.sin_family = AF_INET;
1010 saddr.sin_port = 0;
1011 saddr.sin_addr = addr;
1012#ifdef HAVE_SOCKADDR_SA_LEN
1013 saddr.sin_len = sizeof(struct sockaddr_in);
1014#endif
1015
1016 memset(&packet.icmp, 0, sizeof(packet.icmp));
1017 packet.icmp.icmp_type = ICMP_ECHO;
1018 packet.icmp.icmp_id = id;
1019 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1020 j += ((u16 *)&packet.icmp)[i];
1021 while (j>>16)
1022 j = (j & 0xffff) + (j >> 16);
1023 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1024
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001025 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001026 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1027 retry_send());
1028
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001029 for (now = start = dnsmasq_time();
1030 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001031 {
1032 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001033 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001034 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001035 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001036 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001037
1038 tv.tv_usec = 250000;
1039 tv.tv_sec = 0;
1040
1041 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001042 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001043 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001044 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001045 set_log_writer(&wset, &maxfd);
1046
1047 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1048 {
1049 FD_ZERO(&rset);
1050 FD_ZERO(&wset);
1051 }
1052
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001053 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001054
1055 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001056 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001057
1058#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001059 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001060#endif
1061
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001062 if (FD_ISSET(fd, &rset) &&
1063 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001064 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1065 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1066 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1067 packet.icmp.icmp_seq == 0 &&
1068 packet.icmp.icmp_id == id)
1069 {
1070 gotreply = 1;
1071 break;
1072 }
1073 }
1074
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001075#ifdef HAVE_LINUX_NETWORK
1076 close(fd);
1077#else
Simon Kelley3be34542004-09-11 19:12:13 +01001078 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001079 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1080#endif
1081
Simon Kelley3be34542004-09-11 19:12:13 +01001082 return gotreply;
1083}
Simon Kelley0a852542005-03-23 20:28:59 +00001084
1085