blob: 03f94493e201035958ed6145f0080b824dd1a84d [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))
101 daemon->keyname = safe_malloc(MAXDNAME);
102#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000103
Simon Kelley7622fc02009-06-04 20:32:05 +0100104#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100105 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000106 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000107 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100108 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100110#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111
Simon Kelleya2761752012-01-18 16:07:21 +0000112 /* Close any file descriptors we inherited apart from std{in|out|err}
113
114 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
115 otherwise file descriptors we create can end up being 0, 1, or 2
116 and then get accidentally closed later when we make 0, 1, and 2
117 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
118 but it's not guaranteed. By opening /dev/null three times, we
119 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100120 for (i = 0; i < max_fd; i++)
121 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
122 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000123 else
124 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100125
Simon Kelley801ca9a2012-03-06 19:30:17 +0000126#ifndef HAVE_LINUX_NETWORK
127# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000128 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100129 {
130 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000131 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100132 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000133# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100134
135 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100136 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100137 {
138 bind_fallback = 1;
139 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100140 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100141 }
Simon Kelley309331f2006-04-22 15:05:01 +0100142#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100143
Simon Kelley0744ca62014-01-25 16:40:15 +0000144 if (option_bool(OPT_DNSSEC_VALID))
145 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000146#ifdef HAVE_DNSSEC
Simon Kelley0744ca62014-01-25 16:40:15 +0000147 if (!daemon->dnskeys)
148 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
149
150 if (daemon->cachesize < CACHESIZ)
151 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
152#else
153 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000154#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000155 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000156
Simon Kelley832af0b2007-01-21 20:01:28 +0000157#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100158 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100159 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000160#endif
161
Simon Kelley7de060b2011-08-26 17:24:52 +0100162#ifdef HAVE_CONNTRACK
163 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
164 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
165#else
166 if (option_bool(OPT_CONNTRACK))
167 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
168#endif
169
Simon Kelley824af852008-02-12 20:43:05 +0000170#ifdef HAVE_SOLARIS_NETWORK
171 if (daemon->max_logs != 0)
172 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
173#endif
174
Simon Kelley572b41e2011-02-18 18:11:18 +0000175#ifdef __ANDROID__
176 if (daemon->max_logs != 0)
177 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
178#endif
179
Simon Kelley4820dce2012-12-18 18:30:30 +0000180#ifndef HAVE_AUTH
181 if (daemon->authserver)
182 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
183#endif
184
Simon Kelley1a6bca82008-07-11 11:11:42 +0100185 rand_init();
186
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100187 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000188
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000189 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000190 if (daemon->authinterface && daemon->soa_sn == 0)
191#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000192 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000193#else
194 daemon->soa_sn = now;
195#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000196
Simon Kelleyff7eea22013-09-04 18:01:38 +0100197#ifdef HAVE_DHCP6
198 if (daemon->dhcp6)
199 {
200 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000201
Simon Kelleyff7eea22013-09-04 18:01:38 +0100202 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000203 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100204 if (context->flags & CONTEXT_DHCP)
205 daemon->doing_dhcp6 = 1;
206 if (context->flags & CONTEXT_RA)
207 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000208#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100209 if (context->flags & CONTEXT_TEMPLATE)
210 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000211#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000212 }
Simon Kelley1f776932012-12-16 19:46:08 +0000213 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100214#endif
215
216#ifdef HAVE_DHCP
217 /* Note that order matters here, we must call lease_init before
218 creating any file descriptors which shouldn't be leaked
219 to the lease-script init process. We need to call common_init
220 before lease_init to allocate buffers it uses.*/
221 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
222 {
223 dhcp_common_init();
224 if (daemon->dhcp || daemon->doing_dhcp6)
225 lease_init(now);
226 }
227
228 if (daemon->dhcp || daemon->relay4)
229 dhcp_init();
230
231# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100232 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100233 ra_init(now);
234
235 if (daemon->doing_dhcp6 || daemon->relay6)
236 dhcp6_init();
237# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000238
Simon Kelley7622fc02009-06-04 20:32:05 +0100239#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100240
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000241#ifdef HAVE_IPSET
242 if (daemon->ipsets)
243 ipset_init();
244#endif
245
Simon Kelley1ee9be42013-12-09 16:50:19 +0000246#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000247 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000248#elif defined(HAVE_BSD_NETWORK)
249 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000250#endif
251
Simon Kelley1ee9be42013-12-09 16:50:19 +0000252 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
253 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
254
Simon Kelley115ac3e2013-05-20 11:28:32 +0100255 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100256 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000257
Simon Kelley54dd3932012-06-20 11:23:38 +0100258 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100259 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100260 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100261
262 if (!option_bool(OPT_CLEVERBIND))
263 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
264 if (if_tmp->name && !if_tmp->used)
265 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100266
267#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
268 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100269 bound_device = whichdevice();
270
Simon Kelley9380ba72012-04-16 14:41:56 +0100271 if (daemon->dhcp)
272 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100273 if (!daemon->relay4 && bound_device)
274 {
275 bindtodevice(bound_device, daemon->dhcpfd);
276 did_bind = 1;
277 }
278 if (daemon->enable_pxe && bound_device)
279 {
280 bindtodevice(bound_device, daemon->pxefd);
281 did_bind = 1;
282 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100283 }
284#endif
285
286#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100287 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
288 {
289 bindtodevice(bound_device, daemon->dhcp6fd);
290 did_bind = 1;
291 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100292#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100293 }
Simon Kelley28866e92011-02-14 20:19:14 +0000294 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100295 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000296
297#ifdef HAVE_DHCP6
298 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100299 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000300 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000301
302 /* After netlink_init() and before create_helper() */
303 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000304#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100305
Simon Kelley824af852008-02-12 20:43:05 +0000306 if (daemon->port != 0)
307 cache_init();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100308
Simon Kelley28866e92011-02-14 20:19:14 +0000309 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100310#ifdef HAVE_DBUS
311 {
312 char *err;
313 daemon->dbus = NULL;
314 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100315 if ((err = dbus_init()))
316 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100317 }
318#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100319 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100320#endif
321
Simon Kelley824af852008-02-12 20:43:05 +0000322 if (daemon->port != 0)
323 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100324
Simon Kelleyc72daea2012-01-05 21:33:27 +0000325#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100326 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000327 if ((daemon->dhcp || daemon->dhcp6) &&
328 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000329 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100330 {
331 if ((ent_pw = getpwnam(daemon->scriptuser)))
332 {
333 script_uid = ent_pw->pw_uid;
334 script_gid = ent_pw->pw_gid;
335 }
336 else
337 baduser = daemon->scriptuser;
338 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100339#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000340
Simon Kelley1a6bca82008-07-11 11:11:42 +0100341 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
342 baduser = daemon->username;
343 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
344 baduser = daemon->groupname;
345
346 if (baduser)
347 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
348
349 /* implement group defaults, "dip" if available, or group associated with uid */
350 if (!daemon->group_set && !gp)
351 {
352 if (!(gp = getgrnam(CHGRP)) && ent_pw)
353 gp = getgrgid(ent_pw->pw_gid);
354
355 /* for error message */
356 if (gp)
357 daemon->groupname = gp->gr_name;
358 }
359
360#if defined(HAVE_LINUX_NETWORK)
361 /* determine capability API version here, while we can still
362 call safe_malloc */
363 if (ent_pw && ent_pw->pw_uid != 0)
364 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100366 hdr = safe_malloc(sizeof(*hdr));
367
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 /* find version supported by kernel */
369 memset(hdr, 0, sizeof(*hdr));
370 capget(hdr, NULL);
371
372 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
373 {
374 /* if unknown version, use largest supported version (3) */
375 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
376 hdr->version = LINUX_CAPABILITY_VERSION_3;
377 capsize = 2;
378 }
379
380 data = safe_malloc(sizeof(*data) * capsize);
381 memset(data, 0, sizeof(*data) * capsize);
382 }
383#endif
384
Simon Kelley5aabfc72007-08-29 11:24:47 +0100385 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100386 in a race-free manner and another to carry errors to daemon-invoking process */
387 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100388
389 piperead = pipefd[0];
390 pipewrite = pipefd[1];
391 /* prime the pipe to load stuff first time. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000392 send_event(pipewrite, EVENT_RELOAD, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100393
394 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100395
Simon Kelley28866e92011-02-14 20:19:14 +0000396 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000397 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000398 /* The following code "daemonizes" the process.
399 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100400
Simon Kelley9e038942008-05-30 20:06:34 +0100401 if (chdir("/") != 0)
402 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
403
Simon Kelley16972692006-10-16 20:04:18 +0100404#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000405 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100406 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100407 pid_t pid;
408
Simon Kelley1a6bca82008-07-11 11:11:42 +0100409 /* pipe to carry errors back to original process.
410 When startup is complete we close this and the process terminates. */
411 safe_pipe(err_pipe, 0);
412
Simon Kelley7622fc02009-06-04 20:32:05 +0100413 if ((pid = fork()) == -1)
414 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000415 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100416
Simon Kelley5aabfc72007-08-29 11:24:47 +0100417 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418 {
419 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000420 char *msg;
421
Simon Kelley1a6bca82008-07-11 11:11:42 +0100422 /* close our copy of write-end */
423 close(err_pipe[1]);
424
425 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000426 if (read_event(err_pipe[0], &ev, &msg))
427 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100428
429 _exit(EC_GOOD);
430 }
431
432 close(err_pipe[0]);
433
434 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100435
436 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100437
438 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000439 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100440
441 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100442 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100443 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000444#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100445
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100447 if (daemon->runfile)
448 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100449 int fd, err = 0;
450
451 sprintf(daemon->namebuff, "%d\n", (int) getpid());
452
453 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
454 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
455 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
456 extent that an attacker running as the unprivileged user could replace the pidfile with a
457 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
458
459 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
460 ensuring that the open() fails should there be any existing file (because the unlink() failed,
461 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
462 attack can succeed.
463
464 Any compromise of the non-privileged user still theoretically allows the pid-file to be
465 replaced whilst dnsmasq is running. The worst that could allow is that the usual
466 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
467
468 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
469 failure to write the pid-file.
470 */
471
472 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100473
Simon Kelley79cfefd2012-09-02 13:29:51 +0100474 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 +0100475 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100476 /* only complain if started as root */
477 if (getuid() == 0)
478 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100479 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100480 else
481 {
482 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
483 err = 1;
484
485 while (!err && close(fd) == -1)
486 if (!retry_send())
487 err = 1;
488 }
489
490 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100491 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000492 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100493 _exit(0);
494 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000495 }
Simon Kelley16972692006-10-16 20:04:18 +0100496 }
497
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100498 log_err = log_start(ent_pw, err_pipe[1]);
499
Simon Kelley28866e92011-02-14 20:19:14 +0000500 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100501 {
502 /* open stdout etc to /dev/null */
503 int nullfd = open("/dev/null", O_RDWR);
504 dup2(nullfd, STDOUT_FILENO);
505 dup2(nullfd, STDERR_FILENO);
506 dup2(nullfd, STDIN_FILENO);
507 close(nullfd);
508 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100509
Simon Kelley1a6bca82008-07-11 11:11:42 +0100510 /* if we are to run scripts, we need to fork a helper before dropping root. */
511 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000512#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000513 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100514 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
515#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100516
Simon Kelley28866e92011-02-14 20:19:14 +0000517 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100518 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100519 int bad_capabilities = 0;
520 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100521
Simon Kelley1a6bca82008-07-11 11:11:42 +0100522 /* remove all supplimentary groups */
523 if (gp &&
524 (setgroups(0, &dummy) == -1 ||
525 setgid(gp->gr_gid) == -1))
526 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000527 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100528 _exit(0);
529 }
530
Simon Kelley7cebd202006-05-06 14:13:33 +0100531 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100532 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100533#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100534 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100535 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100536 ports because of DAD, or we're doing it dynamically,
537 we need CAP_NET_BIND_SERVICE too. */
538 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100539 data->effective = data->permitted = data->inheritable =
540 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
541 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
542 else
543 data->effective = data->permitted = data->inheritable =
544 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100545
Simon Kelley16972692006-10-16 20:04:18 +0100546 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000547 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100548 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100549
Simon Kelley7622fc02009-06-04 20:32:05 +0100550#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000551 /* http://developers.sun.com/solaris/articles/program_privileges.html */
552 priv_set_t *priv_set;
553
554 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
555 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
556 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
557 bad_capabilities = errno;
558
559 if (priv_set && bad_capabilities == 0)
560 {
561 priv_inverse(priv_set);
562
563 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
564 bad_capabilities = errno;
565 }
566
567 if (priv_set)
568 priv_freeset(priv_set);
569
Simon Kelley824af852008-02-12 20:43:05 +0000570#endif
571
Simon Kelley1a6bca82008-07-11 11:11:42 +0100572 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100573 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000574 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100575 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100576 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100577
578 /* finally drop root */
579 if (setuid(ent_pw->pw_uid) == -1)
580 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000581 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100582 _exit(0);
583 }
584
585#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100586 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100587 data->effective = data->permitted =
588 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
589 else
590 data->effective = data->permitted =
591 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100592 data->inheritable = 0;
593
594 /* lose the setuid and setgid capbilities */
595 if (capset(hdr, data) == -1)
596 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000597 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100598 _exit(0);
599 }
600#endif
601
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000602 }
Simon Kelley849a8352006-06-09 21:02:31 +0100603 }
Simon Kelley16972692006-10-16 20:04:18 +0100604
Simon Kelley16972692006-10-16 20:04:18 +0100605#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000606 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000607 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100608#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100609
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100610#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100611 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100612 {
613 DIR *dir;
614 struct tftp_prefix *p;
615
616 if (daemon->tftp_prefix)
617 {
618 if (!((dir = opendir(daemon->tftp_prefix))))
619 {
620 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
621 _exit(0);
622 }
623 closedir(dir);
624 }
625
626 for (p = daemon->if_prefix; p; p = p->next)
627 {
628 if (!((dir = opendir(p->prefix))))
629 {
630 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
631 _exit(0);
632 }
633 closedir(dir);
634 }
635 }
636#endif
637
Simon Kelley824af852008-02-12 20:43:05 +0000638 if (daemon->port == 0)
639 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
640 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100641 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000642 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100643 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100644
Simon Kelleyf2621c72007-04-29 19:47:21 +0100645 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100646
Simon Kelley3d8df262005-08-29 12:19:27 +0100647#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000648 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100649 {
650 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100651 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100652 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100653 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100654 }
655#endif
Simon Kelleydb737462014-01-31 10:32:45 +0000656
Simon Kelley1d97ac42014-01-31 11:12:27 +0000657#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000658 if (option_bool(OPT_DNSSEC_VALID))
659 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
660#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100661
Simon Kelley1a6bca82008-07-11 11:11:42 +0100662 if (log_err != 0)
663 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
664 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000665
Simon Kelleyde379512004-06-22 20:23:33 +0100666 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100667 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100668
Simon Kelleyf7029f52013-11-21 15:09:09 +0000669 if (option_bool(OPT_NOWILD))
670 warn_bound_listeners();
671
672 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100673
Simon Kelley28866e92011-02-14 20:19:14 +0000674 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000675 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
676 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100677 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100678
Simon Kelley28866e92011-02-14 20:19:14 +0000679 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100680 {
681 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100682 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100683 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000684 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100685 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100686 }
687
Simon Kelleyf2621c72007-04-29 19:47:21 +0100688 if (daemon->max_logs != 0)
689 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000690
Simon Kelleyf2621c72007-04-29 19:47:21 +0100691
Simon Kelley7622fc02009-06-04 20:32:05 +0100692#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000693 for (context = daemon->dhcp; context; context = context->next)
694 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100695
Simon Kelleyff7eea22013-09-04 18:01:38 +0100696 for (relay = daemon->relay4; relay; relay = relay->next)
697 log_relay(AF_INET, relay);
698
Simon Kelley1f776932012-12-16 19:46:08 +0000699# ifdef HAVE_DHCP6
700 for (context = daemon->dhcp6; context; context = context->next)
701 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000702
Simon Kelleyff7eea22013-09-04 18:01:38 +0100703 for (relay = daemon->relay6; relay; relay = relay->next)
704 log_relay(AF_INET6, relay);
705
Simon Kelley1f776932012-12-16 19:46:08 +0000706 if (daemon->doing_dhcp6 || daemon->doing_ra)
707 dhcp_construct_contexts(now);
708
709 if (option_bool(OPT_RA))
710 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
711# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000712
Simon Kelley3b3f4412013-10-11 16:33:28 +0100713# ifdef HAVE_LINUX_NETWORK
714 if (did_bind)
715 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
716# endif
717
Simon Kelley8445f5d2012-12-17 21:54:08 +0000718 /* after dhcp_contruct_contexts */
719 if (daemon->dhcp || daemon->doing_dhcp6)
720 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000721#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000722
Simon Kelley832af0b2007-01-21 20:01:28 +0000723#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100724 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000725 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000726#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100727 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000728 max_fd = FD_SETSIZE;
729#endif
730
Simon Kelley7622fc02009-06-04 20:32:05 +0100731 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100732 daemon->tftp_prefix ? _("root is ") : _("enabled"),
733 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000734 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100735
Simon Kelley832af0b2007-01-21 20:01:28 +0000736 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100737 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000738 a single file will be sent to may clients (the file only needs
739 one fd). */
740
741 max_fd -= 30; /* use other than TFTP */
742
743 if (max_fd < 0)
744 max_fd = 5;
745 else if (max_fd < 100)
746 max_fd = max_fd/2;
747 else
748 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000749
750 /* if we have to use a limited range of ports,
751 that will limit the number of transfers */
752 if (daemon->start_tftp_port != 0 &&
753 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
754 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000755
756 if (daemon->tftp_max > max_fd)
757 {
758 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100759 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100760 _("restricting maximum simultaneous TFTP transfers to %d"),
761 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000762 }
763 }
764#endif
765
Simon Kelley1a6bca82008-07-11 11:11:42 +0100766 /* finished start-up - release original process */
767 if (err_pipe[1] != -1)
768 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000769
Simon Kelley824af852008-02-12 20:43:05 +0000770 if (daemon->port != 0)
771 check_servers();
772
Simon Kelley7cebd202006-05-06 14:13:33 +0100773 pid = getpid();
774
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100775 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000776 {
Simon Kelley16972692006-10-16 20:04:18 +0100777 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100778 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100779 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000780
781 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100782 FD_ZERO(&wset);
783 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784
Simon Kelley16972692006-10-16 20:04:18 +0100785 /* if we are out of resources, find how long we have to wait
786 for some to come free, we'll loop around then and restart
787 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100788 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100789 {
790 t.tv_usec = 0;
791 tp = &t;
792 }
793
Simon Kelley832af0b2007-01-21 20:01:28 +0000794 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
795 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000796 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000797 {
Simon Kelley16972692006-10-16 20:04:18 +0100798 t.tv_sec = 0;
799 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100800 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000801 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100802 /* Wake every second whilst waiting for DAD to complete */
803 else if (is_dad_listeners())
804 {
805 t.tv_sec = 1;
806 t.tv_usec = 0;
807 tp = &t;
808 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100809
Simon Kelley832af0b2007-01-21 20:01:28 +0000810#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100811 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100812#endif
813
Simon Kelley7622fc02009-06-04 20:32:05 +0100814#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100815 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100816 {
817 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100818 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000819 if (daemon->pxefd != -1)
820 {
821 FD_SET(daemon->pxefd, &rset);
822 bump_maxfd(daemon->pxefd, &maxfd);
823 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100824 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100825#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100826
Simon Kelley52b92f42012-01-22 16:05:15 +0000827#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100828 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000829 {
830 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000831 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000832 }
833
Simon Kelley1f776932012-12-16 19:46:08 +0000834 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000835 {
836 FD_SET(daemon->icmp6fd, &rset);
837 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000838 }
839#endif
840
Simon Kelley1ee9be42013-12-09 16:50:19 +0000841#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100842 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100843 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000844#elif defined(HAVE_BSD_NETWORK)
845 FD_SET(daemon->routefd, &rset);
846 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100847#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000848
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100849 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100850 bump_maxfd(piperead, &maxfd);
851
Simon Kelley7622fc02009-06-04 20:32:05 +0100852#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100853# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100854 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100855
Simon Kelleya9530962012-03-20 22:07:35 +0000856# ifdef HAVE_TFTP
857 while (helper_buf_empty() && do_tftp_script_run());
858# endif
859
Simon Kelley16972692006-10-16 20:04:18 +0100860 if (!helper_buf_empty())
861 {
862 FD_SET(daemon->helperfd, &wset);
863 bump_maxfd(daemon->helperfd, &maxfd);
864 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100865# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100866 /* need this for other side-effects */
867 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000868
869# ifdef HAVE_TFTP
870 while (do_tftp_script_run());
871# endif
872
Simon Kelley7622fc02009-06-04 20:32:05 +0100873# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100874#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100875
Simon Kelleyf2621c72007-04-29 19:47:21 +0100876 /* must do this just before select(), when we know no
877 more calls to my_syslog() can occur */
878 set_log_writer(&wset, &maxfd);
879
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100880 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
881 {
882 /* otherwise undefined after error */
883 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
884 }
885
886 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000887
Simon Kelleyf2621c72007-04-29 19:47:21 +0100888 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100889
890 /* prime. */
891 enumerate_interfaces(1);
892
Simon Kelley74c95c22011-10-19 09:33:39 +0100893 /* Check the interfaces to see if any have exited DAD state
894 and if so, bind the address. */
895 if (is_dad_listeners())
896 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100897 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100898 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
899 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100900 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100901 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100902
Simon Kelley1ee9be42013-12-09 16:50:19 +0000903#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100904 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelley1f776932012-12-16 19:46:08 +0000905 netlink_multicast(now);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000906#elif defined(HAVE_BSD_NETWORK)
907 if (FD_ISSET(daemon->routefd, &rset))
908 route_sock(now);
Simon Kelleyc52e1892010-06-07 22:01:39 +0100909#endif
910
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000911 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100912 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000913 if (daemon->last_resolv == 0 ||
914 difftime(now, daemon->last_resolv) > 1.0 ||
915 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000916 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100917 /* poll_resolv doesn't need to reload first time through, since
918 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100919
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100920 poll_resolv(0, daemon->last_resolv != 0, now);
921 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000922 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100923
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100924 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100925 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100926
Simon Kelley3d8df262005-08-29 12:19:27 +0100927#ifdef HAVE_DBUS
928 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000929 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100930 {
931 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100932 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100933 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100934 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100935 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100936 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100938#endif
Simon Kelley824af852008-02-12 20:43:05 +0000939
Simon Kelley5aabfc72007-08-29 11:24:47 +0100940 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000941
942#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100943 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000944#endif
945
Simon Kelley7622fc02009-06-04 20:32:05 +0100946#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100947 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000948 {
949 if (FD_ISSET(daemon->dhcpfd, &rset))
950 dhcp_packet(now, 0);
951 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
952 dhcp_packet(now, 1);
953 }
Simon Kelley16972692006-10-16 20:04:18 +0100954
Simon Kelley52b92f42012-01-22 16:05:15 +0000955#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100956 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100957 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000958
Simon Kelley1f776932012-12-16 19:46:08 +0000959 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
960 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000961#endif
962
Simon Kelley1f15b812009-10-13 17:49:32 +0100963# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100964 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100965 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100966# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100967#endif
968
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000969 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970}
971
Simon Kelley3be34542004-09-11 19:12:13 +0100972static void sig_handler(int sig)
973{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100974 if (pid == 0)
975 {
Simon Kelley16972692006-10-16 20:04:18 +0100976 /* ignore anything other than TERM during startup
977 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100978 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100979 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100980 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100981 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100982 {
Simon Kelley16972692006-10-16 20:04:18 +0100983 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100984 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +0100985 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100986 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100987 else
988 {
989 /* master process */
990 int event, errsave = errno;
991
992 if (sig == SIGHUP)
993 event = EVENT_RELOAD;
994 else if (sig == SIGCHLD)
995 event = EVENT_CHILD;
996 else if (sig == SIGALRM)
997 event = EVENT_ALARM;
998 else if (sig == SIGTERM)
999 event = EVENT_TERM;
1000 else if (sig == SIGUSR1)
1001 event = EVENT_DUMP;
1002 else if (sig == SIGUSR2)
1003 event = EVENT_REOPEN;
1004 else
1005 return;
1006
Simon Kelleyc72daea2012-01-05 21:33:27 +00001007 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001008 errno = errsave;
1009 }
Simon Kelley3be34542004-09-11 19:12:13 +01001010}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001011
Simon Kelley353ae4d2012-03-19 20:07:51 +00001012/* now == 0 -> queue immediate callback */
1013void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001014{
Simon Kelley884a6df2012-03-20 16:20:22 +00001015 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001016 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001017 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1018 if ((now == 0 || difftime(event, now) <= 0.0))
1019 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1020 else
1021 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001022 }
Simon Kelley741c2952012-02-25 13:09:18 +00001023}
1024
Simon Kelleyc72daea2012-01-05 21:33:27 +00001025void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001026{
1027 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001028 struct iovec iov[2];
1029
Simon Kelley5aabfc72007-08-29 11:24:47 +01001030 ev.event = event;
1031 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001032 ev.msg_sz = msg ? strlen(msg) : 0;
1033
1034 iov[0].iov_base = &ev;
1035 iov[0].iov_len = sizeof(ev);
1036 iov[1].iov_base = msg;
1037 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001038
1039 /* error pipe, debug mode. */
1040 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001041 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001042 else
1043 /* pipe is non-blocking and struct event_desc is smaller than
1044 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001045 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001046}
Simon Kelley3d8df262005-08-29 12:19:27 +01001047
Simon Kelleyc72daea2012-01-05 21:33:27 +00001048/* NOTE: the memory used to return msg is leaked: use msgs in events only
1049 to describe fatal errors. */
1050static int read_event(int fd, struct event_desc *evp, char **msg)
1051{
1052 char *buf;
1053
1054 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1055 return 0;
1056
1057 *msg = NULL;
1058
1059 if (evp->msg_sz != 0 &&
1060 (buf = malloc(evp->msg_sz + 1)) &&
1061 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1062 {
1063 buf[evp->msg_sz] = 0;
1064 *msg = buf;
1065 }
1066
1067 return 1;
1068}
1069
1070static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001071{
1072 errno = ev->data;
1073
1074 switch (ev->event)
1075 {
1076 case EVENT_DIE:
1077 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001078
1079 case EVENT_FORK_ERR:
1080 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001081
1082 case EVENT_PIPE_ERR:
1083 die(_("failed to create helper: %s"), NULL, EC_MISC);
1084
1085 case EVENT_CAP_ERR:
1086 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1087
1088 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001089 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001090
1091 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001092 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001093
1094 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001095 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001096
1097 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001098 die(_("cannot open log %s: %s"), msg, EC_FILE);
1099
1100 case EVENT_LUA_ERR:
1101 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001102
1103 case EVENT_TFTP_ERR:
1104 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001105 }
1106}
1107
Simon Kelley5aabfc72007-08-29 11:24:47 +01001108static void async_event(int pipe, time_t now)
1109{
1110 pid_t p;
1111 struct event_desc ev;
1112 int i;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001113 char *msg;
1114
1115 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1116 to describe fatal errors. */
1117
1118 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001119 switch (ev.event)
1120 {
1121 case EVENT_RELOAD:
1122 clear_cache_and_reload(now);
Simon Kelley28866e92011-02-14 20:19:14 +00001123 if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001124 {
1125 reload_servers(daemon->resolv_files->name);
1126 check_servers();
1127 }
Simon Kelley7622fc02009-06-04 20:32:05 +01001128#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001129 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001130#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001131 break;
1132
1133 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001134 if (daemon->port != 0)
1135 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001136 break;
1137
1138 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001139#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001140 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001141 {
1142 lease_prune(NULL, now);
1143 lease_update_file(now);
1144 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001145#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001146 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001147 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1148 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001149#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001150#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001151 break;
1152
1153 case EVENT_CHILD:
1154 /* See Stevens 5.10 */
1155 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1156 if (p == -1)
1157 {
1158 if (errno != EINTR)
1159 break;
1160 }
1161 else
1162 for (i = 0 ; i < MAX_PROCS; i++)
1163 if (daemon->tcp_pids[i] == p)
1164 daemon->tcp_pids[i] = 0;
1165 break;
1166
1167 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001168 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001169 break;
1170
1171 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001172 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001173 break;
1174
1175 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001176 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1177 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001178 break;
1179
Simon Kelley1a6bca82008-07-11 11:11:42 +01001180 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001181 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001182 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001183 case EVENT_LUA_ERR:
1184 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001185 break;
1186
Simon Kelley5aabfc72007-08-29 11:24:47 +01001187 case EVENT_REOPEN:
1188 /* Note: this may leave TCP-handling processes with the old file still open.
1189 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1190 we leave them logging to the old file. */
1191 if (daemon->log_file != NULL)
1192 log_reopen(daemon->log_file);
1193 break;
1194
1195 case EVENT_TERM:
1196 /* Knock all our children on the head. */
1197 for (i = 0; i < MAX_PROCS; i++)
1198 if (daemon->tcp_pids[i] != 0)
1199 kill(daemon->tcp_pids[i], SIGALRM);
1200
Simon Kelleyc72daea2012-01-05 21:33:27 +00001201#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001202 /* handle pending lease transitions */
1203 if (daemon->helperfd != -1)
1204 {
1205 /* block in writes until all done */
1206 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1207 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1208 do {
1209 helper_write();
1210 } while (!helper_buf_empty() || do_script_run(now));
1211 close(daemon->helperfd);
1212 }
1213#endif
1214
1215 if (daemon->lease_stream)
1216 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001217
1218 if (daemon->runfile)
1219 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001220
1221 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1222 flush_log();
1223 exit(EC_GOOD);
1224 }
1225}
1226
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001227void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001228{
1229 struct resolvc *res, *latest;
1230 struct stat statbuf;
1231 time_t last_change = 0;
1232 /* There may be more than one possible file.
1233 Go through and find the one which changed _last_.
1234 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001235
Simon Kelley28866e92011-02-14 20:19:14 +00001236 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001237 return;
1238
Simon Kelley5aabfc72007-08-29 11:24:47 +01001239 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1240 if (stat(res->name, &statbuf) == -1)
1241 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001242 if (force)
1243 {
1244 res->mtime = 0;
1245 continue;
1246 }
1247
Simon Kelley5aabfc72007-08-29 11:24:47 +01001248 if (!res->logged)
1249 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1250 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001251
1252 if (res->mtime != 0)
1253 {
1254 /* existing file evaporated, force selection of the latest
1255 file even if its mtime hasn't changed since we last looked */
1256 poll_resolv(1, do_reload, now);
1257 return;
1258 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001259 }
1260 else
1261 {
1262 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001263 if (force || (statbuf.st_mtime != res->mtime))
1264 {
1265 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001266 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1267 {
1268 last_change = statbuf.st_mtime;
1269 latest = res;
1270 }
1271 }
1272 }
1273
1274 if (latest)
1275 {
1276 static int warned = 0;
1277 if (reload_servers(latest->name))
1278 {
1279 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1280 warned = 0;
1281 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001282 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001283 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001284 }
1285 else
1286 {
1287 latest->mtime = 0;
1288 if (!warned)
1289 {
1290 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1291 warned = 1;
1292 }
1293 }
1294 }
1295}
1296
1297void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001298{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001299 (void)now;
1300
Simon Kelley824af852008-02-12 20:43:05 +00001301 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001302 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001303
Simon Kelley7622fc02009-06-04 20:32:05 +01001304#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001305 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001306 {
Simon Kelley28866e92011-02-14 20:19:14 +00001307 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001308 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001309 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001310 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001311 lease_update_from_configs();
1312 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001313 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001314 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001315#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001316 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001317 /* Not doing DHCP, so no lease system, manage
1318 alarms for ra only */
1319 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001320#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001321#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001322}
1323
Simon Kelley5aabfc72007-08-29 11:24:47 +01001324static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001325{
1326 struct serverfd *serverfdp;
1327 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001328 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001329
1330#ifdef HAVE_TFTP
1331 int tftp = 0;
1332 struct tftp_transfer *transfer;
1333 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1334 {
1335 tftp++;
1336 FD_SET(transfer->sockfd, set);
1337 bump_maxfd(transfer->sockfd, maxfdp);
1338 }
1339#endif
1340
Simon Kelley16972692006-10-16 20:04:18 +01001341 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001342 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001343 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001344
Simon Kelley3be34542004-09-11 19:12:13 +01001345 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1346 {
1347 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001348 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001349 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001350
1351 if (daemon->port != 0 && !daemon->osport)
1352 for (i = 0; i < RANDOM_SOCKS; i++)
1353 if (daemon->randomsocks[i].refcount != 0)
1354 {
1355 FD_SET(daemon->randomsocks[i].fd, set);
1356 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1357 }
1358
Simon Kelley3be34542004-09-11 19:12:13 +01001359 for (listener = daemon->listeners; listener; listener = listener->next)
1360 {
Simon Kelley16972692006-10-16 20:04:18 +01001361 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001362 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001363 {
1364 FD_SET(listener->fd, set);
1365 bump_maxfd(listener->fd, maxfdp);
1366 }
1367
1368 /* death of a child goes through the select loop, so
1369 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001370 if (listener->tcpfd != -1)
1371 for (i = 0; i < MAX_PROCS; i++)
1372 if (daemon->tcp_pids[i] == 0)
1373 {
1374 FD_SET(listener->tcpfd, set);
1375 bump_maxfd(listener->tcpfd, maxfdp);
1376 break;
1377 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001378
Simon Kelley832af0b2007-01-21 20:01:28 +00001379#ifdef HAVE_TFTP
1380 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1381 {
1382 FD_SET(listener->tftpfd, set);
1383 bump_maxfd(listener->tftpfd, maxfdp);
1384 }
1385#endif
1386
1387 }
1388
Simon Kelley16972692006-10-16 20:04:18 +01001389 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001390}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001391
Simon Kelley5aabfc72007-08-29 11:24:47 +01001392static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001393{
1394 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001395 struct listener *listener;
1396 int i;
1397
Simon Kelley832af0b2007-01-21 20:01:28 +00001398 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1399 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001400 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1401
1402 if (daemon->port != 0 && !daemon->osport)
1403 for (i = 0; i < RANDOM_SOCKS; i++)
1404 if (daemon->randomsocks[i].refcount != 0 &&
1405 FD_ISSET(daemon->randomsocks[i].fd, set))
1406 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001407
1408 for (listener = daemon->listeners; listener; listener = listener->next)
1409 {
Simon Kelley824af852008-02-12 20:43:05 +00001410 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001411 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001412
Simon Kelley832af0b2007-01-21 20:01:28 +00001413#ifdef HAVE_TFTP
1414 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001415 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001416#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001417
Simon Kelley824af852008-02-12 20:43:05 +00001418 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001419 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001420 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001421 struct irec *iface = NULL;
1422 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001423 union mysockaddr tcp_addr;
1424 socklen_t tcp_len = sizeof(union mysockaddr);
1425
1426 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001427
Simon Kelley46b06652013-02-04 21:47:59 +00001428 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001429 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001430
Simon Kelley46b06652013-02-04 21:47:59 +00001431 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1432 {
1433 close(confd);
1434 continue;
1435 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001436
1437 /* Make sure that the interface list is up-to-date.
1438
1439 We do this here as we may need the results below, and
1440 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001441
Simon Kelley76dd75d2013-05-23 10:04:25 +01001442 Multiple calls to enumerate_interfaces() per select loop are
1443 inhibited, so calls to it in the child process (which doesn't select())
1444 have no effect. This avoids two processes reading from the same
1445 netlink fd and screwing the pooch entirely.
1446 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001447
Simon Kelley76dd75d2013-05-23 10:04:25 +01001448 enumerate_interfaces(0);
1449
1450 if (option_bool(OPT_NOWILD))
1451 iface = listener->iface; /* May be NULL */
1452 else
1453 {
1454 int if_index;
1455 char intr_name[IF_NAMESIZE];
1456
1457 /* if we can find the arrival interface, check it's one that's allowed */
1458 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1459 indextoname(listener->tcpfd, if_index, intr_name))
1460 {
1461 struct all_addr addr;
1462 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001463#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001464 if (tcp_addr.sa.sa_family == AF_INET6)
1465 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001466#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001467
1468 for (iface = daemon->interfaces; iface; iface = iface->next)
1469 if (iface->index == if_index)
1470 break;
1471
1472 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1473 client_ok = 0;
1474 }
1475
1476 if (option_bool(OPT_CLEVERBIND))
1477 iface = listener->iface; /* May be NULL */
1478 else
1479 {
1480 /* Check for allowed interfaces when binding the wildcard address:
1481 we do this by looking for an interface with the same address as
1482 the local address of the TCP connection, then looking to see if that's
1483 an allowed interface. As a side effect, we get the netmask of the
1484 interface too, for localisation. */
1485
1486 for (iface = daemon->interfaces; iface; iface = iface->next)
1487 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1488 break;
1489
1490 if (!iface)
1491 client_ok = 0;
1492 }
1493 }
1494
Simon Kelley22ce5502013-01-22 13:53:04 +00001495 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001496 {
1497 shutdown(confd, SHUT_RDWR);
1498 close(confd);
1499 }
1500#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001501 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001502 {
1503 if (p != -1)
1504 {
1505 int i;
1506 for (i = 0; i < MAX_PROCS; i++)
1507 if (daemon->tcp_pids[i] == 0)
1508 {
1509 daemon->tcp_pids[i] = p;
1510 break;
1511 }
1512 }
1513 close(confd);
1514 }
1515#endif
1516 else
1517 {
1518 unsigned char *buff;
1519 struct server *s;
1520 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001521 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001522 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001523
1524 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001525 {
1526 netmask = iface->netmask;
1527 auth_dns = iface->dns_auth;
1528 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001529 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001530 {
1531 netmask.s_addr = 0;
1532 auth_dns = 0;
1533 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001534
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001535#ifndef NO_FORK
1536 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1537 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001538 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001539 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001540#endif
1541
Simon Kelley832af0b2007-01-21 20:01:28 +00001542 /* start with no upstream connections. */
1543 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001544 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001545
1546 /* The connected socket inherits non-blocking
1547 attribute from the listening socket.
1548 Reset that here. */
1549 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1550 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1551
Simon Kelley4f7b3042012-11-28 21:27:02 +00001552 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001553
Simon Kelley832af0b2007-01-21 20:01:28 +00001554 shutdown(confd, SHUT_RDWR);
1555 close(confd);
1556
1557 if (buff)
1558 free(buff);
1559
1560 for (s = daemon->servers; s; s = s->next)
1561 if (s->tcpfd != -1)
1562 {
1563 shutdown(s->tcpfd, SHUT_RDWR);
1564 close(s->tcpfd);
1565 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001566#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001567 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001568 {
1569 flush_log();
1570 _exit(0);
1571 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001572#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001573 }
1574 }
1575 }
Simon Kelley3be34542004-09-11 19:12:13 +01001576}
1577
Simon Kelley7622fc02009-06-04 20:32:05 +01001578#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001579int make_icmp_sock(void)
1580{
Simon Kelley7cebd202006-05-06 14:13:33 +01001581 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001582 int zeroopt = 0;
1583
1584 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1585 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001586 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001587 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1588 {
1589 close(fd);
1590 fd = -1;
1591 }
1592 }
1593
1594 return fd;
1595}
1596
Simon Kelley5aabfc72007-08-29 11:24:47 +01001597int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001598{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001599 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001600
1601 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001602 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001603 better not use any resources our caller has in use...)
1604 but we remain deaf to signals or further DHCP packets. */
1605
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001606 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001607 struct sockaddr_in saddr;
1608 struct {
1609 struct ip ip;
1610 struct icmp icmp;
1611 } packet;
1612 unsigned short id = rand16();
1613 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001614 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001615 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001616
Simon Kelley824af852008-02-12 20:43:05 +00001617#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001618 if ((fd = make_icmp_sock()) == -1)
1619 return 0;
1620#else
1621 int opt = 2000;
1622 fd = daemon->dhcp_icmp_fd;
1623 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1624#endif
1625
Simon Kelley3be34542004-09-11 19:12:13 +01001626 saddr.sin_family = AF_INET;
1627 saddr.sin_port = 0;
1628 saddr.sin_addr = addr;
1629#ifdef HAVE_SOCKADDR_SA_LEN
1630 saddr.sin_len = sizeof(struct sockaddr_in);
1631#endif
1632
1633 memset(&packet.icmp, 0, sizeof(packet.icmp));
1634 packet.icmp.icmp_type = ICMP_ECHO;
1635 packet.icmp.icmp_id = id;
1636 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1637 j += ((u16 *)&packet.icmp)[i];
1638 while (j>>16)
1639 j = (j & 0xffff) + (j >> 16);
1640 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1641
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001642 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001643 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1644 retry_send());
1645
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001646 for (now = start = dnsmasq_time();
1647 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001648 {
1649 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001650 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001651 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001652 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001653 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001654
1655 tv.tv_usec = 250000;
1656 tv.tv_sec = 0;
1657
1658 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001659 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001660 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001661 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001662 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001663
1664#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001665 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001666 {
1667 FD_SET(daemon->icmp6fd, &rset);
1668 bump_maxfd(daemon->icmp6fd, &maxfd);
1669 }
1670#endif
1671
Simon Kelleyf2621c72007-04-29 19:47:21 +01001672 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1673 {
1674 FD_ZERO(&rset);
1675 FD_ZERO(&wset);
1676 }
1677
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001678 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001679
1680 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001681 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001682
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001683#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001684 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1685 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001686#endif
1687
Simon Kelley832af0b2007-01-21 20:01:28 +00001688#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001689 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001690#endif
1691
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001692 if (FD_ISSET(fd, &rset) &&
1693 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001694 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1695 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1696 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1697 packet.icmp.icmp_seq == 0 &&
1698 packet.icmp.icmp_id == id)
1699 {
1700 gotreply = 1;
1701 break;
1702 }
1703 }
1704
Simon Kelley824af852008-02-12 20:43:05 +00001705#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001706 close(fd);
1707#else
Simon Kelley3be34542004-09-11 19:12:13 +01001708 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001709 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1710#endif
1711
Simon Kelley3be34542004-09-11 19:12:13 +01001712 return gotreply;
1713}
Simon Kelley7622fc02009-06-04 20:32:05 +01001714#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001715
1716