blob: 5c7750d365fa8ba2b1aeede34c0aa255da863949 [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 Kelley47a95162014-07-08 22:22:02 +010033static void poll_resolv(int force, int do_reload, time_t now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000034
35int main (int argc, char **argv)
36{
Simon Kelleyde379512004-06-22 20:23:33 +010037 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000038 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000039 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000040 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010041 int piperead, pipefd[2], err_pipe[2];
42 struct passwd *ent_pw = NULL;
Simon Kelleyc72daea2012-01-05 21:33:27 +000043#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010044 uid_t script_uid = 0;
45 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010046#endif
47 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010048 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010049 char *baduser = NULL;
50 int log_err;
51#if defined(HAVE_LINUX_NETWORK)
52 cap_user_header_t hdr = NULL;
53 cap_user_data_t data = NULL;
Simon Kelley3b3f4412013-10-11 16:33:28 +010054 char *bound_device = NULL;
55 int did_bind = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010056#endif
Vladislav Grishenko408c3682013-09-24 16:18:49 +010057#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
Simon Kelley1f776932012-12-16 19:46:08 +000058 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +010059 struct dhcp_relay *relay;
Vladislav Grishenko408c3682013-09-24 16:18:49 +010060#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010061
Simon Kelley824af852008-02-12 20:43:05 +000062#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000063 setlocale(LC_ALL, "");
64 bindtextdomain("dnsmasq", LOCALEDIR);
65 textdomain("dnsmasq");
66#endif
67
Simon Kelley9e4abcb2004-01-22 19:47:41 +000068 sigact.sa_handler = sig_handler;
69 sigact.sa_flags = 0;
70 sigemptyset(&sigact.sa_mask);
71 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010072 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000073 sigaction(SIGHUP, &sigact, NULL);
74 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000075 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010076 sigaction(SIGCHLD, &sigact, NULL);
77
78 /* ignore SIGPIPE */
79 sigact.sa_handler = SIG_IGN;
80 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081
Simon Kelley5aabfc72007-08-29 11:24:47 +010082 umask(022); /* known umask, create leases and pid files as 0644 */
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +010083
84 rand_init(); /* Must precede read_opts() */
85
Simon Kelley5aabfc72007-08-29 11:24:47 +010086 read_opts(argc, argv, compile_opts);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000087
Simon Kelley3be34542004-09-11 19:12:13 +010088 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000089 daemon->edns_pktsz = PACKETSZ;
Simon Kelley3ddacb82014-01-08 14:32:03 +000090
Simon Kelley0a852542005-03-23 20:28:59 +000091 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
92 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
93 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000094
Simon Kelleyc72daea2012-01-05 21:33:27 +000095 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +000096
97#ifdef HAVE_DNSSEC
98 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley5107ace2014-02-23 10:48:32 +000099 {
100 daemon->keyname = safe_malloc(MAXDNAME);
101 daemon->workspacename = safe_malloc(MAXDNAME);
102 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000103#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000104
Simon Kelley7622fc02009-06-04 20:32:05 +0100105#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100106 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000108 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100109 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000110 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100111#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000112
Simon Kelleya2761752012-01-18 16:07:21 +0000113 /* Close any file descriptors we inherited apart from std{in|out|err}
114
115 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
116 otherwise file descriptors we create can end up being 0, 1, or 2
117 and then get accidentally closed later when we make 0, 1, and 2
118 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
119 but it's not guaranteed. By opening /dev/null three times, we
120 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100121 for (i = 0; i < max_fd; i++)
122 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
123 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000124 else
125 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100126
Simon Kelley801ca9a2012-03-06 19:30:17 +0000127#ifndef HAVE_LINUX_NETWORK
128# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000129 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100130 {
131 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000132 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100133 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000134# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100135
136 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100137 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100138 {
139 bind_fallback = 1;
140 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100141 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100142 }
Simon Kelley309331f2006-04-22 15:05:01 +0100143#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100144
Simon Kelley0744ca62014-01-25 16:40:15 +0000145 if (option_bool(OPT_DNSSEC_VALID))
146 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000147#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000148 if (!daemon->ds)
Simon Kelley0744ca62014-01-25 16:40:15 +0000149 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
150
151 if (daemon->cachesize < CACHESIZ)
152 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
153#else
154 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000155#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000156 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000157
Simon Kelley832af0b2007-01-21 20:01:28 +0000158#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100159 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100160 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000161#endif
162
Simon Kelley7de060b2011-08-26 17:24:52 +0100163#ifdef HAVE_CONNTRACK
164 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
165 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
166#else
167 if (option_bool(OPT_CONNTRACK))
168 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
169#endif
170
Simon Kelley824af852008-02-12 20:43:05 +0000171#ifdef HAVE_SOLARIS_NETWORK
172 if (daemon->max_logs != 0)
173 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
174#endif
175
Simon Kelley572b41e2011-02-18 18:11:18 +0000176#ifdef __ANDROID__
177 if (daemon->max_logs != 0)
178 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
179#endif
180
Simon Kelley4820dce2012-12-18 18:30:30 +0000181#ifndef HAVE_AUTH
182 if (daemon->authserver)
183 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
184#endif
185
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100186#ifndef HAVE_LOOP
187 if (option_bool(OPT_LOOP_DETECT))
188 die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
189#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100190
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100191 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000192
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000193 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000194 if (daemon->authinterface && daemon->soa_sn == 0)
195#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000196 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000197#else
198 daemon->soa_sn = now;
199#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000200
Simon Kelleyff7eea22013-09-04 18:01:38 +0100201#ifdef HAVE_DHCP6
202 if (daemon->dhcp6)
203 {
204 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000205
Simon Kelleyff7eea22013-09-04 18:01:38 +0100206 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000207 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100208 if (context->flags & CONTEXT_DHCP)
209 daemon->doing_dhcp6 = 1;
210 if (context->flags & CONTEXT_RA)
211 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000212#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100213 if (context->flags & CONTEXT_TEMPLATE)
214 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000215#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000216 }
Simon Kelley1f776932012-12-16 19:46:08 +0000217 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100218#endif
219
220#ifdef HAVE_DHCP
221 /* Note that order matters here, we must call lease_init before
222 creating any file descriptors which shouldn't be leaked
223 to the lease-script init process. We need to call common_init
224 before lease_init to allocate buffers it uses.*/
225 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
226 {
227 dhcp_common_init();
228 if (daemon->dhcp || daemon->doing_dhcp6)
229 lease_init(now);
230 }
231
232 if (daemon->dhcp || daemon->relay4)
233 dhcp_init();
234
235# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100236 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100237 ra_init(now);
238
239 if (daemon->doing_dhcp6 || daemon->relay6)
240 dhcp6_init();
241# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000242
Simon Kelley7622fc02009-06-04 20:32:05 +0100243#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100244
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000245#ifdef HAVE_IPSET
246 if (daemon->ipsets)
247 ipset_init();
248#endif
249
Simon Kelley1ee9be42013-12-09 16:50:19 +0000250#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000251 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000252#elif defined(HAVE_BSD_NETWORK)
253 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000254#endif
255
Simon Kelley1ee9be42013-12-09 16:50:19 +0000256 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
257 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
258
Simon Kelley115ac3e2013-05-20 11:28:32 +0100259 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100260 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000261
Simon Kelley54dd3932012-06-20 11:23:38 +0100262 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100263 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100264 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100265
266 if (!option_bool(OPT_CLEVERBIND))
267 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
268 if (if_tmp->name && !if_tmp->used)
269 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100270
271#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
272 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100273 bound_device = whichdevice();
274
Simon Kelley9380ba72012-04-16 14:41:56 +0100275 if (daemon->dhcp)
276 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100277 if (!daemon->relay4 && bound_device)
278 {
279 bindtodevice(bound_device, daemon->dhcpfd);
280 did_bind = 1;
281 }
282 if (daemon->enable_pxe && bound_device)
283 {
284 bindtodevice(bound_device, daemon->pxefd);
285 did_bind = 1;
286 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100287 }
288#endif
289
290#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100291 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
292 {
293 bindtodevice(bound_device, daemon->dhcp6fd);
294 did_bind = 1;
295 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100296#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100297 }
Simon Kelley28866e92011-02-14 20:19:14 +0000298 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100299 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000300
301#ifdef HAVE_DHCP6
302 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100303 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000304 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000305
306 /* After netlink_init() and before create_helper() */
307 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000308#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100309
Simon Kelley824af852008-02-12 20:43:05 +0000310 if (daemon->port != 0)
Simon Kelley82e3f452014-01-31 21:05:48 +0000311 {
312 cache_init();
Simon Kelley193de4a2014-12-10 17:32:16 +0000313
Simon Kelley82e3f452014-01-31 21:05:48 +0000314#ifdef HAVE_DNSSEC
315 blockdata_init();
316#endif
Simon Kelley193de4a2014-12-10 17:32:16 +0000317
318#ifdef HAVE_LINUX_NETWORK
319 if (!option_bool(OPT_NO_POLL))
320 inotify_dnsmasq_init();
321#endif
Simon Kelley82e3f452014-01-31 21:05:48 +0000322 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100323
Simon Kelley28866e92011-02-14 20:19:14 +0000324 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100325#ifdef HAVE_DBUS
326 {
327 char *err;
328 daemon->dbus = NULL;
329 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100330 if ((err = dbus_init()))
331 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100332 }
333#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100334 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100335#endif
336
Simon Kelley824af852008-02-12 20:43:05 +0000337 if (daemon->port != 0)
338 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100339
Simon Kelleyc72daea2012-01-05 21:33:27 +0000340#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100341 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000342 if ((daemon->dhcp || daemon->dhcp6) &&
343 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000344 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100345 {
346 if ((ent_pw = getpwnam(daemon->scriptuser)))
347 {
348 script_uid = ent_pw->pw_uid;
349 script_gid = ent_pw->pw_gid;
350 }
351 else
352 baduser = daemon->scriptuser;
353 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100354#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000355
Simon Kelley1a6bca82008-07-11 11:11:42 +0100356 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
357 baduser = daemon->username;
358 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
359 baduser = daemon->groupname;
360
361 if (baduser)
362 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
363
364 /* implement group defaults, "dip" if available, or group associated with uid */
365 if (!daemon->group_set && !gp)
366 {
367 if (!(gp = getgrnam(CHGRP)) && ent_pw)
368 gp = getgrgid(ent_pw->pw_gid);
369
370 /* for error message */
371 if (gp)
372 daemon->groupname = gp->gr_name;
373 }
374
375#if defined(HAVE_LINUX_NETWORK)
376 /* determine capability API version here, while we can still
377 call safe_malloc */
378 if (ent_pw && ent_pw->pw_uid != 0)
379 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100380 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100381 hdr = safe_malloc(sizeof(*hdr));
382
Simon Kelley1a6bca82008-07-11 11:11:42 +0100383 /* find version supported by kernel */
384 memset(hdr, 0, sizeof(*hdr));
385 capget(hdr, NULL);
386
387 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
388 {
389 /* if unknown version, use largest supported version (3) */
390 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
391 hdr->version = LINUX_CAPABILITY_VERSION_3;
392 capsize = 2;
393 }
394
395 data = safe_malloc(sizeof(*data) * capsize);
396 memset(data, 0, sizeof(*data) * capsize);
397 }
398#endif
399
Simon Kelley5aabfc72007-08-29 11:24:47 +0100400 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100401 in a race-free manner and another to carry errors to daemon-invoking process */
402 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100403
404 piperead = pipefd[0];
405 pipewrite = pipefd[1];
406 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000407 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100408
409 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100410
Simon Kelley28866e92011-02-14 20:19:14 +0000411 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000413 /* The following code "daemonizes" the process.
414 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100415
Simon Kelley9e038942008-05-30 20:06:34 +0100416 if (chdir("/") != 0)
417 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
418
Simon Kelley16972692006-10-16 20:04:18 +0100419#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000420 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100421 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100422 pid_t pid;
423
Simon Kelley1a6bca82008-07-11 11:11:42 +0100424 /* pipe to carry errors back to original process.
425 When startup is complete we close this and the process terminates. */
426 safe_pipe(err_pipe, 0);
427
Simon Kelley7622fc02009-06-04 20:32:05 +0100428 if ((pid = fork()) == -1)
429 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000430 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100431
Simon Kelley5aabfc72007-08-29 11:24:47 +0100432 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100433 {
434 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000435 char *msg;
436
Simon Kelley1a6bca82008-07-11 11:11:42 +0100437 /* close our copy of write-end */
438 close(err_pipe[1]);
439
440 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000441 if (read_event(err_pipe[0], &ev, &msg))
442 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100443
444 _exit(EC_GOOD);
445 }
446
447 close(err_pipe[0]);
448
449 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100450
451 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100452
453 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000454 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100455
456 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100457 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100458 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000459#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100460
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000461 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100462 if (daemon->runfile)
463 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100464 int fd, err = 0;
465
466 sprintf(daemon->namebuff, "%d\n", (int) getpid());
467
468 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
469 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
470 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
471 extent that an attacker running as the unprivileged user could replace the pidfile with a
472 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
473
474 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
475 ensuring that the open() fails should there be any existing file (because the unlink() failed,
476 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
477 attack can succeed.
478
479 Any compromise of the non-privileged user still theoretically allows the pid-file to be
480 replaced whilst dnsmasq is running. The worst that could allow is that the usual
481 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
482
483 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
484 failure to write the pid-file.
485 */
486
487 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100488
Simon Kelley79cfefd2012-09-02 13:29:51 +0100489 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 +0100490 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100491 /* only complain if started as root */
492 if (getuid() == 0)
493 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100494 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100495 else
496 {
497 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
498 err = 1;
499
500 while (!err && close(fd) == -1)
501 if (!retry_send())
502 err = 1;
503 }
504
505 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100506 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000507 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100508 _exit(0);
509 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000510 }
Simon Kelley16972692006-10-16 20:04:18 +0100511 }
512
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100513 log_err = log_start(ent_pw, err_pipe[1]);
514
Simon Kelley28866e92011-02-14 20:19:14 +0000515 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100516 {
517 /* open stdout etc to /dev/null */
518 int nullfd = open("/dev/null", O_RDWR);
519 dup2(nullfd, STDOUT_FILENO);
520 dup2(nullfd, STDERR_FILENO);
521 dup2(nullfd, STDIN_FILENO);
522 close(nullfd);
523 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100524
Simon Kelley1a6bca82008-07-11 11:11:42 +0100525 /* if we are to run scripts, we need to fork a helper before dropping root. */
526 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000527#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000528 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100529 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
530#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100531
Simon Kelley28866e92011-02-14 20:19:14 +0000532 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100533 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100534 int bad_capabilities = 0;
535 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100536
Simon Kelley1a6bca82008-07-11 11:11:42 +0100537 /* remove all supplimentary groups */
538 if (gp &&
539 (setgroups(0, &dummy) == -1 ||
540 setgid(gp->gr_gid) == -1))
541 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000542 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100543 _exit(0);
544 }
545
Simon Kelley7cebd202006-05-06 14:13:33 +0100546 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100547 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100548#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100549 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100550 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100551 ports because of DAD, or we're doing it dynamically,
552 we need CAP_NET_BIND_SERVICE too. */
553 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100554 data->effective = data->permitted = data->inheritable =
555 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
556 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
557 else
558 data->effective = data->permitted = data->inheritable =
559 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100560
Simon Kelley16972692006-10-16 20:04:18 +0100561 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000562 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100563 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100564
Simon Kelley7622fc02009-06-04 20:32:05 +0100565#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000566 /* http://developers.sun.com/solaris/articles/program_privileges.html */
567 priv_set_t *priv_set;
568
569 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
570 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
571 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
572 bad_capabilities = errno;
573
574 if (priv_set && bad_capabilities == 0)
575 {
576 priv_inverse(priv_set);
577
578 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
579 bad_capabilities = errno;
580 }
581
582 if (priv_set)
583 priv_freeset(priv_set);
584
Simon Kelley824af852008-02-12 20:43:05 +0000585#endif
586
Simon Kelley1a6bca82008-07-11 11:11:42 +0100587 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100588 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000589 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100590 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100591 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100592
593 /* finally drop root */
594 if (setuid(ent_pw->pw_uid) == -1)
595 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000596 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100597 _exit(0);
598 }
599
600#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100601 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100602 data->effective = data->permitted =
603 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
604 else
605 data->effective = data->permitted =
606 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100607 data->inheritable = 0;
608
609 /* lose the setuid and setgid capbilities */
610 if (capset(hdr, data) == -1)
611 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000612 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100613 _exit(0);
614 }
615#endif
616
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000617 }
Simon Kelley849a8352006-06-09 21:02:31 +0100618 }
Simon Kelley16972692006-10-16 20:04:18 +0100619
Simon Kelley16972692006-10-16 20:04:18 +0100620#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000621 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000622 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100623#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100624
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100625#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100626 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100627 {
628 DIR *dir;
629 struct tftp_prefix *p;
630
631 if (daemon->tftp_prefix)
632 {
633 if (!((dir = opendir(daemon->tftp_prefix))))
634 {
635 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
636 _exit(0);
637 }
638 closedir(dir);
639 }
640
641 for (p = daemon->if_prefix; p; p = p->next)
642 {
643 if (!((dir = opendir(p->prefix))))
644 {
645 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
646 _exit(0);
647 }
648 closedir(dir);
649 }
650 }
651#endif
652
Simon Kelley824af852008-02-12 20:43:05 +0000653 if (daemon->port == 0)
654 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
655 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100656 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000657 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100658 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100659
Simon Kelleyf2621c72007-04-29 19:47:21 +0100660 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100661
Simon Kelley3d8df262005-08-29 12:19:27 +0100662#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000663 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100664 {
665 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100666 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100667 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100668 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100669 }
670#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000671
672 if (option_bool(OPT_LOCAL_SERVICE))
673 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000674
Simon Kelley1d97ac42014-01-31 11:12:27 +0000675#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000676 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000677 {
678 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
679 if (option_bool(OPT_DNSSEC_TIME))
680 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
681 }
Simon Kelleydb737462014-01-31 10:32:45 +0000682#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100683
Simon Kelley1a6bca82008-07-11 11:11:42 +0100684 if (log_err != 0)
685 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
686 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000687
Simon Kelleyde379512004-06-22 20:23:33 +0100688 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100689 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100690
Simon Kelleyf7029f52013-11-21 15:09:09 +0000691 if (option_bool(OPT_NOWILD))
692 warn_bound_listeners();
693
694 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100695
Simon Kelley28866e92011-02-14 20:19:14 +0000696 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000697 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
698 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100699 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100700
Simon Kelley28866e92011-02-14 20:19:14 +0000701 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100702 {
703 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100704 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100705 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000706 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100707 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100708 }
709
Simon Kelleyf2621c72007-04-29 19:47:21 +0100710 if (daemon->max_logs != 0)
711 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000712
Simon Kelleyf2621c72007-04-29 19:47:21 +0100713
Simon Kelley7622fc02009-06-04 20:32:05 +0100714#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000715 for (context = daemon->dhcp; context; context = context->next)
716 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100717
Simon Kelleyff7eea22013-09-04 18:01:38 +0100718 for (relay = daemon->relay4; relay; relay = relay->next)
719 log_relay(AF_INET, relay);
720
Simon Kelley1f776932012-12-16 19:46:08 +0000721# ifdef HAVE_DHCP6
722 for (context = daemon->dhcp6; context; context = context->next)
723 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000724
Simon Kelleyff7eea22013-09-04 18:01:38 +0100725 for (relay = daemon->relay6; relay; relay = relay->next)
726 log_relay(AF_INET6, relay);
727
Simon Kelley1f776932012-12-16 19:46:08 +0000728 if (daemon->doing_dhcp6 || daemon->doing_ra)
729 dhcp_construct_contexts(now);
730
731 if (option_bool(OPT_RA))
732 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
733# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000734
Simon Kelley3b3f4412013-10-11 16:33:28 +0100735# ifdef HAVE_LINUX_NETWORK
736 if (did_bind)
737 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
738# endif
739
Simon Kelley8445f5d2012-12-17 21:54:08 +0000740 /* after dhcp_contruct_contexts */
741 if (daemon->dhcp || daemon->doing_dhcp6)
742 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000743#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000744
Simon Kelley832af0b2007-01-21 20:01:28 +0000745#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100746 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000747 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000748#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100749 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000750 max_fd = FD_SETSIZE;
751#endif
752
Simon Kelley7622fc02009-06-04 20:32:05 +0100753 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100754 daemon->tftp_prefix ? _("root is ") : _("enabled"),
755 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000756 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100757
Simon Kelley832af0b2007-01-21 20:01:28 +0000758 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100759 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000760 a single file will be sent to may clients (the file only needs
761 one fd). */
762
763 max_fd -= 30; /* use other than TFTP */
764
765 if (max_fd < 0)
766 max_fd = 5;
767 else if (max_fd < 100)
768 max_fd = max_fd/2;
769 else
770 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000771
772 /* if we have to use a limited range of ports,
773 that will limit the number of transfers */
774 if (daemon->start_tftp_port != 0 &&
775 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
776 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000777
778 if (daemon->tftp_max > max_fd)
779 {
780 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100781 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100782 _("restricting maximum simultaneous TFTP transfers to %d"),
783 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000784 }
785 }
786#endif
787
Simon Kelley1a6bca82008-07-11 11:11:42 +0100788 /* finished start-up - release original process */
789 if (err_pipe[1] != -1)
790 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000791
Simon Kelley824af852008-02-12 20:43:05 +0000792 if (daemon->port != 0)
793 check_servers();
794
Simon Kelley7cebd202006-05-06 14:13:33 +0100795 pid = getpid();
796
Simon Kelley193de4a2014-12-10 17:32:16 +0000797#ifdef HAVE_LINUX_NETWORK
798 /* Using inotify, have to select a resolv file at startup */
799 poll_resolv(1, 0, now);
800#endif
801
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100802 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000803 {
Simon Kelley16972692006-10-16 20:04:18 +0100804 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100805 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100806 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000807
808 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100809 FD_ZERO(&wset);
810 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000811
Simon Kelley16972692006-10-16 20:04:18 +0100812 /* if we are out of resources, find how long we have to wait
813 for some to come free, we'll loop around then and restart
814 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100815 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100816 {
817 t.tv_usec = 0;
818 tp = &t;
819 }
820
Simon Kelley832af0b2007-01-21 20:01:28 +0000821 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
822 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000823 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000824 {
Simon Kelley16972692006-10-16 20:04:18 +0100825 t.tv_sec = 0;
826 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100827 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000828 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100829 /* Wake every second whilst waiting for DAD to complete */
830 else if (is_dad_listeners())
831 {
832 t.tv_sec = 1;
833 t.tv_usec = 0;
834 tp = &t;
835 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100836
Simon Kelley832af0b2007-01-21 20:01:28 +0000837#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100838 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100839#endif
840
Simon Kelley7622fc02009-06-04 20:32:05 +0100841#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100842 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100843 {
844 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100845 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000846 if (daemon->pxefd != -1)
847 {
848 FD_SET(daemon->pxefd, &rset);
849 bump_maxfd(daemon->pxefd, &maxfd);
850 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100851 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100852#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100853
Simon Kelley52b92f42012-01-22 16:05:15 +0000854#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100855 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000856 {
857 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000858 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000859 }
860
Simon Kelley1f776932012-12-16 19:46:08 +0000861 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000862 {
863 FD_SET(daemon->icmp6fd, &rset);
864 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000865 }
866#endif
867
Simon Kelley1ee9be42013-12-09 16:50:19 +0000868#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100869 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100870 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley193de4a2014-12-10 17:32:16 +0000871 if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
872 {
873 FD_SET(daemon->inotifyfd, &rset);
874 bump_maxfd(daemon->inotifyfd, &maxfd);
875 }
Simon Kelley1ee9be42013-12-09 16:50:19 +0000876#elif defined(HAVE_BSD_NETWORK)
877 FD_SET(daemon->routefd, &rset);
878 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100879#endif
Simon Kelley193de4a2014-12-10 17:32:16 +0000880
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100881 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100882 bump_maxfd(piperead, &maxfd);
883
Simon Kelley7622fc02009-06-04 20:32:05 +0100884#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100885# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100886 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100887
Simon Kelleya9530962012-03-20 22:07:35 +0000888# ifdef HAVE_TFTP
889 while (helper_buf_empty() && do_tftp_script_run());
890# endif
891
Simon Kelley16972692006-10-16 20:04:18 +0100892 if (!helper_buf_empty())
893 {
894 FD_SET(daemon->helperfd, &wset);
895 bump_maxfd(daemon->helperfd, &maxfd);
896 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100897# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100898 /* need this for other side-effects */
899 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000900
901# ifdef HAVE_TFTP
902 while (do_tftp_script_run());
903# endif
904
Simon Kelley7622fc02009-06-04 20:32:05 +0100905# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100906#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100907
Simon Kelleyf2621c72007-04-29 19:47:21 +0100908 /* must do this just before select(), when we know no
909 more calls to my_syslog() can occur */
910 set_log_writer(&wset, &maxfd);
911
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100912 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
913 {
914 /* otherwise undefined after error */
915 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
916 }
917
918 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000919
Simon Kelleyf2621c72007-04-29 19:47:21 +0100920 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100921
922 /* prime. */
923 enumerate_interfaces(1);
924
Simon Kelley74c95c22011-10-19 09:33:39 +0100925 /* Check the interfaces to see if any have exited DAD state
926 and if so, bind the address. */
927 if (is_dad_listeners())
928 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100929 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100930 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
931 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100932 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100933 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100934
Simon Kelley1ee9be42013-12-09 16:50:19 +0000935#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100936 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100937 netlink_multicast();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000938#elif defined(HAVE_BSD_NETWORK)
939 if (FD_ISSET(daemon->routefd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100940 route_sock();
Simon Kelleyc52e1892010-06-07 22:01:39 +0100941#endif
942
Simon Kelley193de4a2014-12-10 17:32:16 +0000943#ifdef HAVE_LINUX_NETWORK
944 if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check())
945 poll_resolv(1, 1, now);
946#else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000947 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100948 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000949 if (daemon->last_resolv == 0 ||
950 difftime(now, daemon->last_resolv) > 1.0 ||
951 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000952 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100953 /* poll_resolv doesn't need to reload first time through, since
954 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100955
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100956 poll_resolv(0, daemon->last_resolv != 0, now);
957 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000958 }
Simon Kelley193de4a2014-12-10 17:32:16 +0000959#endif
960
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100961 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100962 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100963
Simon Kelley3d8df262005-08-29 12:19:27 +0100964#ifdef HAVE_DBUS
965 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000966 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100967 {
968 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100969 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100970 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100971 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100972 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100973 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100974 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100975#endif
Simon Kelley824af852008-02-12 20:43:05 +0000976
Simon Kelley5aabfc72007-08-29 11:24:47 +0100977 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000978
979#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100980 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000981#endif
982
Simon Kelley7622fc02009-06-04 20:32:05 +0100983#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100984 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000985 {
986 if (FD_ISSET(daemon->dhcpfd, &rset))
987 dhcp_packet(now, 0);
988 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
989 dhcp_packet(now, 1);
990 }
Simon Kelley16972692006-10-16 20:04:18 +0100991
Simon Kelley52b92f42012-01-22 16:05:15 +0000992#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100993 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100994 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000995
Simon Kelley1f776932012-12-16 19:46:08 +0000996 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
997 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000998#endif
999
Simon Kelley1f15b812009-10-13 17:49:32 +01001000# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +01001001 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001002 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +01001003# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001004#endif
1005
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001006 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001007}
1008
Simon Kelley3be34542004-09-11 19:12:13 +01001009static void sig_handler(int sig)
1010{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001011 if (pid == 0)
1012 {
Simon Kelley16972692006-10-16 20:04:18 +01001013 /* ignore anything other than TERM during startup
1014 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001015 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001016 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001017 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001018 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +01001019 {
Simon Kelley16972692006-10-16 20:04:18 +01001020 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001021 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001022 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001023 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001024 else
1025 {
1026 /* master process */
1027 int event, errsave = errno;
1028
1029 if (sig == SIGHUP)
1030 event = EVENT_RELOAD;
1031 else if (sig == SIGCHLD)
1032 event = EVENT_CHILD;
1033 else if (sig == SIGALRM)
1034 event = EVENT_ALARM;
1035 else if (sig == SIGTERM)
1036 event = EVENT_TERM;
1037 else if (sig == SIGUSR1)
1038 event = EVENT_DUMP;
1039 else if (sig == SIGUSR2)
1040 event = EVENT_REOPEN;
1041 else
1042 return;
1043
Simon Kelleyc72daea2012-01-05 21:33:27 +00001044 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001045 errno = errsave;
1046 }
Simon Kelley3be34542004-09-11 19:12:13 +01001047}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001048
Simon Kelley353ae4d2012-03-19 20:07:51 +00001049/* now == 0 -> queue immediate callback */
1050void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001051{
Simon Kelley884a6df2012-03-20 16:20:22 +00001052 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001053 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001054 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1055 if ((now == 0 || difftime(event, now) <= 0.0))
1056 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1057 else
1058 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001059 }
Simon Kelley741c2952012-02-25 13:09:18 +00001060}
1061
Simon Kelley47a95162014-07-08 22:22:02 +01001062void queue_event(int event)
Simon Kelleya0358e52014-06-07 13:38:48 +01001063{
Simon Kelley47a95162014-07-08 22:22:02 +01001064 send_event(pipewrite, event, 0, NULL);
Simon Kelleya0358e52014-06-07 13:38:48 +01001065}
1066
Simon Kelleyc72daea2012-01-05 21:33:27 +00001067void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001068{
1069 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001070 struct iovec iov[2];
1071
Simon Kelley5aabfc72007-08-29 11:24:47 +01001072 ev.event = event;
1073 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001074 ev.msg_sz = msg ? strlen(msg) : 0;
1075
1076 iov[0].iov_base = &ev;
1077 iov[0].iov_len = sizeof(ev);
1078 iov[1].iov_base = msg;
1079 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001080
1081 /* error pipe, debug mode. */
1082 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001083 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001084 else
1085 /* pipe is non-blocking and struct event_desc is smaller than
1086 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001087 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001088}
Simon Kelley3d8df262005-08-29 12:19:27 +01001089
Simon Kelleyc72daea2012-01-05 21:33:27 +00001090/* NOTE: the memory used to return msg is leaked: use msgs in events only
1091 to describe fatal errors. */
1092static int read_event(int fd, struct event_desc *evp, char **msg)
1093{
1094 char *buf;
1095
1096 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1097 return 0;
1098
1099 *msg = NULL;
1100
1101 if (evp->msg_sz != 0 &&
1102 (buf = malloc(evp->msg_sz + 1)) &&
1103 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1104 {
1105 buf[evp->msg_sz] = 0;
1106 *msg = buf;
1107 }
1108
1109 return 1;
1110}
1111
1112static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001113{
1114 errno = ev->data;
1115
1116 switch (ev->event)
1117 {
1118 case EVENT_DIE:
1119 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001120
1121 case EVENT_FORK_ERR:
1122 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001123
1124 case EVENT_PIPE_ERR:
1125 die(_("failed to create helper: %s"), NULL, EC_MISC);
1126
1127 case EVENT_CAP_ERR:
1128 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1129
1130 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001131 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001132
1133 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001134 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001135
1136 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001137 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001138
1139 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001140 die(_("cannot open log %s: %s"), msg, EC_FILE);
1141
1142 case EVENT_LUA_ERR:
1143 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001144
1145 case EVENT_TFTP_ERR:
1146 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001147 }
1148}
1149
Simon Kelley5aabfc72007-08-29 11:24:47 +01001150static void async_event(int pipe, time_t now)
1151{
1152 pid_t p;
1153 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001154 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001155 char *msg;
1156
1157 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1158 to describe fatal errors. */
1159
1160 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001161 switch (ev.event)
1162 {
1163 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001164#ifdef HAVE_DNSSEC
1165 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1166 {
1167 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1168 reset_option_bool(OPT_DNSSEC_TIME);
1169 }
1170#endif
1171 /* fall through */
1172
1173 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001174 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001175
Simon Kelley7b1eae42014-02-20 13:43:28 +00001176 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001177 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001178 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1179 {
1180 reload_servers(daemon->resolv_files->name);
1181 check = 1;
1182 }
1183
1184 if (daemon->servers_file)
1185 {
1186 read_servers_file();
1187 check = 1;
1188 }
1189
1190 if (check)
1191 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001192 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001193
Simon Kelley7622fc02009-06-04 20:32:05 +01001194#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001195 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001196#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001197 break;
1198
1199 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001200 if (daemon->port != 0)
1201 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001202 break;
1203
1204 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001205#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001206 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001207 {
1208 lease_prune(NULL, now);
1209 lease_update_file(now);
1210 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001211#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001212 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001213 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1214 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001215#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001216#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001217 break;
1218
1219 case EVENT_CHILD:
1220 /* See Stevens 5.10 */
1221 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1222 if (p == -1)
1223 {
1224 if (errno != EINTR)
1225 break;
1226 }
1227 else
1228 for (i = 0 ; i < MAX_PROCS; i++)
1229 if (daemon->tcp_pids[i] == p)
1230 daemon->tcp_pids[i] = 0;
1231 break;
1232
1233 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001234 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001235 break;
1236
1237 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001238 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001239 break;
1240
1241 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001242 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1243 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001244 break;
1245
Simon Kelley1a6bca82008-07-11 11:11:42 +01001246 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001247 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001248 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001249 case EVENT_LUA_ERR:
1250 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001251 break;
1252
Simon Kelley5aabfc72007-08-29 11:24:47 +01001253 case EVENT_REOPEN:
1254 /* Note: this may leave TCP-handling processes with the old file still open.
1255 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1256 we leave them logging to the old file. */
1257 if (daemon->log_file != NULL)
1258 log_reopen(daemon->log_file);
1259 break;
Simon Kelleya0358e52014-06-07 13:38:48 +01001260
1261 case EVENT_NEWADDR:
1262 newaddress(now);
1263 break;
Simon Kelley47a95162014-07-08 22:22:02 +01001264
1265 case EVENT_NEWROUTE:
1266 resend_query();
1267 /* Force re-reading resolv file right now, for luck. */
1268 poll_resolv(0, 1, now);
1269 break;
1270
Simon Kelley5aabfc72007-08-29 11:24:47 +01001271 case EVENT_TERM:
1272 /* Knock all our children on the head. */
1273 for (i = 0; i < MAX_PROCS; i++)
1274 if (daemon->tcp_pids[i] != 0)
1275 kill(daemon->tcp_pids[i], SIGALRM);
1276
Simon Kelleyc72daea2012-01-05 21:33:27 +00001277#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001278 /* handle pending lease transitions */
1279 if (daemon->helperfd != -1)
1280 {
1281 /* block in writes until all done */
1282 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1283 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1284 do {
1285 helper_write();
1286 } while (!helper_buf_empty() || do_script_run(now));
1287 close(daemon->helperfd);
1288 }
1289#endif
1290
1291 if (daemon->lease_stream)
1292 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001293
1294 if (daemon->runfile)
1295 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001296
1297 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1298 flush_log();
1299 exit(EC_GOOD);
1300 }
1301}
1302
Simon Kelley47a95162014-07-08 22:22:02 +01001303static void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001304{
1305 struct resolvc *res, *latest;
1306 struct stat statbuf;
1307 time_t last_change = 0;
1308 /* There may be more than one possible file.
1309 Go through and find the one which changed _last_.
1310 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001311
Simon Kelley28866e92011-02-14 20:19:14 +00001312 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001313 return;
1314
Simon Kelley5aabfc72007-08-29 11:24:47 +01001315 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1316 if (stat(res->name, &statbuf) == -1)
1317 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001318 if (force)
1319 {
1320 res->mtime = 0;
1321 continue;
1322 }
1323
Simon Kelley5aabfc72007-08-29 11:24:47 +01001324 if (!res->logged)
1325 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1326 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001327
1328 if (res->mtime != 0)
1329 {
1330 /* existing file evaporated, force selection of the latest
1331 file even if its mtime hasn't changed since we last looked */
1332 poll_resolv(1, do_reload, now);
1333 return;
1334 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001335 }
1336 else
1337 {
1338 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001339 if (force || (statbuf.st_mtime != res->mtime))
1340 {
1341 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001342 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1343 {
1344 last_change = statbuf.st_mtime;
1345 latest = res;
1346 }
1347 }
1348 }
1349
1350 if (latest)
1351 {
1352 static int warned = 0;
1353 if (reload_servers(latest->name))
1354 {
1355 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1356 warned = 0;
1357 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001358 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001359 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001360 }
1361 else
1362 {
1363 latest->mtime = 0;
1364 if (!warned)
1365 {
1366 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1367 warned = 1;
1368 }
1369 }
1370 }
1371}
1372
1373void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001374{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001375 (void)now;
1376
Simon Kelley824af852008-02-12 20:43:05 +00001377 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001378 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001379
Simon Kelley7622fc02009-06-04 20:32:05 +01001380#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001381 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001382 {
Simon Kelley28866e92011-02-14 20:19:14 +00001383 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001384 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001385 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001386 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001387 lease_update_from_configs();
1388 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001389 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001390 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001391#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001392 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001393 /* Not doing DHCP, so no lease system, manage
1394 alarms for ra only */
1395 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001396#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001397#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001398}
1399
Simon Kelley5aabfc72007-08-29 11:24:47 +01001400static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001401{
1402 struct serverfd *serverfdp;
1403 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001404 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001405
1406#ifdef HAVE_TFTP
1407 int tftp = 0;
1408 struct tftp_transfer *transfer;
1409 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1410 {
1411 tftp++;
1412 FD_SET(transfer->sockfd, set);
1413 bump_maxfd(transfer->sockfd, maxfdp);
1414 }
1415#endif
1416
Simon Kelley16972692006-10-16 20:04:18 +01001417 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001418 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001419 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001420
Simon Kelley3be34542004-09-11 19:12:13 +01001421 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1422 {
1423 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001424 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001425 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001426
1427 if (daemon->port != 0 && !daemon->osport)
1428 for (i = 0; i < RANDOM_SOCKS; i++)
1429 if (daemon->randomsocks[i].refcount != 0)
1430 {
1431 FD_SET(daemon->randomsocks[i].fd, set);
1432 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1433 }
1434
Simon Kelley3be34542004-09-11 19:12:13 +01001435 for (listener = daemon->listeners; listener; listener = listener->next)
1436 {
Simon Kelley16972692006-10-16 20:04:18 +01001437 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001438 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001439 {
1440 FD_SET(listener->fd, set);
1441 bump_maxfd(listener->fd, maxfdp);
1442 }
1443
1444 /* death of a child goes through the select loop, so
1445 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001446 if (listener->tcpfd != -1)
1447 for (i = 0; i < MAX_PROCS; i++)
1448 if (daemon->tcp_pids[i] == 0)
1449 {
1450 FD_SET(listener->tcpfd, set);
1451 bump_maxfd(listener->tcpfd, maxfdp);
1452 break;
1453 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001454
Simon Kelley832af0b2007-01-21 20:01:28 +00001455#ifdef HAVE_TFTP
1456 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1457 {
1458 FD_SET(listener->tftpfd, set);
1459 bump_maxfd(listener->tftpfd, maxfdp);
1460 }
1461#endif
1462
1463 }
1464
Simon Kelley16972692006-10-16 20:04:18 +01001465 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001466}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001467
Simon Kelley5aabfc72007-08-29 11:24:47 +01001468static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001469{
1470 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001471 struct listener *listener;
1472 int i;
1473
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1475 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001476 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1477
1478 if (daemon->port != 0 && !daemon->osport)
1479 for (i = 0; i < RANDOM_SOCKS; i++)
1480 if (daemon->randomsocks[i].refcount != 0 &&
1481 FD_ISSET(daemon->randomsocks[i].fd, set))
1482 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001483
1484 for (listener = daemon->listeners; listener; listener = listener->next)
1485 {
Simon Kelley824af852008-02-12 20:43:05 +00001486 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001487 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001488
Simon Kelley832af0b2007-01-21 20:01:28 +00001489#ifdef HAVE_TFTP
1490 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001491 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001492#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001493
Simon Kelley824af852008-02-12 20:43:05 +00001494 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001495 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001496 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001497 struct irec *iface = NULL;
1498 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001499 union mysockaddr tcp_addr;
1500 socklen_t tcp_len = sizeof(union mysockaddr);
1501
1502 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001503
Simon Kelley46b06652013-02-04 21:47:59 +00001504 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001505 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001506
Simon Kelley46b06652013-02-04 21:47:59 +00001507 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1508 {
1509 close(confd);
1510 continue;
1511 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001512
1513 /* Make sure that the interface list is up-to-date.
1514
1515 We do this here as we may need the results below, and
1516 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001517
Simon Kelley76dd75d2013-05-23 10:04:25 +01001518 Multiple calls to enumerate_interfaces() per select loop are
1519 inhibited, so calls to it in the child process (which doesn't select())
1520 have no effect. This avoids two processes reading from the same
1521 netlink fd and screwing the pooch entirely.
1522 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001523
Simon Kelley76dd75d2013-05-23 10:04:25 +01001524 enumerate_interfaces(0);
1525
1526 if (option_bool(OPT_NOWILD))
1527 iface = listener->iface; /* May be NULL */
1528 else
1529 {
1530 int if_index;
1531 char intr_name[IF_NAMESIZE];
1532
1533 /* if we can find the arrival interface, check it's one that's allowed */
1534 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1535 indextoname(listener->tcpfd, if_index, intr_name))
1536 {
1537 struct all_addr addr;
1538 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001539#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001540 if (tcp_addr.sa.sa_family == AF_INET6)
1541 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001542#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001543
1544 for (iface = daemon->interfaces; iface; iface = iface->next)
1545 if (iface->index == if_index)
1546 break;
1547
1548 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1549 client_ok = 0;
1550 }
1551
1552 if (option_bool(OPT_CLEVERBIND))
1553 iface = listener->iface; /* May be NULL */
1554 else
1555 {
1556 /* Check for allowed interfaces when binding the wildcard address:
1557 we do this by looking for an interface with the same address as
1558 the local address of the TCP connection, then looking to see if that's
1559 an allowed interface. As a side effect, we get the netmask of the
1560 interface too, for localisation. */
1561
1562 for (iface = daemon->interfaces; iface; iface = iface->next)
1563 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1564 break;
1565
1566 if (!iface)
1567 client_ok = 0;
1568 }
1569 }
1570
Simon Kelley22ce5502013-01-22 13:53:04 +00001571 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001572 {
1573 shutdown(confd, SHUT_RDWR);
1574 close(confd);
1575 }
1576#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001577 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001578 {
1579 if (p != -1)
1580 {
1581 int i;
1582 for (i = 0; i < MAX_PROCS; i++)
1583 if (daemon->tcp_pids[i] == 0)
1584 {
1585 daemon->tcp_pids[i] = p;
1586 break;
1587 }
1588 }
1589 close(confd);
1590 }
1591#endif
1592 else
1593 {
1594 unsigned char *buff;
1595 struct server *s;
1596 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001597 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001598 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001599
1600 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001601 {
1602 netmask = iface->netmask;
1603 auth_dns = iface->dns_auth;
1604 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001605 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001606 {
1607 netmask.s_addr = 0;
1608 auth_dns = 0;
1609 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001610
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001611#ifndef NO_FORK
1612 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1613 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001614 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001615 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001616#endif
1617
Simon Kelley832af0b2007-01-21 20:01:28 +00001618 /* start with no upstream connections. */
1619 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001620 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001621
1622 /* The connected socket inherits non-blocking
1623 attribute from the listening socket.
1624 Reset that here. */
1625 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1626 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1627
Simon Kelley4f7b3042012-11-28 21:27:02 +00001628 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001629
Simon Kelley832af0b2007-01-21 20:01:28 +00001630 shutdown(confd, SHUT_RDWR);
1631 close(confd);
1632
1633 if (buff)
1634 free(buff);
1635
1636 for (s = daemon->servers; s; s = s->next)
1637 if (s->tcpfd != -1)
1638 {
1639 shutdown(s->tcpfd, SHUT_RDWR);
1640 close(s->tcpfd);
1641 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001642#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001643 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001644 {
1645 flush_log();
1646 _exit(0);
1647 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001648#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001649 }
1650 }
1651 }
Simon Kelley3be34542004-09-11 19:12:13 +01001652}
1653
Simon Kelley7622fc02009-06-04 20:32:05 +01001654#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001655int make_icmp_sock(void)
1656{
Simon Kelley7cebd202006-05-06 14:13:33 +01001657 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001658 int zeroopt = 0;
1659
1660 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1661 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001662 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001663 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1664 {
1665 close(fd);
1666 fd = -1;
1667 }
1668 }
1669
1670 return fd;
1671}
1672
Simon Kelley5aabfc72007-08-29 11:24:47 +01001673int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001674{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001675 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001676
1677 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001678 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001679 better not use any resources our caller has in use...)
1680 but we remain deaf to signals or further DHCP packets. */
1681
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001682 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001683 struct sockaddr_in saddr;
1684 struct {
1685 struct ip ip;
1686 struct icmp icmp;
1687 } packet;
1688 unsigned short id = rand16();
1689 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001690 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001691 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001692
Simon Kelley824af852008-02-12 20:43:05 +00001693#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001694 if ((fd = make_icmp_sock()) == -1)
1695 return 0;
1696#else
1697 int opt = 2000;
1698 fd = daemon->dhcp_icmp_fd;
1699 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1700#endif
1701
Simon Kelley3be34542004-09-11 19:12:13 +01001702 saddr.sin_family = AF_INET;
1703 saddr.sin_port = 0;
1704 saddr.sin_addr = addr;
1705#ifdef HAVE_SOCKADDR_SA_LEN
1706 saddr.sin_len = sizeof(struct sockaddr_in);
1707#endif
1708
1709 memset(&packet.icmp, 0, sizeof(packet.icmp));
1710 packet.icmp.icmp_type = ICMP_ECHO;
1711 packet.icmp.icmp_id = id;
1712 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1713 j += ((u16 *)&packet.icmp)[i];
1714 while (j>>16)
1715 j = (j & 0xffff) + (j >> 16);
1716 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1717
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001718 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001719 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1720 retry_send());
1721
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001722 for (now = start = dnsmasq_time();
1723 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001724 {
1725 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001726 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001727 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001728 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001729 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001730
1731 tv.tv_usec = 250000;
1732 tv.tv_sec = 0;
1733
1734 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001735 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001736 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001737 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001738 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001739
1740#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001741 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001742 {
1743 FD_SET(daemon->icmp6fd, &rset);
1744 bump_maxfd(daemon->icmp6fd, &maxfd);
1745 }
1746#endif
1747
Simon Kelleyf2621c72007-04-29 19:47:21 +01001748 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1749 {
1750 FD_ZERO(&rset);
1751 FD_ZERO(&wset);
1752 }
1753
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001754 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001755
1756 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001757 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001758
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001759#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001760 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1761 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001762#endif
1763
Simon Kelley832af0b2007-01-21 20:01:28 +00001764#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001765 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001766#endif
1767
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001768 if (FD_ISSET(fd, &rset) &&
1769 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001770 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1771 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1772 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1773 packet.icmp.icmp_seq == 0 &&
1774 packet.icmp.icmp_id == id)
1775 {
1776 gotreply = 1;
1777 break;
1778 }
1779 }
1780
Simon Kelley824af852008-02-12 20:43:05 +00001781#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001782 close(fd);
1783#else
Simon Kelley3be34542004-09-11 19:12:13 +01001784 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001785 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1786#endif
1787
Simon Kelley3be34542004-09-11 19:12:13 +01001788 return gotreply;
1789}
Simon Kelley7622fc02009-06-04 20:32:05 +01001790#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001791
1792