blob: 0d2503670a5fd5c9f7cfc3a39d40f34ee3f52519 [file] [log] [blame]
Simon Kelley3be34542004-09-11 19:12:13 +01001/* dnsmasq is Copyright (c) 2000-2004 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 Kelleyfeba5c12004-07-27 20:28:58 +010017static int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000018
Simon Kelley3be34542004-09-11 19:12:13 +010019static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
20static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now);
21static void sig_handler(int sig);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000022
23int main (int argc, char **argv)
24{
Simon Kelley3be34542004-09-11 19:12:13 +010025 struct daemon *daemon;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026 int first_loop = 1;
Simon Kelleyde379512004-06-22 20:23:33 +010027 int bind_fallback = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000028 time_t resolv_changed = 0;
29 time_t now, last = 0;
Simon Kelley3be34542004-09-11 19:12:13 +010030 struct irec *interfaces;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031 struct sigaction sigact;
32 sigset_t sigmask;
Simon Kelley33820b72004-04-03 21:10:00 +010033
Simon Kelley9e4abcb2004-01-22 19:47:41 +000034 sighup = 1; /* init cache the first time through */
35 sigusr1 = 0; /* but don't dump */
Simon Kelley9e4abcb2004-01-22 19:47:41 +000036 sigterm = 0; /* or die */
Simon Kelley44a2a312004-03-10 20:04:35 +000037#ifdef HAVE_BROKEN_RTC
38 sigalarm = 1; /* need regular lease dumps */
39#else
40 sigalarm = 0; /* or not */
41#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +010042 num_kids = 0;
43 in_child = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000044
45 sigact.sa_handler = sig_handler;
46 sigact.sa_flags = 0;
47 sigemptyset(&sigact.sa_mask);
48 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000049 sigaction(SIGHUP, &sigact, NULL);
50 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000051 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010052 sigaction(SIGCHLD, &sigact, NULL);
53
54 /* ignore SIGPIPE */
55 sigact.sa_handler = SIG_IGN;
56 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000057
58 /* now block all the signals, they stay that way except
59 during the call to pselect */
60 sigaddset(&sigact.sa_mask, SIGUSR1);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000061 sigaddset(&sigact.sa_mask, SIGTERM);
62 sigaddset(&sigact.sa_mask, SIGHUP);
Simon Kelley44a2a312004-03-10 20:04:35 +000063 sigaddset(&sigact.sa_mask, SIGALRM);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010064 sigaddset(&sigact.sa_mask, SIGCHLD);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065 sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
66
Simon Kelley3be34542004-09-11 19:12:13 +010067 daemon = read_opts(argc, argv);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000068
Simon Kelley3be34542004-09-11 19:12:13 +010069 if (daemon->edns_pktsz < PACKETSZ)
70 daemon->edns_pktsz = PACKETSZ;
71 daemon->packet = safe_malloc(daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
72 daemon->edns_pktsz : DNSMASQ_PACKETSZ);
73
74 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000075 {
Simon Kelley3be34542004-09-11 19:12:13 +010076 if (daemon->dhcp)
77 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000078 }
Simon Kelley33820b72004-04-03 21:10:00 +010079#ifndef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +010080 else if (!daemon->dhcp)
Simon Kelley33820b72004-04-03 21:10:00 +010081 die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
82#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000083
Simon Kelley3be34542004-09-11 19:12:13 +010084 interfaces = enumerate_interfaces(daemon);
85
86 if (!(daemon->options & OPT_NOWILD) &&
87 !(daemon->listeners = create_wildcard_listeners(daemon->port)))
Simon Kelleyde379512004-06-22 20:23:33 +010088 {
89 bind_fallback = 1;
Simon Kelley3be34542004-09-11 19:12:13 +010090 daemon->options |= OPT_NOWILD;
Simon Kelleyde379512004-06-22 20:23:33 +010091 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +000092
Simon Kelley3be34542004-09-11 19:12:13 +010093 if (daemon->options & OPT_NOWILD)
Simon Kelleyde379512004-06-22 20:23:33 +010094 {
95 struct iname *if_tmp;
Simon Kelley3be34542004-09-11 19:12:13 +010096 daemon->listeners = create_bound_listeners(interfaces, daemon->port);
Simon Kelleyde379512004-06-22 20:23:33 +010097
Simon Kelley3be34542004-09-11 19:12:13 +010098 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +010099 if (if_tmp->name && !if_tmp->used)
100 die("unknown interface %s", if_tmp->name);
101
Simon Kelley3be34542004-09-11 19:12:13 +0100102 for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100103 if (!if_tmp->used)
104 {
Simon Kelley3be34542004-09-11 19:12:13 +0100105 char *addrbuff = daemon->namebuff;
Simon Kelleyde379512004-06-22 20:23:33 +0100106#ifdef HAVE_IPV6
107 if (if_tmp->addr.sa.sa_family == AF_INET)
108 inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
109 addrbuff, ADDRSTRLEN);
110 else
111 inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
112 addrbuff, ADDRSTRLEN);
113#else
114 strcpy(addrbuff, inet_ntoa(if_tmp->addr.in.sin_addr));
115#endif
116 die("no interface with address %s", addrbuff);
117 }
118 }
119
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000120 forward_init(1);
Simon Kelley3be34542004-09-11 19:12:13 +0100121 cache_init(daemon->cachesize, daemon->options & OPT_LOG);
Simon Kelley44a2a312004-03-10 20:04:35 +0000122
123#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100124 if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1)
Simon Kelley44a2a312004-03-10 20:04:35 +0000125 die("cannot open " UPTIME ":%s", NULL);
126#endif
127
Simon Kelley3be34542004-09-11 19:12:13 +0100128 now = dnsmasq_time(daemon->uptime_fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000129
Simon Kelley3be34542004-09-11 19:12:13 +0100130 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000131 {
Simon Kelleyde379512004-06-22 20:23:33 +0100132#if !defined(IP_PKTINFO) && !defined(IP_RECVIF)
133 int c;
134 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +0100135 for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
Simon Kelleyde379512004-06-22 20:23:33 +0100136 if (!tmp->isloop)
137 c++;
138 if (c != 1)
139 die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
140#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100141 dhcp_init(daemon);
142 lease_init(daemon, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000143 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100144
145 /* If query_port is set then create a socket now, before dumping root
146 for use to access nameservers without more specific source addresses.
147 This allows query_port to be a low port */
Simon Kelley3be34542004-09-11 19:12:13 +0100148 if (daemon->query_port)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100149 {
150 union mysockaddr addr;
151 addr.in.sin_family = AF_INET;
152 addr.in.sin_addr.s_addr = INADDR_ANY;
Simon Kelley3be34542004-09-11 19:12:13 +0100153 addr.in.sin_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100154#ifdef HAVE_SOCKADDR_SA_LEN
155 addr.in.sin_len = sizeof(struct sockaddr_in);
156#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100157 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100158#ifdef HAVE_IPV6
159 addr.in6.sin6_family = AF_INET6;
160 addr.in6.sin6_addr = in6addr_any;
Simon Kelley3be34542004-09-11 19:12:13 +0100161 addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100162 addr.in6.sin6_flowinfo = htonl(0);
163#ifdef HAVE_SOCKADDR_SA_LEN
164 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
165#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100166 allocate_sfd(&addr, &daemon->sfds);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100167#endif
168 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000169
170 setbuf(stdout, NULL);
171
Simon Kelley3be34542004-09-11 19:12:13 +0100172 if (!(daemon->options & OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173 {
174 FILE *pidfile;
Simon Kelley3be34542004-09-11 19:12:13 +0100175 struct serverfd *serverfdp;
176 struct listener *listener;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000177 struct passwd *ent_pw;
178 int i;
179
180 /* The following code "daemonizes" the process.
181 See Stevens section 12.4 */
182
183#ifndef NO_FORK
Simon Kelley3be34542004-09-11 19:12:13 +0100184 if (!(daemon->options & OPT_NO_FORK))
185 {
186 if (fork() != 0 )
187 exit(0);
188
189 setsid();
190
191 if (fork() != 0)
192 exit(0);
193 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000194#endif
195
196 chdir("/");
197 umask(022); /* make pidfile 0644 */
198
199 /* write pidfile _after_ forking ! */
Simon Kelley3be34542004-09-11 19:12:13 +0100200 if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000201 {
202 fprintf(pidfile, "%d\n", (int) getpid());
203 fclose(pidfile);
204 }
205
206 umask(0);
207
208 for (i=0; i<64; i++)
209 {
Simon Kelley3be34542004-09-11 19:12:13 +0100210 for (listener = daemon->listeners; listener; listener = listener->next)
211 if (listener->fd == i || listener->tcpfd == i)
212 break;
Simon Kelley44a2a312004-03-10 20:04:35 +0000213 if (listener)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000214 continue;
215
Simon Kelley3be34542004-09-11 19:12:13 +0100216#ifdef HAVE_BROKEN_RTC
217 if (i == daemon->uptime_fd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000218 continue;
Simon Kelley3be34542004-09-11 19:12:13 +0100219#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000220
Simon Kelley3be34542004-09-11 19:12:13 +0100221 if (daemon->dhcp &&
222 (i == daemon->lease_fd ||
223 i == daemon->dhcpfd ||
224 i == daemon->dhcp_raw_fd ||
225 i == daemon->dhcp_icmp_fd))
226 continue;
227
228 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100229 if (serverfdp->fd == i)
230 break;
231 if (serverfdp)
232 continue;
233
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000234 close(i);
235 }
236
237 /* Change uid and gid for security */
Simon Kelley3be34542004-09-11 19:12:13 +0100238 if (daemon->username && (ent_pw = getpwnam(daemon->username)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000239 {
240 gid_t dummy;
241 struct group *gp;
242 /* remove all supplimentary groups */
243 setgroups(0, &dummy);
244 /* change group for /etc/ppp/resolv.conf
245 otherwise get the group for "nobody" */
Simon Kelley3be34542004-09-11 19:12:13 +0100246 if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000247 (gp = getgrgid(ent_pw->pw_gid)))
248 setgid(gp->gr_gid);
249 /* finally drop root */
250 setuid(ent_pw->pw_uid);
251 }
252 }
253
254 openlog("dnsmasq",
Simon Kelley3be34542004-09-11 19:12:13 +0100255 DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG),
256 DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000257
Simon Kelley3be34542004-09-11 19:12:13 +0100258 if (daemon->cachesize != 0)
259 syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000260 else
261 syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
262
Simon Kelleyde379512004-06-22 20:23:33 +0100263 if (bind_fallback)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100264 syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
Simon Kelleyde379512004-06-22 20:23:33 +0100265
Simon Kelley3be34542004-09-11 19:12:13 +0100266 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000267 {
Simon Kelley3be34542004-09-11 19:12:13 +0100268 struct dhcp_context *dhcp_tmp;
269 for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100270 {
Simon Kelley3be34542004-09-11 19:12:13 +0100271 char *time = daemon->dhcp_buff2;
272 strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
273 if (dhcp_tmp->lease_time == 0)
274 sprintf(time, "infinite");
275 else
276 {
277 unsigned int x, p = 0, t = (unsigned int)dhcp_tmp->lease_time;
278 if ((x = t/3600))
279 p += sprintf(&time[p], "%dh", x);
280 if ((x = (t/60)%60))
281 p += sprintf(&time[p], "%dm", x);
282 if ((x = t%60))
283 p += sprintf(&time[p], "%ds", x);
284 }
285 syslog(LOG_INFO,
286 dhcp_tmp->static_only ?
287 "DHCP, static leases only on %.0s%s, lease time %s" :
288 "DHCP, IP range %s -- %s, lease time %s",
289 daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100290 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000291 }
292
Simon Kelley44a2a312004-03-10 20:04:35 +0000293#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100294 if (daemon->dhcp)
295 syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
Simon Kelley44a2a312004-03-10 20:04:35 +0000296#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297
Simon Kelley3be34542004-09-11 19:12:13 +0100298 if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100299 syslog(LOG_WARNING, "running as root");
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000300
Simon Kelley3be34542004-09-11 19:12:13 +0100301 check_servers(daemon, interfaces);
302
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000303 while (sigterm == 0)
304 {
305 fd_set rset;
306
307 if (sighup)
308 {
Simon Kelley3be34542004-09-11 19:12:13 +0100309 cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
310 if (daemon->dhcp)
Simon Kelley44a2a312004-03-10 20:04:35 +0000311 {
Simon Kelley3be34542004-09-11 19:12:13 +0100312 if (daemon->options & OPT_ETHERS)
313 dhcp_read_ethers(daemon);
314 dhcp_update_configs(daemon->dhcp_conf);
315 lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
Simon Kelley44a2a312004-03-10 20:04:35 +0000316 lease_update_file(0, now);
317 lease_update_dns();
318 }
Simon Kelley3be34542004-09-11 19:12:13 +0100319 if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
Simon Kelleyde379512004-06-22 20:23:33 +0100320 {
Simon Kelley3be34542004-09-11 19:12:13 +0100321 reload_servers(daemon->resolv_files->name, daemon);
322 check_servers(daemon, interfaces);
Simon Kelleyde379512004-06-22 20:23:33 +0100323 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000324 sighup = 0;
325 }
326
327 if (sigusr1)
328 {
Simon Kelley3be34542004-09-11 19:12:13 +0100329 dump_cache(daemon->options & (OPT_DEBUG | OPT_LOG), daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000330 sigusr1 = 0;
331 }
332
Simon Kelley44a2a312004-03-10 20:04:35 +0000333 if (sigalarm)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000334 {
Simon Kelley3be34542004-09-11 19:12:13 +0100335 if (daemon->dhcp)
Simon Kelley44a2a312004-03-10 20:04:35 +0000336 {
337 lease_update_file(1, now);
338#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100339 alarm(daemon->min_leasetime/3);
Simon Kelley44a2a312004-03-10 20:04:35 +0000340#endif
341 }
342 sigalarm = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343 }
344
345 FD_ZERO(&rset);
346
347 if (!first_loop)
348 {
Simon Kelley3be34542004-09-11 19:12:13 +0100349 int maxfd = set_dns_listeners(daemon, &rset, 0);
350
351 if (daemon->dhcp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000352 {
Simon Kelley3be34542004-09-11 19:12:13 +0100353 FD_SET(daemon->dhcpfd, &rset);
354 if (daemon->dhcpfd > maxfd)
355 maxfd = daemon->dhcpfd;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000356 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000357
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000358#ifdef HAVE_PSELECT
359 if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
360 FD_ZERO(&rset); /* rset otherwise undefined after error */
361#else
362 {
363 sigset_t save_mask;
364 sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
365 if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
366 FD_ZERO(&rset); /* rset otherwise undefined after error */
367 sigprocmask(SIG_SETMASK, &save_mask, NULL);
368 }
369#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000370 }
371
372 first_loop = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100373 now = dnsmasq_time(daemon->uptime_fd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000374
375 /* Check for changes to resolv files once per second max. */
376 if (last == 0 || difftime(now, last) > 1.0)
377 {
378 last = now;
Simon Kelley33820b72004-04-03 21:10:00 +0100379
380#ifdef HAVE_ISC_READER
Simon Kelley3be34542004-09-11 19:12:13 +0100381 if (daemon->lease_file && !daemon->dhcp)
382 load_dhcp(daemon->lease_file, daemon->domain_suffix, now, daemon->namebuff);
Simon Kelley33820b72004-04-03 21:10:00 +0100383#endif
384
Simon Kelley3be34542004-09-11 19:12:13 +0100385 if (!(daemon->options & OPT_NO_POLL))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000386 {
Simon Kelley3be34542004-09-11 19:12:13 +0100387 struct resolvc *res = daemon->resolv_files, *latest = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000388 struct stat statbuf;
Simon Kelley33820b72004-04-03 21:10:00 +0100389 time_t last_change = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000390 /* There may be more than one possible file.
391 Go through and find the one which changed _last_.
392 Warn of any which can't be read. */
393 while (res)
394 {
395 if (stat(res->name, &statbuf) == -1)
396 {
397 if (!res->logged)
398 syslog(LOG_WARNING, "failed to access %s: %m", res->name);
399 res->logged = 1;
400 }
401 else
402 {
403 res->logged = 0;
Simon Kelleyde379512004-06-22 20:23:33 +0100404 if (difftime(statbuf.st_mtime, last_change) > 0.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000405 {
406 last_change = statbuf.st_mtime;
407 latest = res;
408 }
409 }
410 res = res->next;
411 }
412
Simon Kelleyde379512004-06-22 20:23:33 +0100413 if (latest && difftime(last_change, resolv_changed) > 0.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000414 {
415 resolv_changed = last_change;
Simon Kelley3be34542004-09-11 19:12:13 +0100416 reload_servers(latest->name, daemon);
417 check_servers(daemon, interfaces);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 }
419 }
420 }
421
Simon Kelley3be34542004-09-11 19:12:13 +0100422 check_dns_listeners(daemon, &rset, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000423
Simon Kelley3be34542004-09-11 19:12:13 +0100424 if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
425 dhcp_packet(daemon, now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000426 }
427
428 syslog(LOG_INFO, "exiting on receipt of SIGTERM");
Simon Kelley44a2a312004-03-10 20:04:35 +0000429
Simon Kelley3be34542004-09-11 19:12:13 +0100430 if (daemon->dhcp)
431 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000432#ifdef HAVE_BROKEN_RTC
Simon Kelley3be34542004-09-11 19:12:13 +0100433 lease_update_file(1, now);
Simon Kelley44a2a312004-03-10 20:04:35 +0000434#endif
Simon Kelley3be34542004-09-11 19:12:13 +0100435 close(daemon->lease_fd);
436 }
437
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000438 return 0;
439}
440
Simon Kelley3be34542004-09-11 19:12:13 +0100441static void sig_handler(int sig)
442{
443 if (sig == SIGTERM)
444 sigterm = 1;
445 else if (sig == SIGHUP)
446 sighup = 1;
447 else if (sig == SIGUSR1)
448 sigusr1 = 1;
449 else if (sig == SIGALRM)
450 {
451 /* alarm is used to kill children after a fixed time. */
452 if (in_child)
453 exit(0);
454 else
455 sigalarm = 1;
456 }
457 else if (sig == SIGCHLD)
458 {
459 /* See Stevens 5.10 */
460
461 while (waitpid(-1, NULL, WNOHANG) > 0)
462 num_kids--;
463 }
464}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000465
Simon Kelley3be34542004-09-11 19:12:13 +0100466static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
467{
468 struct serverfd *serverfdp;
469 struct listener *listener;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000470
Simon Kelley3be34542004-09-11 19:12:13 +0100471 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
472 {
473 FD_SET(serverfdp->fd, set);
474 if (serverfdp->fd > maxfd)
475 maxfd = serverfdp->fd;
476 }
477
478 for (listener = daemon->listeners; listener; listener = listener->next)
479 {
480 FD_SET(listener->fd, set);
481 if (listener->fd > maxfd)
482 maxfd = listener->fd;
483 FD_SET(listener->tcpfd, set);
484 if (listener->tcpfd > maxfd)
485 maxfd = listener->tcpfd;
486 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487
Simon Kelley3be34542004-09-11 19:12:13 +0100488 return maxfd;
489}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000490
Simon Kelley3be34542004-09-11 19:12:13 +0100491static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now)
492{
493 struct serverfd *serverfdp;
494 struct listener *listener;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000495
Simon Kelley3be34542004-09-11 19:12:13 +0100496 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
497 if (FD_ISSET(serverfdp->fd, set))
498 reply_query(serverfdp, daemon, now);
499
500 for (listener = daemon->listeners; listener; listener = listener->next)
501 {
502 if (FD_ISSET(listener->fd, set))
503 receive_query(listener, daemon, now);
504
505 if (FD_ISSET(listener->tcpfd, set))
506 {
507 int confd;
508
509 while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
510
511 if (confd != -1)
512 {
513 int match = 1;
514 if (!(daemon->options & OPT_NOWILD))
515 {
516 /* Check for allowed interfaces when binding the wildcard address */
517 /* Don't know how to get interface of a connection, so we have to
518 check by address. This will break when interfaces change address */
519 union mysockaddr tcp_addr;
520 socklen_t tcp_len = sizeof(union mysockaddr);
521 struct iname *tmp;
522
523 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
524 {
525#ifdef HAVE_IPV6
526 if (tcp_addr.sa.sa_family == AF_INET6)
527 tcp_addr.in6.sin6_flowinfo = htonl(0);
528#endif
529 for (match = 1, tmp = daemon->if_except; tmp; tmp = tmp->next)
530 if (sockaddr_isequal(&tmp->addr, &tcp_addr))
531 match = 0;
532
533 if (match && (daemon->if_names || daemon->if_addrs))
534 {
535 match = 0;
536 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
537 if (sockaddr_isequal(&tmp->addr, &tcp_addr))
538 match = 1;
539 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
540 if (sockaddr_isequal(&tmp->addr, &tcp_addr))
541 match = 1;
542 }
543 }
544 }
545
546 if (!match || (num_kids >= MAX_PROCS))
547 close(confd);
548 else if (!(daemon->options & OPT_DEBUG) && fork())
549 {
550 num_kids++;
551 close(confd);
552 }
553 else
554 {
555 char *buff;
556 struct server *s;
557 int flags;
558
559 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
560 terminate the process. */
561 if (!(daemon->options & OPT_DEBUG))
562 {
563 sigset_t mask;
564 sigemptyset(&mask);
565 sigaddset(&mask, SIGALRM);
566 sigprocmask(SIG_UNBLOCK, &mask, NULL);
567 alarm(CHILD_LIFETIME);
568 in_child = 1;
569 }
570
571 /* start with no upstream connections. */
572 for (s = daemon->servers; s; s = s->next)
573 s->tcpfd = -1;
574
575 /* The connected socket inherits non-blocking
576 attribute from the listening socket.
577 Reset that here. */
578 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
579 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
580
581 buff = tcp_request(daemon, confd, now);
582
583 if (!(daemon->options & OPT_DEBUG))
584 exit(0);
585
586 close(confd);
587 if (buff)
588 free(buff);
589 for (s = daemon->servers; s; s = s->next)
590 if (s->tcpfd != -1)
591 close(s->tcpfd);
592 }
593 }
594 }
595 }
596}
597
598int icmp_ping(struct daemon *daemon, struct in_addr addr)
599{
600 /* Try and get an ICMP echo from a machine.
601 Note that we can't create the raw socket each time
602 we do this, since that needs root. Therefore the socket has to hang
603 around all the time. Since most of the time we won't read the
604 socket, it will accumulate buffers full of ICMP messages,
605 wasting memory. To avoid that we set the receive buffer
606 length to zero except when we're actively pinging. */
607
608 /* Note that whilst in the three second wait, we check for
609 (and service) events on the DNS sockets, (so doing that
610 better not use any resources our caller has in use...)
611 but we remain deaf to signals or further DHCP packets. */
612
613 struct sockaddr_in saddr;
614 struct {
615 struct ip ip;
616 struct icmp icmp;
617 } packet;
618 unsigned short id = rand16();
619 unsigned int i, j;
620 int opt = 2000, gotreply = 0;
621 time_t start, now;
622
623 saddr.sin_family = AF_INET;
624 saddr.sin_port = 0;
625 saddr.sin_addr = addr;
626#ifdef HAVE_SOCKADDR_SA_LEN
627 saddr.sin_len = sizeof(struct sockaddr_in);
628#endif
629
630 memset(&packet.icmp, 0, sizeof(packet.icmp));
631 packet.icmp.icmp_type = ICMP_ECHO;
632 packet.icmp.icmp_id = id;
633 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
634 j += ((u16 *)&packet.icmp)[i];
635 while (j>>16)
636 j = (j & 0xffff) + (j >> 16);
637 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
638
639 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
640
641 if (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
642 (struct sockaddr *)&saddr, sizeof(saddr)) == sizeof(struct icmp))
643 for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
644 {
645 struct timeval tv;
646 fd_set rset;
647 struct sockaddr_in faddr;
648 int maxfd, len = sizeof(faddr);
649
650 tv.tv_usec = 250000;
651 tv.tv_sec = 0;
652
653 FD_ZERO(&rset);
654 FD_SET(daemon->dhcp_icmp_fd, &rset);
655 maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
656
657 if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
658 FD_ZERO(&rset);
659
660 now = dnsmasq_time(daemon->uptime_fd);
661 check_dns_listeners(daemon, &rset, now);
662
663 if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
664 recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
665 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
666 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
667 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
668 packet.icmp.icmp_seq == 0 &&
669 packet.icmp.icmp_id == id)
670 {
671 gotreply = 1;
672 break;
673 }
674 }
675
676 opt = 1;
677 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
678
679 return gotreply;
680}