blob: 8b375dee42e7328a04c030fff3af440a2d257737 [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 */
83
84 read_opts(argc, argv, compile_opts);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000085
Simon Kelley3be34542004-09-11 19:12:13 +010086 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000087 daemon->edns_pktsz = PACKETSZ;
88#ifdef HAVE_DNSSEC
89 /* Enforce min packet big enough for DNSSEC */
90 if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
91 daemon->edns_pktsz = EDNS_PKTSZ;
92#endif
Simon Kelley3ddacb82014-01-08 14:32:03 +000093
Simon Kelley0a852542005-03-23 20:28:59 +000094 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
95 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
96 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000097
Simon Kelleyc72daea2012-01-05 21:33:27 +000098 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +000099
100#ifdef HAVE_DNSSEC
101 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley5107ace2014-02-23 10:48:32 +0000102 {
103 daemon->keyname = safe_malloc(MAXDNAME);
104 daemon->workspacename = safe_malloc(MAXDNAME);
105 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000106#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000107
Simon Kelley7622fc02009-06-04 20:32:05 +0100108#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100109 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000110 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000111 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100112 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000113 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100114#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000115
Simon Kelleya2761752012-01-18 16:07:21 +0000116 /* Close any file descriptors we inherited apart from std{in|out|err}
117
118 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
119 otherwise file descriptors we create can end up being 0, 1, or 2
120 and then get accidentally closed later when we make 0, 1, and 2
121 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
122 but it's not guaranteed. By opening /dev/null three times, we
123 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100124 for (i = 0; i < max_fd; i++)
125 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
126 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000127 else
128 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100129
Simon Kelley801ca9a2012-03-06 19:30:17 +0000130#ifndef HAVE_LINUX_NETWORK
131# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000132 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100133 {
134 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000135 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100136 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000137# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100138
139 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100140 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100141 {
142 bind_fallback = 1;
143 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100144 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100145 }
Simon Kelley309331f2006-04-22 15:05:01 +0100146#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100147
Simon Kelley0744ca62014-01-25 16:40:15 +0000148 if (option_bool(OPT_DNSSEC_VALID))
149 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000150#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000151 if (!daemon->ds)
Simon Kelley0744ca62014-01-25 16:40:15 +0000152 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
153
154 if (daemon->cachesize < CACHESIZ)
155 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
156#else
157 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000158#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000159 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000160
Simon Kelley832af0b2007-01-21 20:01:28 +0000161#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100162 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100163 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000164#endif
165
Simon Kelley7de060b2011-08-26 17:24:52 +0100166#ifdef HAVE_CONNTRACK
167 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
168 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
169#else
170 if (option_bool(OPT_CONNTRACK))
171 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
172#endif
173
Simon Kelley824af852008-02-12 20:43:05 +0000174#ifdef HAVE_SOLARIS_NETWORK
175 if (daemon->max_logs != 0)
176 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
177#endif
178
Simon Kelley572b41e2011-02-18 18:11:18 +0000179#ifdef __ANDROID__
180 if (daemon->max_logs != 0)
181 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
182#endif
183
Simon Kelley4820dce2012-12-18 18:30:30 +0000184#ifndef HAVE_AUTH
185 if (daemon->authserver)
186 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
187#endif
188
Simon Kelley1a6bca82008-07-11 11:11:42 +0100189 rand_init();
190
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();
313#ifdef HAVE_DNSSEC
314 blockdata_init();
315#endif
316 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100317
Simon Kelley28866e92011-02-14 20:19:14 +0000318 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100319#ifdef HAVE_DBUS
320 {
321 char *err;
322 daemon->dbus = NULL;
323 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100324 if ((err = dbus_init()))
325 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100326 }
327#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100328 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100329#endif
330
Simon Kelley824af852008-02-12 20:43:05 +0000331 if (daemon->port != 0)
332 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100333
Simon Kelleyc72daea2012-01-05 21:33:27 +0000334#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100335 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000336 if ((daemon->dhcp || daemon->dhcp6) &&
337 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000338 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100339 {
340 if ((ent_pw = getpwnam(daemon->scriptuser)))
341 {
342 script_uid = ent_pw->pw_uid;
343 script_gid = ent_pw->pw_gid;
344 }
345 else
346 baduser = daemon->scriptuser;
347 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100348#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000349
Simon Kelley1a6bca82008-07-11 11:11:42 +0100350 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
351 baduser = daemon->username;
352 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
353 baduser = daemon->groupname;
354
355 if (baduser)
356 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
357
358 /* implement group defaults, "dip" if available, or group associated with uid */
359 if (!daemon->group_set && !gp)
360 {
361 if (!(gp = getgrnam(CHGRP)) && ent_pw)
362 gp = getgrgid(ent_pw->pw_gid);
363
364 /* for error message */
365 if (gp)
366 daemon->groupname = gp->gr_name;
367 }
368
369#if defined(HAVE_LINUX_NETWORK)
370 /* determine capability API version here, while we can still
371 call safe_malloc */
372 if (ent_pw && ent_pw->pw_uid != 0)
373 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100374 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100375 hdr = safe_malloc(sizeof(*hdr));
376
Simon Kelley1a6bca82008-07-11 11:11:42 +0100377 /* find version supported by kernel */
378 memset(hdr, 0, sizeof(*hdr));
379 capget(hdr, NULL);
380
381 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
382 {
383 /* if unknown version, use largest supported version (3) */
384 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
385 hdr->version = LINUX_CAPABILITY_VERSION_3;
386 capsize = 2;
387 }
388
389 data = safe_malloc(sizeof(*data) * capsize);
390 memset(data, 0, sizeof(*data) * capsize);
391 }
392#endif
393
Simon Kelley5aabfc72007-08-29 11:24:47 +0100394 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100395 in a race-free manner and another to carry errors to daemon-invoking process */
396 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100397
398 piperead = pipefd[0];
399 pipewrite = pipefd[1];
400 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000401 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100402
403 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100404
Simon Kelley28866e92011-02-14 20:19:14 +0000405 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000406 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000407 /* The following code "daemonizes" the process.
408 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100409
Simon Kelley9e038942008-05-30 20:06:34 +0100410 if (chdir("/") != 0)
411 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
412
Simon Kelley16972692006-10-16 20:04:18 +0100413#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000414 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100415 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100416 pid_t pid;
417
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418 /* pipe to carry errors back to original process.
419 When startup is complete we close this and the process terminates. */
420 safe_pipe(err_pipe, 0);
421
Simon Kelley7622fc02009-06-04 20:32:05 +0100422 if ((pid = fork()) == -1)
423 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000424 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100425
Simon Kelley5aabfc72007-08-29 11:24:47 +0100426 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100427 {
428 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000429 char *msg;
430
Simon Kelley1a6bca82008-07-11 11:11:42 +0100431 /* close our copy of write-end */
432 close(err_pipe[1]);
433
434 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000435 if (read_event(err_pipe[0], &ev, &msg))
436 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100437
438 _exit(EC_GOOD);
439 }
440
441 close(err_pipe[0]);
442
443 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100444
445 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100446
447 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000448 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100449
450 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100451 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100452 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100454
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000455 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100456 if (daemon->runfile)
457 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100458 int fd, err = 0;
459
460 sprintf(daemon->namebuff, "%d\n", (int) getpid());
461
462 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
463 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
464 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
465 extent that an attacker running as the unprivileged user could replace the pidfile with a
466 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
467
468 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
469 ensuring that the open() fails should there be any existing file (because the unlink() failed,
470 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
471 attack can succeed.
472
473 Any compromise of the non-privileged user still theoretically allows the pid-file to be
474 replaced whilst dnsmasq is running. The worst that could allow is that the usual
475 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
476
477 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
478 failure to write the pid-file.
479 */
480
481 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100482
Simon Kelley79cfefd2012-09-02 13:29:51 +0100483 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 +0100484 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100485 /* only complain if started as root */
486 if (getuid() == 0)
487 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100488 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100489 else
490 {
491 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
492 err = 1;
493
494 while (!err && close(fd) == -1)
495 if (!retry_send())
496 err = 1;
497 }
498
499 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100500 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000501 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100502 _exit(0);
503 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000504 }
Simon Kelley16972692006-10-16 20:04:18 +0100505 }
506
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100507 log_err = log_start(ent_pw, err_pipe[1]);
508
Simon Kelley28866e92011-02-14 20:19:14 +0000509 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100510 {
511 /* open stdout etc to /dev/null */
512 int nullfd = open("/dev/null", O_RDWR);
513 dup2(nullfd, STDOUT_FILENO);
514 dup2(nullfd, STDERR_FILENO);
515 dup2(nullfd, STDIN_FILENO);
516 close(nullfd);
517 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100518
Simon Kelley1a6bca82008-07-11 11:11:42 +0100519 /* if we are to run scripts, we need to fork a helper before dropping root. */
520 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000521#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000522 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100523 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
524#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100525
Simon Kelley28866e92011-02-14 20:19:14 +0000526 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100527 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100528 int bad_capabilities = 0;
529 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100530
Simon Kelley1a6bca82008-07-11 11:11:42 +0100531 /* remove all supplimentary groups */
532 if (gp &&
533 (setgroups(0, &dummy) == -1 ||
534 setgid(gp->gr_gid) == -1))
535 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000536 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100537 _exit(0);
538 }
539
Simon Kelley7cebd202006-05-06 14:13:33 +0100540 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100541 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100542#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100543 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100544 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100545 ports because of DAD, or we're doing it dynamically,
546 we need CAP_NET_BIND_SERVICE too. */
547 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100548 data->effective = data->permitted = data->inheritable =
549 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
550 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
551 else
552 data->effective = data->permitted = data->inheritable =
553 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100554
Simon Kelley16972692006-10-16 20:04:18 +0100555 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000556 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100557 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100558
Simon Kelley7622fc02009-06-04 20:32:05 +0100559#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000560 /* http://developers.sun.com/solaris/articles/program_privileges.html */
561 priv_set_t *priv_set;
562
563 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
564 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
565 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
566 bad_capabilities = errno;
567
568 if (priv_set && bad_capabilities == 0)
569 {
570 priv_inverse(priv_set);
571
572 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
573 bad_capabilities = errno;
574 }
575
576 if (priv_set)
577 priv_freeset(priv_set);
578
Simon Kelley824af852008-02-12 20:43:05 +0000579#endif
580
Simon Kelley1a6bca82008-07-11 11:11:42 +0100581 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100582 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000583 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100584 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100585 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100586
587 /* finally drop root */
588 if (setuid(ent_pw->pw_uid) == -1)
589 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000590 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100591 _exit(0);
592 }
593
594#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100595 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100596 data->effective = data->permitted =
597 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
598 else
599 data->effective = data->permitted =
600 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100601 data->inheritable = 0;
602
603 /* lose the setuid and setgid capbilities */
604 if (capset(hdr, data) == -1)
605 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000606 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100607 _exit(0);
608 }
609#endif
610
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000611 }
Simon Kelley849a8352006-06-09 21:02:31 +0100612 }
Simon Kelley16972692006-10-16 20:04:18 +0100613
Simon Kelley16972692006-10-16 20:04:18 +0100614#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000615 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000616 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100617#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100618
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100619#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100620 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100621 {
622 DIR *dir;
623 struct tftp_prefix *p;
624
625 if (daemon->tftp_prefix)
626 {
627 if (!((dir = opendir(daemon->tftp_prefix))))
628 {
629 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
630 _exit(0);
631 }
632 closedir(dir);
633 }
634
635 for (p = daemon->if_prefix; p; p = p->next)
636 {
637 if (!((dir = opendir(p->prefix))))
638 {
639 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
640 _exit(0);
641 }
642 closedir(dir);
643 }
644 }
645#endif
646
Simon Kelley824af852008-02-12 20:43:05 +0000647 if (daemon->port == 0)
648 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
649 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100650 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000651 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100652 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100653
Simon Kelleyf2621c72007-04-29 19:47:21 +0100654 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100655
Simon Kelley3d8df262005-08-29 12:19:27 +0100656#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000657 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100658 {
659 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100660 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100661 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100662 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100663 }
664#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000665
666 if (option_bool(OPT_LOCAL_SERVICE))
667 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000668
Simon Kelley1d97ac42014-01-31 11:12:27 +0000669#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000670 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000671 {
672 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
673 if (option_bool(OPT_DNSSEC_TIME))
674 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
675 }
Simon Kelleydb737462014-01-31 10:32:45 +0000676#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100677
Simon Kelley1a6bca82008-07-11 11:11:42 +0100678 if (log_err != 0)
679 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
680 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000681
Simon Kelleyde379512004-06-22 20:23:33 +0100682 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100683 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100684
Simon Kelleyf7029f52013-11-21 15:09:09 +0000685 if (option_bool(OPT_NOWILD))
686 warn_bound_listeners();
687
688 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100689
Simon Kelley28866e92011-02-14 20:19:14 +0000690 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000691 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
692 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100693 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100694
Simon Kelley28866e92011-02-14 20:19:14 +0000695 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100696 {
697 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100698 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100699 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000700 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100701 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100702 }
703
Simon Kelleyf2621c72007-04-29 19:47:21 +0100704 if (daemon->max_logs != 0)
705 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000706
Simon Kelleyf2621c72007-04-29 19:47:21 +0100707
Simon Kelley7622fc02009-06-04 20:32:05 +0100708#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000709 for (context = daemon->dhcp; context; context = context->next)
710 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100711
Simon Kelleyff7eea22013-09-04 18:01:38 +0100712 for (relay = daemon->relay4; relay; relay = relay->next)
713 log_relay(AF_INET, relay);
714
Simon Kelley1f776932012-12-16 19:46:08 +0000715# ifdef HAVE_DHCP6
716 for (context = daemon->dhcp6; context; context = context->next)
717 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000718
Simon Kelleyff7eea22013-09-04 18:01:38 +0100719 for (relay = daemon->relay6; relay; relay = relay->next)
720 log_relay(AF_INET6, relay);
721
Simon Kelley1f776932012-12-16 19:46:08 +0000722 if (daemon->doing_dhcp6 || daemon->doing_ra)
723 dhcp_construct_contexts(now);
724
725 if (option_bool(OPT_RA))
726 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
727# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000728
Simon Kelley3b3f4412013-10-11 16:33:28 +0100729# ifdef HAVE_LINUX_NETWORK
730 if (did_bind)
731 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
732# endif
733
Simon Kelley8445f5d2012-12-17 21:54:08 +0000734 /* after dhcp_contruct_contexts */
735 if (daemon->dhcp || daemon->doing_dhcp6)
736 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000737#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000738
Simon Kelley832af0b2007-01-21 20:01:28 +0000739#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100740 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000741 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000742#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100743 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000744 max_fd = FD_SETSIZE;
745#endif
746
Simon Kelley7622fc02009-06-04 20:32:05 +0100747 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100748 daemon->tftp_prefix ? _("root is ") : _("enabled"),
749 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000750 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100751
Simon Kelley832af0b2007-01-21 20:01:28 +0000752 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100753 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000754 a single file will be sent to may clients (the file only needs
755 one fd). */
756
757 max_fd -= 30; /* use other than TFTP */
758
759 if (max_fd < 0)
760 max_fd = 5;
761 else if (max_fd < 100)
762 max_fd = max_fd/2;
763 else
764 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000765
766 /* if we have to use a limited range of ports,
767 that will limit the number of transfers */
768 if (daemon->start_tftp_port != 0 &&
769 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
770 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000771
772 if (daemon->tftp_max > max_fd)
773 {
774 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100775 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100776 _("restricting maximum simultaneous TFTP transfers to %d"),
777 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000778 }
779 }
780#endif
781
Simon Kelley1a6bca82008-07-11 11:11:42 +0100782 /* finished start-up - release original process */
783 if (err_pipe[1] != -1)
784 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000785
Simon Kelley824af852008-02-12 20:43:05 +0000786 if (daemon->port != 0)
787 check_servers();
788
Simon Kelley7cebd202006-05-06 14:13:33 +0100789 pid = getpid();
790
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100791 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000792 {
Simon Kelley16972692006-10-16 20:04:18 +0100793 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100794 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100795 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000796
797 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100798 FD_ZERO(&wset);
799 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000800
Simon Kelley16972692006-10-16 20:04:18 +0100801 /* if we are out of resources, find how long we have to wait
802 for some to come free, we'll loop around then and restart
803 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100804 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100805 {
806 t.tv_usec = 0;
807 tp = &t;
808 }
809
Simon Kelley832af0b2007-01-21 20:01:28 +0000810 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
811 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000812 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000813 {
Simon Kelley16972692006-10-16 20:04:18 +0100814 t.tv_sec = 0;
815 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100816 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000817 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100818 /* Wake every second whilst waiting for DAD to complete */
819 else if (is_dad_listeners())
820 {
821 t.tv_sec = 1;
822 t.tv_usec = 0;
823 tp = &t;
824 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100825
Simon Kelley832af0b2007-01-21 20:01:28 +0000826#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100827 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100828#endif
829
Simon Kelley7622fc02009-06-04 20:32:05 +0100830#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100831 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100832 {
833 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100834 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000835 if (daemon->pxefd != -1)
836 {
837 FD_SET(daemon->pxefd, &rset);
838 bump_maxfd(daemon->pxefd, &maxfd);
839 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100840 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100841#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100842
Simon Kelley52b92f42012-01-22 16:05:15 +0000843#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100844 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000845 {
846 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000847 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000848 }
849
Simon Kelley1f776932012-12-16 19:46:08 +0000850 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000851 {
852 FD_SET(daemon->icmp6fd, &rset);
853 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000854 }
855#endif
856
Simon Kelley1ee9be42013-12-09 16:50:19 +0000857#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100858 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100859 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000860#elif defined(HAVE_BSD_NETWORK)
861 FD_SET(daemon->routefd, &rset);
862 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100863#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000864
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100865 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100866 bump_maxfd(piperead, &maxfd);
867
Simon Kelley7622fc02009-06-04 20:32:05 +0100868#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100869# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100870 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100871
Simon Kelleya9530962012-03-20 22:07:35 +0000872# ifdef HAVE_TFTP
873 while (helper_buf_empty() && do_tftp_script_run());
874# endif
875
Simon Kelley16972692006-10-16 20:04:18 +0100876 if (!helper_buf_empty())
877 {
878 FD_SET(daemon->helperfd, &wset);
879 bump_maxfd(daemon->helperfd, &maxfd);
880 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100881# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100882 /* need this for other side-effects */
883 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000884
885# ifdef HAVE_TFTP
886 while (do_tftp_script_run());
887# endif
888
Simon Kelley7622fc02009-06-04 20:32:05 +0100889# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100890#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100891
Simon Kelleyf2621c72007-04-29 19:47:21 +0100892 /* must do this just before select(), when we know no
893 more calls to my_syslog() can occur */
894 set_log_writer(&wset, &maxfd);
895
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100896 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
897 {
898 /* otherwise undefined after error */
899 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
900 }
901
902 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000903
Simon Kelleyf2621c72007-04-29 19:47:21 +0100904 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100905
906 /* prime. */
907 enumerate_interfaces(1);
908
Simon Kelley74c95c22011-10-19 09:33:39 +0100909 /* Check the interfaces to see if any have exited DAD state
910 and if so, bind the address. */
911 if (is_dad_listeners())
912 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100913 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100914 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
915 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100916 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100917 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100918
Simon Kelley1ee9be42013-12-09 16:50:19 +0000919#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100920 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100921 netlink_multicast();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000922#elif defined(HAVE_BSD_NETWORK)
923 if (FD_ISSET(daemon->routefd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100924 route_sock();
Simon Kelleyc52e1892010-06-07 22:01:39 +0100925#endif
926
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000927 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100928 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000929 if (daemon->last_resolv == 0 ||
930 difftime(now, daemon->last_resolv) > 1.0 ||
931 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100933 /* poll_resolv doesn't need to reload first time through, since
934 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100935
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100936 poll_resolv(0, daemon->last_resolv != 0, now);
937 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000938 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100939
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100940 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100941 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100942
Simon Kelley3d8df262005-08-29 12:19:27 +0100943#ifdef HAVE_DBUS
944 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000945 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100946 {
947 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100948 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100949 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100950 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100951 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100952 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100953 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100954#endif
Simon Kelley824af852008-02-12 20:43:05 +0000955
Simon Kelley5aabfc72007-08-29 11:24:47 +0100956 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000957
958#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100959 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000960#endif
961
Simon Kelley7622fc02009-06-04 20:32:05 +0100962#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100963 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000964 {
965 if (FD_ISSET(daemon->dhcpfd, &rset))
966 dhcp_packet(now, 0);
967 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
968 dhcp_packet(now, 1);
969 }
Simon Kelley16972692006-10-16 20:04:18 +0100970
Simon Kelley52b92f42012-01-22 16:05:15 +0000971#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100972 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100973 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000974
Simon Kelley1f776932012-12-16 19:46:08 +0000975 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
976 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000977#endif
978
Simon Kelley1f15b812009-10-13 17:49:32 +0100979# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100980 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100981 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100982# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100983#endif
984
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000985 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000986}
987
Simon Kelley3be34542004-09-11 19:12:13 +0100988static void sig_handler(int sig)
989{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100990 if (pid == 0)
991 {
Simon Kelley16972692006-10-16 20:04:18 +0100992 /* ignore anything other than TERM during startup
993 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100994 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100995 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100996 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100997 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +0100998 {
Simon Kelley16972692006-10-16 20:04:18 +0100999 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001000 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001001 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001002 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001003 else
1004 {
1005 /* master process */
1006 int event, errsave = errno;
1007
1008 if (sig == SIGHUP)
1009 event = EVENT_RELOAD;
1010 else if (sig == SIGCHLD)
1011 event = EVENT_CHILD;
1012 else if (sig == SIGALRM)
1013 event = EVENT_ALARM;
1014 else if (sig == SIGTERM)
1015 event = EVENT_TERM;
1016 else if (sig == SIGUSR1)
1017 event = EVENT_DUMP;
1018 else if (sig == SIGUSR2)
1019 event = EVENT_REOPEN;
1020 else
1021 return;
1022
Simon Kelleyc72daea2012-01-05 21:33:27 +00001023 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001024 errno = errsave;
1025 }
Simon Kelley3be34542004-09-11 19:12:13 +01001026}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001027
Simon Kelley353ae4d2012-03-19 20:07:51 +00001028/* now == 0 -> queue immediate callback */
1029void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001030{
Simon Kelley884a6df2012-03-20 16:20:22 +00001031 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001032 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001033 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1034 if ((now == 0 || difftime(event, now) <= 0.0))
1035 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1036 else
1037 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001038 }
Simon Kelley741c2952012-02-25 13:09:18 +00001039}
1040
Simon Kelley47a95162014-07-08 22:22:02 +01001041void queue_event(int event)
Simon Kelleya0358e52014-06-07 13:38:48 +01001042{
Simon Kelley47a95162014-07-08 22:22:02 +01001043 send_event(pipewrite, event, 0, NULL);
Simon Kelleya0358e52014-06-07 13:38:48 +01001044}
1045
Simon Kelleyc72daea2012-01-05 21:33:27 +00001046void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001047{
1048 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001049 struct iovec iov[2];
1050
Simon Kelley5aabfc72007-08-29 11:24:47 +01001051 ev.event = event;
1052 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001053 ev.msg_sz = msg ? strlen(msg) : 0;
1054
1055 iov[0].iov_base = &ev;
1056 iov[0].iov_len = sizeof(ev);
1057 iov[1].iov_base = msg;
1058 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001059
1060 /* error pipe, debug mode. */
1061 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001062 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001063 else
1064 /* pipe is non-blocking and struct event_desc is smaller than
1065 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001066 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001067}
Simon Kelley3d8df262005-08-29 12:19:27 +01001068
Simon Kelleyc72daea2012-01-05 21:33:27 +00001069/* NOTE: the memory used to return msg is leaked: use msgs in events only
1070 to describe fatal errors. */
1071static int read_event(int fd, struct event_desc *evp, char **msg)
1072{
1073 char *buf;
1074
1075 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1076 return 0;
1077
1078 *msg = NULL;
1079
1080 if (evp->msg_sz != 0 &&
1081 (buf = malloc(evp->msg_sz + 1)) &&
1082 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1083 {
1084 buf[evp->msg_sz] = 0;
1085 *msg = buf;
1086 }
1087
1088 return 1;
1089}
1090
1091static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001092{
1093 errno = ev->data;
1094
1095 switch (ev->event)
1096 {
1097 case EVENT_DIE:
1098 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001099
1100 case EVENT_FORK_ERR:
1101 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001102
1103 case EVENT_PIPE_ERR:
1104 die(_("failed to create helper: %s"), NULL, EC_MISC);
1105
1106 case EVENT_CAP_ERR:
1107 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1108
1109 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001110 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001111
1112 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001113 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001114
1115 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001116 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001117
1118 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001119 die(_("cannot open log %s: %s"), msg, EC_FILE);
1120
1121 case EVENT_LUA_ERR:
1122 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001123
1124 case EVENT_TFTP_ERR:
1125 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001126 }
1127}
1128
Simon Kelley5aabfc72007-08-29 11:24:47 +01001129static void async_event(int pipe, time_t now)
1130{
1131 pid_t p;
1132 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001133 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001134 char *msg;
1135
1136 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1137 to describe fatal errors. */
1138
1139 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001140 switch (ev.event)
1141 {
1142 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001143#ifdef HAVE_DNSSEC
1144 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1145 {
1146 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1147 reset_option_bool(OPT_DNSSEC_TIME);
1148 }
1149#endif
1150 /* fall through */
1151
1152 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001153 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001154
Simon Kelley7b1eae42014-02-20 13:43:28 +00001155 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001156 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001157 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1158 {
1159 reload_servers(daemon->resolv_files->name);
1160 check = 1;
1161 }
1162
1163 if (daemon->servers_file)
1164 {
1165 read_servers_file();
1166 check = 1;
1167 }
1168
1169 if (check)
1170 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001171 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001172
Simon Kelley7622fc02009-06-04 20:32:05 +01001173#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001174 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001175#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001176 break;
1177
1178 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001179 if (daemon->port != 0)
1180 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001181 break;
1182
1183 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001184#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001185 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001186 {
1187 lease_prune(NULL, now);
1188 lease_update_file(now);
1189 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001190#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001191 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001192 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1193 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001194#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001195#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001196 break;
1197
1198 case EVENT_CHILD:
1199 /* See Stevens 5.10 */
1200 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1201 if (p == -1)
1202 {
1203 if (errno != EINTR)
1204 break;
1205 }
1206 else
1207 for (i = 0 ; i < MAX_PROCS; i++)
1208 if (daemon->tcp_pids[i] == p)
1209 daemon->tcp_pids[i] = 0;
1210 break;
1211
1212 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001213 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001214 break;
1215
1216 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001217 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001218 break;
1219
1220 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001221 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1222 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001223 break;
1224
Simon Kelley1a6bca82008-07-11 11:11:42 +01001225 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001226 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001227 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001228 case EVENT_LUA_ERR:
1229 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001230 break;
1231
Simon Kelley5aabfc72007-08-29 11:24:47 +01001232 case EVENT_REOPEN:
1233 /* Note: this may leave TCP-handling processes with the old file still open.
1234 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1235 we leave them logging to the old file. */
1236 if (daemon->log_file != NULL)
1237 log_reopen(daemon->log_file);
1238 break;
Simon Kelleya0358e52014-06-07 13:38:48 +01001239
1240 case EVENT_NEWADDR:
1241 newaddress(now);
1242 break;
Simon Kelley47a95162014-07-08 22:22:02 +01001243
1244 case EVENT_NEWROUTE:
1245 resend_query();
1246 /* Force re-reading resolv file right now, for luck. */
1247 poll_resolv(0, 1, now);
1248 break;
1249
Simon Kelley5aabfc72007-08-29 11:24:47 +01001250 case EVENT_TERM:
1251 /* Knock all our children on the head. */
1252 for (i = 0; i < MAX_PROCS; i++)
1253 if (daemon->tcp_pids[i] != 0)
1254 kill(daemon->tcp_pids[i], SIGALRM);
1255
Simon Kelleyc72daea2012-01-05 21:33:27 +00001256#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001257 /* handle pending lease transitions */
1258 if (daemon->helperfd != -1)
1259 {
1260 /* block in writes until all done */
1261 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1262 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1263 do {
1264 helper_write();
1265 } while (!helper_buf_empty() || do_script_run(now));
1266 close(daemon->helperfd);
1267 }
1268#endif
1269
1270 if (daemon->lease_stream)
1271 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001272
1273 if (daemon->runfile)
1274 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001275
1276 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1277 flush_log();
1278 exit(EC_GOOD);
1279 }
1280}
1281
Simon Kelley47a95162014-07-08 22:22:02 +01001282static void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001283{
1284 struct resolvc *res, *latest;
1285 struct stat statbuf;
1286 time_t last_change = 0;
1287 /* There may be more than one possible file.
1288 Go through and find the one which changed _last_.
1289 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001290
Simon Kelley28866e92011-02-14 20:19:14 +00001291 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001292 return;
1293
Simon Kelley5aabfc72007-08-29 11:24:47 +01001294 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1295 if (stat(res->name, &statbuf) == -1)
1296 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001297 if (force)
1298 {
1299 res->mtime = 0;
1300 continue;
1301 }
1302
Simon Kelley5aabfc72007-08-29 11:24:47 +01001303 if (!res->logged)
1304 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1305 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001306
1307 if (res->mtime != 0)
1308 {
1309 /* existing file evaporated, force selection of the latest
1310 file even if its mtime hasn't changed since we last looked */
1311 poll_resolv(1, do_reload, now);
1312 return;
1313 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001314 }
1315 else
1316 {
1317 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001318 if (force || (statbuf.st_mtime != res->mtime))
1319 {
1320 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001321 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1322 {
1323 last_change = statbuf.st_mtime;
1324 latest = res;
1325 }
1326 }
1327 }
1328
1329 if (latest)
1330 {
1331 static int warned = 0;
1332 if (reload_servers(latest->name))
1333 {
1334 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1335 warned = 0;
1336 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001337 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001338 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001339 }
1340 else
1341 {
1342 latest->mtime = 0;
1343 if (!warned)
1344 {
1345 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1346 warned = 1;
1347 }
1348 }
1349 }
1350}
1351
1352void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001353{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001354 (void)now;
1355
Simon Kelley824af852008-02-12 20:43:05 +00001356 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001357 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001358
Simon Kelley7622fc02009-06-04 20:32:05 +01001359#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001360 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001361 {
Simon Kelley28866e92011-02-14 20:19:14 +00001362 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001363 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001364 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001365 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001366 lease_update_from_configs();
1367 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001368 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001369 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001370#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001371 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001372 /* Not doing DHCP, so no lease system, manage
1373 alarms for ra only */
1374 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001375#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001376#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001377}
1378
Simon Kelley5aabfc72007-08-29 11:24:47 +01001379static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001380{
1381 struct serverfd *serverfdp;
1382 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001383 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001384
1385#ifdef HAVE_TFTP
1386 int tftp = 0;
1387 struct tftp_transfer *transfer;
1388 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1389 {
1390 tftp++;
1391 FD_SET(transfer->sockfd, set);
1392 bump_maxfd(transfer->sockfd, maxfdp);
1393 }
1394#endif
1395
Simon Kelley16972692006-10-16 20:04:18 +01001396 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001397 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001398 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001399
Simon Kelley3be34542004-09-11 19:12:13 +01001400 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1401 {
1402 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001403 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001404 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001405
1406 if (daemon->port != 0 && !daemon->osport)
1407 for (i = 0; i < RANDOM_SOCKS; i++)
1408 if (daemon->randomsocks[i].refcount != 0)
1409 {
1410 FD_SET(daemon->randomsocks[i].fd, set);
1411 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1412 }
1413
Simon Kelley3be34542004-09-11 19:12:13 +01001414 for (listener = daemon->listeners; listener; listener = listener->next)
1415 {
Simon Kelley16972692006-10-16 20:04:18 +01001416 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001417 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001418 {
1419 FD_SET(listener->fd, set);
1420 bump_maxfd(listener->fd, maxfdp);
1421 }
1422
1423 /* death of a child goes through the select loop, so
1424 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001425 if (listener->tcpfd != -1)
1426 for (i = 0; i < MAX_PROCS; i++)
1427 if (daemon->tcp_pids[i] == 0)
1428 {
1429 FD_SET(listener->tcpfd, set);
1430 bump_maxfd(listener->tcpfd, maxfdp);
1431 break;
1432 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001433
Simon Kelley832af0b2007-01-21 20:01:28 +00001434#ifdef HAVE_TFTP
1435 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1436 {
1437 FD_SET(listener->tftpfd, set);
1438 bump_maxfd(listener->tftpfd, maxfdp);
1439 }
1440#endif
1441
1442 }
1443
Simon Kelley16972692006-10-16 20:04:18 +01001444 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001445}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001446
Simon Kelley5aabfc72007-08-29 11:24:47 +01001447static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001448{
1449 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001450 struct listener *listener;
1451 int i;
1452
Simon Kelley832af0b2007-01-21 20:01:28 +00001453 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1454 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001455 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1456
1457 if (daemon->port != 0 && !daemon->osport)
1458 for (i = 0; i < RANDOM_SOCKS; i++)
1459 if (daemon->randomsocks[i].refcount != 0 &&
1460 FD_ISSET(daemon->randomsocks[i].fd, set))
1461 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001462
1463 for (listener = daemon->listeners; listener; listener = listener->next)
1464 {
Simon Kelley824af852008-02-12 20:43:05 +00001465 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001466 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001467
Simon Kelley832af0b2007-01-21 20:01:28 +00001468#ifdef HAVE_TFTP
1469 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001470 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001471#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001472
Simon Kelley824af852008-02-12 20:43:05 +00001473 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001475 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001476 struct irec *iface = NULL;
1477 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001478 union mysockaddr tcp_addr;
1479 socklen_t tcp_len = sizeof(union mysockaddr);
1480
1481 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001482
Simon Kelley46b06652013-02-04 21:47:59 +00001483 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001484 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001485
Simon Kelley46b06652013-02-04 21:47:59 +00001486 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1487 {
1488 close(confd);
1489 continue;
1490 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001491
1492 /* Make sure that the interface list is up-to-date.
1493
1494 We do this here as we may need the results below, and
1495 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001496
Simon Kelley76dd75d2013-05-23 10:04:25 +01001497 Multiple calls to enumerate_interfaces() per select loop are
1498 inhibited, so calls to it in the child process (which doesn't select())
1499 have no effect. This avoids two processes reading from the same
1500 netlink fd and screwing the pooch entirely.
1501 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001502
Simon Kelley76dd75d2013-05-23 10:04:25 +01001503 enumerate_interfaces(0);
1504
1505 if (option_bool(OPT_NOWILD))
1506 iface = listener->iface; /* May be NULL */
1507 else
1508 {
1509 int if_index;
1510 char intr_name[IF_NAMESIZE];
1511
1512 /* if we can find the arrival interface, check it's one that's allowed */
1513 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1514 indextoname(listener->tcpfd, if_index, intr_name))
1515 {
1516 struct all_addr addr;
1517 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001518#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001519 if (tcp_addr.sa.sa_family == AF_INET6)
1520 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001521#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001522
1523 for (iface = daemon->interfaces; iface; iface = iface->next)
1524 if (iface->index == if_index)
1525 break;
1526
1527 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1528 client_ok = 0;
1529 }
1530
1531 if (option_bool(OPT_CLEVERBIND))
1532 iface = listener->iface; /* May be NULL */
1533 else
1534 {
1535 /* Check for allowed interfaces when binding the wildcard address:
1536 we do this by looking for an interface with the same address as
1537 the local address of the TCP connection, then looking to see if that's
1538 an allowed interface. As a side effect, we get the netmask of the
1539 interface too, for localisation. */
1540
1541 for (iface = daemon->interfaces; iface; iface = iface->next)
1542 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1543 break;
1544
1545 if (!iface)
1546 client_ok = 0;
1547 }
1548 }
1549
Simon Kelley22ce5502013-01-22 13:53:04 +00001550 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001551 {
1552 shutdown(confd, SHUT_RDWR);
1553 close(confd);
1554 }
1555#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001556 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001557 {
1558 if (p != -1)
1559 {
1560 int i;
1561 for (i = 0; i < MAX_PROCS; i++)
1562 if (daemon->tcp_pids[i] == 0)
1563 {
1564 daemon->tcp_pids[i] = p;
1565 break;
1566 }
1567 }
1568 close(confd);
1569 }
1570#endif
1571 else
1572 {
1573 unsigned char *buff;
1574 struct server *s;
1575 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001576 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001577 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001578
1579 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001580 {
1581 netmask = iface->netmask;
1582 auth_dns = iface->dns_auth;
1583 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001584 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001585 {
1586 netmask.s_addr = 0;
1587 auth_dns = 0;
1588 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001589
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001590#ifndef NO_FORK
1591 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1592 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001593 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001594 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001595#endif
1596
Simon Kelley832af0b2007-01-21 20:01:28 +00001597 /* start with no upstream connections. */
1598 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001599 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001600
1601 /* The connected socket inherits non-blocking
1602 attribute from the listening socket.
1603 Reset that here. */
1604 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1605 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1606
Simon Kelley4f7b3042012-11-28 21:27:02 +00001607 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001608
Simon Kelley832af0b2007-01-21 20:01:28 +00001609 shutdown(confd, SHUT_RDWR);
1610 close(confd);
1611
1612 if (buff)
1613 free(buff);
1614
1615 for (s = daemon->servers; s; s = s->next)
1616 if (s->tcpfd != -1)
1617 {
1618 shutdown(s->tcpfd, SHUT_RDWR);
1619 close(s->tcpfd);
1620 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001621#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001622 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001623 {
1624 flush_log();
1625 _exit(0);
1626 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001627#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001628 }
1629 }
1630 }
Simon Kelley3be34542004-09-11 19:12:13 +01001631}
1632
Simon Kelley7622fc02009-06-04 20:32:05 +01001633#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001634int make_icmp_sock(void)
1635{
Simon Kelley7cebd202006-05-06 14:13:33 +01001636 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001637 int zeroopt = 0;
1638
1639 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1640 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001641 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001642 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1643 {
1644 close(fd);
1645 fd = -1;
1646 }
1647 }
1648
1649 return fd;
1650}
1651
Simon Kelley5aabfc72007-08-29 11:24:47 +01001652int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001653{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001654 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001655
1656 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001657 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001658 better not use any resources our caller has in use...)
1659 but we remain deaf to signals or further DHCP packets. */
1660
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001661 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001662 struct sockaddr_in saddr;
1663 struct {
1664 struct ip ip;
1665 struct icmp icmp;
1666 } packet;
1667 unsigned short id = rand16();
1668 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001669 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001670 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001671
Simon Kelley824af852008-02-12 20:43:05 +00001672#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001673 if ((fd = make_icmp_sock()) == -1)
1674 return 0;
1675#else
1676 int opt = 2000;
1677 fd = daemon->dhcp_icmp_fd;
1678 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1679#endif
1680
Simon Kelley3be34542004-09-11 19:12:13 +01001681 saddr.sin_family = AF_INET;
1682 saddr.sin_port = 0;
1683 saddr.sin_addr = addr;
1684#ifdef HAVE_SOCKADDR_SA_LEN
1685 saddr.sin_len = sizeof(struct sockaddr_in);
1686#endif
1687
1688 memset(&packet.icmp, 0, sizeof(packet.icmp));
1689 packet.icmp.icmp_type = ICMP_ECHO;
1690 packet.icmp.icmp_id = id;
1691 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1692 j += ((u16 *)&packet.icmp)[i];
1693 while (j>>16)
1694 j = (j & 0xffff) + (j >> 16);
1695 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1696
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001697 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001698 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1699 retry_send());
1700
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001701 for (now = start = dnsmasq_time();
1702 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001703 {
1704 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001705 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001706 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001707 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001708 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001709
1710 tv.tv_usec = 250000;
1711 tv.tv_sec = 0;
1712
1713 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001714 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001715 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001716 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001717 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001718
1719#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001720 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001721 {
1722 FD_SET(daemon->icmp6fd, &rset);
1723 bump_maxfd(daemon->icmp6fd, &maxfd);
1724 }
1725#endif
1726
Simon Kelleyf2621c72007-04-29 19:47:21 +01001727 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1728 {
1729 FD_ZERO(&rset);
1730 FD_ZERO(&wset);
1731 }
1732
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001733 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001734
1735 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001736 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001737
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001738#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001739 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1740 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001741#endif
1742
Simon Kelley832af0b2007-01-21 20:01:28 +00001743#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001744 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001745#endif
1746
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001747 if (FD_ISSET(fd, &rset) &&
1748 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001749 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1750 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1751 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1752 packet.icmp.icmp_seq == 0 &&
1753 packet.icmp.icmp_id == id)
1754 {
1755 gotreply = 1;
1756 break;
1757 }
1758 }
1759
Simon Kelley824af852008-02-12 20:43:05 +00001760#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001761 close(fd);
1762#else
Simon Kelley3be34542004-09-11 19:12:13 +01001763 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001764 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1765#endif
1766
Simon Kelley3be34542004-09-11 19:12:13 +01001767 return gotreply;
1768}
Simon Kelley7622fc02009-06-04 20:32:05 +01001769#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001770
1771