blob: c0c0589d4ce18731b01633d324dae178dd7323e1 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelleyc72daea2012-01-05 21:33:27 +000017/* Declare static char *compiler_opts in config.h */
18#define DNSMASQ_COMPILE_OPTS
19
Simon Kelley9e4abcb2004-01-22 19:47:41 +000020#include "dnsmasq.h"
21
Simon Kelley5aabfc72007-08-29 11:24:47 +010022struct daemon *daemon;
23
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static volatile pid_t pid = 0;
25static volatile int pipewrite;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000026
Simon Kelley5aabfc72007-08-29 11:24:47 +010027static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
28static void check_dns_listeners(fd_set *set, time_t now);
Simon Kelley3be34542004-09-11 19:12:13 +010029static void sig_handler(int sig);
Simon Kelley5aabfc72007-08-29 11:24:47 +010030static void async_event(int pipe, time_t now);
Simon Kelleyc72daea2012-01-05 21:33:27 +000031static void fatal_event(struct event_desc *ev, char *msg);
32static int read_event(int fd, struct event_desc *evp, char **msg);
Simon Kelley47a95162014-07-08 22:22:02 +010033static void poll_resolv(int force, int do_reload, time_t now);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000034
35int main (int argc, char **argv)
36{
Simon Kelleyde379512004-06-22 20:23:33 +010037 int bind_fallback = 0;
Simon Kelley9009d742008-11-14 20:04:27 +000038 time_t now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000039 struct sigaction sigact;
Simon Kelley26128d22004-11-14 16:43:54 +000040 struct iname *if_tmp;
Simon Kelley1a6bca82008-07-11 11:11:42 +010041 int piperead, pipefd[2], err_pipe[2];
42 struct passwd *ent_pw = NULL;
Simon Kelleyc72daea2012-01-05 21:33:27 +000043#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +010044 uid_t script_uid = 0;
45 gid_t script_gid = 0;
Simon Kelley7622fc02009-06-04 20:32:05 +010046#endif
47 struct group *gp = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +010048 long i, max_fd = sysconf(_SC_OPEN_MAX);
Simon Kelley1a6bca82008-07-11 11:11:42 +010049 char *baduser = NULL;
50 int log_err;
51#if defined(HAVE_LINUX_NETWORK)
52 cap_user_header_t hdr = NULL;
53 cap_user_data_t data = NULL;
Simon Kelley3b3f4412013-10-11 16:33:28 +010054 char *bound_device = NULL;
55 int did_bind = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +010056#endif
Vladislav Grishenko408c3682013-09-24 16:18:49 +010057#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
Simon Kelley1f776932012-12-16 19:46:08 +000058 struct dhcp_context *context;
Simon Kelleyff7eea22013-09-04 18:01:38 +010059 struct dhcp_relay *relay;
Vladislav Grishenko408c3682013-09-24 16:18:49 +010060#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010061
Simon Kelley824af852008-02-12 20:43:05 +000062#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000063 setlocale(LC_ALL, "");
64 bindtextdomain("dnsmasq", LOCALEDIR);
65 textdomain("dnsmasq");
66#endif
67
Simon Kelley9e4abcb2004-01-22 19:47:41 +000068 sigact.sa_handler = sig_handler;
69 sigact.sa_flags = 0;
70 sigemptyset(&sigact.sa_mask);
71 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010072 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000073 sigaction(SIGHUP, &sigact, NULL);
74 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000075 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010076 sigaction(SIGCHLD, &sigact, NULL);
77
78 /* ignore SIGPIPE */
79 sigact.sa_handler = SIG_IGN;
80 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081
Simon Kelley5aabfc72007-08-29 11:24:47 +010082 umask(022); /* known umask, create leases and pid files as 0644 */
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +010083
84 rand_init(); /* Must precede read_opts() */
85
Simon Kelley5aabfc72007-08-29 11:24:47 +010086 read_opts(argc, argv, compile_opts);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000087
Simon Kelley3be34542004-09-11 19:12:13 +010088 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000089 daemon->edns_pktsz = PACKETSZ;
Simon Kelley3ddacb82014-01-08 14:32:03 +000090
Simon Kelley0a852542005-03-23 20:28:59 +000091 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
92 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
93 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000094
Simon Kelleyc72daea2012-01-05 21:33:27 +000095 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley25cf5e32015-01-09 15:53:03 +000096 if (option_bool(OPT_EXTRALOG))
97 daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
Simon Kelley3ddacb82014-01-08 14:32:03 +000098
99#ifdef HAVE_DNSSEC
100 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley5107ace2014-02-23 10:48:32 +0000101 {
102 daemon->keyname = safe_malloc(MAXDNAME);
103 daemon->workspacename = safe_malloc(MAXDNAME);
104 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000105#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +0000106
Simon Kelley7622fc02009-06-04 20:32:05 +0100107#ifdef HAVE_DHCP
Simon Kelley3be34542004-09-11 19:12:13 +0100108 if (!daemon->lease_file)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 {
Simon Kelley52b92f42012-01-22 16:05:15 +0000110 if (daemon->dhcp || daemon->dhcp6)
Simon Kelley3be34542004-09-11 19:12:13 +0100111 daemon->lease_file = LEASEFILE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000112 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100113#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114
Simon Kelleya2761752012-01-18 16:07:21 +0000115 /* Close any file descriptors we inherited apart from std{in|out|err}
116
117 Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
118 otherwise file descriptors we create can end up being 0, 1, or 2
119 and then get accidentally closed later when we make 0, 1, and 2
120 open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
121 but it's not guaranteed. By opening /dev/null three times, we
122 ensure that we're not using those fds for real stuff. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100123 for (i = 0; i < max_fd; i++)
124 if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
125 close(i);
Simon Kelleya2761752012-01-18 16:07:21 +0000126 else
127 open("/dev/null", O_RDWR);
Simon Kelley5aabfc72007-08-29 11:24:47 +0100128
Simon Kelley801ca9a2012-03-06 19:30:17 +0000129#ifndef HAVE_LINUX_NETWORK
130# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
Simon Kelley28866e92011-02-14 20:19:14 +0000131 if (!option_bool(OPT_NOWILD))
Simon Kelleyde379512004-06-22 20:23:33 +0100132 {
133 bind_fallback = 1;
Simon Kelley28866e92011-02-14 20:19:14 +0000134 set_option_bool(OPT_NOWILD);
Simon Kelleyde379512004-06-22 20:23:33 +0100135 }
Simon Kelley801ca9a2012-03-06 19:30:17 +0000136# endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100137
138 /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
Simon Kelley54dd3932012-06-20 11:23:38 +0100139 if (option_bool(OPT_CLEVERBIND))
Simon Kelley2b5bae92012-06-26 16:55:23 +0100140 {
141 bind_fallback = 1;
142 set_option_bool(OPT_NOWILD);
Simon Kelley236e0722012-06-26 21:33:01 +0100143 reset_option_bool(OPT_CLEVERBIND);
Simon Kelley2b5bae92012-06-26 16:55:23 +0100144 }
Simon Kelley309331f2006-04-22 15:05:01 +0100145#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100146
Simon Kelley0744ca62014-01-25 16:40:15 +0000147 if (option_bool(OPT_DNSSEC_VALID))
148 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000149#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000150 if (!daemon->ds)
Simon Kelley0744ca62014-01-25 16:40:15 +0000151 die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
152
153 if (daemon->cachesize < CACHESIZ)
154 die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
155#else
156 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000157#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000158 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000159
Simon Kelley832af0b2007-01-21 20:01:28 +0000160#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100161 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100162 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000163#endif
164
Simon Kelley7de060b2011-08-26 17:24:52 +0100165#ifdef HAVE_CONNTRACK
166 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
167 die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
168#else
169 if (option_bool(OPT_CONNTRACK))
170 die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
171#endif
172
Simon Kelley824af852008-02-12 20:43:05 +0000173#ifdef HAVE_SOLARIS_NETWORK
174 if (daemon->max_logs != 0)
175 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
176#endif
177
Simon Kelley572b41e2011-02-18 18:11:18 +0000178#ifdef __ANDROID__
179 if (daemon->max_logs != 0)
180 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
181#endif
182
Simon Kelley4820dce2012-12-18 18:30:30 +0000183#ifndef HAVE_AUTH
184 if (daemon->authserver)
185 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
186#endif
187
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100188#ifndef HAVE_LOOP
189 if (option_bool(OPT_LOOP_DETECT))
190 die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
191#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100192
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100193 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000194
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000195 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000196 if (daemon->authinterface && daemon->soa_sn == 0)
197#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000198 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000199#else
200 daemon->soa_sn = now;
201#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000202
Simon Kelleyff7eea22013-09-04 18:01:38 +0100203#ifdef HAVE_DHCP6
204 if (daemon->dhcp6)
205 {
206 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000207
Simon Kelleyff7eea22013-09-04 18:01:38 +0100208 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000209 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100210 if (context->flags & CONTEXT_DHCP)
211 daemon->doing_dhcp6 = 1;
212 if (context->flags & CONTEXT_RA)
213 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000214#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100215 if (context->flags & CONTEXT_TEMPLATE)
216 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000217#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000218 }
Simon Kelley1f776932012-12-16 19:46:08 +0000219 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100220#endif
221
222#ifdef HAVE_DHCP
223 /* Note that order matters here, we must call lease_init before
224 creating any file descriptors which shouldn't be leaked
225 to the lease-script init process. We need to call common_init
226 before lease_init to allocate buffers it uses.*/
227 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
228 {
229 dhcp_common_init();
230 if (daemon->dhcp || daemon->doing_dhcp6)
231 lease_init(now);
232 }
233
234 if (daemon->dhcp || daemon->relay4)
235 dhcp_init();
236
237# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100238 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100239 ra_init(now);
240
241 if (daemon->doing_dhcp6 || daemon->relay6)
242 dhcp6_init();
243# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000244
Simon Kelley7622fc02009-06-04 20:32:05 +0100245#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100246
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000247#ifdef HAVE_IPSET
248 if (daemon->ipsets)
249 ipset_init();
250#endif
251
Simon Kelley1ee9be42013-12-09 16:50:19 +0000252#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000253 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000254#elif defined(HAVE_BSD_NETWORK)
255 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000256#endif
257
Simon Kelley1ee9be42013-12-09 16:50:19 +0000258 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
259 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
260
Simon Kelley115ac3e2013-05-20 11:28:32 +0100261 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100262 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000263
Simon Kelley54dd3932012-06-20 11:23:38 +0100264 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100265 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100266 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100267
268 if (!option_bool(OPT_CLEVERBIND))
269 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
270 if (if_tmp->name && !if_tmp->used)
271 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100272
273#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
274 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100275 bound_device = whichdevice();
276
Simon Kelley9380ba72012-04-16 14:41:56 +0100277 if (daemon->dhcp)
278 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100279 if (!daemon->relay4 && bound_device)
280 {
281 bindtodevice(bound_device, daemon->dhcpfd);
282 did_bind = 1;
283 }
284 if (daemon->enable_pxe && bound_device)
285 {
286 bindtodevice(bound_device, daemon->pxefd);
287 did_bind = 1;
288 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100289 }
290#endif
291
292#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100293 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
294 {
295 bindtodevice(bound_device, daemon->dhcp6fd);
296 did_bind = 1;
297 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100298#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100299 }
Simon Kelley28866e92011-02-14 20:19:14 +0000300 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100301 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000302
303#ifdef HAVE_DHCP6
304 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100305 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000306 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000307
308 /* After netlink_init() and before create_helper() */
309 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000310#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311
Simon Kelley824af852008-02-12 20:43:05 +0000312 if (daemon->port != 0)
Simon Kelley82e3f452014-01-31 21:05:48 +0000313 {
314 cache_init();
Simon Kelley193de4a2014-12-10 17:32:16 +0000315
Simon Kelley82e3f452014-01-31 21:05:48 +0000316#ifdef HAVE_DNSSEC
317 blockdata_init();
318#endif
Simon Kelley193de4a2014-12-10 17:32:16 +0000319
320#ifdef HAVE_LINUX_NETWORK
321 if (!option_bool(OPT_NO_POLL))
322 inotify_dnsmasq_init();
323#endif
Simon Kelley82e3f452014-01-31 21:05:48 +0000324 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100325
Simon Kelley28866e92011-02-14 20:19:14 +0000326 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100327#ifdef HAVE_DBUS
328 {
329 char *err;
330 daemon->dbus = NULL;
331 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100332 if ((err = dbus_init()))
333 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100334 }
335#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100336 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100337#endif
338
Simon Kelley824af852008-02-12 20:43:05 +0000339 if (daemon->port != 0)
340 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100341
Simon Kelleyc72daea2012-01-05 21:33:27 +0000342#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100343 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000344 if ((daemon->dhcp || daemon->dhcp6) &&
345 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000346 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100347 {
348 if ((ent_pw = getpwnam(daemon->scriptuser)))
349 {
350 script_uid = ent_pw->pw_uid;
351 script_gid = ent_pw->pw_gid;
352 }
353 else
354 baduser = daemon->scriptuser;
355 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100356#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000357
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
359 baduser = daemon->username;
360 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
361 baduser = daemon->groupname;
362
363 if (baduser)
364 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
365
366 /* implement group defaults, "dip" if available, or group associated with uid */
367 if (!daemon->group_set && !gp)
368 {
369 if (!(gp = getgrnam(CHGRP)) && ent_pw)
370 gp = getgrgid(ent_pw->pw_gid);
371
372 /* for error message */
373 if (gp)
374 daemon->groupname = gp->gr_name;
375 }
376
377#if defined(HAVE_LINUX_NETWORK)
378 /* determine capability API version here, while we can still
379 call safe_malloc */
380 if (ent_pw && ent_pw->pw_uid != 0)
381 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100382 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100383 hdr = safe_malloc(sizeof(*hdr));
384
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 /* find version supported by kernel */
386 memset(hdr, 0, sizeof(*hdr));
387 capget(hdr, NULL);
388
389 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
390 {
391 /* if unknown version, use largest supported version (3) */
392 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
393 hdr->version = LINUX_CAPABILITY_VERSION_3;
394 capsize = 2;
395 }
396
397 data = safe_malloc(sizeof(*data) * capsize);
398 memset(data, 0, sizeof(*data) * capsize);
399 }
400#endif
401
Simon Kelley5aabfc72007-08-29 11:24:47 +0100402 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100403 in a race-free manner and another to carry errors to daemon-invoking process */
404 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100405
406 piperead = pipefd[0];
407 pipewrite = pipefd[1];
408 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000409 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100410
411 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100412
Simon Kelley28866e92011-02-14 20:19:14 +0000413 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000414 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000415 /* The following code "daemonizes" the process.
416 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100417
Simon Kelley9e038942008-05-30 20:06:34 +0100418 if (chdir("/") != 0)
419 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
420
Simon Kelley16972692006-10-16 20:04:18 +0100421#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000422 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100423 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100424 pid_t pid;
425
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 /* pipe to carry errors back to original process.
427 When startup is complete we close this and the process terminates. */
428 safe_pipe(err_pipe, 0);
429
Simon Kelley7622fc02009-06-04 20:32:05 +0100430 if ((pid = fork()) == -1)
431 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000432 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100433
Simon Kelley5aabfc72007-08-29 11:24:47 +0100434 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100435 {
436 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000437 char *msg;
438
Simon Kelley1a6bca82008-07-11 11:11:42 +0100439 /* close our copy of write-end */
440 close(err_pipe[1]);
441
442 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000443 if (read_event(err_pipe[0], &ev, &msg))
444 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445
446 _exit(EC_GOOD);
447 }
448
449 close(err_pipe[0]);
450
451 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100452
453 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100454
455 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000456 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100457
458 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100459 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100460 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000461#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100462
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000463 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100464 if (daemon->runfile)
465 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100466 int fd, err = 0;
467
468 sprintf(daemon->namebuff, "%d\n", (int) getpid());
469
470 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
471 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
472 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
473 extent that an attacker running as the unprivileged user could replace the pidfile with a
474 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
475
476 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
477 ensuring that the open() fails should there be any existing file (because the unlink() failed,
478 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
479 attack can succeed.
480
481 Any compromise of the non-privileged user still theoretically allows the pid-file to be
482 replaced whilst dnsmasq is running. The worst that could allow is that the usual
483 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
484
485 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
486 failure to write the pid-file.
487 */
488
489 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100490
Simon Kelley79cfefd2012-09-02 13:29:51 +0100491 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 +0100492 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100493 /* only complain if started as root */
494 if (getuid() == 0)
495 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100496 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100497 else
498 {
499 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
500 err = 1;
501
502 while (!err && close(fd) == -1)
503 if (!retry_send())
504 err = 1;
505 }
506
507 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100508 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000509 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100510 _exit(0);
511 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000512 }
Simon Kelley16972692006-10-16 20:04:18 +0100513 }
514
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100515 log_err = log_start(ent_pw, err_pipe[1]);
516
Simon Kelley28866e92011-02-14 20:19:14 +0000517 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100518 {
519 /* open stdout etc to /dev/null */
520 int nullfd = open("/dev/null", O_RDWR);
521 dup2(nullfd, STDOUT_FILENO);
522 dup2(nullfd, STDERR_FILENO);
523 dup2(nullfd, STDIN_FILENO);
524 close(nullfd);
525 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100526
Simon Kelley1a6bca82008-07-11 11:11:42 +0100527 /* if we are to run scripts, we need to fork a helper before dropping root. */
528 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000529#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000530 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100531 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
532#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100533
Simon Kelley28866e92011-02-14 20:19:14 +0000534 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100535 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536 int bad_capabilities = 0;
537 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100538
Simon Kelley1a6bca82008-07-11 11:11:42 +0100539 /* remove all supplimentary groups */
540 if (gp &&
541 (setgroups(0, &dummy) == -1 ||
542 setgid(gp->gr_gid) == -1))
543 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000544 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100545 _exit(0);
546 }
547
Simon Kelley7cebd202006-05-06 14:13:33 +0100548 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100549 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100550#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100551 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100552 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100553 ports because of DAD, or we're doing it dynamically,
554 we need CAP_NET_BIND_SERVICE too. */
555 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100556 data->effective = data->permitted = data->inheritable =
557 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
558 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
559 else
560 data->effective = data->permitted = data->inheritable =
561 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100562
Simon Kelley16972692006-10-16 20:04:18 +0100563 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000564 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100565 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100566
Simon Kelley7622fc02009-06-04 20:32:05 +0100567#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000568 /* http://developers.sun.com/solaris/articles/program_privileges.html */
569 priv_set_t *priv_set;
570
571 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
572 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
573 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
574 bad_capabilities = errno;
575
576 if (priv_set && bad_capabilities == 0)
577 {
578 priv_inverse(priv_set);
579
580 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
581 bad_capabilities = errno;
582 }
583
584 if (priv_set)
585 priv_freeset(priv_set);
586
Simon Kelley824af852008-02-12 20:43:05 +0000587#endif
588
Simon Kelley1a6bca82008-07-11 11:11:42 +0100589 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100590 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000591 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100592 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100593 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100594
595 /* finally drop root */
596 if (setuid(ent_pw->pw_uid) == -1)
597 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000598 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100599 _exit(0);
600 }
601
602#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100603 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100604 data->effective = data->permitted =
605 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
606 else
607 data->effective = data->permitted =
608 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100609 data->inheritable = 0;
610
611 /* lose the setuid and setgid capbilities */
612 if (capset(hdr, data) == -1)
613 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000614 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100615 _exit(0);
616 }
617#endif
618
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000619 }
Simon Kelley849a8352006-06-09 21:02:31 +0100620 }
Simon Kelley16972692006-10-16 20:04:18 +0100621
Simon Kelley16972692006-10-16 20:04:18 +0100622#ifdef HAVE_LINUX_NETWORK
Simon Kelley28866e92011-02-14 20:19:14 +0000623 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000624 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100625#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100626
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100627#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100628 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100629 {
630 DIR *dir;
631 struct tftp_prefix *p;
632
633 if (daemon->tftp_prefix)
634 {
635 if (!((dir = opendir(daemon->tftp_prefix))))
636 {
637 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
638 _exit(0);
639 }
640 closedir(dir);
641 }
642
643 for (p = daemon->if_prefix; p; p = p->next)
644 {
645 if (!((dir = opendir(p->prefix))))
646 {
647 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
648 _exit(0);
649 }
650 closedir(dir);
651 }
652 }
653#endif
654
Simon Kelley824af852008-02-12 20:43:05 +0000655 if (daemon->port == 0)
656 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
657 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100658 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000659 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100660 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100661
Simon Kelleyf2621c72007-04-29 19:47:21 +0100662 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100663
Simon Kelley3d8df262005-08-29 12:19:27 +0100664#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000665 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100666 {
667 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100668 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100669 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100670 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100671 }
672#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000673
674 if (option_bool(OPT_LOCAL_SERVICE))
675 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000676
Simon Kelley1d97ac42014-01-31 11:12:27 +0000677#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000678 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000679 {
680 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
681 if (option_bool(OPT_DNSSEC_TIME))
682 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
683 }
Simon Kelleydb737462014-01-31 10:32:45 +0000684#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100685
Simon Kelley1a6bca82008-07-11 11:11:42 +0100686 if (log_err != 0)
687 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
688 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000689
Simon Kelleyde379512004-06-22 20:23:33 +0100690 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100691 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100692
Simon Kelleyf7029f52013-11-21 15:09:09 +0000693 if (option_bool(OPT_NOWILD))
694 warn_bound_listeners();
695
696 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100697
Simon Kelley28866e92011-02-14 20:19:14 +0000698 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000699 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
700 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100701 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100702
Simon Kelley28866e92011-02-14 20:19:14 +0000703 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100704 {
705 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100706 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100707 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000708 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100709 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100710 }
711
Simon Kelleyf2621c72007-04-29 19:47:21 +0100712 if (daemon->max_logs != 0)
713 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000714
Simon Kelleyf2621c72007-04-29 19:47:21 +0100715
Simon Kelley7622fc02009-06-04 20:32:05 +0100716#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000717 for (context = daemon->dhcp; context; context = context->next)
718 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100719
Simon Kelleyff7eea22013-09-04 18:01:38 +0100720 for (relay = daemon->relay4; relay; relay = relay->next)
721 log_relay(AF_INET, relay);
722
Simon Kelley1f776932012-12-16 19:46:08 +0000723# ifdef HAVE_DHCP6
724 for (context = daemon->dhcp6; context; context = context->next)
725 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000726
Simon Kelleyff7eea22013-09-04 18:01:38 +0100727 for (relay = daemon->relay6; relay; relay = relay->next)
728 log_relay(AF_INET6, relay);
729
Simon Kelley1f776932012-12-16 19:46:08 +0000730 if (daemon->doing_dhcp6 || daemon->doing_ra)
731 dhcp_construct_contexts(now);
732
733 if (option_bool(OPT_RA))
734 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
735# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000736
Simon Kelley3b3f4412013-10-11 16:33:28 +0100737# ifdef HAVE_LINUX_NETWORK
738 if (did_bind)
739 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
740# endif
741
Simon Kelley8445f5d2012-12-17 21:54:08 +0000742 /* after dhcp_contruct_contexts */
743 if (daemon->dhcp || daemon->doing_dhcp6)
744 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000745#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000746
Simon Kelley832af0b2007-01-21 20:01:28 +0000747#ifdef HAVE_TFTP
Simon Kelley8bc4cec2012-07-03 21:04:11 +0100748 if (option_bool(OPT_TFTP))
Simon Kelley832af0b2007-01-21 20:01:28 +0000749 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000750#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100751 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000752 max_fd = FD_SETSIZE;
753#endif
754
Simon Kelley7622fc02009-06-04 20:32:05 +0100755 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100756 daemon->tftp_prefix ? _("root is ") : _("enabled"),
757 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000758 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Simon Kelleyf2621c72007-04-29 19:47:21 +0100759
Simon Kelley832af0b2007-01-21 20:01:28 +0000760 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100761 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000762 a single file will be sent to may clients (the file only needs
763 one fd). */
764
765 max_fd -= 30; /* use other than TFTP */
766
767 if (max_fd < 0)
768 max_fd = 5;
769 else if (max_fd < 100)
770 max_fd = max_fd/2;
771 else
772 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000773
774 /* if we have to use a limited range of ports,
775 that will limit the number of transfers */
776 if (daemon->start_tftp_port != 0 &&
777 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
778 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000779
780 if (daemon->tftp_max > max_fd)
781 {
782 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100783 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100784 _("restricting maximum simultaneous TFTP transfers to %d"),
785 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000786 }
787 }
788#endif
789
Simon Kelley1a6bca82008-07-11 11:11:42 +0100790 /* finished start-up - release original process */
791 if (err_pipe[1] != -1)
792 close(err_pipe[1]);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000793
Simon Kelley824af852008-02-12 20:43:05 +0000794 if (daemon->port != 0)
795 check_servers();
796
Simon Kelley7cebd202006-05-06 14:13:33 +0100797 pid = getpid();
798
Simon Kelley193de4a2014-12-10 17:32:16 +0000799#ifdef HAVE_LINUX_NETWORK
800 /* Using inotify, have to select a resolv file at startup */
801 poll_resolv(1, 0, now);
802#endif
803
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100804 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000805 {
Simon Kelley16972692006-10-16 20:04:18 +0100806 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100807 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100808 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000809
810 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100811 FD_ZERO(&wset);
812 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000813
Simon Kelley16972692006-10-16 20:04:18 +0100814 /* if we are out of resources, find how long we have to wait
815 for some to come free, we'll loop around then and restart
816 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100817 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100818 {
819 t.tv_usec = 0;
820 tp = &t;
821 }
822
Simon Kelley832af0b2007-01-21 20:01:28 +0000823 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
824 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000825 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000826 {
Simon Kelley16972692006-10-16 20:04:18 +0100827 t.tv_sec = 0;
828 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100829 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000830 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100831 /* Wake every second whilst waiting for DAD to complete */
832 else if (is_dad_listeners())
833 {
834 t.tv_sec = 1;
835 t.tv_usec = 0;
836 tp = &t;
837 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100838
Simon Kelley832af0b2007-01-21 20:01:28 +0000839#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100840 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100841#endif
842
Simon Kelley7622fc02009-06-04 20:32:05 +0100843#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100844 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100845 {
846 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100847 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000848 if (daemon->pxefd != -1)
849 {
850 FD_SET(daemon->pxefd, &rset);
851 bump_maxfd(daemon->pxefd, &maxfd);
852 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100853 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100854#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100855
Simon Kelley52b92f42012-01-22 16:05:15 +0000856#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100857 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000858 {
859 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000860 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000861 }
862
Simon Kelley1f776932012-12-16 19:46:08 +0000863 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000864 {
865 FD_SET(daemon->icmp6fd, &rset);
866 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000867 }
868#endif
869
Simon Kelley1ee9be42013-12-09 16:50:19 +0000870#if defined(HAVE_LINUX_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100871 FD_SET(daemon->netlinkfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100872 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley193de4a2014-12-10 17:32:16 +0000873 if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
874 {
875 FD_SET(daemon->inotifyfd, &rset);
876 bump_maxfd(daemon->inotifyfd, &maxfd);
877 }
Simon Kelley1ee9be42013-12-09 16:50:19 +0000878#elif defined(HAVE_BSD_NETWORK)
879 FD_SET(daemon->routefd, &rset);
880 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100881#endif
Simon Kelley193de4a2014-12-10 17:32:16 +0000882
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100883 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100884 bump_maxfd(piperead, &maxfd);
885
Simon Kelley7622fc02009-06-04 20:32:05 +0100886#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100887# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100888 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100889
Simon Kelleya9530962012-03-20 22:07:35 +0000890# ifdef HAVE_TFTP
891 while (helper_buf_empty() && do_tftp_script_run());
892# endif
893
Simon Kelley16972692006-10-16 20:04:18 +0100894 if (!helper_buf_empty())
895 {
896 FD_SET(daemon->helperfd, &wset);
897 bump_maxfd(daemon->helperfd, &maxfd);
898 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100899# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100900 /* need this for other side-effects */
901 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000902
903# ifdef HAVE_TFTP
904 while (do_tftp_script_run());
905# endif
906
Simon Kelley7622fc02009-06-04 20:32:05 +0100907# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100908#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100909
Simon Kelleyf2621c72007-04-29 19:47:21 +0100910 /* must do this just before select(), when we know no
911 more calls to my_syslog() can occur */
912 set_log_writer(&wset, &maxfd);
913
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100914 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
915 {
916 /* otherwise undefined after error */
917 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
918 }
919
920 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000921
Simon Kelleyf2621c72007-04-29 19:47:21 +0100922 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100923
924 /* prime. */
925 enumerate_interfaces(1);
926
Simon Kelley74c95c22011-10-19 09:33:39 +0100927 /* Check the interfaces to see if any have exited DAD state
928 and if so, bind the address. */
929 if (is_dad_listeners())
930 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100931 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100932 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
933 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100934 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100935 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100936
Simon Kelley1ee9be42013-12-09 16:50:19 +0000937#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100938 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100939 netlink_multicast();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000940#elif defined(HAVE_BSD_NETWORK)
941 if (FD_ISSET(daemon->routefd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100942 route_sock();
Simon Kelleyc52e1892010-06-07 22:01:39 +0100943#endif
944
Simon Kelley193de4a2014-12-10 17:32:16 +0000945#ifdef HAVE_LINUX_NETWORK
946 if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check())
947 poll_resolv(1, 1, now);
948#else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000949 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100950 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +0000951 if (daemon->last_resolv == 0 ||
952 difftime(now, daemon->last_resolv) > 1.0 ||
953 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000954 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100955 /* poll_resolv doesn't need to reload first time through, since
956 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +0100957
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100958 poll_resolv(0, daemon->last_resolv != 0, now);
959 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000960 }
Simon Kelley193de4a2014-12-10 17:32:16 +0000961#endif
962
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100963 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100964 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +0100965
Simon Kelley3d8df262005-08-29 12:19:27 +0100966#ifdef HAVE_DBUS
967 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +0000968 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +0100969 {
970 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100971 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100972 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +0100973 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100974 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100975 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100976 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100977#endif
Simon Kelley824af852008-02-12 20:43:05 +0000978
Simon Kelley5aabfc72007-08-29 11:24:47 +0100979 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000980
981#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +0100982 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +0000983#endif
984
Simon Kelley7622fc02009-06-04 20:32:05 +0100985#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100986 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +0000987 {
988 if (FD_ISSET(daemon->dhcpfd, &rset))
989 dhcp_packet(now, 0);
990 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
991 dhcp_packet(now, 1);
992 }
Simon Kelley16972692006-10-16 20:04:18 +0100993
Simon Kelley52b92f42012-01-22 16:05:15 +0000994#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100995 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +0100996 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000997
Simon Kelley1f776932012-12-16 19:46:08 +0000998 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
999 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +00001000#endif
1001
Simon Kelley1f15b812009-10-13 17:49:32 +01001002# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +01001003 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001004 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +01001005# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001006#endif
1007
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001008 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001009}
1010
Simon Kelley3be34542004-09-11 19:12:13 +01001011static void sig_handler(int sig)
1012{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001013 if (pid == 0)
1014 {
Simon Kelley16972692006-10-16 20:04:18 +01001015 /* ignore anything other than TERM during startup
1016 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001017 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001018 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001019 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001020 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +01001021 {
Simon Kelley16972692006-10-16 20:04:18 +01001022 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001023 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001024 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001025 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001026 else
1027 {
1028 /* master process */
1029 int event, errsave = errno;
1030
1031 if (sig == SIGHUP)
1032 event = EVENT_RELOAD;
1033 else if (sig == SIGCHLD)
1034 event = EVENT_CHILD;
1035 else if (sig == SIGALRM)
1036 event = EVENT_ALARM;
1037 else if (sig == SIGTERM)
1038 event = EVENT_TERM;
1039 else if (sig == SIGUSR1)
1040 event = EVENT_DUMP;
1041 else if (sig == SIGUSR2)
1042 event = EVENT_REOPEN;
1043 else
1044 return;
1045
Simon Kelleyc72daea2012-01-05 21:33:27 +00001046 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001047 errno = errsave;
1048 }
Simon Kelley3be34542004-09-11 19:12:13 +01001049}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001050
Simon Kelley353ae4d2012-03-19 20:07:51 +00001051/* now == 0 -> queue immediate callback */
1052void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001053{
Simon Kelley884a6df2012-03-20 16:20:22 +00001054 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001055 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001056 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1057 if ((now == 0 || difftime(event, now) <= 0.0))
1058 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1059 else
1060 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001061 }
Simon Kelley741c2952012-02-25 13:09:18 +00001062}
1063
Simon Kelley47a95162014-07-08 22:22:02 +01001064void queue_event(int event)
Simon Kelleya0358e52014-06-07 13:38:48 +01001065{
Simon Kelley47a95162014-07-08 22:22:02 +01001066 send_event(pipewrite, event, 0, NULL);
Simon Kelleya0358e52014-06-07 13:38:48 +01001067}
1068
Simon Kelleyc72daea2012-01-05 21:33:27 +00001069void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001070{
1071 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001072 struct iovec iov[2];
1073
Simon Kelley5aabfc72007-08-29 11:24:47 +01001074 ev.event = event;
1075 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001076 ev.msg_sz = msg ? strlen(msg) : 0;
1077
1078 iov[0].iov_base = &ev;
1079 iov[0].iov_len = sizeof(ev);
1080 iov[1].iov_base = msg;
1081 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001082
1083 /* error pipe, debug mode. */
1084 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001085 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001086 else
1087 /* pipe is non-blocking and struct event_desc is smaller than
1088 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001089 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001090}
Simon Kelley3d8df262005-08-29 12:19:27 +01001091
Simon Kelleyc72daea2012-01-05 21:33:27 +00001092/* NOTE: the memory used to return msg is leaked: use msgs in events only
1093 to describe fatal errors. */
1094static int read_event(int fd, struct event_desc *evp, char **msg)
1095{
1096 char *buf;
1097
1098 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1099 return 0;
1100
1101 *msg = NULL;
1102
1103 if (evp->msg_sz != 0 &&
1104 (buf = malloc(evp->msg_sz + 1)) &&
1105 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1106 {
1107 buf[evp->msg_sz] = 0;
1108 *msg = buf;
1109 }
1110
1111 return 1;
1112}
1113
1114static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001115{
1116 errno = ev->data;
1117
1118 switch (ev->event)
1119 {
1120 case EVENT_DIE:
1121 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001122
1123 case EVENT_FORK_ERR:
1124 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001125
1126 case EVENT_PIPE_ERR:
1127 die(_("failed to create helper: %s"), NULL, EC_MISC);
1128
1129 case EVENT_CAP_ERR:
1130 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1131
1132 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001133 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001134
1135 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001136 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001137
1138 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001139 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001140
1141 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001142 die(_("cannot open log %s: %s"), msg, EC_FILE);
1143
1144 case EVENT_LUA_ERR:
1145 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001146
1147 case EVENT_TFTP_ERR:
1148 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001149 }
1150}
1151
Simon Kelley5aabfc72007-08-29 11:24:47 +01001152static void async_event(int pipe, time_t now)
1153{
1154 pid_t p;
1155 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001156 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001157 char *msg;
1158
1159 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1160 to describe fatal errors. */
1161
1162 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001163 switch (ev.event)
1164 {
1165 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001166#ifdef HAVE_DNSSEC
1167 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1168 {
1169 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1170 reset_option_bool(OPT_DNSSEC_TIME);
1171 }
1172#endif
1173 /* fall through */
1174
1175 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001176 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001177
Simon Kelley7b1eae42014-02-20 13:43:28 +00001178 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001179 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001180 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1181 {
1182 reload_servers(daemon->resolv_files->name);
1183 check = 1;
1184 }
1185
1186 if (daemon->servers_file)
1187 {
1188 read_servers_file();
1189 check = 1;
1190 }
1191
1192 if (check)
1193 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001194 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001195
Simon Kelley7622fc02009-06-04 20:32:05 +01001196#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001197 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001198#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001199 break;
1200
1201 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001202 if (daemon->port != 0)
1203 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001204 break;
1205
1206 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001207#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001208 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001209 {
1210 lease_prune(NULL, now);
1211 lease_update_file(now);
1212 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001213#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001214 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001215 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1216 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001217#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001218#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001219 break;
1220
1221 case EVENT_CHILD:
1222 /* See Stevens 5.10 */
1223 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1224 if (p == -1)
1225 {
1226 if (errno != EINTR)
1227 break;
1228 }
1229 else
1230 for (i = 0 ; i < MAX_PROCS; i++)
1231 if (daemon->tcp_pids[i] == p)
1232 daemon->tcp_pids[i] = 0;
1233 break;
1234
1235 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001236 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001237 break;
1238
1239 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001240 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001241 break;
1242
1243 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001244 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1245 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001246 break;
1247
Simon Kelley1a6bca82008-07-11 11:11:42 +01001248 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001249 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001250 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001251 case EVENT_LUA_ERR:
1252 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001253 break;
1254
Simon Kelley5aabfc72007-08-29 11:24:47 +01001255 case EVENT_REOPEN:
1256 /* Note: this may leave TCP-handling processes with the old file still open.
1257 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1258 we leave them logging to the old file. */
1259 if (daemon->log_file != NULL)
1260 log_reopen(daemon->log_file);
1261 break;
Simon Kelleya0358e52014-06-07 13:38:48 +01001262
1263 case EVENT_NEWADDR:
1264 newaddress(now);
1265 break;
Simon Kelley47a95162014-07-08 22:22:02 +01001266
1267 case EVENT_NEWROUTE:
1268 resend_query();
1269 /* Force re-reading resolv file right now, for luck. */
1270 poll_resolv(0, 1, now);
1271 break;
1272
Simon Kelley5aabfc72007-08-29 11:24:47 +01001273 case EVENT_TERM:
1274 /* Knock all our children on the head. */
1275 for (i = 0; i < MAX_PROCS; i++)
1276 if (daemon->tcp_pids[i] != 0)
1277 kill(daemon->tcp_pids[i], SIGALRM);
1278
Simon Kelleyc72daea2012-01-05 21:33:27 +00001279#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001280 /* handle pending lease transitions */
1281 if (daemon->helperfd != -1)
1282 {
1283 /* block in writes until all done */
1284 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1285 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1286 do {
1287 helper_write();
1288 } while (!helper_buf_empty() || do_script_run(now));
1289 close(daemon->helperfd);
1290 }
1291#endif
1292
1293 if (daemon->lease_stream)
1294 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001295
1296 if (daemon->runfile)
1297 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001298
1299 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1300 flush_log();
1301 exit(EC_GOOD);
1302 }
1303}
1304
Simon Kelley47a95162014-07-08 22:22:02 +01001305static void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001306{
1307 struct resolvc *res, *latest;
1308 struct stat statbuf;
1309 time_t last_change = 0;
1310 /* There may be more than one possible file.
1311 Go through and find the one which changed _last_.
1312 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001313
Simon Kelley28866e92011-02-14 20:19:14 +00001314 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001315 return;
1316
Simon Kelley5aabfc72007-08-29 11:24:47 +01001317 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1318 if (stat(res->name, &statbuf) == -1)
1319 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001320 if (force)
1321 {
1322 res->mtime = 0;
1323 continue;
1324 }
1325
Simon Kelley5aabfc72007-08-29 11:24:47 +01001326 if (!res->logged)
1327 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1328 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001329
1330 if (res->mtime != 0)
1331 {
1332 /* existing file evaporated, force selection of the latest
1333 file even if its mtime hasn't changed since we last looked */
1334 poll_resolv(1, do_reload, now);
1335 return;
1336 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001337 }
1338 else
1339 {
1340 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001341 if (force || (statbuf.st_mtime != res->mtime))
1342 {
1343 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001344 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1345 {
1346 last_change = statbuf.st_mtime;
1347 latest = res;
1348 }
1349 }
1350 }
1351
1352 if (latest)
1353 {
1354 static int warned = 0;
1355 if (reload_servers(latest->name))
1356 {
1357 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1358 warned = 0;
1359 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001360 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001361 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001362 }
1363 else
1364 {
1365 latest->mtime = 0;
1366 if (!warned)
1367 {
1368 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1369 warned = 1;
1370 }
1371 }
1372 }
1373}
1374
1375void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001376{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001377 (void)now;
1378
Simon Kelley824af852008-02-12 20:43:05 +00001379 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001380 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001381
Simon Kelley7622fc02009-06-04 20:32:05 +01001382#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001383 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001384 {
Simon Kelley28866e92011-02-14 20:19:14 +00001385 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001386 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001387 reread_dhcp();
Simon Kelley3d8df262005-08-29 12:19:27 +01001388 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001389 lease_update_from_configs();
1390 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001391 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001392 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001393#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001394 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001395 /* Not doing DHCP, so no lease system, manage
1396 alarms for ra only */
1397 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001398#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001399#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001400}
1401
Simon Kelley5aabfc72007-08-29 11:24:47 +01001402static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001403{
1404 struct serverfd *serverfdp;
1405 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001406 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001407
1408#ifdef HAVE_TFTP
1409 int tftp = 0;
1410 struct tftp_transfer *transfer;
1411 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1412 {
1413 tftp++;
1414 FD_SET(transfer->sockfd, set);
1415 bump_maxfd(transfer->sockfd, maxfdp);
1416 }
1417#endif
1418
Simon Kelley16972692006-10-16 20:04:18 +01001419 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001420 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001421 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001422
Simon Kelley3be34542004-09-11 19:12:13 +01001423 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1424 {
1425 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001426 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001427 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001428
1429 if (daemon->port != 0 && !daemon->osport)
1430 for (i = 0; i < RANDOM_SOCKS; i++)
1431 if (daemon->randomsocks[i].refcount != 0)
1432 {
1433 FD_SET(daemon->randomsocks[i].fd, set);
1434 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1435 }
1436
Simon Kelley3be34542004-09-11 19:12:13 +01001437 for (listener = daemon->listeners; listener; listener = listener->next)
1438 {
Simon Kelley16972692006-10-16 20:04:18 +01001439 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001440 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001441 {
1442 FD_SET(listener->fd, set);
1443 bump_maxfd(listener->fd, maxfdp);
1444 }
1445
1446 /* death of a child goes through the select loop, so
1447 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001448 if (listener->tcpfd != -1)
1449 for (i = 0; i < MAX_PROCS; i++)
1450 if (daemon->tcp_pids[i] == 0)
1451 {
1452 FD_SET(listener->tcpfd, set);
1453 bump_maxfd(listener->tcpfd, maxfdp);
1454 break;
1455 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001456
Simon Kelley832af0b2007-01-21 20:01:28 +00001457#ifdef HAVE_TFTP
1458 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1459 {
1460 FD_SET(listener->tftpfd, set);
1461 bump_maxfd(listener->tftpfd, maxfdp);
1462 }
1463#endif
1464
1465 }
1466
Simon Kelley16972692006-10-16 20:04:18 +01001467 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001468}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001469
Simon Kelley5aabfc72007-08-29 11:24:47 +01001470static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001471{
1472 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001473 struct listener *listener;
1474 int i;
1475
Simon Kelley832af0b2007-01-21 20:01:28 +00001476 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1477 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001478 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1479
1480 if (daemon->port != 0 && !daemon->osport)
1481 for (i = 0; i < RANDOM_SOCKS; i++)
1482 if (daemon->randomsocks[i].refcount != 0 &&
1483 FD_ISSET(daemon->randomsocks[i].fd, set))
1484 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001485
1486 for (listener = daemon->listeners; listener; listener = listener->next)
1487 {
Simon Kelley824af852008-02-12 20:43:05 +00001488 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001489 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001490
Simon Kelley832af0b2007-01-21 20:01:28 +00001491#ifdef HAVE_TFTP
1492 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001493 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001494#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001495
Simon Kelley824af852008-02-12 20:43:05 +00001496 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001497 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001498 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001499 struct irec *iface = NULL;
1500 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001501 union mysockaddr tcp_addr;
1502 socklen_t tcp_len = sizeof(union mysockaddr);
1503
1504 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001505
Simon Kelley46b06652013-02-04 21:47:59 +00001506 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001507 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001508
Simon Kelley46b06652013-02-04 21:47:59 +00001509 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1510 {
1511 close(confd);
1512 continue;
1513 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001514
1515 /* Make sure that the interface list is up-to-date.
1516
1517 We do this here as we may need the results below, and
1518 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001519
Simon Kelley76dd75d2013-05-23 10:04:25 +01001520 Multiple calls to enumerate_interfaces() per select loop are
1521 inhibited, so calls to it in the child process (which doesn't select())
1522 have no effect. This avoids two processes reading from the same
1523 netlink fd and screwing the pooch entirely.
1524 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001525
Simon Kelley76dd75d2013-05-23 10:04:25 +01001526 enumerate_interfaces(0);
1527
1528 if (option_bool(OPT_NOWILD))
1529 iface = listener->iface; /* May be NULL */
1530 else
1531 {
1532 int if_index;
1533 char intr_name[IF_NAMESIZE];
1534
1535 /* if we can find the arrival interface, check it's one that's allowed */
1536 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1537 indextoname(listener->tcpfd, if_index, intr_name))
1538 {
1539 struct all_addr addr;
1540 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001541#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001542 if (tcp_addr.sa.sa_family == AF_INET6)
1543 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001544#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001545
1546 for (iface = daemon->interfaces; iface; iface = iface->next)
1547 if (iface->index == if_index)
1548 break;
1549
1550 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1551 client_ok = 0;
1552 }
1553
1554 if (option_bool(OPT_CLEVERBIND))
1555 iface = listener->iface; /* May be NULL */
1556 else
1557 {
1558 /* Check for allowed interfaces when binding the wildcard address:
1559 we do this by looking for an interface with the same address as
1560 the local address of the TCP connection, then looking to see if that's
1561 an allowed interface. As a side effect, we get the netmask of the
1562 interface too, for localisation. */
1563
1564 for (iface = daemon->interfaces; iface; iface = iface->next)
1565 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1566 break;
1567
1568 if (!iface)
1569 client_ok = 0;
1570 }
1571 }
1572
Simon Kelley22ce5502013-01-22 13:53:04 +00001573 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001574 {
1575 shutdown(confd, SHUT_RDWR);
1576 close(confd);
1577 }
1578#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001579 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001580 {
1581 if (p != -1)
1582 {
1583 int i;
1584 for (i = 0; i < MAX_PROCS; i++)
1585 if (daemon->tcp_pids[i] == 0)
1586 {
1587 daemon->tcp_pids[i] = p;
1588 break;
1589 }
1590 }
1591 close(confd);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001592
1593 /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
1594 daemon->log_id += TCP_MAX_QUERIES;
Simon Kelley832af0b2007-01-21 20:01:28 +00001595 }
1596#endif
1597 else
1598 {
1599 unsigned char *buff;
1600 struct server *s;
1601 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001602 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001603 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001604
1605 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001606 {
1607 netmask = iface->netmask;
1608 auth_dns = iface->dns_auth;
1609 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001610 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001611 {
1612 netmask.s_addr = 0;
1613 auth_dns = 0;
1614 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001615
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001616#ifndef NO_FORK
1617 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1618 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001619 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001620 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001621#endif
1622
Simon Kelley832af0b2007-01-21 20:01:28 +00001623 /* start with no upstream connections. */
1624 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001625 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001626
1627 /* The connected socket inherits non-blocking
1628 attribute from the listening socket.
1629 Reset that here. */
1630 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1631 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1632
Simon Kelley4f7b3042012-11-28 21:27:02 +00001633 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001634
Simon Kelley832af0b2007-01-21 20:01:28 +00001635 shutdown(confd, SHUT_RDWR);
1636 close(confd);
1637
1638 if (buff)
1639 free(buff);
1640
1641 for (s = daemon->servers; s; s = s->next)
1642 if (s->tcpfd != -1)
1643 {
1644 shutdown(s->tcpfd, SHUT_RDWR);
1645 close(s->tcpfd);
1646 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001647#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001648 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001649 {
1650 flush_log();
1651 _exit(0);
1652 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001653#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001654 }
1655 }
1656 }
Simon Kelley3be34542004-09-11 19:12:13 +01001657}
1658
Simon Kelley7622fc02009-06-04 20:32:05 +01001659#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001660int make_icmp_sock(void)
1661{
Simon Kelley7cebd202006-05-06 14:13:33 +01001662 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001663 int zeroopt = 0;
1664
1665 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1666 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001667 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001668 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1669 {
1670 close(fd);
1671 fd = -1;
1672 }
1673 }
1674
1675 return fd;
1676}
1677
Simon Kelley5aabfc72007-08-29 11:24:47 +01001678int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001679{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001680 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001681
1682 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001683 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001684 better not use any resources our caller has in use...)
1685 but we remain deaf to signals or further DHCP packets. */
1686
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001687 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001688 struct sockaddr_in saddr;
1689 struct {
1690 struct ip ip;
1691 struct icmp icmp;
1692 } packet;
1693 unsigned short id = rand16();
1694 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001695 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001696 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001697
Simon Kelley824af852008-02-12 20:43:05 +00001698#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001699 if ((fd = make_icmp_sock()) == -1)
1700 return 0;
1701#else
1702 int opt = 2000;
1703 fd = daemon->dhcp_icmp_fd;
1704 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1705#endif
1706
Simon Kelley3be34542004-09-11 19:12:13 +01001707 saddr.sin_family = AF_INET;
1708 saddr.sin_port = 0;
1709 saddr.sin_addr = addr;
1710#ifdef HAVE_SOCKADDR_SA_LEN
1711 saddr.sin_len = sizeof(struct sockaddr_in);
1712#endif
1713
1714 memset(&packet.icmp, 0, sizeof(packet.icmp));
1715 packet.icmp.icmp_type = ICMP_ECHO;
1716 packet.icmp.icmp_id = id;
1717 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1718 j += ((u16 *)&packet.icmp)[i];
1719 while (j>>16)
1720 j = (j & 0xffff) + (j >> 16);
1721 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1722
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001723 while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001724 (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
1725 retry_send());
1726
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001727 for (now = start = dnsmasq_time();
1728 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001729 {
1730 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001731 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001732 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001733 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001734 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001735
1736 tv.tv_usec = 250000;
1737 tv.tv_sec = 0;
1738
1739 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001740 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001741 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001742 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001743 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001744
1745#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001746 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001747 {
1748 FD_SET(daemon->icmp6fd, &rset);
1749 bump_maxfd(daemon->icmp6fd, &maxfd);
1750 }
1751#endif
1752
Simon Kelleyf2621c72007-04-29 19:47:21 +01001753 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1754 {
1755 FD_ZERO(&rset);
1756 FD_ZERO(&wset);
1757 }
1758
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001759 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001760
1761 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001762 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001763
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001764#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001765 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1766 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001767#endif
1768
Simon Kelley832af0b2007-01-21 20:01:28 +00001769#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001770 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001771#endif
1772
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001773 if (FD_ISSET(fd, &rset) &&
1774 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001775 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1776 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1777 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1778 packet.icmp.icmp_seq == 0 &&
1779 packet.icmp.icmp_id == id)
1780 {
1781 gotreply = 1;
1782 break;
1783 }
1784 }
1785
Simon Kelley824af852008-02-12 20:43:05 +00001786#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001787 close(fd);
1788#else
Simon Kelley3be34542004-09-11 19:12:13 +01001789 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001790 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1791#endif
1792
Simon Kelley3be34542004-09-11 19:12:13 +01001793 return gotreply;
1794}
Simon Kelley7622fc02009-06-04 20:32:05 +01001795#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001796
1797