blob: 1c96a0e35d074d4124cff98bcd7ad86fbfbfbd15 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelleyc72daea2012-01-05 21:33:27 +000017/* Declare static char *compiler_opts in config.h */
18#define DNSMASQ_COMPILE_OPTS
19
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020#include "dnsmasq.h"
21
Simon Kelley5aabfc72007-08-29 11:24:47 +010022struct daemon *daemon;
23
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static volatile pid_t pid = 0;
25static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley5aabfc72007-08-29 11:24:47 +010027static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
28static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010029static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010030static void async_event(int pipe, time_t now);
Simon Kelleyc72daea2012-01-05 21:33:27 +000031static void fatal_event(struct event_desc *ev, char *msg);
32static int read_event(int fd, struct event_desc *evp, char **msg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000033
34int main (int argc, char **argv)
35{
Simon Kelleyde379512004-06-22 20:23:33 +010036 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000037 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000038 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000039 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010040 int piperead, pipefd[2], err_pipe[2];
41 struct passwd *ent_pw = NULL;
Simon Kelleyc72daea2012-01-05 21:33:27 +000042#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010043 uid_t script_uid = 0;
44 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010045#endif
46 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010047 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010048 char *baduser = NULL;
49 int log_err;
50#if defined(HAVE_LINUX_NETWORK)
51 cap_user_header_t hdr = NULL;
52 cap_user_data_t data = NULL;
Simon Kelley3b3f4412013-10-11 16:33:28 +010053 char *bound_device = NULL;
54 int did_bind = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010055#endif
Vladislav Grishenko408c3682013-09-24 16:18:49 +010056#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
Simon Kelley1f776932012-12-16 19:46:08 +000057 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +010058 struct dhcp_relay *relay;
Vladislav Grishenko408c3682013-09-24 16:18:49 +010059#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010060
Simon Kelley824af852008-02-12 20:43:05 +000061#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000062 setlocale(LC_ALL, "");
63 bindtextdomain("dnsmasq", LOCALEDIR);
64 textdomain("dnsmasq");
65#endif
66
Simon Kelley9e4abcb2004-01-22 19:47:41 +000067 sigact.sa_handler = sig_handler;
68 sigact.sa_flags = 0;
69 sigemptyset(&sigact.sa_mask);
70 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010071 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000072 sigaction(SIGHUP, &sigact, NULL);
73 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000074 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010075 sigaction(SIGCHLD, &sigact, NULL);
76
77 /* ignore SIGPIPE */
78 sigact.sa_handler = SIG_IGN;
79 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000080
Simon Kelley5aabfc72007-08-29 11:24:47 +010081 umask(022); /* known umask, create leases and pid files as 0644 */
82
83 read_opts(argc, argv, compile_opts);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000084
Simon Kelley3be34542004-09-11 19:12:13 +010085 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000086 daemon->edns_pktsz = PACKETSZ;
87#ifdef HAVE_DNSSEC
88 /* Enforce min packet big enough for DNSSEC */
89 if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
90 daemon->edns_pktsz = EDNS_PKTSZ;
91#endif
Simon Kelley3ddacb82014-01-08 14:32:03 +000092
Simon Kelley0a852542005-03-23 20:28:59 +000093 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
94 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
95 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000096
Simon Kelleyc72daea2012-01-05 21:33:27 +000097 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +000098
99#ifdef HAVE_DNSSEC
100 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley5107ace2014-02-23 10:48:32 +0000101 {
102 daemon->keyname = safe_malloc(MAXDNAME);
103 daemon->workspacename = safe_malloc(MAXDNAME);
104 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000105#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000106
Simon Kelley7622fc02009-06-04 20:32:05 +0100107#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100108 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000110 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100111 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000112 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100113#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114
Simon Kelleya2761752012-01-18 16:07:21 +0000115 /* Close any file descriptors we inherited apart from std{in|out|err}
116
117 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
118 otherwise file descriptors we create can end up being 0, 1, or 2
119 and then get accidentally closed later when we make 0, 1, and 2
120 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
121 but it's not guaranteed. By opening /dev/null three times, we
122 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100123 for (i = 0; i < max_fd; i++)
124 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
125 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000126 else
127 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100128
Simon Kelley801ca9a2012-03-06 19:30:17 +0000129#ifndef HAVE_LINUX_NETWORK
130# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000131 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100132 {
133 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000134 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100135 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000136# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100137
138 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100139 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100140 {
141 bind_fallback = 1;
142 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100143 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100144 }
Simon Kelley309331f2006-04-22 15:05:01 +0100145#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100146
Simon Kelley0744ca62014-01-25 16:40:15 +0000147 if (option_bool(OPT_DNSSEC_VALID))
148 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000149#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000150 if (!daemon->ds)
Simon Kelley0744ca62014-01-25 16:40:15 +0000151 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
152
153 if (daemon->cachesize < CACHESIZ)
154 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
155#else
156 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000157#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000158 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000159
Simon Kelley832af0b2007-01-21 20:01:28 +0000160#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100161 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100162 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000163#endif
164
Simon Kelley7de060b2011-08-26 17:24:52 +0100165#ifdef HAVE_CONNTRACK
166 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
167 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
168#else
169 if (option_bool(OPT_CONNTRACK))
170 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
171#endif
172
Simon Kelley824af852008-02-12 20:43:05 +0000173#ifdef HAVE_SOLARIS_NETWORK
174 if (daemon->max_logs != 0)
175 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
176#endif
177
Simon Kelley572b41e2011-02-18 18:11:18 +0000178#ifdef __ANDROID__
179 if (daemon->max_logs != 0)
180 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
181#endif
182
Simon Kelley4820dce2012-12-18 18:30:30 +0000183#ifndef HAVE_AUTH
184 if (daemon->authserver)
185 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
186#endif
187
Simon Kelley1a6bca82008-07-11 11:11:42 +0100188 rand_init();
189
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100190 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000191
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000192 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000193 if (daemon->authinterface && daemon->soa_sn == 0)
194#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000195 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000196#else
197 daemon->soa_sn = now;
198#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000199
Simon Kelleyff7eea22013-09-04 18:01:38 +0100200#ifdef HAVE_DHCP6
201 if (daemon->dhcp6)
202 {
203 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000204
Simon Kelleyff7eea22013-09-04 18:01:38 +0100205 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000206 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100207 if (context->flags & CONTEXT_DHCP)
208 daemon->doing_dhcp6 = 1;
209 if (context->flags & CONTEXT_RA)
210 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000211#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100212 if (context->flags & CONTEXT_TEMPLATE)
213 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000214#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000215 }
Simon Kelley1f776932012-12-16 19:46:08 +0000216 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100217#endif
218
219#ifdef HAVE_DHCP
220 /* Note that order matters here, we must call lease_init before
221 creating any file descriptors which shouldn't be leaked
222 to the lease-script init process. We need to call common_init
223 before lease_init to allocate buffers it uses.*/
224 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
225 {
226 dhcp_common_init();
227 if (daemon->dhcp || daemon->doing_dhcp6)
228 lease_init(now);
229 }
230
231 if (daemon->dhcp || daemon->relay4)
232 dhcp_init();
233
234# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100235 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100236 ra_init(now);
237
238 if (daemon->doing_dhcp6 || daemon->relay6)
239 dhcp6_init();
240# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000241
Simon Kelley7622fc02009-06-04 20:32:05 +0100242#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100243
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000244#ifdef HAVE_IPSET
245 if (daemon->ipsets)
246 ipset_init();
247#endif
248
Simon Kelley1ee9be42013-12-09 16:50:19 +0000249#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000250 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000251#elif defined(HAVE_BSD_NETWORK)
252 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000253#endif
254
Simon Kelley1ee9be42013-12-09 16:50:19 +0000255 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
256 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
257
Simon Kelley115ac3e2013-05-20 11:28:32 +0100258 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100259 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000260
Simon Kelley54dd3932012-06-20 11:23:38 +0100261 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100262 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100263 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100264
265 if (!option_bool(OPT_CLEVERBIND))
266 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
267 if (if_tmp->name && !if_tmp->used)
268 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100269
270#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
271 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100272 bound_device = whichdevice();
273
Simon Kelley9380ba72012-04-16 14:41:56 +0100274 if (daemon->dhcp)
275 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100276 if (!daemon->relay4 && bound_device)
277 {
278 bindtodevice(bound_device, daemon->dhcpfd);
279 did_bind = 1;
280 }
281 if (daemon->enable_pxe && bound_device)
282 {
283 bindtodevice(bound_device, daemon->pxefd);
284 did_bind = 1;
285 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100286 }
287#endif
288
289#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100290 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
291 {
292 bindtodevice(bound_device, daemon->dhcp6fd);
293 did_bind = 1;
294 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100295#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100296 }
Simon Kelley28866e92011-02-14 20:19:14 +0000297 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100298 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000299
300#ifdef HAVE_DHCP6
301 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100302 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000303 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000304
305 /* After netlink_init() and before create_helper() */
306 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000307#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308
Simon Kelley824af852008-02-12 20:43:05 +0000309 if (daemon->port != 0)
Simon Kelley82e3f452014-01-31 21:05:48 +0000310 {
311 cache_init();
312#ifdef HAVE_DNSSEC
313 blockdata_init();
314#endif
315 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100316
Simon Kelley28866e92011-02-14 20:19:14 +0000317 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100318#ifdef HAVE_DBUS
319 {
320 char *err;
321 daemon->dbus = NULL;
322 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100323 if ((err = dbus_init()))
324 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100325 }
326#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100327 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100328#endif
329
Simon Kelley824af852008-02-12 20:43:05 +0000330 if (daemon->port != 0)
331 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100332
Simon Kelleyc72daea2012-01-05 21:33:27 +0000333#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100334 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000335 if ((daemon->dhcp || daemon->dhcp6) &&
336 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000337 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100338 {
339 if ((ent_pw = getpwnam(daemon->scriptuser)))
340 {
341 script_uid = ent_pw->pw_uid;
342 script_gid = ent_pw->pw_gid;
343 }
344 else
345 baduser = daemon->scriptuser;
346 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100347#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348
Simon Kelley1a6bca82008-07-11 11:11:42 +0100349 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
350 baduser = daemon->username;
351 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
352 baduser = daemon->groupname;
353
354 if (baduser)
355 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
356
357 /* implement group defaults, "dip" if available, or group associated with uid */
358 if (!daemon->group_set && !gp)
359 {
360 if (!(gp = getgrnam(CHGRP)) && ent_pw)
361 gp = getgrgid(ent_pw->pw_gid);
362
363 /* for error message */
364 if (gp)
365 daemon->groupname = gp->gr_name;
366 }
367
368#if defined(HAVE_LINUX_NETWORK)
369 /* determine capability API version here, while we can still
370 call safe_malloc */
371 if (ent_pw && ent_pw->pw_uid != 0)
372 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100373 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100374 hdr = safe_malloc(sizeof(*hdr));
375
Simon Kelley1a6bca82008-07-11 11:11:42 +0100376 /* find version supported by kernel */
377 memset(hdr, 0, sizeof(*hdr));
378 capget(hdr, NULL);
379
380 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
381 {
382 /* if unknown version, use largest supported version (3) */
383 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
384 hdr->version = LINUX_CAPABILITY_VERSION_3;
385 capsize = 2;
386 }
387
388 data = safe_malloc(sizeof(*data) * capsize);
389 memset(data, 0, sizeof(*data) * capsize);
390 }
391#endif
392
Simon Kelley5aabfc72007-08-29 11:24:47 +0100393 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100394 in a race-free manner and another to carry errors to daemon-invoking process */
395 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100396
397 piperead = pipefd[0];
398 pipewrite = pipefd[1];
399 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000400 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100401
402 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100403
Simon Kelley28866e92011-02-14 20:19:14 +0000404 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000405 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000406 /* The following code "daemonizes" the process.
407 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100408
Simon Kelley9e038942008-05-30 20:06:34 +0100409 if (chdir("/") != 0)
410 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
411
Simon Kelley16972692006-10-16 20:04:18 +0100412#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000413 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100414 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100415 pid_t pid;
416
Simon Kelley1a6bca82008-07-11 11:11:42 +0100417 /* pipe to carry errors back to original process.
418 When startup is complete we close this and the process terminates. */
419 safe_pipe(err_pipe, 0);
420
Simon Kelley7622fc02009-06-04 20:32:05 +0100421 if ((pid = fork()) == -1)
422 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000423 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100424
Simon Kelley5aabfc72007-08-29 11:24:47 +0100425 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 {
427 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000428 char *msg;
429
Simon Kelley1a6bca82008-07-11 11:11:42 +0100430 /* close our copy of write-end */
431 close(err_pipe[1]);
432
433 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000434 if (read_event(err_pipe[0], &ev, &msg))
435 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100436
437 _exit(EC_GOOD);
438 }
439
440 close(err_pipe[0]);
441
442 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100443
444 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100445
446 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000447 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100448
449 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100450 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100451 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000452#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100453
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000454 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100455 if (daemon->runfile)
456 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100457 int fd, err = 0;
458
459 sprintf(daemon->namebuff, "%d\n", (int) getpid());
460
461 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
462 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
463 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
464 extent that an attacker running as the unprivileged user could replace the pidfile with a
465 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
466
467 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
468 ensuring that the open() fails should there be any existing file (because the unlink() failed,
469 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
470 attack can succeed.
471
472 Any compromise of the non-privileged user still theoretically allows the pid-file to be
473 replaced whilst dnsmasq is running. The worst that could allow is that the usual
474 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
475
476 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
477 failure to write the pid-file.
478 */
479
480 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100481
Simon Kelley79cfefd2012-09-02 13:29:51 +0100482 if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100483 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100484 /* only complain if started as root */
485 if (getuid() == 0)
486 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100487 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100488 else
489 {
490 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
491 err = 1;
492
493 while (!err && close(fd) == -1)
494 if (!retry_send())
495 err = 1;
496 }
497
498 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100499 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000500 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100501 _exit(0);
502 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000503 }
Simon Kelley16972692006-10-16 20:04:18 +0100504 }
505
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100506 log_err = log_start(ent_pw, err_pipe[1]);
507
Simon Kelley28866e92011-02-14 20:19:14 +0000508 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100509 {
510 /* open stdout etc to /dev/null */
511 int nullfd = open("/dev/null", O_RDWR);
512 dup2(nullfd, STDOUT_FILENO);
513 dup2(nullfd, STDERR_FILENO);
514 dup2(nullfd, STDIN_FILENO);
515 close(nullfd);
516 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100517
Simon Kelley1a6bca82008-07-11 11:11:42 +0100518 /* if we are to run scripts, we need to fork a helper before dropping root. */
519 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000520#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000521 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100522 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
523#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100524
Simon Kelley28866e92011-02-14 20:19:14 +0000525 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100526 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100527 int bad_capabilities = 0;
528 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100529
Simon Kelley1a6bca82008-07-11 11:11:42 +0100530 /* remove all supplimentary groups */
531 if (gp &&
532 (setgroups(0, &dummy) == -1 ||
533 setgid(gp->gr_gid) == -1))
534 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000535 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536 _exit(0);
537 }
538
Simon Kelley7cebd202006-05-06 14:13:33 +0100539 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100540 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100541#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100542 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100543 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100544 ports because of DAD, or we're doing it dynamically,
545 we need CAP_NET_BIND_SERVICE too. */
546 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100547 data->effective = data->permitted = data->inheritable =
548 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
549 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
550 else
551 data->effective = data->permitted = data->inheritable =
552 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100553
Simon Kelley16972692006-10-16 20:04:18 +0100554 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000555 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100556 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100557
Simon Kelley7622fc02009-06-04 20:32:05 +0100558#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000559 /* http://developers.sun.com/solaris/articles/program_privileges.html */
560 priv_set_t *priv_set;
561
562 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
563 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
564 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
565 bad_capabilities = errno;
566
567 if (priv_set && bad_capabilities == 0)
568 {
569 priv_inverse(priv_set);
570
571 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
572 bad_capabilities = errno;
573 }
574
575 if (priv_set)
576 priv_freeset(priv_set);
577
Simon Kelley824af852008-02-12 20:43:05 +0000578#endif
579
Simon Kelley1a6bca82008-07-11 11:11:42 +0100580 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100581 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000582 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100583 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100584 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100585
586 /* finally drop root */
587 if (setuid(ent_pw->pw_uid) == -1)
588 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000589 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100590 _exit(0);
591 }
592
593#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100594 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100595 data->effective = data->permitted =
596 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
597 else
598 data->effective = data->permitted =
599 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100600 data->inheritable = 0;
601
602 /* lose the setuid and setgid capbilities */
603 if (capset(hdr, data) == -1)
604 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000605 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100606 _exit(0);
607 }
608#endif
609
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000610 }
Simon Kelley849a8352006-06-09 21:02:31 +0100611 }
Simon Kelley16972692006-10-16 20:04:18 +0100612
Simon Kelley16972692006-10-16 20:04:18 +0100613#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000614 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000615 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100616#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100617
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100618#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100619 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100620 {
621 DIR *dir;
622 struct tftp_prefix *p;
623
624 if (daemon->tftp_prefix)
625 {
626 if (!((dir = opendir(daemon->tftp_prefix))))
627 {
628 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
629 _exit(0);
630 }
631 closedir(dir);
632 }
633
634 for (p = daemon->if_prefix; p; p = p->next)
635 {
636 if (!((dir = opendir(p->prefix))))
637 {
638 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
639 _exit(0);
640 }
641 closedir(dir);
642 }
643 }
644#endif
645
Simon Kelley824af852008-02-12 20:43:05 +0000646 if (daemon->port == 0)
647 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
648 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100649 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000650 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100651 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100652
Simon Kelleyf2621c72007-04-29 19:47:21 +0100653 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100654
Simon Kelley3d8df262005-08-29 12:19:27 +0100655#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000656 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100657 {
658 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100659 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100660 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100661 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100662 }
663#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000664
665 if (option_bool(OPT_LOCAL_SERVICE))
666 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000667
Simon Kelley1d97ac42014-01-31 11:12:27 +0000668#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000669 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000670 {
671 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
672 if (option_bool(OPT_DNSSEC_TIME))
673 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
674 }
Simon Kelleydb737462014-01-31 10:32:45 +0000675#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100676
Simon Kelley1a6bca82008-07-11 11:11:42 +0100677 if (log_err != 0)
678 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
679 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000680
Simon Kelleyde379512004-06-22 20:23:33 +0100681 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100682 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100683
Simon Kelleyf7029f52013-11-21 15:09:09 +0000684 if (option_bool(OPT_NOWILD))
685 warn_bound_listeners();
686
687 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100688
Simon Kelley28866e92011-02-14 20:19:14 +0000689 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000690 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
691 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100692 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100693
Simon Kelley28866e92011-02-14 20:19:14 +0000694 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100695 {
696 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100697 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100698 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000699 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100700 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100701 }
702
Simon Kelleyf2621c72007-04-29 19:47:21 +0100703 if (daemon->max_logs != 0)
704 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000705
Simon Kelleyf2621c72007-04-29 19:47:21 +0100706
Simon Kelley7622fc02009-06-04 20:32:05 +0100707#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000708 for (context = daemon->dhcp; context; context = context->next)
709 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100710
Simon Kelleyff7eea22013-09-04 18:01:38 +0100711 for (relay = daemon->relay4; relay; relay = relay->next)
712 log_relay(AF_INET, relay);
713
Simon Kelley1f776932012-12-16 19:46:08 +0000714# ifdef HAVE_DHCP6
715 for (context = daemon->dhcp6; context; context = context->next)
716 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000717
Simon Kelleyff7eea22013-09-04 18:01:38 +0100718 for (relay = daemon->relay6; relay; relay = relay->next)
719 log_relay(AF_INET6, relay);
720
Simon Kelley1f776932012-12-16 19:46:08 +0000721 if (daemon->doing_dhcp6 || daemon->doing_ra)
722 dhcp_construct_contexts(now);
723
724 if (option_bool(OPT_RA))
725 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
726# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000727
Simon Kelley3b3f4412013-10-11 16:33:28 +0100728# ifdef HAVE_LINUX_NETWORK
729 if (did_bind)
730 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
731# endif
732
Simon Kelley8445f5d2012-12-17 21:54:08 +0000733 /* after dhcp_contruct_contexts */
734 if (daemon->dhcp || daemon->doing_dhcp6)
735 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000736#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000737
Simon Kelley832af0b2007-01-21 20:01:28 +0000738#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100739 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000740 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000741#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100742 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000743 max_fd = FD_SETSIZE;
744#endif
745
Simon Kelley7622fc02009-06-04 20:32:05 +0100746 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100747 daemon->tftp_prefix ? _("root is ") : _("enabled"),
748 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000749 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100750
Simon Kelley832af0b2007-01-21 20:01:28 +0000751 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100752 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000753 a single file will be sent to may clients (the file only needs
754 one fd). */
755
756 max_fd -= 30; /* use other than TFTP */
757
758 if (max_fd < 0)
759 max_fd = 5;
760 else if (max_fd < 100)
761 max_fd = max_fd/2;
762 else
763 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000764
765 /* if we have to use a limited range of ports,
766 that will limit the number of transfers */
767 if (daemon->start_tftp_port != 0 &&
768 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
769 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000770
771 if (daemon->tftp_max > max_fd)
772 {
773 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100774 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100775 _("restricting maximum simultaneous TFTP transfers to %d"),
776 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000777 }
778 }
779#endif
780
Simon Kelley1a6bca82008-07-11 11:11:42 +0100781 /* finished start-up - release original process */
782 if (err_pipe[1] != -1)
783 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784
Simon Kelley824af852008-02-12 20:43:05 +0000785 if (daemon->port != 0)
786 check_servers();
787
Simon Kelley7cebd202006-05-06 14:13:33 +0100788 pid = getpid();
789
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100790 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000791 {
Simon Kelley16972692006-10-16 20:04:18 +0100792 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100793 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100794 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000795
796 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100797 FD_ZERO(&wset);
798 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000799
Simon Kelley16972692006-10-16 20:04:18 +0100800 /* if we are out of resources, find how long we have to wait
801 for some to come free, we'll loop around then and restart
802 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100803 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100804 {
805 t.tv_usec = 0;
806 tp = &t;
807 }
808
Simon Kelley832af0b2007-01-21 20:01:28 +0000809 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
810 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000811 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000812 {
Simon Kelley16972692006-10-16 20:04:18 +0100813 t.tv_sec = 0;
814 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100815 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100817 /* Wake every second whilst waiting for DAD to complete */
818 else if (is_dad_listeners())
819 {
820 t.tv_sec = 1;
821 t.tv_usec = 0;
822 tp = &t;
823 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100824
Simon Kelley832af0b2007-01-21 20:01:28 +0000825#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100826 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100827#endif
828
Simon Kelley7622fc02009-06-04 20:32:05 +0100829#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100830 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100831 {
832 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100833 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000834 if (daemon->pxefd != -1)
835 {
836 FD_SET(daemon->pxefd, &rset);
837 bump_maxfd(daemon->pxefd, &maxfd);
838 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100839 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100840#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100841
Simon Kelley52b92f42012-01-22 16:05:15 +0000842#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100843 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000844 {
845 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000846 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000847 }
848
Simon Kelley1f776932012-12-16 19:46:08 +0000849 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000850 {
851 FD_SET(daemon->icmp6fd, &rset);
852 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000853 }
854#endif
855
Simon Kelley1ee9be42013-12-09 16:50:19 +0000856#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100857 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100858 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000859#elif defined(HAVE_BSD_NETWORK)
860 FD_SET(daemon->routefd, &rset);
861 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100862#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000863
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100864 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100865 bump_maxfd(piperead, &maxfd);
866
Simon Kelley7622fc02009-06-04 20:32:05 +0100867#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100868# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100869 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100870
Simon Kelleya9530962012-03-20 22:07:35 +0000871# ifdef HAVE_TFTP
872 while (helper_buf_empty() && do_tftp_script_run());
873# endif
874
Simon Kelley16972692006-10-16 20:04:18 +0100875 if (!helper_buf_empty())
876 {
877 FD_SET(daemon->helperfd, &wset);
878 bump_maxfd(daemon->helperfd, &maxfd);
879 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100880# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100881 /* need this for other side-effects */
882 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000883
884# ifdef HAVE_TFTP
885 while (do_tftp_script_run());
886# endif
887
Simon Kelley7622fc02009-06-04 20:32:05 +0100888# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100889#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100890
Simon Kelleyf2621c72007-04-29 19:47:21 +0100891 /* must do this just before select(), when we know no
892 more calls to my_syslog() can occur */
893 set_log_writer(&wset, &maxfd);
894
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100895 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
896 {
897 /* otherwise undefined after error */
898 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
899 }
900
901 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000902
Simon Kelleyf2621c72007-04-29 19:47:21 +0100903 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100904
905 /* prime. */
906 enumerate_interfaces(1);
907
Simon Kelley74c95c22011-10-19 09:33:39 +0100908 /* Check the interfaces to see if any have exited DAD state
909 and if so, bind the address. */
910 if (is_dad_listeners())
911 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100912 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100913 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
914 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100915 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100916 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100917
Simon Kelley1ee9be42013-12-09 16:50:19 +0000918#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100919 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000920 netlink_multicast(now);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000921#elif defined(HAVE_BSD_NETWORK)
922 if (FD_ISSET(daemon->routefd, &rset))
923 route_sock(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100924#endif
925
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000926 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100927 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000928 if (daemon->last_resolv == 0 ||
929 difftime(now, daemon->last_resolv) > 1.0 ||
930 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100932 /* poll_resolv doesn't need to reload first time through, since
933 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100934
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100935 poll_resolv(0, daemon->last_resolv != 0, now);
936 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000937 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100938
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100939 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100940 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100941
Simon Kelley3d8df262005-08-29 12:19:27 +0100942#ifdef HAVE_DBUS
943 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000944 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100945 {
946 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100947 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100948 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100949 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100950 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100951 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100952 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100953#endif
Simon Kelley824af852008-02-12 20:43:05 +0000954
Simon Kelley5aabfc72007-08-29 11:24:47 +0100955 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000956
957#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100958 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000959#endif
960
Simon Kelley7622fc02009-06-04 20:32:05 +0100961#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100962 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000963 {
964 if (FD_ISSET(daemon->dhcpfd, &rset))
965 dhcp_packet(now, 0);
966 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
967 dhcp_packet(now, 1);
968 }
Simon Kelley16972692006-10-16 20:04:18 +0100969
Simon Kelley52b92f42012-01-22 16:05:15 +0000970#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100971 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100972 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000973
Simon Kelley1f776932012-12-16 19:46:08 +0000974 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
975 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000976#endif
977
Simon Kelley1f15b812009-10-13 17:49:32 +0100978# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100979 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100980 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100981# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100982#endif
983
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000984 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000985}
986
Simon Kelley3be34542004-09-11 19:12:13 +0100987static void sig_handler(int sig)
988{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100989 if (pid == 0)
990 {
Simon Kelley16972692006-10-16 20:04:18 +0100991 /* ignore anything other than TERM during startup
992 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100993 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100994 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100995 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100996 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100997 {
Simon Kelley16972692006-10-16 20:04:18 +0100998 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100999 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001000 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001001 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001002 else
1003 {
1004 /* master process */
1005 int event, errsave = errno;
1006
1007 if (sig == SIGHUP)
1008 event = EVENT_RELOAD;
1009 else if (sig == SIGCHLD)
1010 event = EVENT_CHILD;
1011 else if (sig == SIGALRM)
1012 event = EVENT_ALARM;
1013 else if (sig == SIGTERM)
1014 event = EVENT_TERM;
1015 else if (sig == SIGUSR1)
1016 event = EVENT_DUMP;
1017 else if (sig == SIGUSR2)
1018 event = EVENT_REOPEN;
1019 else
1020 return;
1021
Simon Kelleyc72daea2012-01-05 21:33:27 +00001022 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001023 errno = errsave;
1024 }
Simon Kelley3be34542004-09-11 19:12:13 +01001025}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001026
Simon Kelley353ae4d2012-03-19 20:07:51 +00001027/* now == 0 -> queue immediate callback */
1028void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001029{
Simon Kelley884a6df2012-03-20 16:20:22 +00001030 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001031 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001032 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1033 if ((now == 0 || difftime(event, now) <= 0.0))
1034 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1035 else
1036 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001037 }
Simon Kelley741c2952012-02-25 13:09:18 +00001038}
1039
Simon Kelleyc72daea2012-01-05 21:33:27 +00001040void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001041{
1042 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001043 struct iovec iov[2];
1044
Simon Kelley5aabfc72007-08-29 11:24:47 +01001045 ev.event = event;
1046 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001047 ev.msg_sz = msg ? strlen(msg) : 0;
1048
1049 iov[0].iov_base = &ev;
1050 iov[0].iov_len = sizeof(ev);
1051 iov[1].iov_base = msg;
1052 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001053
1054 /* error pipe, debug mode. */
1055 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001056 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001057 else
1058 /* pipe is non-blocking and struct event_desc is smaller than
1059 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001060 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001061}
Simon Kelley3d8df262005-08-29 12:19:27 +01001062
Simon Kelleyc72daea2012-01-05 21:33:27 +00001063/* NOTE: the memory used to return msg is leaked: use msgs in events only
1064 to describe fatal errors. */
1065static int read_event(int fd, struct event_desc *evp, char **msg)
1066{
1067 char *buf;
1068
1069 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1070 return 0;
1071
1072 *msg = NULL;
1073
1074 if (evp->msg_sz != 0 &&
1075 (buf = malloc(evp->msg_sz + 1)) &&
1076 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1077 {
1078 buf[evp->msg_sz] = 0;
1079 *msg = buf;
1080 }
1081
1082 return 1;
1083}
1084
1085static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001086{
1087 errno = ev->data;
1088
1089 switch (ev->event)
1090 {
1091 case EVENT_DIE:
1092 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001093
1094 case EVENT_FORK_ERR:
1095 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001096
1097 case EVENT_PIPE_ERR:
1098 die(_("failed to create helper: %s"), NULL, EC_MISC);
1099
1100 case EVENT_CAP_ERR:
1101 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1102
1103 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001104 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001105
1106 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001107 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001108
1109 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001110 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001111
1112 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001113 die(_("cannot open log %s: %s"), msg, EC_FILE);
1114
1115 case EVENT_LUA_ERR:
1116 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001117
1118 case EVENT_TFTP_ERR:
1119 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001120 }
1121}
1122
Simon Kelley5aabfc72007-08-29 11:24:47 +01001123static void async_event(int pipe, time_t now)
1124{
1125 pid_t p;
1126 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001127 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001128 char *msg;
1129
1130 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1131 to describe fatal errors. */
1132
1133 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001134 switch (ev.event)
1135 {
1136 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001137#ifdef HAVE_DNSSEC
1138 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1139 {
1140 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1141 reset_option_bool(OPT_DNSSEC_TIME);
1142 }
1143#endif
1144 /* fall through */
1145
1146 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001147 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001148
Simon Kelley7b1eae42014-02-20 13:43:28 +00001149 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001150 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001151 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1152 {
1153 reload_servers(daemon->resolv_files->name);
1154 check = 1;
1155 }
1156
1157 if (daemon->servers_file)
1158 {
1159 read_servers_file();
1160 check = 1;
1161 }
1162
1163 if (check)
1164 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001165 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001166
Simon Kelley7622fc02009-06-04 20:32:05 +01001167#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001168 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001169#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001170 break;
1171
1172 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001173 if (daemon->port != 0)
1174 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001175 break;
1176
1177 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001178#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001179 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001180 {
1181 lease_prune(NULL, now);
1182 lease_update_file(now);
1183 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001184#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001185 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001186 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1187 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001188#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001189#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001190 break;
1191
1192 case EVENT_CHILD:
1193 /* See Stevens 5.10 */
1194 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1195 if (p == -1)
1196 {
1197 if (errno != EINTR)
1198 break;
1199 }
1200 else
1201 for (i = 0 ; i < MAX_PROCS; i++)
1202 if (daemon->tcp_pids[i] == p)
1203 daemon->tcp_pids[i] = 0;
1204 break;
1205
1206 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001207 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001208 break;
1209
1210 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001211 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001212 break;
1213
1214 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001215 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1216 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001217 break;
1218
Simon Kelley1a6bca82008-07-11 11:11:42 +01001219 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001220 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001221 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001222 case EVENT_LUA_ERR:
1223 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001224 break;
1225
Simon Kelley5aabfc72007-08-29 11:24:47 +01001226 case EVENT_REOPEN:
1227 /* Note: this may leave TCP-handling processes with the old file still open.
1228 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1229 we leave them logging to the old file. */
1230 if (daemon->log_file != NULL)
1231 log_reopen(daemon->log_file);
1232 break;
1233
1234 case EVENT_TERM:
1235 /* Knock all our children on the head. */
1236 for (i = 0; i < MAX_PROCS; i++)
1237 if (daemon->tcp_pids[i] != 0)
1238 kill(daemon->tcp_pids[i], SIGALRM);
1239
Simon Kelleyc72daea2012-01-05 21:33:27 +00001240#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001241 /* handle pending lease transitions */
1242 if (daemon->helperfd != -1)
1243 {
1244 /* block in writes until all done */
1245 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1246 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1247 do {
1248 helper_write();
1249 } while (!helper_buf_empty() || do_script_run(now));
1250 close(daemon->helperfd);
1251 }
1252#endif
1253
1254 if (daemon->lease_stream)
1255 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001256
1257 if (daemon->runfile)
1258 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001259
1260 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1261 flush_log();
1262 exit(EC_GOOD);
1263 }
1264}
1265
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001266void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001267{
1268 struct resolvc *res, *latest;
1269 struct stat statbuf;
1270 time_t last_change = 0;
1271 /* There may be more than one possible file.
1272 Go through and find the one which changed _last_.
1273 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001274
Simon Kelley28866e92011-02-14 20:19:14 +00001275 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001276 return;
1277
Simon Kelley5aabfc72007-08-29 11:24:47 +01001278 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1279 if (stat(res->name, &statbuf) == -1)
1280 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001281 if (force)
1282 {
1283 res->mtime = 0;
1284 continue;
1285 }
1286
Simon Kelley5aabfc72007-08-29 11:24:47 +01001287 if (!res->logged)
1288 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1289 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001290
1291 if (res->mtime != 0)
1292 {
1293 /* existing file evaporated, force selection of the latest
1294 file even if its mtime hasn't changed since we last looked */
1295 poll_resolv(1, do_reload, now);
1296 return;
1297 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001298 }
1299 else
1300 {
1301 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001302 if (force || (statbuf.st_mtime != res->mtime))
1303 {
1304 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001305 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1306 {
1307 last_change = statbuf.st_mtime;
1308 latest = res;
1309 }
1310 }
1311 }
1312
1313 if (latest)
1314 {
1315 static int warned = 0;
1316 if (reload_servers(latest->name))
1317 {
1318 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1319 warned = 0;
1320 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001321 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001322 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001323 }
1324 else
1325 {
1326 latest->mtime = 0;
1327 if (!warned)
1328 {
1329 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1330 warned = 1;
1331 }
1332 }
1333 }
1334}
1335
1336void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001337{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001338 (void)now;
1339
Simon Kelley824af852008-02-12 20:43:05 +00001340 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001341 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001342
Simon Kelley7622fc02009-06-04 20:32:05 +01001343#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001344 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001345 {
Simon Kelley28866e92011-02-14 20:19:14 +00001346 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001347 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001348 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001349 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001350 lease_update_from_configs();
1351 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001352 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001353 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001354#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001355 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001356 /* Not doing DHCP, so no lease system, manage
1357 alarms for ra only */
1358 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001359#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001360#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001361}
1362
Simon Kelley5aabfc72007-08-29 11:24:47 +01001363static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001364{
1365 struct serverfd *serverfdp;
1366 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001367 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001368
1369#ifdef HAVE_TFTP
1370 int tftp = 0;
1371 struct tftp_transfer *transfer;
1372 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1373 {
1374 tftp++;
1375 FD_SET(transfer->sockfd, set);
1376 bump_maxfd(transfer->sockfd, maxfdp);
1377 }
1378#endif
1379
Simon Kelley16972692006-10-16 20:04:18 +01001380 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001381 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001382 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001383
Simon Kelley3be34542004-09-11 19:12:13 +01001384 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1385 {
1386 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001387 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001388 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001389
1390 if (daemon->port != 0 && !daemon->osport)
1391 for (i = 0; i < RANDOM_SOCKS; i++)
1392 if (daemon->randomsocks[i].refcount != 0)
1393 {
1394 FD_SET(daemon->randomsocks[i].fd, set);
1395 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1396 }
1397
Simon Kelley3be34542004-09-11 19:12:13 +01001398 for (listener = daemon->listeners; listener; listener = listener->next)
1399 {
Simon Kelley16972692006-10-16 20:04:18 +01001400 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001401 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001402 {
1403 FD_SET(listener->fd, set);
1404 bump_maxfd(listener->fd, maxfdp);
1405 }
1406
1407 /* death of a child goes through the select loop, so
1408 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001409 if (listener->tcpfd != -1)
1410 for (i = 0; i < MAX_PROCS; i++)
1411 if (daemon->tcp_pids[i] == 0)
1412 {
1413 FD_SET(listener->tcpfd, set);
1414 bump_maxfd(listener->tcpfd, maxfdp);
1415 break;
1416 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001417
Simon Kelley832af0b2007-01-21 20:01:28 +00001418#ifdef HAVE_TFTP
1419 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1420 {
1421 FD_SET(listener->tftpfd, set);
1422 bump_maxfd(listener->tftpfd, maxfdp);
1423 }
1424#endif
1425
1426 }
1427
Simon Kelley16972692006-10-16 20:04:18 +01001428 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001429}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001430
Simon Kelley5aabfc72007-08-29 11:24:47 +01001431static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001432{
1433 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001434 struct listener *listener;
1435 int i;
1436
Simon Kelley832af0b2007-01-21 20:01:28 +00001437 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1438 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001439 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1440
1441 if (daemon->port != 0 && !daemon->osport)
1442 for (i = 0; i < RANDOM_SOCKS; i++)
1443 if (daemon->randomsocks[i].refcount != 0 &&
1444 FD_ISSET(daemon->randomsocks[i].fd, set))
1445 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001446
1447 for (listener = daemon->listeners; listener; listener = listener->next)
1448 {
Simon Kelley824af852008-02-12 20:43:05 +00001449 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001450 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001451
Simon Kelley832af0b2007-01-21 20:01:28 +00001452#ifdef HAVE_TFTP
1453 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001454 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001455#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001456
Simon Kelley824af852008-02-12 20:43:05 +00001457 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001458 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001459 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001460 struct irec *iface = NULL;
1461 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001462 union mysockaddr tcp_addr;
1463 socklen_t tcp_len = sizeof(union mysockaddr);
1464
1465 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001466
Simon Kelley46b06652013-02-04 21:47:59 +00001467 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001468 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001469
Simon Kelley46b06652013-02-04 21:47:59 +00001470 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1471 {
1472 close(confd);
1473 continue;
1474 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001475
1476 /* Make sure that the interface list is up-to-date.
1477
1478 We do this here as we may need the results below, and
1479 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001480
Simon Kelley76dd75d2013-05-23 10:04:25 +01001481 Multiple calls to enumerate_interfaces() per select loop are
1482 inhibited, so calls to it in the child process (which doesn't select())
1483 have no effect. This avoids two processes reading from the same
1484 netlink fd and screwing the pooch entirely.
1485 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001486
Simon Kelley76dd75d2013-05-23 10:04:25 +01001487 enumerate_interfaces(0);
1488
1489 if (option_bool(OPT_NOWILD))
1490 iface = listener->iface; /* May be NULL */
1491 else
1492 {
1493 int if_index;
1494 char intr_name[IF_NAMESIZE];
1495
1496 /* if we can find the arrival interface, check it's one that's allowed */
1497 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1498 indextoname(listener->tcpfd, if_index, intr_name))
1499 {
1500 struct all_addr addr;
1501 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001502#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001503 if (tcp_addr.sa.sa_family == AF_INET6)
1504 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001505#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001506
1507 for (iface = daemon->interfaces; iface; iface = iface->next)
1508 if (iface->index == if_index)
1509 break;
1510
1511 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1512 client_ok = 0;
1513 }
1514
1515 if (option_bool(OPT_CLEVERBIND))
1516 iface = listener->iface; /* May be NULL */
1517 else
1518 {
1519 /* Check for allowed interfaces when binding the wildcard address:
1520 we do this by looking for an interface with the same address as
1521 the local address of the TCP connection, then looking to see if that's
1522 an allowed interface. As a side effect, we get the netmask of the
1523 interface too, for localisation. */
1524
1525 for (iface = daemon->interfaces; iface; iface = iface->next)
1526 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1527 break;
1528
1529 if (!iface)
1530 client_ok = 0;
1531 }
1532 }
1533
Simon Kelley22ce5502013-01-22 13:53:04 +00001534 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001535 {
1536 shutdown(confd, SHUT_RDWR);
1537 close(confd);
1538 }
1539#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001540 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001541 {
1542 if (p != -1)
1543 {
1544 int i;
1545 for (i = 0; i < MAX_PROCS; i++)
1546 if (daemon->tcp_pids[i] == 0)
1547 {
1548 daemon->tcp_pids[i] = p;
1549 break;
1550 }
1551 }
1552 close(confd);
1553 }
1554#endif
1555 else
1556 {
1557 unsigned char *buff;
1558 struct server *s;
1559 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001560 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001561 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001562
1563 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001564 {
1565 netmask = iface->netmask;
1566 auth_dns = iface->dns_auth;
1567 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001568 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001569 {
1570 netmask.s_addr = 0;
1571 auth_dns = 0;
1572 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001573
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001574#ifndef NO_FORK
1575 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1576 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001577 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001578 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001579#endif
1580
Simon Kelley832af0b2007-01-21 20:01:28 +00001581 /* start with no upstream connections. */
1582 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001583 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001584
1585 /* The connected socket inherits non-blocking
1586 attribute from the listening socket.
1587 Reset that here. */
1588 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1589 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1590
Simon Kelley4f7b3042012-11-28 21:27:02 +00001591 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001592
Simon Kelley832af0b2007-01-21 20:01:28 +00001593 shutdown(confd, SHUT_RDWR);
1594 close(confd);
1595
1596 if (buff)
1597 free(buff);
1598
1599 for (s = daemon->servers; s; s = s->next)
1600 if (s->tcpfd != -1)
1601 {
1602 shutdown(s->tcpfd, SHUT_RDWR);
1603 close(s->tcpfd);
1604 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001605#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001606 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001607 {
1608 flush_log();
1609 _exit(0);
1610 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001611#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001612 }
1613 }
1614 }
Simon Kelley3be34542004-09-11 19:12:13 +01001615}
1616
Simon Kelley7622fc02009-06-04 20:32:05 +01001617#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001618int make_icmp_sock(void)
1619{
Simon Kelley7cebd202006-05-06 14:13:33 +01001620 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001621 int zeroopt = 0;
1622
1623 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1624 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001625 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001626 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1627 {
1628 close(fd);
1629 fd = -1;
1630 }
1631 }
1632
1633 return fd;
1634}
1635
Simon Kelley5aabfc72007-08-29 11:24:47 +01001636int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001637{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001638 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001639
1640 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001641 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001642 better not use any resources our caller has in use...)
1643 but we remain deaf to signals or further DHCP packets. */
1644
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001645 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001646 struct sockaddr_in saddr;
1647 struct {
1648 struct ip ip;
1649 struct icmp icmp;
1650 } packet;
1651 unsigned short id = rand16();
1652 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001653 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001654 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001655
Simon Kelley824af852008-02-12 20:43:05 +00001656#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001657 if ((fd = make_icmp_sock()) == -1)
1658 return 0;
1659#else
1660 int opt = 2000;
1661 fd = daemon->dhcp_icmp_fd;
1662 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1663#endif
1664
Simon Kelley3be34542004-09-11 19:12:13 +01001665 saddr.sin_family = AF_INET;
1666 saddr.sin_port = 0;
1667 saddr.sin_addr = addr;
1668#ifdef HAVE_SOCKADDR_SA_LEN
1669 saddr.sin_len = sizeof(struct sockaddr_in);
1670#endif
1671
1672 memset(&packet.icmp, 0, sizeof(packet.icmp));
1673 packet.icmp.icmp_type = ICMP_ECHO;
1674 packet.icmp.icmp_id = id;
1675 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1676 j += ((u16 *)&packet.icmp)[i];
1677 while (j>>16)
1678 j = (j & 0xffff) + (j >> 16);
1679 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1680
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001681 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001682 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1683 retry_send());
1684
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001685 for (now = start = dnsmasq_time();
1686 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001687 {
1688 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001689 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001690 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001691 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001692 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001693
1694 tv.tv_usec = 250000;
1695 tv.tv_sec = 0;
1696
1697 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001698 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001699 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001700 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001701 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001702
1703#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001704 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001705 {
1706 FD_SET(daemon->icmp6fd, &rset);
1707 bump_maxfd(daemon->icmp6fd, &maxfd);
1708 }
1709#endif
1710
Simon Kelleyf2621c72007-04-29 19:47:21 +01001711 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1712 {
1713 FD_ZERO(&rset);
1714 FD_ZERO(&wset);
1715 }
1716
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001717 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001718
1719 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001720 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001721
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001722#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001723 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1724 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001725#endif
1726
Simon Kelley832af0b2007-01-21 20:01:28 +00001727#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001728 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001729#endif
1730
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001731 if (FD_ISSET(fd, &rset) &&
1732 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001733 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1734 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1735 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1736 packet.icmp.icmp_seq == 0 &&
1737 packet.icmp.icmp_id == id)
1738 {
1739 gotreply = 1;
1740 break;
1741 }
1742 }
1743
Simon Kelley824af852008-02-12 20:43:05 +00001744#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001745 close(fd);
1746#else
Simon Kelley3be34542004-09-11 19:12:13 +01001747 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001748 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1749#endif
1750
Simon Kelley3be34542004-09-11 19:12:13 +01001751 return gotreply;
1752}
Simon Kelley7622fc02009-06-04 20:32:05 +01001753#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001754
1755