blob: 93780810011647f560480e2458c62d06b82c7930 [file] [log] [blame]
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001/* dnsmasq is Copyright (c) 2000-2005 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/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
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
29#ifndef HAVE_ISC_READER
30"no-"
31#endif
32"ISC-leasefile "
33#ifndef HAVE_DBUS
34"no-"
35#endif
Simon Kelleyb8187c82005-11-26 21:46:27 +000036"DBus "
37#ifdef NO_GETTEXT
38"no-"
39#endif
40"i18n";
Simon Kelley3d8df262005-08-29 12:19:27 +010041
Simon Kelley0a852542005-03-23 20:28:59 +000042static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000043
Simon Kelley3be34542004-09-11 19:12:13 +010044static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
45static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now);
46static void sig_handler(int sig);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000047
48int main (int argc, char **argv)
49{
Simon Kelley3be34542004-09-11 19:12:13 +010050 struct daemon *daemon;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000051 int first_loop = 1;
Simon Kelleyde379512004-06-22 20:23:33 +010052 int bind_fallback = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000053 time_t now, last = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000054 struct sigaction sigact;
55 sigset_t sigmask;
Simon Kelley26128d22004-11-14 16:43:54 +000056 struct iname *if_tmp;
Simon Kelley33820b72004-04-03 21:10:00 +010057
Simon Kelleyb8187c82005-11-26 21:46:27 +000058#ifndef NO_GETTEXT
59 setlocale(LC_ALL, "");
60 bindtextdomain("dnsmasq", LOCALEDIR);
61 textdomain("dnsmasq");
62#endif
63
Simon Kelley9e4abcb2004-01-22 19:47:41 +000064 sighup = 1; /* init cache the first time through */
65 sigusr1 = 0; /* but don't dump */
Simon Kelley9e4abcb2004-01-22 19:47:41 +000066 sigterm = 0; /* or die */
Simon Kelley44a2a312004-03-10 20:04:35 +000067#ifdef HAVE_BROKEN_RTC
68 sigalarm = 1; /* need regular lease dumps */
69#else
70 sigalarm = 0; /* or not */
71#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +010072 num_kids = 0;
73 in_child = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074
75 sigact.sa_handler = sig_handler;
76 sigact.sa_flags = 0;
77 sigemptyset(&sigact.sa_mask);
78 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000079 sigaction(SIGHUP, &sigact, NULL);
80 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000081 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010082 sigaction(SIGCHLD, &sigact, NULL);
83
84 /* ignore SIGPIPE */
85 sigact.sa_handler = SIG_IGN;
86 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000087
88 /* now block all the signals, they stay that way except
89 during the call to pselect */
90 sigaddset(&sigact.sa_mask, SIGUSR1);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000091 sigaddset(&sigact.sa_mask, SIGTERM);
92 sigaddset(&sigact.sa_mask, SIGHUP);
Simon Kelley44a2a312004-03-10 20:04:35 +000093 sigaddset(&sigact.sa_mask, SIGALRM);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010094 sigaddset(&sigact.sa_mask, SIGCHLD);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000095 sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
96
Simon Kelley3d8df262005-08-29 12:19:27 +010097 daemon = read_opts(argc, argv, compile_opts);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000098
Simon Kelley3be34542004-09-11 19:12:13 +010099 if (daemon->edns_pktsz < PACKETSZ)
100 daemon->edns_pktsz = PACKETSZ;
Simon Kelley0a852542005-03-23 20:28:59 +0000101 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
102 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
103 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3be34542004-09-11 19:12:13 +0100104
105 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000106 {
Simon Kelley3be34542004-09-11 19:12:13 +0100107 if (daemon->dhcp)
108 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 }
Simon Kelley33820b72004-04-03 21:10:00 +0100110#ifndef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100111 else if (!daemon->dhcp)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000112 die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL);
Simon Kelley33820b72004-04-03 21:10:00 +0100113#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114
Simon Kelley3d8df262005-08-29 12:19:27 +0100115 if (!enumerate_interfaces(daemon, &daemon->interfaces, NULL, NULL))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000116 die(_("failed to find list of interfaces: %s"), NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000117
Simon Kelley3be34542004-09-11 19:12:13 +0100118 if (!(daemon->options & OPT_NOWILD) &&
119 !(daemon->listeners = create_wildcard_listeners(daemon->port)))
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 Kelley9e4abcb2004-01-22 19:47:41 +0000124
Simon Kelley3be34542004-09-11 19:12:13 +0100125 if (daemon->options & OPT_NOWILD)
Simon Kelleyde379512004-06-22 20:23:33 +0100126 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100127 daemon->listeners = create_bound_listeners(daemon->interfaces, daemon->port);
Simon Kelleyde379512004-06-22 20:23:33 +0100128
Simon Kelley3be34542004-09-11 19:12:13 +0100129 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100130 if (if_tmp->name && !if_tmp->used)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000131 die(_("unknown interface %s"), if_tmp->name);
Simon Kelleyde379512004-06-22 20:23:33 +0100132
Simon Kelley3be34542004-09-11 19:12:13 +0100133 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100134 if (!if_tmp->used)
135 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100136 prettyprint_addr(&if_tmp->addr, daemon->namebuff);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000137 die(_("no interface with address %s"), daemon->namebuff);
Simon Kelleyde379512004-06-22 20:23:33 +0100138 }
139 }
140
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000141 forward_init(1);
Simon Kelley3be34542004-09-11 19:12:13 +0100142 cache_init(daemon->cachesize, daemon->options & OPT_LOG);
Simon Kelley44a2a312004-03-10 20:04:35 +0000143
144#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100145 if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000146 die(_("cannot open %s:%s"), UPTIME);
Simon Kelley44a2a312004-03-10 20:04:35 +0000147#endif
148
Simon Kelley3be34542004-09-11 19:12:13 +0100149 now = dnsmasq_time(daemon->uptime_fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000150
Simon Kelley3be34542004-09-11 19:12:13 +0100151 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000152 {
Simon Kelleyde379512004-06-22 20:23:33 +0100153#if !defined(IP_PKTINFO) && !defined(IP_RECVIF)
154 int c;
155 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100156 for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100157 if (!tmp->isloop)
158 c++;
159 if (c != 1)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000160 die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL);
Simon Kelleyde379512004-06-22 20:23:33 +0100161#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100162 dhcp_init(daemon);
163 lease_init(daemon, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000164 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100165
Simon Kelley3d8df262005-08-29 12:19:27 +0100166 if (daemon->options & OPT_DBUS)
167#ifdef HAVE_DBUS
168 {
169 char *err;
170 daemon->dbus = NULL;
171 daemon->watches = NULL;
172 if ((err = dbus_init(daemon)))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000173 die(_("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100174 }
175#else
176 if (daemon->options & OPT_DBUS)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000177 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL);
Simon Kelley3d8df262005-08-29 12:19:27 +0100178#endif
179
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100180 /* If query_port is set then create a socket now, before dumping root
181 for use to access nameservers without more specific source addresses.
182 This allows query_port to be a low port */
Simon Kelley3be34542004-09-11 19:12:13 +0100183 if (daemon->query_port)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100184 {
185 union mysockaddr addr;
186 addr.in.sin_family = AF_INET;
187 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +0100188 addr.in.sin_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100189#ifdef HAVE_SOCKADDR_SA_LEN
190 addr.in.sin_len = sizeof(struct sockaddr_in);
191#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100192 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100193#ifdef HAVE_IPV6
194 addr.in6.sin6_family = AF_INET6;
195 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3be34542004-09-11 19:12:13 +0100196 addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100197 addr.in6.sin6_flowinfo = htonl(0);
198#ifdef HAVE_SOCKADDR_SA_LEN
199 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
200#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100201 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100202#endif
203 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000204
205 setbuf(stdout, NULL);
206
Simon Kelley3be34542004-09-11 19:12:13 +0100207 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000208 {
209 FILE *pidfile;
210 struct passwd *ent_pw;
Simon Kelley3d8df262005-08-29 12:19:27 +0100211 fd_set test_set;
212 int maxfd, i;
213
214 FD_ZERO(&test_set);
215 maxfd = set_dns_listeners(daemon, &test_set, -1);
216#ifdef HAVE_DBUS
217 maxfd = set_dbus_listeners(daemon, maxfd, &test_set, &test_set, &test_set);
218#endif
219
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000220 /* The following code "daemonizes" the process.
221 See Stevens section 12.4 */
Simon Kelley3d8df262005-08-29 12:19:27 +0100222
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000223#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100224 if (!(daemon->options & OPT_NO_FORK))
225 {
226 if (fork() != 0 )
227 exit(0);
228
229 setsid();
230
231 if (fork() != 0)
232 exit(0);
233 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000234#endif
235
236 chdir("/");
237 umask(022); /* make pidfile 0644 */
238
239 /* write pidfile _after_ forking ! */
Simon Kelley3be34542004-09-11 19:12:13 +0100240 if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000241 {
242 fprintf(pidfile, "%d\n", (int) getpid());
243 fclose(pidfile);
244 }
245
246 umask(0);
247
248 for (i=0; i<64; i++)
249 {
Simon Kelley3be34542004-09-11 19:12:13 +0100250#ifdef HAVE_BROKEN_RTC
251 if (i == daemon->uptime_fd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000252 continue;
Simon Kelley3be34542004-09-11 19:12:13 +0100253#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100254
Simon Kelley3be34542004-09-11 19:12:13 +0100255 if (daemon->dhcp &&
256 (i == daemon->lease_fd ||
257 i == daemon->dhcpfd ||
258 i == daemon->dhcp_raw_fd ||
259 i == daemon->dhcp_icmp_fd))
260 continue;
Simon Kelley3d8df262005-08-29 12:19:27 +0100261
262 if (i <= maxfd && FD_ISSET(i, &test_set))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100263 continue;
264
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000265 close(i);
266 }
267
268 /* Change uid and gid for security */
Simon Kelley3be34542004-09-11 19:12:13 +0100269 if (daemon->username && (ent_pw = getpwnam(daemon->username)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000270 {
271 gid_t dummy;
272 struct group *gp;
273 /* remove all supplimentary groups */
274 setgroups(0, &dummy);
275 /* change group for /etc/ppp/resolv.conf
276 otherwise get the group for "nobody" */
Simon Kelley3be34542004-09-11 19:12:13 +0100277 if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000278 (gp = getgrgid(ent_pw->pw_gid)))
279 setgid(gp->gr_gid);
280 /* finally drop root */
281 setuid(ent_pw->pw_uid);
282 }
283 }
284
285 openlog("dnsmasq",
Simon Kelley3be34542004-09-11 19:12:13 +0100286 DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG),
287 DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000288
Simon Kelley3be34542004-09-11 19:12:13 +0100289 if (daemon->cachesize != 0)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000290 syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000291 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000292 syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley3d8df262005-08-29 12:19:27 +0100293
Simon Kelleyb8187c82005-11-26 21:46:27 +0000294 syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley3d8df262005-08-29 12:19:27 +0100295
296#ifdef HAVE_DBUS
297 if (daemon->options & OPT_DBUS)
298 {
299 if (daemon->dbus)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000300 syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100301 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000302 syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100303 }
304#endif
305
Simon Kelleyde379512004-06-22 20:23:33 +0100306 if (bind_fallback)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000307 syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleyde379512004-06-22 20:23:33 +0100308
Simon Kelley26128d22004-11-14 16:43:54 +0000309 if (!(daemon->options & OPT_NOWILD))
310 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
311 if (if_tmp->name && !if_tmp->used)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000312 syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley26128d22004-11-14 16:43:54 +0000313
Simon Kelley3be34542004-09-11 19:12:13 +0100314 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315 {
Simon Kelley3be34542004-09-11 19:12:13 +0100316 struct dhcp_context *dhcp_tmp;
Simon Kelley0a852542005-03-23 20:28:59 +0000317
318#ifdef HAVE_RTNETLINK
319 /* Must do this after daemonizing so that the pid is right */
320 daemon->netlinkfd = netlink_init();
321#endif
322
Simon Kelley3be34542004-09-11 19:12:13 +0100323 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100324 {
Simon Kelley0a852542005-03-23 20:28:59 +0000325 prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
Simon Kelley3be34542004-09-11 19:12:13 +0100326 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
Simon Kelley3be34542004-09-11 19:12:13 +0100327 syslog(LOG_INFO,
Simon Kelley0a852542005-03-23 20:28:59 +0000328 (dhcp_tmp->flags & CONTEXT_STATIC) ?
Simon Kelleyb8187c82005-11-26 21:46:27 +0000329 _("DHCP, static leases only on %.0s%s, lease time %s") :
330 _("DHCP, IP range %s -- %s, lease time %s"),
Simon Kelley0a852542005-03-23 20:28:59 +0000331 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100332 }
Simon Kelley26128d22004-11-14 16:43:54 +0000333
334#ifdef HAVE_BROKEN_RTC
Simon Kelley0a852542005-03-23 20:28:59 +0000335 daemon->min_leasetime = daemon->min_leasetime/3;
336 if (daemon->min_leasetime > (60 * 60 * 24))
337 daemon->min_leasetime = 60 * 60 * 24;
338 if (daemon->min_leasetime < 60)
339 daemon->min_leasetime = 60;
340 prettyprint_time(daemon->dhcp_buff2, daemon->min_leasetime);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000341 syslog(LOG_INFO, _("DHCP, %s will be written every %s"), daemon->lease_file, daemon->dhcp_buff2);
Simon Kelley26128d22004-11-14 16:43:54 +0000342#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343 }
344
Simon Kelley3be34542004-09-11 19:12:13 +0100345 if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000346 syslog(LOG_WARNING, _("running as root"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000347
Simon Kelley3d8df262005-08-29 12:19:27 +0100348 check_servers(daemon);
Simon Kelley3be34542004-09-11 19:12:13 +0100349
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000350 while (sigterm == 0)
351 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100352 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353
354 if (sighup)
355 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100356 clear_cache_and_reload(daemon, now);
Simon Kelley3be34542004-09-11 19:12:13 +0100357 if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
Simon Kelleyde379512004-06-22 20:23:33 +0100358 {
Simon Kelley3be34542004-09-11 19:12:13 +0100359 reload_servers(daemon->resolv_files->name, daemon);
Simon Kelley3d8df262005-08-29 12:19:27 +0100360 check_servers(daemon);
Simon Kelleyde379512004-06-22 20:23:33 +0100361 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000362 sighup = 0;
363 }
364
365 if (sigusr1)
366 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100367 dump_cache(daemon);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000368 sigusr1 = 0;
369 }
370
Simon Kelley44a2a312004-03-10 20:04:35 +0000371 if (sigalarm)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000372 {
Simon Kelley3be34542004-09-11 19:12:13 +0100373 if (daemon->dhcp)
Simon Kelley44a2a312004-03-10 20:04:35 +0000374 {
375 lease_update_file(1, now);
376#ifdef HAVE_BROKEN_RTC
Simon Kelley0a852542005-03-23 20:28:59 +0000377 alarm(daemon->min_leasetime);
Simon Kelley44a2a312004-03-10 20:04:35 +0000378#endif
379 }
380 sigalarm = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000381 }
382
383 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100384 FD_ZERO(&wset);
385 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000386
387 if (!first_loop)
388 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100389 int maxfd = set_dns_listeners(daemon, &rset, -1);
390#ifdef HAVE_DBUS
391 maxfd = set_dbus_listeners(daemon, maxfd, &rset, &wset, &eset);
392#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100393 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000394 {
Simon Kelley3be34542004-09-11 19:12:13 +0100395 FD_SET(daemon->dhcpfd, &rset);
396 if (daemon->dhcpfd > maxfd)
397 maxfd = daemon->dhcpfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000398 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000399
Simon Kelley3d8df262005-08-29 12:19:27 +0100400 /* Whilst polling for the dbus, wake every quarter second */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000401#ifdef HAVE_PSELECT
Simon Kelley3d8df262005-08-29 12:19:27 +0100402 {
403 struct timespec *tp = NULL;
404#ifdef HAVE_DBUS
405 struct timespec t;
406 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
407 {
408 tp = &t;
409 tp->tv_sec = 0;
410 tp->tv_nsec = 250000000;
411 }
412#endif
413 if (pselect(maxfd+1, &rset, &wset, &eset, tp, &sigmask) < 0)
414 {
415 /* otherwise undefined after error */
416 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
417 }
418 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000419#else
420 {
421 sigset_t save_mask;
Simon Kelley3d8df262005-08-29 12:19:27 +0100422 struct timeval *tp = NULL;
423#ifdef HAVE_DBUS
424 struct timeval t;
425 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
426 {
427 tp = &t;
428 tp->tv_sec = 0;
429 tp->tv_usec = 250000;
430 }
431#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000432 sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
Simon Kelley3d8df262005-08-29 12:19:27 +0100433 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
434 {
435 /* otherwise undefined after error */
436 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
437 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000438 sigprocmask(SIG_SETMASK, &save_mask, NULL);
Simon Kelley3d8df262005-08-29 12:19:27 +0100439
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000440 }
441#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100443
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000444 first_loop = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100445 now = dnsmasq_time(daemon->uptime_fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446
447 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100448 /* Don't go silent for long periods if the clock goes backwards. */
449 if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < 1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450 {
451 last = now;
Simon Kelley33820b72004-04-03 21:10:00 +0100452
453#ifdef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100454 if (daemon->lease_file && !daemon->dhcp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100455 load_dhcp(daemon, now);
Simon Kelley33820b72004-04-03 21:10:00 +0100456#endif
457
Simon Kelley3be34542004-09-11 19:12:13 +0100458 if (!(daemon->options & OPT_NO_POLL))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000459 {
Simon Kelley3be34542004-09-11 19:12:13 +0100460 struct resolvc *res = daemon->resolv_files, *latest = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000461 struct stat statbuf;
Simon Kelley33820b72004-04-03 21:10:00 +0100462 time_t last_change = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000463 /* There may be more than one possible file.
464 Go through and find the one which changed _last_.
465 Warn of any which can't be read. */
466 while (res)
467 {
468 if (stat(res->name, &statbuf) == -1)
469 {
470 if (!res->logged)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000471 syslog(LOG_WARNING, _("failed to access %s: %m"), res->name);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472 res->logged = 1;
473 }
474 else
475 {
476 res->logged = 0;
Simon Kelley3d8df262005-08-29 12:19:27 +0100477 if (statbuf.st_mtime != res->mtime)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000478 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100479 res->mtime = statbuf.st_mtime;
480 if (difftime(res->mtime, last_change) > 0.0)
481 {
482 last_change = res->mtime;
483 latest = res;
484 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000485 }
486 }
487 res = res->next;
488 }
489
Simon Kelley3d8df262005-08-29 12:19:27 +0100490 if (latest)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000491 {
Simon Kelley3be34542004-09-11 19:12:13 +0100492 reload_servers(latest->name, daemon);
Simon Kelley3d8df262005-08-29 12:19:27 +0100493 check_servers(daemon);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000494 }
495 }
496 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100497
498#ifdef HAVE_DBUS
499 /* if we didn't create a DBus connection, retry now. */
500 if ((daemon->options & OPT_DBUS) && !daemon->dbus)
501 {
502 char *err;
503 if ((err = dbus_init(daemon)))
Simon Kelleyb8187c82005-11-26 21:46:27 +0000504 syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100505 if (daemon->dbus)
Simon Kelleyb8187c82005-11-26 21:46:27 +0000506 syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100507 }
508 check_dbus_listeners(daemon, &rset, &wset, &eset);
509#endif
510
Simon Kelley3be34542004-09-11 19:12:13 +0100511 check_dns_listeners(daemon, &rset, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000512
Simon Kelley3be34542004-09-11 19:12:13 +0100513 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
514 dhcp_packet(daemon, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000515 }
516
Simon Kelleyb8187c82005-11-26 21:46:27 +0000517 syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100518
Simon Kelley3be34542004-09-11 19:12:13 +0100519 if (daemon->dhcp)
520 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000521#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100522 lease_update_file(1, now);
Simon Kelley44a2a312004-03-10 20:04:35 +0000523#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100524 close(daemon->lease_fd);
525 }
526
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000527 return 0;
528}
529
Simon Kelley3be34542004-09-11 19:12:13 +0100530static void sig_handler(int sig)
531{
532 if (sig == SIGTERM)
533 sigterm = 1;
534 else if (sig == SIGHUP)
535 sighup = 1;
536 else if (sig == SIGUSR1)
537 sigusr1 = 1;
538 else if (sig == SIGALRM)
539 {
540 /* alarm is used to kill children after a fixed time. */
541 if (in_child)
542 exit(0);
543 else
544 sigalarm = 1;
545 }
546 else if (sig == SIGCHLD)
547 {
548 /* See Stevens 5.10 */
549
550 while (waitpid(-1, NULL, WNOHANG) > 0)
551 num_kids--;
552 }
553}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000554
Simon Kelley3d8df262005-08-29 12:19:27 +0100555
556void clear_cache_and_reload(struct daemon *daemon, time_t now)
557{
558 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
559 if (daemon->dhcp)
560 {
561 if (daemon->options & OPT_ETHERS)
562 dhcp_read_ethers(daemon);
563 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000564 lease_update_from_configs(daemon);
Simon Kelley3d8df262005-08-29 12:19:27 +0100565 lease_update_file(0, now);
566 lease_update_dns(daemon);
567 }
568}
569
Simon Kelley3be34542004-09-11 19:12:13 +0100570static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
571{
572 struct serverfd *serverfdp;
573 struct listener *listener;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574
Simon Kelley3be34542004-09-11 19:12:13 +0100575 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
576 {
577 FD_SET(serverfdp->fd, set);
578 if (serverfdp->fd > maxfd)
579 maxfd = serverfdp->fd;
580 }
581
582 for (listener = daemon->listeners; listener; listener = listener->next)
583 {
584 FD_SET(listener->fd, set);
585 if (listener->fd > maxfd)
586 maxfd = listener->fd;
587 FD_SET(listener->tcpfd, set);
588 if (listener->tcpfd > maxfd)
589 maxfd = listener->tcpfd;
590 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000591
Simon Kelley3be34542004-09-11 19:12:13 +0100592 return maxfd;
593}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594
Simon Kelley3be34542004-09-11 19:12:13 +0100595static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
596{
597 struct serverfd *serverfdp;
598 struct listener *listener;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000599
Simon Kelley3be34542004-09-11 19:12:13 +0100600 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
601 if (FD_ISSET(serverfdp->fd, set))
602 reply_query(serverfdp, daemon, now);
603
604 for (listener = daemon->listeners; listener; listener = listener->next)
605 {
606 if (FD_ISSET(listener->fd, set))
607 receive_query(listener, daemon, now);
608
609 if (FD_ISSET(listener->tcpfd, set))
610 {
611 int confd;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000612 struct in_addr netmask, dst_addr_4;
Simon Kelley3be34542004-09-11 19:12:13 +0100613
614 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
615
616 if (confd != -1)
617 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000618 union mysockaddr tcp_addr;
619 socklen_t tcp_len = sizeof(union mysockaddr);
620
621 /* Check for allowed interfaces when binding the wildcard address:
622 we do this by looking for an interface with the same address as
623 the local address of the TCP connection, then looking to see if that's
624 an allowed interface. As a side effect, we get the netmask of the
625 interface too, for localisation. */
626
627 if ((num_kids >= MAX_PROCS) ||
628 (!(daemon->options & OPT_NOWILD) &&
629 (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1 ||
630 !enumerate_interfaces(daemon, NULL, &tcp_addr, &netmask))))
Simon Kelley3be34542004-09-11 19:12:13 +0100631 close(confd);
Simon Kelley59353a62004-11-21 19:34:28 +0000632#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100633 else if (!(daemon->options & OPT_DEBUG) && fork())
634 {
635 num_kids++;
636 close(confd);
637 }
Simon Kelley59353a62004-11-21 19:34:28 +0000638#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100639 else
640 {
Simon Kelley3d8df262005-08-29 12:19:27 +0100641 unsigned char *buff;
Simon Kelley3be34542004-09-11 19:12:13 +0100642 struct server *s;
643 int flags;
644
645 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
646 terminate the process. */
647 if (!(daemon->options & OPT_DEBUG))
648 {
649 sigset_t mask;
650 sigemptyset(&mask);
651 sigaddset(&mask, SIGALRM);
652 sigprocmask(SIG_UNBLOCK, &mask, NULL);
653 alarm(CHILD_LIFETIME);
654 in_child = 1;
655 }
656
657 /* start with no upstream connections. */
658 for (s = daemon->servers; s; s = s->next)
659 s->tcpfd = -1;
660
661 /* The connected socket inherits non-blocking
662 attribute from the listening socket.
663 Reset that here. */
664 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
665 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
666
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000667 if (listener->family == AF_INET)
668 {
669 if (daemon->options & OPT_NOWILD)
670 {
671 netmask = listener->iface->netmask;
672 dst_addr_4 = listener->iface->addr.in.sin_addr;
673 }
674 else
675 /* netmask already set by enumerate_interfaces */
676 dst_addr_4 = tcp_addr.in.sin_addr;
677 }
678 else
679 dst_addr_4.s_addr = 0;
680
681 buff = tcp_request(daemon, confd, now, dst_addr_4, netmask);
Simon Kelley3be34542004-09-11 19:12:13 +0100682
683 if (!(daemon->options & OPT_DEBUG))
684 exit(0);
685
686 close(confd);
687 if (buff)
688 free(buff);
689 for (s = daemon->servers; s; s = s->next)
690 if (s->tcpfd != -1)
691 close(s->tcpfd);
692 }
693 }
694 }
695 }
696}
697
698int icmp_ping(struct daemon *daemon, struct in_addr addr)
699{
700 /* Try and get an ICMP echo from a machine.
701 Note that we can't create the raw socket each time
702 we do this, since that needs root. Therefore the socket has to hang
703 around all the time. Since most of the time we won't read the
704 socket, it will accumulate buffers full of ICMP messages,
705 wasting memory. To avoid that we set the receive buffer
706 length to zero except when we're actively pinging. */
707
708 /* Note that whilst in the three second wait, we check for
709 (and service) events on the DNS sockets, (so doing that
710 better not use any resources our caller has in use...)
711 but we remain deaf to signals or further DHCP packets. */
712
713 struct sockaddr_in saddr;
714 struct {
715 struct ip ip;
716 struct icmp icmp;
717 } packet;
718 unsigned short id = rand16();
719 unsigned int i, j;
720 int opt = 2000, gotreply = 0;
721 time_t start, now;
722
723 saddr.sin_family = AF_INET;
724 saddr.sin_port = 0;
725 saddr.sin_addr = addr;
726#ifdef HAVE_SOCKADDR_SA_LEN
727 saddr.sin_len = sizeof(struct sockaddr_in);
728#endif
729
730 memset(&packet.icmp, 0, sizeof(packet.icmp));
731 packet.icmp.icmp_type = ICMP_ECHO;
732 packet.icmp.icmp_id = id;
733 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
734 j += ((u16 *)&packet.icmp)[i];
735 while (j>>16)
736 j = (j & 0xffff) + (j >> 16);
737 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
738
739 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
740
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100741 while (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
742 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
743 retry_send());
744
745 for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
746 {
747 struct timeval tv;
748 fd_set rset;
749 struct sockaddr_in faddr;
Simon Kelley3d8df262005-08-29 12:19:27 +0100750 int maxfd;
751 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100752
753 tv.tv_usec = 250000;
754 tv.tv_sec = 0;
755
756 FD_ZERO(&rset);
757 FD_SET(daemon->dhcp_icmp_fd, &rset);
758 maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
Simon Kelley3be34542004-09-11 19:12:13 +0100759
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100760 if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
761 FD_ZERO(&rset);
762
763 now = dnsmasq_time(daemon->uptime_fd);
764 check_dns_listeners(daemon, &rset, now);
765
766 if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
767 recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
768 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
769 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
770 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
771 packet.icmp.icmp_seq == 0 &&
772 packet.icmp.icmp_id == id)
773 {
774 gotreply = 1;
775 break;
776 }
777 }
778
Simon Kelley3be34542004-09-11 19:12:13 +0100779 opt = 1;
780 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100781
Simon Kelley3be34542004-09-11 19:12:13 +0100782 return gotreply;
783}
Simon Kelley0a852542005-03-23 20:28:59 +0000784
785