]>
Commit | Line | Data |
---|---|---|
f6b7dc47 | 1 | /* dnsmasq is Copyright (c) 2000-2005 Simon Kelley |
9e4abcb5 SK |
2 | |
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 | ||
9e4abcb5 SK |
13 | /* Author's email: simon@thekelleys.org.uk */ |
14 | ||
15 | #include "dnsmasq.h" | |
16 | ||
3d8df260 SK |
17 | static 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 | |
e17fb629 SK |
29 | #ifdef HAVE_RTNETLINK |
30 | "RTNetlink " | |
31 | #endif | |
3d8df260 SK |
32 | #ifndef HAVE_ISC_READER |
33 | "no-" | |
34 | #endif | |
35 | "ISC-leasefile " | |
36 | #ifndef HAVE_DBUS | |
37 | "no-" | |
38 | #endif | |
b8187c80 SK |
39 | "DBus " |
40 | #ifdef NO_GETTEXT | |
41 | "no-" | |
42 | #endif | |
e17fb629 | 43 | "I18N "; |
3d8df260 | 44 | |
0a852541 | 45 | static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child; |
9e4abcb5 | 46 | |
3be34541 SK |
47 | static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd); |
48 | static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now); | |
49 | static void sig_handler(int sig); | |
9e4abcb5 SK |
50 | |
51 | int main (int argc, char **argv) | |
52 | { | |
3be34541 | 53 | struct daemon *daemon; |
9e4abcb5 | 54 | int first_loop = 1; |
de37951c | 55 | int bind_fallback = 0; |
9e4abcb5 | 56 | time_t now, last = 0; |
9e4abcb5 SK |
57 | struct sigaction sigact; |
58 | sigset_t sigmask; | |
26128d27 | 59 | struct iname *if_tmp; |
33820b7e | 60 | |
b8187c80 SK |
61 | #ifndef NO_GETTEXT |
62 | setlocale(LC_ALL, ""); | |
63 | bindtextdomain("dnsmasq", LOCALEDIR); | |
64 | textdomain("dnsmasq"); | |
65 | #endif | |
66 | ||
9e4abcb5 SK |
67 | sighup = 1; /* init cache the first time through */ |
68 | sigusr1 = 0; /* but don't dump */ | |
9e4abcb5 | 69 | sigterm = 0; /* or die */ |
44a2a316 SK |
70 | #ifdef HAVE_BROKEN_RTC |
71 | sigalarm = 1; /* need regular lease dumps */ | |
72 | #else | |
73 | sigalarm = 0; /* or not */ | |
74 | #endif | |
feba5c1d SK |
75 | num_kids = 0; |
76 | in_child = 0; | |
9e4abcb5 SK |
77 | |
78 | sigact.sa_handler = sig_handler; | |
79 | sigact.sa_flags = 0; | |
80 | sigemptyset(&sigact.sa_mask); | |
81 | sigaction(SIGUSR1, &sigact, NULL); | |
9e4abcb5 SK |
82 | sigaction(SIGHUP, &sigact, NULL); |
83 | sigaction(SIGTERM, &sigact, NULL); | |
44a2a316 | 84 | sigaction(SIGALRM, &sigact, NULL); |
feba5c1d SK |
85 | sigaction(SIGCHLD, &sigact, NULL); |
86 | ||
87 | /* ignore SIGPIPE */ | |
88 | sigact.sa_handler = SIG_IGN; | |
89 | sigaction(SIGPIPE, &sigact, NULL); | |
9e4abcb5 SK |
90 | |
91 | /* now block all the signals, they stay that way except | |
92 | during the call to pselect */ | |
93 | sigaddset(&sigact.sa_mask, SIGUSR1); | |
9e4abcb5 SK |
94 | sigaddset(&sigact.sa_mask, SIGTERM); |
95 | sigaddset(&sigact.sa_mask, SIGHUP); | |
44a2a316 | 96 | sigaddset(&sigact.sa_mask, SIGALRM); |
feba5c1d | 97 | sigaddset(&sigact.sa_mask, SIGCHLD); |
9e4abcb5 SK |
98 | sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask); |
99 | ||
3d8df260 | 100 | daemon = read_opts(argc, argv, compile_opts); |
3be34541 SK |
101 | |
102 | if (daemon->edns_pktsz < PACKETSZ) | |
103 | daemon->edns_pktsz = PACKETSZ; | |
0a852541 SK |
104 | daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? |
105 | daemon->edns_pktsz : DNSMASQ_PACKETSZ; | |
106 | daemon->packet = safe_malloc(daemon->packet_buff_sz); | |
9e4abcb5 | 107 | |
3be34541 | 108 | if (!daemon->lease_file) |
9e4abcb5 | 109 | { |
3be34541 SK |
110 | if (daemon->dhcp) |
111 | daemon->lease_file = LEASEFILE; | |
9e4abcb5 | 112 | } |
33820b7e | 113 | #ifndef HAVE_ISC_READER |
3be34541 | 114 | else if (!daemon->dhcp) |
b8187c80 | 115 | die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL); |
33820b7e | 116 | #endif |
9e4abcb5 | 117 | |
3d8df260 | 118 | if (!enumerate_interfaces(daemon, &daemon->interfaces, NULL, NULL)) |
b8187c80 | 119 | die(_("failed to find list of interfaces: %s"), NULL); |
f6b7dc47 | 120 | |
3be34541 SK |
121 | if (!(daemon->options & OPT_NOWILD) && |
122 | !(daemon->listeners = create_wildcard_listeners(daemon->port))) | |
de37951c SK |
123 | { |
124 | bind_fallback = 1; | |
3be34541 | 125 | daemon->options |= OPT_NOWILD; |
de37951c | 126 | } |
9e4abcb5 | 127 | |
3be34541 | 128 | if (daemon->options & OPT_NOWILD) |
de37951c | 129 | { |
3d8df260 | 130 | daemon->listeners = create_bound_listeners(daemon->interfaces, daemon->port); |
de37951c | 131 | |
3be34541 | 132 | for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) |
de37951c | 133 | if (if_tmp->name && !if_tmp->used) |
b8187c80 | 134 | die(_("unknown interface %s"), if_tmp->name); |
de37951c | 135 | |
3be34541 | 136 | for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next) |
de37951c SK |
137 | if (!if_tmp->used) |
138 | { | |
3d8df260 | 139 | prettyprint_addr(&if_tmp->addr, daemon->namebuff); |
b8187c80 | 140 | die(_("no interface with address %s"), daemon->namebuff); |
de37951c SK |
141 | } |
142 | } | |
143 | ||
9e4abcb5 | 144 | forward_init(1); |
3be34541 | 145 | cache_init(daemon->cachesize, daemon->options & OPT_LOG); |
44a2a316 SK |
146 | |
147 | #ifdef HAVE_BROKEN_RTC | |
3be34541 | 148 | if ((daemon->uptime_fd = open(UPTIME, O_RDONLY)) == -1) |
b8187c80 | 149 | die(_("cannot open %s:%s"), UPTIME); |
44a2a316 SK |
150 | #endif |
151 | ||
3be34541 | 152 | now = dnsmasq_time(daemon->uptime_fd); |
9e4abcb5 | 153 | |
3be34541 | 154 | if (daemon->dhcp) |
9e4abcb5 | 155 | { |
de37951c SK |
156 | #if !defined(IP_PKTINFO) && !defined(IP_RECVIF) |
157 | int c; | |
158 | struct iname *tmp; | |
3be34541 | 159 | for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next) |
de37951c SK |
160 | if (!tmp->isloop) |
161 | c++; | |
162 | if (c != 1) | |
b8187c80 | 163 | die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL); |
de37951c | 164 | #endif |
3be34541 SK |
165 | dhcp_init(daemon); |
166 | lease_init(daemon, now); | |
9e4abcb5 | 167 | } |
feba5c1d | 168 | |
3d8df260 SK |
169 | if (daemon->options & OPT_DBUS) |
170 | #ifdef HAVE_DBUS | |
171 | { | |
172 | char *err; | |
173 | daemon->dbus = NULL; | |
174 | daemon->watches = NULL; | |
175 | if ((err = dbus_init(daemon))) | |
b8187c80 | 176 | die(_("DBus error: %s"), err); |
3d8df260 SK |
177 | } |
178 | #else | |
179 | if (daemon->options & OPT_DBUS) | |
b8187c80 | 180 | die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL); |
3d8df260 SK |
181 | #endif |
182 | ||
feba5c1d SK |
183 | /* If query_port is set then create a socket now, before dumping root |
184 | for use to access nameservers without more specific source addresses. | |
185 | This allows query_port to be a low port */ | |
3be34541 | 186 | if (daemon->query_port) |
feba5c1d SK |
187 | { |
188 | union mysockaddr addr; | |
189 | addr.in.sin_family = AF_INET; | |
190 | addr.in.sin_addr.s_addr = INADDR_ANY; | |
3be34541 | 191 | addr.in.sin_port = htons(daemon->query_port); |
feba5c1d SK |
192 | #ifdef HAVE_SOCKADDR_SA_LEN |
193 | addr.in.sin_len = sizeof(struct sockaddr_in); | |
194 | #endif | |
3be34541 | 195 | allocate_sfd(&addr, &daemon->sfds); |
feba5c1d SK |
196 | #ifdef HAVE_IPV6 |
197 | addr.in6.sin6_family = AF_INET6; | |
198 | addr.in6.sin6_addr = in6addr_any; | |
3be34541 | 199 | addr.in6.sin6_port = htons(daemon->query_port); |
feba5c1d SK |
200 | addr.in6.sin6_flowinfo = htonl(0); |
201 | #ifdef HAVE_SOCKADDR_SA_LEN | |
202 | addr.in6.sin6_len = sizeof(struct sockaddr_in6); | |
203 | #endif | |
3be34541 | 204 | allocate_sfd(&addr, &daemon->sfds); |
feba5c1d SK |
205 | #endif |
206 | } | |
9e4abcb5 SK |
207 | |
208 | setbuf(stdout, NULL); | |
209 | ||
3be34541 | 210 | if (!(daemon->options & OPT_DEBUG)) |
9e4abcb5 SK |
211 | { |
212 | FILE *pidfile; | |
213 | struct passwd *ent_pw; | |
3d8df260 SK |
214 | fd_set test_set; |
215 | int maxfd, i; | |
216 | ||
217 | FD_ZERO(&test_set); | |
218 | maxfd = set_dns_listeners(daemon, &test_set, -1); | |
219 | #ifdef HAVE_DBUS | |
220 | maxfd = set_dbus_listeners(daemon, maxfd, &test_set, &test_set, &test_set); | |
221 | #endif | |
222 | ||
9e4abcb5 SK |
223 | /* The following code "daemonizes" the process. |
224 | See Stevens section 12.4 */ | |
3d8df260 | 225 | |
9e4abcb5 | 226 | #ifndef NO_FORK |
3be34541 SK |
227 | if (!(daemon->options & OPT_NO_FORK)) |
228 | { | |
229 | if (fork() != 0 ) | |
230 | exit(0); | |
231 | ||
232 | setsid(); | |
233 | ||
234 | if (fork() != 0) | |
235 | exit(0); | |
236 | } | |
9e4abcb5 SK |
237 | #endif |
238 | ||
239 | chdir("/"); | |
240 | umask(022); /* make pidfile 0644 */ | |
241 | ||
242 | /* write pidfile _after_ forking ! */ | |
3be34541 | 243 | if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w"))) |
9e4abcb5 SK |
244 | { |
245 | fprintf(pidfile, "%d\n", (int) getpid()); | |
246 | fclose(pidfile); | |
247 | } | |
248 | ||
249 | umask(0); | |
250 | ||
251 | for (i=0; i<64; i++) | |
252 | { | |
3be34541 SK |
253 | #ifdef HAVE_BROKEN_RTC |
254 | if (i == daemon->uptime_fd) | |
9e4abcb5 | 255 | continue; |
3be34541 | 256 | #endif |
3d8df260 | 257 | |
3be34541 SK |
258 | if (daemon->dhcp && |
259 | (i == daemon->lease_fd || | |
260 | i == daemon->dhcpfd || | |
261 | i == daemon->dhcp_raw_fd || | |
262 | i == daemon->dhcp_icmp_fd)) | |
263 | continue; | |
3d8df260 SK |
264 | |
265 | if (i <= maxfd && FD_ISSET(i, &test_set)) | |
feba5c1d SK |
266 | continue; |
267 | ||
9e4abcb5 SK |
268 | close(i); |
269 | } | |
270 | ||
271 | /* Change uid and gid for security */ | |
3be34541 | 272 | if (daemon->username && (ent_pw = getpwnam(daemon->username))) |
9e4abcb5 SK |
273 | { |
274 | gid_t dummy; | |
275 | struct group *gp; | |
276 | /* remove all supplimentary groups */ | |
277 | setgroups(0, &dummy); | |
278 | /* change group for /etc/ppp/resolv.conf | |
279 | otherwise get the group for "nobody" */ | |
3be34541 | 280 | if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) || |
9e4abcb5 SK |
281 | (gp = getgrgid(ent_pw->pw_gid))) |
282 | setgid(gp->gr_gid); | |
283 | /* finally drop root */ | |
284 | setuid(ent_pw->pw_uid); | |
285 | } | |
286 | } | |
287 | ||
288 | openlog("dnsmasq", | |
3be34541 SK |
289 | DNSMASQ_LOG_OPT(daemon->options & OPT_DEBUG), |
290 | DNSMASQ_LOG_FAC(daemon->options & OPT_DEBUG)); | |
9e4abcb5 | 291 | |
3be34541 | 292 | if (daemon->cachesize != 0) |
b8187c80 | 293 | syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize); |
9e4abcb5 | 294 | else |
b8187c80 | 295 | syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION); |
3d8df260 | 296 | |
b8187c80 | 297 | syslog(LOG_INFO, _("compile time options: %s"), compile_opts); |
3d8df260 SK |
298 | |
299 | #ifdef HAVE_DBUS | |
300 | if (daemon->options & OPT_DBUS) | |
301 | { | |
302 | if (daemon->dbus) | |
b8187c80 | 303 | syslog(LOG_INFO, _("DBus support enabled: connected to system bus")); |
3d8df260 | 304 | else |
b8187c80 | 305 | syslog(LOG_INFO, _("DBus support enabled: bus connection pending")); |
3d8df260 SK |
306 | } |
307 | #endif | |
308 | ||
de37951c | 309 | if (bind_fallback) |
b8187c80 | 310 | syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations")); |
de37951c | 311 | |
26128d27 SK |
312 | if (!(daemon->options & OPT_NOWILD)) |
313 | for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) | |
314 | if (if_tmp->name && !if_tmp->used) | |
b8187c80 | 315 | syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name); |
26128d27 | 316 | |
3be34541 | 317 | if (daemon->dhcp) |
9e4abcb5 | 318 | { |
3be34541 | 319 | struct dhcp_context *dhcp_tmp; |
0a852541 SK |
320 | |
321 | #ifdef HAVE_RTNETLINK | |
322 | /* Must do this after daemonizing so that the pid is right */ | |
323 | daemon->netlinkfd = netlink_init(); | |
324 | #endif | |
325 | ||
3be34541 | 326 | for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next) |
feba5c1d | 327 | { |
0a852541 | 328 | prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time); |
3be34541 | 329 | strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start)); |
3be34541 | 330 | syslog(LOG_INFO, |
0a852541 | 331 | (dhcp_tmp->flags & CONTEXT_STATIC) ? |
b8187c80 SK |
332 | _("DHCP, static leases only on %.0s%s, lease time %s") : |
333 | _("DHCP, IP range %s -- %s, lease time %s"), | |
0a852541 | 334 | daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2); |
feba5c1d | 335 | } |
26128d27 | 336 | |
44a2a316 | 337 | #ifdef HAVE_BROKEN_RTC |
0a852541 SK |
338 | daemon->min_leasetime = daemon->min_leasetime/3; |
339 | if (daemon->min_leasetime > (60 * 60 * 24)) | |
340 | daemon->min_leasetime = 60 * 60 * 24; | |
341 | if (daemon->min_leasetime < 60) | |
342 | daemon->min_leasetime = 60; | |
343 | prettyprint_time(daemon->dhcp_buff2, daemon->min_leasetime); | |
b8187c80 | 344 | syslog(LOG_INFO, _("DHCP, %s will be written every %s"), daemon->lease_file, daemon->dhcp_buff2); |
44a2a316 | 345 | #endif |
26128d27 SK |
346 | } |
347 | ||
3be34541 | 348 | if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0)) |
b8187c80 | 349 | syslog(LOG_WARNING, _("running as root")); |
9e4abcb5 | 350 | |
3d8df260 | 351 | check_servers(daemon); |
3be34541 | 352 | |
9e4abcb5 SK |
353 | while (sigterm == 0) |
354 | { | |
3d8df260 | 355 | fd_set rset, wset, eset; |
9e4abcb5 SK |
356 | |
357 | if (sighup) | |
358 | { | |
3d8df260 | 359 | clear_cache_and_reload(daemon, now); |
3be34541 | 360 | if (daemon->resolv_files && (daemon->options & OPT_NO_POLL)) |
de37951c | 361 | { |
3be34541 | 362 | reload_servers(daemon->resolv_files->name, daemon); |
3d8df260 | 363 | check_servers(daemon); |
de37951c | 364 | } |
9e4abcb5 SK |
365 | sighup = 0; |
366 | } | |
367 | ||
368 | if (sigusr1) | |
369 | { | |
fd9fa481 | 370 | dump_cache(daemon); |
9e4abcb5 SK |
371 | sigusr1 = 0; |
372 | } | |
373 | ||
44a2a316 | 374 | if (sigalarm) |
9e4abcb5 | 375 | { |
3be34541 | 376 | if (daemon->dhcp) |
44a2a316 SK |
377 | { |
378 | lease_update_file(1, now); | |
379 | #ifdef HAVE_BROKEN_RTC | |
0a852541 | 380 | alarm(daemon->min_leasetime); |
44a2a316 SK |
381 | #endif |
382 | } | |
383 | sigalarm = 0; | |
9e4abcb5 SK |
384 | } |
385 | ||
386 | FD_ZERO(&rset); | |
3d8df260 SK |
387 | FD_ZERO(&wset); |
388 | FD_ZERO(&eset); | |
9e4abcb5 SK |
389 | |
390 | if (!first_loop) | |
391 | { | |
3d8df260 SK |
392 | int maxfd = set_dns_listeners(daemon, &rset, -1); |
393 | #ifdef HAVE_DBUS | |
394 | maxfd = set_dbus_listeners(daemon, maxfd, &rset, &wset, &eset); | |
395 | #endif | |
3be34541 | 396 | if (daemon->dhcp) |
9e4abcb5 | 397 | { |
3be34541 SK |
398 | FD_SET(daemon->dhcpfd, &rset); |
399 | if (daemon->dhcpfd > maxfd) | |
400 | maxfd = daemon->dhcpfd; | |
9e4abcb5 | 401 | } |
44a2a316 | 402 | |
3d8df260 | 403 | /* Whilst polling for the dbus, wake every quarter second */ |
9e4abcb5 | 404 | #ifdef HAVE_PSELECT |
3d8df260 SK |
405 | { |
406 | struct timespec *tp = NULL; | |
407 | #ifdef HAVE_DBUS | |
408 | struct timespec t; | |
409 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) | |
410 | { | |
411 | tp = &t; | |
412 | tp->tv_sec = 0; | |
413 | tp->tv_nsec = 250000000; | |
414 | } | |
415 | #endif | |
416 | if (pselect(maxfd+1, &rset, &wset, &eset, tp, &sigmask) < 0) | |
417 | { | |
418 | /* otherwise undefined after error */ | |
419 | FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); | |
420 | } | |
421 | } | |
9e4abcb5 SK |
422 | #else |
423 | { | |
424 | sigset_t save_mask; | |
3d8df260 SK |
425 | struct timeval *tp = NULL; |
426 | #ifdef HAVE_DBUS | |
427 | struct timeval t; | |
428 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) | |
429 | { | |
430 | tp = &t; | |
431 | tp->tv_sec = 0; | |
432 | tp->tv_usec = 250000; | |
433 | } | |
434 | #endif | |
9e4abcb5 | 435 | sigprocmask(SIG_SETMASK, &sigmask, &save_mask); |
3d8df260 SK |
436 | if (select(maxfd+1, &rset, &wset, &eset, tp) < 0) |
437 | { | |
438 | /* otherwise undefined after error */ | |
439 | FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); | |
440 | } | |
9e4abcb5 | 441 | sigprocmask(SIG_SETMASK, &save_mask, NULL); |
3d8df260 | 442 | |
9e4abcb5 SK |
443 | } |
444 | #endif | |
9e4abcb5 | 445 | } |
3d8df260 | 446 | |
9e4abcb5 | 447 | first_loop = 0; |
3be34541 | 448 | now = dnsmasq_time(daemon->uptime_fd); |
9e4abcb5 SK |
449 | |
450 | /* Check for changes to resolv files once per second max. */ | |
3d8df260 SK |
451 | /* Don't go silent for long periods if the clock goes backwards. */ |
452 | if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < 1.0) | |
9e4abcb5 SK |
453 | { |
454 | last = now; | |
33820b7e SK |
455 | |
456 | #ifdef HAVE_ISC_READER | |
3be34541 | 457 | if (daemon->lease_file && !daemon->dhcp) |
fd9fa481 | 458 | load_dhcp(daemon, now); |
33820b7e SK |
459 | #endif |
460 | ||
3be34541 | 461 | if (!(daemon->options & OPT_NO_POLL)) |
9e4abcb5 | 462 | { |
3be34541 | 463 | struct resolvc *res = daemon->resolv_files, *latest = NULL; |
9e4abcb5 | 464 | struct stat statbuf; |
33820b7e | 465 | time_t last_change = 0; |
9e4abcb5 SK |
466 | /* There may be more than one possible file. |
467 | Go through and find the one which changed _last_. | |
468 | Warn of any which can't be read. */ | |
469 | while (res) | |
470 | { | |
471 | if (stat(res->name, &statbuf) == -1) | |
472 | { | |
473 | if (!res->logged) | |
b8187c80 | 474 | syslog(LOG_WARNING, _("failed to access %s: %m"), res->name); |
9e4abcb5 SK |
475 | res->logged = 1; |
476 | } | |
477 | else | |
478 | { | |
479 | res->logged = 0; | |
3d8df260 | 480 | if (statbuf.st_mtime != res->mtime) |
9e4abcb5 | 481 | { |
3d8df260 SK |
482 | res->mtime = statbuf.st_mtime; |
483 | if (difftime(res->mtime, last_change) > 0.0) | |
484 | { | |
485 | last_change = res->mtime; | |
486 | latest = res; | |
487 | } | |
9e4abcb5 SK |
488 | } |
489 | } | |
490 | res = res->next; | |
491 | } | |
492 | ||
3d8df260 | 493 | if (latest) |
9e4abcb5 | 494 | { |
3be34541 | 495 | reload_servers(latest->name, daemon); |
3d8df260 | 496 | check_servers(daemon); |
9e4abcb5 SK |
497 | } |
498 | } | |
499 | } | |
3d8df260 SK |
500 | |
501 | #ifdef HAVE_DBUS | |
502 | /* if we didn't create a DBus connection, retry now. */ | |
503 | if ((daemon->options & OPT_DBUS) && !daemon->dbus) | |
504 | { | |
505 | char *err; | |
506 | if ((err = dbus_init(daemon))) | |
b8187c80 | 507 | syslog(LOG_WARNING, _("DBus error: %s"), err); |
3d8df260 | 508 | if (daemon->dbus) |
b8187c80 | 509 | syslog(LOG_INFO, _("connected to system DBus")); |
3d8df260 SK |
510 | } |
511 | check_dbus_listeners(daemon, &rset, &wset, &eset); | |
512 | #endif | |
513 | ||
3be34541 | 514 | check_dns_listeners(daemon, &rset, now); |
9e4abcb5 | 515 | |
3be34541 SK |
516 | if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset)) |
517 | dhcp_packet(daemon, now); | |
9e4abcb5 SK |
518 | } |
519 | ||
b8187c80 | 520 | syslog(LOG_INFO, _("exiting on receipt of SIGTERM")); |
3d8df260 | 521 | |
3be34541 SK |
522 | if (daemon->dhcp) |
523 | { | |
44a2a316 | 524 | #ifdef HAVE_BROKEN_RTC |
3be34541 | 525 | lease_update_file(1, now); |
44a2a316 | 526 | #endif |
3be34541 SK |
527 | close(daemon->lease_fd); |
528 | } | |
529 | ||
9e4abcb5 SK |
530 | return 0; |
531 | } | |
532 | ||
3be34541 SK |
533 | static void sig_handler(int sig) |
534 | { | |
535 | if (sig == SIGTERM) | |
536 | sigterm = 1; | |
537 | else if (sig == SIGHUP) | |
538 | sighup = 1; | |
539 | else if (sig == SIGUSR1) | |
540 | sigusr1 = 1; | |
541 | else if (sig == SIGALRM) | |
542 | { | |
543 | /* alarm is used to kill children after a fixed time. */ | |
544 | if (in_child) | |
545 | exit(0); | |
546 | else | |
547 | sigalarm = 1; | |
548 | } | |
549 | else if (sig == SIGCHLD) | |
550 | { | |
551 | /* See Stevens 5.10 */ | |
552 | ||
553 | while (waitpid(-1, NULL, WNOHANG) > 0) | |
554 | num_kids--; | |
555 | } | |
556 | } | |
557 | ||
3d8df260 SK |
558 | |
559 | void clear_cache_and_reload(struct daemon *daemon, time_t now) | |
560 | { | |
561 | cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); | |
562 | if (daemon->dhcp) | |
563 | { | |
564 | if (daemon->options & OPT_ETHERS) | |
565 | dhcp_read_ethers(daemon); | |
566 | dhcp_update_configs(daemon->dhcp_conf); | |
b8187c80 | 567 | lease_update_from_configs(daemon); |
3d8df260 SK |
568 | lease_update_file(0, now); |
569 | lease_update_dns(daemon); | |
570 | } | |
571 | } | |
572 | ||
3be34541 SK |
573 | static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd) |
574 | { | |
575 | struct serverfd *serverfdp; | |
576 | struct listener *listener; | |
9e4abcb5 | 577 | |
3be34541 SK |
578 | for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) |
579 | { | |
580 | FD_SET(serverfdp->fd, set); | |
581 | if (serverfdp->fd > maxfd) | |
582 | maxfd = serverfdp->fd; | |
583 | } | |
584 | ||
585 | for (listener = daemon->listeners; listener; listener = listener->next) | |
586 | { | |
587 | FD_SET(listener->fd, set); | |
588 | if (listener->fd > maxfd) | |
589 | maxfd = listener->fd; | |
590 | FD_SET(listener->tcpfd, set); | |
591 | if (listener->tcpfd > maxfd) | |
592 | maxfd = listener->tcpfd; | |
593 | } | |
9e4abcb5 | 594 | |
3be34541 SK |
595 | return maxfd; |
596 | } | |
9e4abcb5 | 597 | |
3be34541 SK |
598 | static void check_dns_listeners(struct daemon *daemon, fd_set *set, time_t now) |
599 | { | |
600 | struct serverfd *serverfdp; | |
601 | struct listener *listener; | |
602 | ||
603 | for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) | |
604 | if (FD_ISSET(serverfdp->fd, set)) | |
605 | reply_query(serverfdp, daemon, now); | |
606 | ||
607 | for (listener = daemon->listeners; listener; listener = listener->next) | |
608 | { | |
609 | if (FD_ISSET(listener->fd, set)) | |
610 | receive_query(listener, daemon, now); | |
611 | ||
612 | if (FD_ISSET(listener->tcpfd, set)) | |
613 | { | |
614 | int confd; | |
f6b7dc47 | 615 | struct in_addr netmask, dst_addr_4; |
3be34541 SK |
616 | |
617 | while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR); | |
618 | ||
619 | if (confd != -1) | |
620 | { | |
f6b7dc47 SK |
621 | union mysockaddr tcp_addr; |
622 | socklen_t tcp_len = sizeof(union mysockaddr); | |
623 | ||
624 | /* Check for allowed interfaces when binding the wildcard address: | |
625 | we do this by looking for an interface with the same address as | |
626 | the local address of the TCP connection, then looking to see if that's | |
627 | an allowed interface. As a side effect, we get the netmask of the | |
628 | interface too, for localisation. */ | |
629 | ||
630 | if ((num_kids >= MAX_PROCS) || | |
631 | (!(daemon->options & OPT_NOWILD) && | |
632 | (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1 || | |
633 | !enumerate_interfaces(daemon, NULL, &tcp_addr, &netmask)))) | |
3be34541 | 634 | close(confd); |
59353a6b | 635 | #ifndef NO_FORK |
3be34541 SK |
636 | else if (!(daemon->options & OPT_DEBUG) && fork()) |
637 | { | |
638 | num_kids++; | |
639 | close(confd); | |
640 | } | |
59353a6b | 641 | #endif |
3be34541 SK |
642 | else |
643 | { | |
3d8df260 | 644 | unsigned char *buff; |
3be34541 SK |
645 | struct server *s; |
646 | int flags; | |
647 | ||
648 | /* Arrange for SIGALARM after CHILD_LIFETIME seconds to | |
649 | terminate the process. */ | |
650 | if (!(daemon->options & OPT_DEBUG)) | |
651 | { | |
652 | sigset_t mask; | |
653 | sigemptyset(&mask); | |
654 | sigaddset(&mask, SIGALRM); | |
655 | sigprocmask(SIG_UNBLOCK, &mask, NULL); | |
656 | alarm(CHILD_LIFETIME); | |
657 | in_child = 1; | |
658 | } | |
659 | ||
660 | /* start with no upstream connections. */ | |
661 | for (s = daemon->servers; s; s = s->next) | |
662 | s->tcpfd = -1; | |
663 | ||
664 | /* The connected socket inherits non-blocking | |
665 | attribute from the listening socket. | |
666 | Reset that here. */ | |
667 | if ((flags = fcntl(confd, F_GETFL, 0)) != -1) | |
668 | fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); | |
669 | ||
f6b7dc47 SK |
670 | if (listener->family == AF_INET) |
671 | { | |
672 | if (daemon->options & OPT_NOWILD) | |
673 | { | |
674 | netmask = listener->iface->netmask; | |
675 | dst_addr_4 = listener->iface->addr.in.sin_addr; | |
676 | } | |
677 | else | |
678 | /* netmask already set by enumerate_interfaces */ | |
679 | dst_addr_4 = tcp_addr.in.sin_addr; | |
680 | } | |
681 | else | |
682 | dst_addr_4.s_addr = 0; | |
683 | ||
684 | buff = tcp_request(daemon, confd, now, dst_addr_4, netmask); | |
3be34541 SK |
685 | |
686 | if (!(daemon->options & OPT_DEBUG)) | |
687 | exit(0); | |
688 | ||
689 | close(confd); | |
690 | if (buff) | |
691 | free(buff); | |
692 | for (s = daemon->servers; s; s = s->next) | |
693 | if (s->tcpfd != -1) | |
694 | close(s->tcpfd); | |
695 | } | |
696 | } | |
697 | } | |
698 | } | |
699 | } | |
700 | ||
701 | int icmp_ping(struct daemon *daemon, struct in_addr addr) | |
702 | { | |
703 | /* Try and get an ICMP echo from a machine. | |
704 | Note that we can't create the raw socket each time | |
705 | we do this, since that needs root. Therefore the socket has to hang | |
706 | around all the time. Since most of the time we won't read the | |
707 | socket, it will accumulate buffers full of ICMP messages, | |
708 | wasting memory. To avoid that we set the receive buffer | |
709 | length to zero except when we're actively pinging. */ | |
710 | ||
711 | /* Note that whilst in the three second wait, we check for | |
712 | (and service) events on the DNS sockets, (so doing that | |
713 | better not use any resources our caller has in use...) | |
714 | but we remain deaf to signals or further DHCP packets. */ | |
715 | ||
716 | struct sockaddr_in saddr; | |
717 | struct { | |
718 | struct ip ip; | |
719 | struct icmp icmp; | |
720 | } packet; | |
721 | unsigned short id = rand16(); | |
722 | unsigned int i, j; | |
723 | int opt = 2000, gotreply = 0; | |
724 | time_t start, now; | |
725 | ||
726 | saddr.sin_family = AF_INET; | |
727 | saddr.sin_port = 0; | |
728 | saddr.sin_addr = addr; | |
729 | #ifdef HAVE_SOCKADDR_SA_LEN | |
730 | saddr.sin_len = sizeof(struct sockaddr_in); | |
731 | #endif | |
732 | ||
733 | memset(&packet.icmp, 0, sizeof(packet.icmp)); | |
734 | packet.icmp.icmp_type = ICMP_ECHO; | |
735 | packet.icmp.icmp_id = id; | |
736 | for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++) | |
737 | j += ((u16 *)&packet.icmp)[i]; | |
738 | while (j>>16) | |
739 | j = (j & 0xffff) + (j >> 16); | |
740 | packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j; | |
741 | ||
742 | setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); | |
743 | ||
fd9fa481 SK |
744 | while (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0, |
745 | (struct sockaddr *)&saddr, sizeof(saddr)) == -1 && | |
746 | retry_send()); | |
747 | ||
748 | for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;) | |
749 | { | |
750 | struct timeval tv; | |
751 | fd_set rset; | |
752 | struct sockaddr_in faddr; | |
3d8df260 SK |
753 | int maxfd; |
754 | socklen_t len = sizeof(faddr); | |
fd9fa481 SK |
755 | |
756 | tv.tv_usec = 250000; | |
757 | tv.tv_sec = 0; | |
758 | ||
759 | FD_ZERO(&rset); | |
760 | FD_SET(daemon->dhcp_icmp_fd, &rset); | |
761 | maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd); | |
3be34541 | 762 | |
fd9fa481 SK |
763 | if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0) |
764 | FD_ZERO(&rset); | |
765 | ||
766 | now = dnsmasq_time(daemon->uptime_fd); | |
767 | check_dns_listeners(daemon, &rset, now); | |
768 | ||
769 | if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) && | |
770 | recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0, | |
771 | (struct sockaddr *)&faddr, &len) == sizeof(packet) && | |
772 | saddr.sin_addr.s_addr == faddr.sin_addr.s_addr && | |
773 | packet.icmp.icmp_type == ICMP_ECHOREPLY && | |
774 | packet.icmp.icmp_seq == 0 && | |
775 | packet.icmp.icmp_id == id) | |
776 | { | |
777 | gotreply = 1; | |
778 | break; | |
779 | } | |
780 | } | |
781 | ||
3be34541 SK |
782 | opt = 1; |
783 | setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); | |
fd9fa481 | 784 | |
3be34541 SK |
785 | return gotreply; |
786 | } | |
0a852541 SK |
787 | |
788 |