blob: f4a89fc3818306a82675569f4a842b55a66840e3 [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;
90#ifdef HAVE_DNSSEC
91 /* Enforce min packet big enough for DNSSEC */
92 if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
93 daemon->edns_pktsz = EDNS_PKTSZ;
94#endif
Simon Kelley3ddacb82014-01-08 14:32:03 +000095
Simon Kelley0a852542005-03-23 20:28:59 +000096 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
97 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
98 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000099
Simon Kelleyc72daea2012-01-05 21:33:27 +0000100 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000101
102#ifdef HAVE_DNSSEC
103 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley5107ace2014-02-23 10:48:32 +0000104 {
105 daemon->keyname = safe_malloc(MAXDNAME);
106 daemon->workspacename = safe_malloc(MAXDNAME);
107 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000108#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000109
Simon Kelley7622fc02009-06-04 20:32:05 +0100110#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100111 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000112 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000113 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100114 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000115 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100116#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000117
Simon Kelleya2761752012-01-18 16:07:21 +0000118 /* Close any file descriptors we inherited apart from std{in|out|err}
119
120 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
121 otherwise file descriptors we create can end up being 0, 1, or 2
122 and then get accidentally closed later when we make 0, 1, and 2
123 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
124 but it's not guaranteed. By opening /dev/null three times, we
125 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100126 for (i = 0; i < max_fd; i++)
127 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
128 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000129 else
130 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100131
Simon Kelley801ca9a2012-03-06 19:30:17 +0000132#ifndef HAVE_LINUX_NETWORK
133# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000134 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100135 {
136 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000137 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100138 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000139# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100140
141 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100142 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100143 {
144 bind_fallback = 1;
145 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100146 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100147 }
Simon Kelley309331f2006-04-22 15:05:01 +0100148#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100149
Simon Kelley0744ca62014-01-25 16:40:15 +0000150 if (option_bool(OPT_DNSSEC_VALID))
151 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000152#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000153 if (!daemon->ds)
Simon Kelley0744ca62014-01-25 16:40:15 +0000154 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
155
156 if (daemon->cachesize < CACHESIZ)
157 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
158#else
159 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000160#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000161 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000162
Simon Kelley832af0b2007-01-21 20:01:28 +0000163#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100164 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100165 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000166#endif
167
Simon Kelley7de060b2011-08-26 17:24:52 +0100168#ifdef HAVE_CONNTRACK
169 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
170 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
171#else
172 if (option_bool(OPT_CONNTRACK))
173 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
174#endif
175
Simon Kelley824af852008-02-12 20:43:05 +0000176#ifdef HAVE_SOLARIS_NETWORK
177 if (daemon->max_logs != 0)
178 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
179#endif
180
Simon Kelley572b41e2011-02-18 18:11:18 +0000181#ifdef __ANDROID__
182 if (daemon->max_logs != 0)
183 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
184#endif
185
Simon Kelley4820dce2012-12-18 18:30:30 +0000186#ifndef HAVE_AUTH
187 if (daemon->authserver)
188 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
189#endif
190
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100191#ifndef HAVE_LOOP
192 if (option_bool(OPT_LOOP_DETECT))
193 die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
194#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100195
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100196 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000197
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000198 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000199 if (daemon->authinterface && daemon->soa_sn == 0)
200#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000201 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000202#else
203 daemon->soa_sn = now;
204#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000205
Simon Kelleyff7eea22013-09-04 18:01:38 +0100206#ifdef HAVE_DHCP6
207 if (daemon->dhcp6)
208 {
209 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000210
Simon Kelleyff7eea22013-09-04 18:01:38 +0100211 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000212 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100213 if (context->flags & CONTEXT_DHCP)
214 daemon->doing_dhcp6 = 1;
215 if (context->flags & CONTEXT_RA)
216 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000217#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100218 if (context->flags & CONTEXT_TEMPLATE)
219 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000220#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000221 }
Simon Kelley1f776932012-12-16 19:46:08 +0000222 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100223#endif
224
225#ifdef HAVE_DHCP
226 /* Note that order matters here, we must call lease_init before
227 creating any file descriptors which shouldn't be leaked
228 to the lease-script init process. We need to call common_init
229 before lease_init to allocate buffers it uses.*/
230 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
231 {
232 dhcp_common_init();
233 if (daemon->dhcp || daemon->doing_dhcp6)
234 lease_init(now);
235 }
236
237 if (daemon->dhcp || daemon->relay4)
238 dhcp_init();
239
240# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100241 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100242 ra_init(now);
243
244 if (daemon->doing_dhcp6 || daemon->relay6)
245 dhcp6_init();
246# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000247
Simon Kelley7622fc02009-06-04 20:32:05 +0100248#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100249
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000250#ifdef HAVE_IPSET
251 if (daemon->ipsets)
252 ipset_init();
253#endif
254
Simon Kelley1ee9be42013-12-09 16:50:19 +0000255#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000256 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000257#elif defined(HAVE_BSD_NETWORK)
258 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000259#endif
260
Simon Kelley1ee9be42013-12-09 16:50:19 +0000261 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
262 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
263
Simon Kelley115ac3e2013-05-20 11:28:32 +0100264 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100265 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000266
Simon Kelley54dd3932012-06-20 11:23:38 +0100267 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100268 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100269 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100270
271 if (!option_bool(OPT_CLEVERBIND))
272 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
273 if (if_tmp->name && !if_tmp->used)
274 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100275
276#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
277 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100278 bound_device = whichdevice();
279
Simon Kelley9380ba72012-04-16 14:41:56 +0100280 if (daemon->dhcp)
281 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100282 if (!daemon->relay4 && bound_device)
283 {
284 bindtodevice(bound_device, daemon->dhcpfd);
285 did_bind = 1;
286 }
287 if (daemon->enable_pxe && bound_device)
288 {
289 bindtodevice(bound_device, daemon->pxefd);
290 did_bind = 1;
291 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100292 }
293#endif
294
295#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100296 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
297 {
298 bindtodevice(bound_device, daemon->dhcp6fd);
299 did_bind = 1;
300 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100301#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100302 }
Simon Kelley28866e92011-02-14 20:19:14 +0000303 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100304 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000305
306#ifdef HAVE_DHCP6
307 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100308 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000309 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000310
311 /* After netlink_init() and before create_helper() */
312 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000313#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100314
Simon Kelley824af852008-02-12 20:43:05 +0000315 if (daemon->port != 0)
Simon Kelley82e3f452014-01-31 21:05:48 +0000316 {
317 cache_init();
318#ifdef HAVE_DNSSEC
319 blockdata_init();
320#endif
321 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100322
Simon Kelley28866e92011-02-14 20:19:14 +0000323 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100324#ifdef HAVE_DBUS
325 {
326 char *err;
327 daemon->dbus = NULL;
328 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100329 if ((err = dbus_init()))
330 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100331 }
332#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100333 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100334#endif
335
Simon Kelley824af852008-02-12 20:43:05 +0000336 if (daemon->port != 0)
337 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100338
Simon Kelleyc72daea2012-01-05 21:33:27 +0000339#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100340 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000341 if ((daemon->dhcp || daemon->dhcp6) &&
342 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000343 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100344 {
345 if ((ent_pw = getpwnam(daemon->scriptuser)))
346 {
347 script_uid = ent_pw->pw_uid;
348 script_gid = ent_pw->pw_gid;
349 }
350 else
351 baduser = daemon->scriptuser;
352 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100353#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000354
Simon Kelley1a6bca82008-07-11 11:11:42 +0100355 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
356 baduser = daemon->username;
357 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
358 baduser = daemon->groupname;
359
360 if (baduser)
361 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
362
363 /* implement group defaults, "dip" if available, or group associated with uid */
364 if (!daemon->group_set && !gp)
365 {
366 if (!(gp = getgrnam(CHGRP)) && ent_pw)
367 gp = getgrgid(ent_pw->pw_gid);
368
369 /* for error message */
370 if (gp)
371 daemon->groupname = gp->gr_name;
372 }
373
374#if defined(HAVE_LINUX_NETWORK)
375 /* determine capability API version here, while we can still
376 call safe_malloc */
377 if (ent_pw && ent_pw->pw_uid != 0)
378 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100379 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100380 hdr = safe_malloc(sizeof(*hdr));
381
Simon Kelley1a6bca82008-07-11 11:11:42 +0100382 /* find version supported by kernel */
383 memset(hdr, 0, sizeof(*hdr));
384 capget(hdr, NULL);
385
386 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
387 {
388 /* if unknown version, use largest supported version (3) */
389 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
390 hdr->version = LINUX_CAPABILITY_VERSION_3;
391 capsize = 2;
392 }
393
394 data = safe_malloc(sizeof(*data) * capsize);
395 memset(data, 0, sizeof(*data) * capsize);
396 }
397#endif
398
Simon Kelley5aabfc72007-08-29 11:24:47 +0100399 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100400 in a race-free manner and another to carry errors to daemon-invoking process */
401 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100402
403 piperead = pipefd[0];
404 pipewrite = pipefd[1];
405 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000406 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100407
408 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100409
Simon Kelley28866e92011-02-14 20:19:14 +0000410 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000411 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 /* The following code "daemonizes" the process.
413 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100414
Simon Kelley9e038942008-05-30 20:06:34 +0100415 if (chdir("/") != 0)
416 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
417
Simon Kelley16972692006-10-16 20:04:18 +0100418#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000419 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100420 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100421 pid_t pid;
422
Simon Kelley1a6bca82008-07-11 11:11:42 +0100423 /* pipe to carry errors back to original process.
424 When startup is complete we close this and the process terminates. */
425 safe_pipe(err_pipe, 0);
426
Simon Kelley7622fc02009-06-04 20:32:05 +0100427 if ((pid = fork()) == -1)
428 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000429 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100430
Simon Kelley5aabfc72007-08-29 11:24:47 +0100431 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100432 {
433 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000434 char *msg;
435
Simon Kelley1a6bca82008-07-11 11:11:42 +0100436 /* close our copy of write-end */
437 close(err_pipe[1]);
438
439 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000440 if (read_event(err_pipe[0], &ev, &msg))
441 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100442
443 _exit(EC_GOOD);
444 }
445
446 close(err_pipe[0]);
447
448 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100449
450 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100451
452 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000453 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100454
455 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100456 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100457 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000458#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100459
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000460 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100461 if (daemon->runfile)
462 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100463 int fd, err = 0;
464
465 sprintf(daemon->namebuff, "%d\n", (int) getpid());
466
467 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
468 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
469 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
470 extent that an attacker running as the unprivileged user could replace the pidfile with a
471 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
472
473 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
474 ensuring that the open() fails should there be any existing file (because the unlink() failed,
475 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
476 attack can succeed.
477
478 Any compromise of the non-privileged user still theoretically allows the pid-file to be
479 replaced whilst dnsmasq is running. The worst that could allow is that the usual
480 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
481
482 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
483 failure to write the pid-file.
484 */
485
486 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100487
Simon Kelley79cfefd2012-09-02 13:29:51 +0100488 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 +0100489 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100490 /* only complain if started as root */
491 if (getuid() == 0)
492 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100493 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100494 else
495 {
496 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
497 err = 1;
498
499 while (!err && close(fd) == -1)
500 if (!retry_send())
501 err = 1;
502 }
503
504 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100505 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000506 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100507 _exit(0);
508 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000509 }
Simon Kelley16972692006-10-16 20:04:18 +0100510 }
511
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100512 log_err = log_start(ent_pw, err_pipe[1]);
513
Simon Kelley28866e92011-02-14 20:19:14 +0000514 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100515 {
516 /* open stdout etc to /dev/null */
517 int nullfd = open("/dev/null", O_RDWR);
518 dup2(nullfd, STDOUT_FILENO);
519 dup2(nullfd, STDERR_FILENO);
520 dup2(nullfd, STDIN_FILENO);
521 close(nullfd);
522 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100523
Simon Kelley1a6bca82008-07-11 11:11:42 +0100524 /* if we are to run scripts, we need to fork a helper before dropping root. */
525 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000526#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000527 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100528 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
529#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100530
Simon Kelley28866e92011-02-14 20:19:14 +0000531 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100532 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100533 int bad_capabilities = 0;
534 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100535
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536 /* remove all supplimentary groups */
537 if (gp &&
538 (setgroups(0, &dummy) == -1 ||
539 setgid(gp->gr_gid) == -1))
540 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000541 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100542 _exit(0);
543 }
544
Simon Kelley7cebd202006-05-06 14:13:33 +0100545 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100546 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100547#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100548 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100549 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100550 ports because of DAD, or we're doing it dynamically,
551 we need CAP_NET_BIND_SERVICE too. */
552 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100553 data->effective = data->permitted = data->inheritable =
554 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
555 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
556 else
557 data->effective = data->permitted = data->inheritable =
558 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100559
Simon Kelley16972692006-10-16 20:04:18 +0100560 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000561 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100562 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100563
Simon Kelley7622fc02009-06-04 20:32:05 +0100564#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000565 /* http://developers.sun.com/solaris/articles/program_privileges.html */
566 priv_set_t *priv_set;
567
568 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
569 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
570 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
571 bad_capabilities = errno;
572
573 if (priv_set && bad_capabilities == 0)
574 {
575 priv_inverse(priv_set);
576
577 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
578 bad_capabilities = errno;
579 }
580
581 if (priv_set)
582 priv_freeset(priv_set);
583
Simon Kelley824af852008-02-12 20:43:05 +0000584#endif
585
Simon Kelley1a6bca82008-07-11 11:11:42 +0100586 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100587 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000588 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100589 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100590 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100591
592 /* finally drop root */
593 if (setuid(ent_pw->pw_uid) == -1)
594 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000595 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100596 _exit(0);
597 }
598
599#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100600 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100601 data->effective = data->permitted =
602 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
603 else
604 data->effective = data->permitted =
605 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100606 data->inheritable = 0;
607
608 /* lose the setuid and setgid capbilities */
609 if (capset(hdr, data) == -1)
610 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000611 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100612 _exit(0);
613 }
614#endif
615
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000616 }
Simon Kelley849a8352006-06-09 21:02:31 +0100617 }
Simon Kelley16972692006-10-16 20:04:18 +0100618
Simon Kelley16972692006-10-16 20:04:18 +0100619#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000620 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000621 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100622#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100623
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100624#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100625 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100626 {
627 DIR *dir;
628 struct tftp_prefix *p;
629
630 if (daemon->tftp_prefix)
631 {
632 if (!((dir = opendir(daemon->tftp_prefix))))
633 {
634 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
635 _exit(0);
636 }
637 closedir(dir);
638 }
639
640 for (p = daemon->if_prefix; p; p = p->next)
641 {
642 if (!((dir = opendir(p->prefix))))
643 {
644 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
645 _exit(0);
646 }
647 closedir(dir);
648 }
649 }
650#endif
651
Simon Kelley824af852008-02-12 20:43:05 +0000652 if (daemon->port == 0)
653 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
654 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100655 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000656 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100657 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100658
Simon Kelleyf2621c72007-04-29 19:47:21 +0100659 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100660
Simon Kelley3d8df262005-08-29 12:19:27 +0100661#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000662 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100663 {
664 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100665 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100666 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100667 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100668 }
669#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000670
671 if (option_bool(OPT_LOCAL_SERVICE))
672 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000673
Simon Kelley1d97ac42014-01-31 11:12:27 +0000674#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000675 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000676 {
677 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
678 if (option_bool(OPT_DNSSEC_TIME))
679 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
680 }
Simon Kelleydb737462014-01-31 10:32:45 +0000681#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100682
Simon Kelley1a6bca82008-07-11 11:11:42 +0100683 if (log_err != 0)
684 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
685 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000686
Simon Kelleyde379512004-06-22 20:23:33 +0100687 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100688 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100689
Simon Kelleyf7029f52013-11-21 15:09:09 +0000690 if (option_bool(OPT_NOWILD))
691 warn_bound_listeners();
692
693 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100694
Simon Kelley28866e92011-02-14 20:19:14 +0000695 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000696 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
697 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100698 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100699
Simon Kelley28866e92011-02-14 20:19:14 +0000700 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100701 {
702 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100703 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100704 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000705 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100706 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100707 }
708
Simon Kelleyf2621c72007-04-29 19:47:21 +0100709 if (daemon->max_logs != 0)
710 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000711
Simon Kelleyf2621c72007-04-29 19:47:21 +0100712
Simon Kelley7622fc02009-06-04 20:32:05 +0100713#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000714 for (context = daemon->dhcp; context; context = context->next)
715 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100716
Simon Kelleyff7eea22013-09-04 18:01:38 +0100717 for (relay = daemon->relay4; relay; relay = relay->next)
718 log_relay(AF_INET, relay);
719
Simon Kelley1f776932012-12-16 19:46:08 +0000720# ifdef HAVE_DHCP6
721 for (context = daemon->dhcp6; context; context = context->next)
722 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000723
Simon Kelleyff7eea22013-09-04 18:01:38 +0100724 for (relay = daemon->relay6; relay; relay = relay->next)
725 log_relay(AF_INET6, relay);
726
Simon Kelley1f776932012-12-16 19:46:08 +0000727 if (daemon->doing_dhcp6 || daemon->doing_ra)
728 dhcp_construct_contexts(now);
729
730 if (option_bool(OPT_RA))
731 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
732# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000733
Simon Kelley3b3f4412013-10-11 16:33:28 +0100734# ifdef HAVE_LINUX_NETWORK
735 if (did_bind)
736 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
737# endif
738
Simon Kelley8445f5d2012-12-17 21:54:08 +0000739 /* after dhcp_contruct_contexts */
740 if (daemon->dhcp || daemon->doing_dhcp6)
741 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000742#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000743
Simon Kelley832af0b2007-01-21 20:01:28 +0000744#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100745 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000746 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000747#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100748 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000749 max_fd = FD_SETSIZE;
750#endif
751
Simon Kelley7622fc02009-06-04 20:32:05 +0100752 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100753 daemon->tftp_prefix ? _("root is ") : _("enabled"),
754 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000755 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100756
Simon Kelley832af0b2007-01-21 20:01:28 +0000757 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100758 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000759 a single file will be sent to may clients (the file only needs
760 one fd). */
761
762 max_fd -= 30; /* use other than TFTP */
763
764 if (max_fd < 0)
765 max_fd = 5;
766 else if (max_fd < 100)
767 max_fd = max_fd/2;
768 else
769 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000770
771 /* if we have to use a limited range of ports,
772 that will limit the number of transfers */
773 if (daemon->start_tftp_port != 0 &&
774 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
775 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000776
777 if (daemon->tftp_max > max_fd)
778 {
779 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100780 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100781 _("restricting maximum simultaneous TFTP transfers to %d"),
782 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000783 }
784 }
785#endif
786
Simon Kelley1a6bca82008-07-11 11:11:42 +0100787 /* finished start-up - release original process */
788 if (err_pipe[1] != -1)
789 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000790
Simon Kelley824af852008-02-12 20:43:05 +0000791 if (daemon->port != 0)
792 check_servers();
793
Simon Kelley7cebd202006-05-06 14:13:33 +0100794 pid = getpid();
795
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100796 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000797 {
Simon Kelley16972692006-10-16 20:04:18 +0100798 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100799 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100800 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000801
802 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100803 FD_ZERO(&wset);
804 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000805
Simon Kelley16972692006-10-16 20:04:18 +0100806 /* if we are out of resources, find how long we have to wait
807 for some to come free, we'll loop around then and restart
808 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100809 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100810 {
811 t.tv_usec = 0;
812 tp = &t;
813 }
814
Simon Kelley832af0b2007-01-21 20:01:28 +0000815 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
816 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000817 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818 {
Simon Kelley16972692006-10-16 20:04:18 +0100819 t.tv_sec = 0;
820 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100821 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000822 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100823 /* Wake every second whilst waiting for DAD to complete */
824 else if (is_dad_listeners())
825 {
826 t.tv_sec = 1;
827 t.tv_usec = 0;
828 tp = &t;
829 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100830
Simon Kelley832af0b2007-01-21 20:01:28 +0000831#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100832 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100833#endif
834
Simon Kelley7622fc02009-06-04 20:32:05 +0100835#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100836 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100837 {
838 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100839 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000840 if (daemon->pxefd != -1)
841 {
842 FD_SET(daemon->pxefd, &rset);
843 bump_maxfd(daemon->pxefd, &maxfd);
844 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100845 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100846#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100847
Simon Kelley52b92f42012-01-22 16:05:15 +0000848#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100849 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000850 {
851 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000852 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000853 }
854
Simon Kelley1f776932012-12-16 19:46:08 +0000855 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000856 {
857 FD_SET(daemon->icmp6fd, &rset);
858 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000859 }
860#endif
861
Simon Kelley1ee9be42013-12-09 16:50:19 +0000862#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100863 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100864 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000865#elif defined(HAVE_BSD_NETWORK)
866 FD_SET(daemon->routefd, &rset);
867 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100868#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000869
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100870 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100871 bump_maxfd(piperead, &maxfd);
872
Simon Kelley7622fc02009-06-04 20:32:05 +0100873#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100874# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100875 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100876
Simon Kelleya9530962012-03-20 22:07:35 +0000877# ifdef HAVE_TFTP
878 while (helper_buf_empty() && do_tftp_script_run());
879# endif
880
Simon Kelley16972692006-10-16 20:04:18 +0100881 if (!helper_buf_empty())
882 {
883 FD_SET(daemon->helperfd, &wset);
884 bump_maxfd(daemon->helperfd, &maxfd);
885 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100886# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100887 /* need this for other side-effects */
888 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000889
890# ifdef HAVE_TFTP
891 while (do_tftp_script_run());
892# endif
893
Simon Kelley7622fc02009-06-04 20:32:05 +0100894# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100895#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100896
Simon Kelleyf2621c72007-04-29 19:47:21 +0100897 /* must do this just before select(), when we know no
898 more calls to my_syslog() can occur */
899 set_log_writer(&wset, &maxfd);
900
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100901 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
902 {
903 /* otherwise undefined after error */
904 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
905 }
906
907 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000908
Simon Kelleyf2621c72007-04-29 19:47:21 +0100909 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100910
911 /* prime. */
912 enumerate_interfaces(1);
913
Simon Kelley74c95c22011-10-19 09:33:39 +0100914 /* Check the interfaces to see if any have exited DAD state
915 and if so, bind the address. */
916 if (is_dad_listeners())
917 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100918 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100919 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
920 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100921 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100922 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100923
Simon Kelley1ee9be42013-12-09 16:50:19 +0000924#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100925 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100926 netlink_multicast();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000927#elif defined(HAVE_BSD_NETWORK)
928 if (FD_ISSET(daemon->routefd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100929 route_sock();
Simon Kelleyc52e1892010-06-07 22:01:39 +0100930#endif
931
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100933 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000934 if (daemon->last_resolv == 0 ||
935 difftime(now, daemon->last_resolv) > 1.0 ||
936 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000937 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100938 /* poll_resolv doesn't need to reload first time through, since
939 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100940
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100941 poll_resolv(0, daemon->last_resolv != 0, now);
942 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100944
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100945 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100946 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100947
Simon Kelley3d8df262005-08-29 12:19:27 +0100948#ifdef HAVE_DBUS
949 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000950 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100951 {
952 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100953 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100954 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100955 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100956 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100957 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100958 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100959#endif
Simon Kelley824af852008-02-12 20:43:05 +0000960
Simon Kelley5aabfc72007-08-29 11:24:47 +0100961 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000962
963#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100964 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000965#endif
966
Simon Kelley7622fc02009-06-04 20:32:05 +0100967#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100968 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000969 {
970 if (FD_ISSET(daemon->dhcpfd, &rset))
971 dhcp_packet(now, 0);
972 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
973 dhcp_packet(now, 1);
974 }
Simon Kelley16972692006-10-16 20:04:18 +0100975
Simon Kelley52b92f42012-01-22 16:05:15 +0000976#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100977 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100978 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000979
Simon Kelley1f776932012-12-16 19:46:08 +0000980 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
981 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +0000982#endif
983
Simon Kelley1f15b812009-10-13 17:49:32 +0100984# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +0100985 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100986 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +0100987# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100988#endif
989
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000990 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000991}
992
Simon Kelley3be34542004-09-11 19:12:13 +0100993static void sig_handler(int sig)
994{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100995 if (pid == 0)
996 {
Simon Kelley16972692006-10-16 20:04:18 +0100997 /* ignore anything other than TERM during startup
998 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100999 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001000 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001001 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001002 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +01001003 {
Simon Kelley16972692006-10-16 20:04:18 +01001004 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001005 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001006 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001007 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001008 else
1009 {
1010 /* master process */
1011 int event, errsave = errno;
1012
1013 if (sig == SIGHUP)
1014 event = EVENT_RELOAD;
1015 else if (sig == SIGCHLD)
1016 event = EVENT_CHILD;
1017 else if (sig == SIGALRM)
1018 event = EVENT_ALARM;
1019 else if (sig == SIGTERM)
1020 event = EVENT_TERM;
1021 else if (sig == SIGUSR1)
1022 event = EVENT_DUMP;
1023 else if (sig == SIGUSR2)
1024 event = EVENT_REOPEN;
1025 else
1026 return;
1027
Simon Kelleyc72daea2012-01-05 21:33:27 +00001028 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001029 errno = errsave;
1030 }
Simon Kelley3be34542004-09-11 19:12:13 +01001031}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001032
Simon Kelley353ae4d2012-03-19 20:07:51 +00001033/* now == 0 -> queue immediate callback */
1034void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001035{
Simon Kelley884a6df2012-03-20 16:20:22 +00001036 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001037 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001038 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1039 if ((now == 0 || difftime(event, now) <= 0.0))
1040 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1041 else
1042 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001043 }
Simon Kelley741c2952012-02-25 13:09:18 +00001044}
1045
Simon Kelley47a95162014-07-08 22:22:02 +01001046void queue_event(int event)
Simon Kelleya0358e52014-06-07 13:38:48 +01001047{
Simon Kelley47a95162014-07-08 22:22:02 +01001048 send_event(pipewrite, event, 0, NULL);
Simon Kelleya0358e52014-06-07 13:38:48 +01001049}
1050
Simon Kelleyc72daea2012-01-05 21:33:27 +00001051void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001052{
1053 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001054 struct iovec iov[2];
1055
Simon Kelley5aabfc72007-08-29 11:24:47 +01001056 ev.event = event;
1057 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001058 ev.msg_sz = msg ? strlen(msg) : 0;
1059
1060 iov[0].iov_base = &ev;
1061 iov[0].iov_len = sizeof(ev);
1062 iov[1].iov_base = msg;
1063 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001064
1065 /* error pipe, debug mode. */
1066 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001067 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001068 else
1069 /* pipe is non-blocking and struct event_desc is smaller than
1070 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001071 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001072}
Simon Kelley3d8df262005-08-29 12:19:27 +01001073
Simon Kelleyc72daea2012-01-05 21:33:27 +00001074/* NOTE: the memory used to return msg is leaked: use msgs in events only
1075 to describe fatal errors. */
1076static int read_event(int fd, struct event_desc *evp, char **msg)
1077{
1078 char *buf;
1079
1080 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1081 return 0;
1082
1083 *msg = NULL;
1084
1085 if (evp->msg_sz != 0 &&
1086 (buf = malloc(evp->msg_sz + 1)) &&
1087 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1088 {
1089 buf[evp->msg_sz] = 0;
1090 *msg = buf;
1091 }
1092
1093 return 1;
1094}
1095
1096static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001097{
1098 errno = ev->data;
1099
1100 switch (ev->event)
1101 {
1102 case EVENT_DIE:
1103 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001104
1105 case EVENT_FORK_ERR:
1106 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001107
1108 case EVENT_PIPE_ERR:
1109 die(_("failed to create helper: %s"), NULL, EC_MISC);
1110
1111 case EVENT_CAP_ERR:
1112 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1113
1114 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001115 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001116
1117 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001118 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001119
1120 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001121 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001122
1123 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001124 die(_("cannot open log %s: %s"), msg, EC_FILE);
1125
1126 case EVENT_LUA_ERR:
1127 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001128
1129 case EVENT_TFTP_ERR:
1130 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001131 }
1132}
1133
Simon Kelley5aabfc72007-08-29 11:24:47 +01001134static void async_event(int pipe, time_t now)
1135{
1136 pid_t p;
1137 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001138 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001139 char *msg;
1140
1141 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1142 to describe fatal errors. */
1143
1144 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001145 switch (ev.event)
1146 {
1147 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001148#ifdef HAVE_DNSSEC
1149 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1150 {
1151 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1152 reset_option_bool(OPT_DNSSEC_TIME);
1153 }
1154#endif
1155 /* fall through */
1156
1157 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001158 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001159
Simon Kelley7b1eae42014-02-20 13:43:28 +00001160 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001161 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001162 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1163 {
1164 reload_servers(daemon->resolv_files->name);
1165 check = 1;
1166 }
1167
1168 if (daemon->servers_file)
1169 {
1170 read_servers_file();
1171 check = 1;
1172 }
1173
1174 if (check)
1175 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001176 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001177
Simon Kelley7622fc02009-06-04 20:32:05 +01001178#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001179 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001180#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001181 break;
1182
1183 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001184 if (daemon->port != 0)
1185 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001186 break;
1187
1188 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001189#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001190 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001191 {
1192 lease_prune(NULL, now);
1193 lease_update_file(now);
1194 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001195#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001196 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001197 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1198 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001199#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001200#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001201 break;
1202
1203 case EVENT_CHILD:
1204 /* See Stevens 5.10 */
1205 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1206 if (p == -1)
1207 {
1208 if (errno != EINTR)
1209 break;
1210 }
1211 else
1212 for (i = 0 ; i < MAX_PROCS; i++)
1213 if (daemon->tcp_pids[i] == p)
1214 daemon->tcp_pids[i] = 0;
1215 break;
1216
1217 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001218 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001219 break;
1220
1221 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001222 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001223 break;
1224
1225 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001226 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1227 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001228 break;
1229
Simon Kelley1a6bca82008-07-11 11:11:42 +01001230 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001231 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001232 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001233 case EVENT_LUA_ERR:
1234 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001235 break;
1236
Simon Kelley5aabfc72007-08-29 11:24:47 +01001237 case EVENT_REOPEN:
1238 /* Note: this may leave TCP-handling processes with the old file still open.
1239 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1240 we leave them logging to the old file. */
1241 if (daemon->log_file != NULL)
1242 log_reopen(daemon->log_file);
1243 break;
Simon Kelleya0358e52014-06-07 13:38:48 +01001244
1245 case EVENT_NEWADDR:
1246 newaddress(now);
1247 break;
Simon Kelley47a95162014-07-08 22:22:02 +01001248
1249 case EVENT_NEWROUTE:
1250 resend_query();
1251 /* Force re-reading resolv file right now, for luck. */
1252 poll_resolv(0, 1, now);
1253 break;
1254
Simon Kelley5aabfc72007-08-29 11:24:47 +01001255 case EVENT_TERM:
1256 /* Knock all our children on the head. */
1257 for (i = 0; i < MAX_PROCS; i++)
1258 if (daemon->tcp_pids[i] != 0)
1259 kill(daemon->tcp_pids[i], SIGALRM);
1260
Simon Kelleyc72daea2012-01-05 21:33:27 +00001261#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001262 /* handle pending lease transitions */
1263 if (daemon->helperfd != -1)
1264 {
1265 /* block in writes until all done */
1266 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1267 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1268 do {
1269 helper_write();
1270 } while (!helper_buf_empty() || do_script_run(now));
1271 close(daemon->helperfd);
1272 }
1273#endif
1274
1275 if (daemon->lease_stream)
1276 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001277
1278 if (daemon->runfile)
1279 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001280
1281 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1282 flush_log();
1283 exit(EC_GOOD);
1284 }
1285}
1286
Simon Kelley47a95162014-07-08 22:22:02 +01001287static void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001288{
1289 struct resolvc *res, *latest;
1290 struct stat statbuf;
1291 time_t last_change = 0;
1292 /* There may be more than one possible file.
1293 Go through and find the one which changed _last_.
1294 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001295
Simon Kelley28866e92011-02-14 20:19:14 +00001296 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001297 return;
1298
Simon Kelley5aabfc72007-08-29 11:24:47 +01001299 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1300 if (stat(res->name, &statbuf) == -1)
1301 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001302 if (force)
1303 {
1304 res->mtime = 0;
1305 continue;
1306 }
1307
Simon Kelley5aabfc72007-08-29 11:24:47 +01001308 if (!res->logged)
1309 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1310 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001311
1312 if (res->mtime != 0)
1313 {
1314 /* existing file evaporated, force selection of the latest
1315 file even if its mtime hasn't changed since we last looked */
1316 poll_resolv(1, do_reload, now);
1317 return;
1318 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001319 }
1320 else
1321 {
1322 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001323 if (force || (statbuf.st_mtime != res->mtime))
1324 {
1325 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001326 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1327 {
1328 last_change = statbuf.st_mtime;
1329 latest = res;
1330 }
1331 }
1332 }
1333
1334 if (latest)
1335 {
1336 static int warned = 0;
1337 if (reload_servers(latest->name))
1338 {
1339 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1340 warned = 0;
1341 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001342 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001343 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001344 }
1345 else
1346 {
1347 latest->mtime = 0;
1348 if (!warned)
1349 {
1350 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1351 warned = 1;
1352 }
1353 }
1354 }
1355}
1356
1357void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001358{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001359 (void)now;
1360
Simon Kelley824af852008-02-12 20:43:05 +00001361 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001362 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001363
Simon Kelley7622fc02009-06-04 20:32:05 +01001364#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001365 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001366 {
Simon Kelley28866e92011-02-14 20:19:14 +00001367 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001368 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001369 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001370 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001371 lease_update_from_configs();
1372 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001373 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001374 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001375#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001376 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001377 /* Not doing DHCP, so no lease system, manage
1378 alarms for ra only */
1379 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001380#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001381#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001382}
1383
Simon Kelley5aabfc72007-08-29 11:24:47 +01001384static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001385{
1386 struct serverfd *serverfdp;
1387 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001388 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001389
1390#ifdef HAVE_TFTP
1391 int tftp = 0;
1392 struct tftp_transfer *transfer;
1393 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1394 {
1395 tftp++;
1396 FD_SET(transfer->sockfd, set);
1397 bump_maxfd(transfer->sockfd, maxfdp);
1398 }
1399#endif
1400
Simon Kelley16972692006-10-16 20:04:18 +01001401 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001402 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001403 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001404
Simon Kelley3be34542004-09-11 19:12:13 +01001405 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1406 {
1407 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001408 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001409 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001410
1411 if (daemon->port != 0 && !daemon->osport)
1412 for (i = 0; i < RANDOM_SOCKS; i++)
1413 if (daemon->randomsocks[i].refcount != 0)
1414 {
1415 FD_SET(daemon->randomsocks[i].fd, set);
1416 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1417 }
1418
Simon Kelley3be34542004-09-11 19:12:13 +01001419 for (listener = daemon->listeners; listener; listener = listener->next)
1420 {
Simon Kelley16972692006-10-16 20:04:18 +01001421 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001422 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001423 {
1424 FD_SET(listener->fd, set);
1425 bump_maxfd(listener->fd, maxfdp);
1426 }
1427
1428 /* death of a child goes through the select loop, so
1429 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001430 if (listener->tcpfd != -1)
1431 for (i = 0; i < MAX_PROCS; i++)
1432 if (daemon->tcp_pids[i] == 0)
1433 {
1434 FD_SET(listener->tcpfd, set);
1435 bump_maxfd(listener->tcpfd, maxfdp);
1436 break;
1437 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001438
Simon Kelley832af0b2007-01-21 20:01:28 +00001439#ifdef HAVE_TFTP
1440 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1441 {
1442 FD_SET(listener->tftpfd, set);
1443 bump_maxfd(listener->tftpfd, maxfdp);
1444 }
1445#endif
1446
1447 }
1448
Simon Kelley16972692006-10-16 20:04:18 +01001449 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001450}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001451
Simon Kelley5aabfc72007-08-29 11:24:47 +01001452static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001453{
1454 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001455 struct listener *listener;
1456 int i;
1457
Simon Kelley832af0b2007-01-21 20:01:28 +00001458 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1459 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001460 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1461
1462 if (daemon->port != 0 && !daemon->osport)
1463 for (i = 0; i < RANDOM_SOCKS; i++)
1464 if (daemon->randomsocks[i].refcount != 0 &&
1465 FD_ISSET(daemon->randomsocks[i].fd, set))
1466 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001467
1468 for (listener = daemon->listeners; listener; listener = listener->next)
1469 {
Simon Kelley824af852008-02-12 20:43:05 +00001470 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001471 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001472
Simon Kelley832af0b2007-01-21 20:01:28 +00001473#ifdef HAVE_TFTP
1474 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001475 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001476#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001477
Simon Kelley824af852008-02-12 20:43:05 +00001478 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001479 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001480 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001481 struct irec *iface = NULL;
1482 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001483 union mysockaddr tcp_addr;
1484 socklen_t tcp_len = sizeof(union mysockaddr);
1485
1486 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001487
Simon Kelley46b06652013-02-04 21:47:59 +00001488 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001489 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001490
Simon Kelley46b06652013-02-04 21:47:59 +00001491 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1492 {
1493 close(confd);
1494 continue;
1495 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001496
1497 /* Make sure that the interface list is up-to-date.
1498
1499 We do this here as we may need the results below, and
1500 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001501
Simon Kelley76dd75d2013-05-23 10:04:25 +01001502 Multiple calls to enumerate_interfaces() per select loop are
1503 inhibited, so calls to it in the child process (which doesn't select())
1504 have no effect. This avoids two processes reading from the same
1505 netlink fd and screwing the pooch entirely.
1506 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001507
Simon Kelley76dd75d2013-05-23 10:04:25 +01001508 enumerate_interfaces(0);
1509
1510 if (option_bool(OPT_NOWILD))
1511 iface = listener->iface; /* May be NULL */
1512 else
1513 {
1514 int if_index;
1515 char intr_name[IF_NAMESIZE];
1516
1517 /* if we can find the arrival interface, check it's one that's allowed */
1518 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1519 indextoname(listener->tcpfd, if_index, intr_name))
1520 {
1521 struct all_addr addr;
1522 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001523#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001524 if (tcp_addr.sa.sa_family == AF_INET6)
1525 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001526#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001527
1528 for (iface = daemon->interfaces; iface; iface = iface->next)
1529 if (iface->index == if_index)
1530 break;
1531
1532 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1533 client_ok = 0;
1534 }
1535
1536 if (option_bool(OPT_CLEVERBIND))
1537 iface = listener->iface; /* May be NULL */
1538 else
1539 {
1540 /* Check for allowed interfaces when binding the wildcard address:
1541 we do this by looking for an interface with the same address as
1542 the local address of the TCP connection, then looking to see if that's
1543 an allowed interface. As a side effect, we get the netmask of the
1544 interface too, for localisation. */
1545
1546 for (iface = daemon->interfaces; iface; iface = iface->next)
1547 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1548 break;
1549
1550 if (!iface)
1551 client_ok = 0;
1552 }
1553 }
1554
Simon Kelley22ce5502013-01-22 13:53:04 +00001555 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001556 {
1557 shutdown(confd, SHUT_RDWR);
1558 close(confd);
1559 }
1560#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001561 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001562 {
1563 if (p != -1)
1564 {
1565 int i;
1566 for (i = 0; i < MAX_PROCS; i++)
1567 if (daemon->tcp_pids[i] == 0)
1568 {
1569 daemon->tcp_pids[i] = p;
1570 break;
1571 }
1572 }
1573 close(confd);
1574 }
1575#endif
1576 else
1577 {
1578 unsigned char *buff;
1579 struct server *s;
1580 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001581 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001582 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001583
1584 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001585 {
1586 netmask = iface->netmask;
1587 auth_dns = iface->dns_auth;
1588 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001589 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001590 {
1591 netmask.s_addr = 0;
1592 auth_dns = 0;
1593 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001594
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001595#ifndef NO_FORK
1596 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1597 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001598 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001599 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001600#endif
1601
Simon Kelley832af0b2007-01-21 20:01:28 +00001602 /* start with no upstream connections. */
1603 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001604 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001605
1606 /* The connected socket inherits non-blocking
1607 attribute from the listening socket.
1608 Reset that here. */
1609 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1610 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1611
Simon Kelley4f7b3042012-11-28 21:27:02 +00001612 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001613
Simon Kelley832af0b2007-01-21 20:01:28 +00001614 shutdown(confd, SHUT_RDWR);
1615 close(confd);
1616
1617 if (buff)
1618 free(buff);
1619
1620 for (s = daemon->servers; s; s = s->next)
1621 if (s->tcpfd != -1)
1622 {
1623 shutdown(s->tcpfd, SHUT_RDWR);
1624 close(s->tcpfd);
1625 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001626#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001627 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001628 {
1629 flush_log();
1630 _exit(0);
1631 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001632#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001633 }
1634 }
1635 }
Simon Kelley3be34542004-09-11 19:12:13 +01001636}
1637
Simon Kelley7622fc02009-06-04 20:32:05 +01001638#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001639int make_icmp_sock(void)
1640{
Simon Kelley7cebd202006-05-06 14:13:33 +01001641 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001642 int zeroopt = 0;
1643
1644 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1645 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001646 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001647 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1648 {
1649 close(fd);
1650 fd = -1;
1651 }
1652 }
1653
1654 return fd;
1655}
1656
Simon Kelley5aabfc72007-08-29 11:24:47 +01001657int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001658{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001659 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001660
1661 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001662 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001663 better not use any resources our caller has in use...)
1664 but we remain deaf to signals or further DHCP packets. */
1665
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001666 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001667 struct sockaddr_in saddr;
1668 struct {
1669 struct ip ip;
1670 struct icmp icmp;
1671 } packet;
1672 unsigned short id = rand16();
1673 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001674 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001675 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001676
Simon Kelley824af852008-02-12 20:43:05 +00001677#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001678 if ((fd = make_icmp_sock()) == -1)
1679 return 0;
1680#else
1681 int opt = 2000;
1682 fd = daemon->dhcp_icmp_fd;
1683 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1684#endif
1685
Simon Kelley3be34542004-09-11 19:12:13 +01001686 saddr.sin_family = AF_INET;
1687 saddr.sin_port = 0;
1688 saddr.sin_addr = addr;
1689#ifdef HAVE_SOCKADDR_SA_LEN
1690 saddr.sin_len = sizeof(struct sockaddr_in);
1691#endif
1692
1693 memset(&packet.icmp, 0, sizeof(packet.icmp));
1694 packet.icmp.icmp_type = ICMP_ECHO;
1695 packet.icmp.icmp_id = id;
1696 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1697 j += ((u16 *)&packet.icmp)[i];
1698 while (j>>16)
1699 j = (j & 0xffff) + (j >> 16);
1700 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1701
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001702 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001703 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1704 retry_send());
1705
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001706 for (now = start = dnsmasq_time();
1707 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001708 {
1709 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001710 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001711 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001712 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001713 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001714
1715 tv.tv_usec = 250000;
1716 tv.tv_sec = 0;
1717
1718 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001719 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001720 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001721 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001722 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001723
1724#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001725 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001726 {
1727 FD_SET(daemon->icmp6fd, &rset);
1728 bump_maxfd(daemon->icmp6fd, &maxfd);
1729 }
1730#endif
1731
Simon Kelleyf2621c72007-04-29 19:47:21 +01001732 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1733 {
1734 FD_ZERO(&rset);
1735 FD_ZERO(&wset);
1736 }
1737
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001738 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001739
1740 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001741 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001742
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001743#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001744 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1745 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001746#endif
1747
Simon Kelley832af0b2007-01-21 20:01:28 +00001748#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001749 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001750#endif
1751
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001752 if (FD_ISSET(fd, &rset) &&
1753 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001754 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1755 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1756 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1757 packet.icmp.icmp_seq == 0 &&
1758 packet.icmp.icmp_id == id)
1759 {
1760 gotreply = 1;
1761 break;
1762 }
1763 }
1764
Simon Kelley824af852008-02-12 20:43:05 +00001765#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001766 close(fd);
1767#else
Simon Kelley3be34542004-09-11 19:12:13 +01001768 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001769 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1770#endif
1771
Simon Kelley3be34542004-09-11 19:12:13 +01001772 return gotreply;
1773}
Simon Kelley7622fc02009-06-04 20:32:05 +01001774#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001775
1776