blob: a7c5da8fbd01fad50b2dbf87e3b11eb4eed0aaa4 [file] [log] [blame]
Simon Kelleyaff33962015-01-31 20:13:40 +00001/* dnsmasq is Copyright (c) 2000-2015 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
Stefan Tomanek30d08792015-03-31 22:32:11 +010061#ifdef HAVE_TFTP
62 int tftp_prefix_missing = 0;
63#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +010064
Simon Kelley824af852008-02-12 20:43:05 +000065#ifdef LOCALEDIR
Simon Kelleyb8187c82005-11-26 21:46:27 +000066 setlocale(LC_ALL, "");
67 bindtextdomain("dnsmasq", LOCALEDIR);
68 textdomain("dnsmasq");
69#endif
70
Simon Kelley9e4abcb2004-01-22 19:47:41 +000071 sigact.sa_handler = sig_handler;
72 sigact.sa_flags = 0;
73 sigemptyset(&sigact.sa_mask);
74 sigaction(SIGUSR1, &sigact, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +010075 sigaction(SIGUSR2, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000076 sigaction(SIGHUP, &sigact, NULL);
77 sigaction(SIGTERM, &sigact, NULL);
Simon Kelley44a2a312004-03-10 20:04:35 +000078 sigaction(SIGALRM, &sigact, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +010079 sigaction(SIGCHLD, &sigact, NULL);
80
81 /* ignore SIGPIPE */
82 sigact.sa_handler = SIG_IGN;
83 sigaction(SIGPIPE, &sigact, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084
Simon Kelley5aabfc72007-08-29 11:24:47 +010085 umask(022); /* known umask, create leases and pid files as 0644 */
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +010086
87 rand_init(); /* Must precede read_opts() */
88
Simon Kelley5aabfc72007-08-29 11:24:47 +010089 read_opts(argc, argv, compile_opts);
Simon Kelleyc3e0b9b2013-12-31 13:50:39 +000090
Simon Kelley3be34542004-09-11 19:12:13 +010091 if (daemon->edns_pktsz < PACKETSZ)
Simon Kelley60b68062014-01-08 12:10:28 +000092 daemon->edns_pktsz = PACKETSZ;
Simon Kelley3ddacb82014-01-08 14:32:03 +000093
Simon Kelley0a852542005-03-23 20:28:59 +000094 daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
95 daemon->edns_pktsz : DNSMASQ_PACKETSZ;
96 daemon->packet = safe_malloc(daemon->packet_buff_sz);
Simon Kelley3ddacb82014-01-08 14:32:03 +000097
Simon Kelleyc72daea2012-01-05 21:33:27 +000098 daemon->addrbuff = safe_malloc(ADDRSTRLEN);
Simon Kelley25cf5e32015-01-09 15:53:03 +000099 if (option_bool(OPT_EXTRALOG))
100 daemon->addrbuff2 = 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 Kelley04918052015-01-26 11:23:43 +0000148#endif
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000149
Simon Kelley04918052015-01-26 11:23:43 +0000150#ifndef HAVE_INOTIFY
Simon Kelley70d18732015-01-31 19:59:29 +0000151 if (daemon->dynamic_dirs)
152 die(_("dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"), NULL, EC_BADCONF);
Simon Kelley309331f2006-04-22 15:05:01 +0100153#endif
Simon Kelley2b5bae92012-06-26 16:55:23 +0100154
Simon Kelley0744ca62014-01-25 16:40:15 +0000155 if (option_bool(OPT_DNSSEC_VALID))
156 {
Simon Kelley3ddacb82014-01-08 14:32:03 +0000157#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000158 if (!daemon->ds)
Simon Kelley360f2512015-03-07 18:28:06 +0000159 die(_("no trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
Simon Kelley0744ca62014-01-25 16:40:15 +0000160
161 if (daemon->cachesize < CACHESIZ)
Simon Kelley360f2512015-03-07 18:28:06 +0000162 die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
Simon Kelley0744ca62014-01-25 16:40:15 +0000163#else
164 die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3ddacb82014-01-08 14:32:03 +0000165#endif
Simon Kelley0744ca62014-01-25 16:40:15 +0000166 }
Simon Kelley3ddacb82014-01-08 14:32:03 +0000167
Simon Kelley832af0b2007-01-21 20:01:28 +0000168#ifndef HAVE_TFTP
Simon Kelley9b40cbf2012-07-13 19:58:26 +0100169 if (option_bool(OPT_TFTP))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100170 die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Simon Kelley832af0b2007-01-21 20:01:28 +0000171#endif
172
Simon Kelley7de060b2011-08-26 17:24:52 +0100173#ifdef HAVE_CONNTRACK
174 if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
Simon Kelley360f2512015-03-07 18:28:06 +0000175 die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
Simon Kelley7de060b2011-08-26 17:24:52 +0100176#else
177 if (option_bool(OPT_CONNTRACK))
Simon Kelley360f2512015-03-07 18:28:06 +0000178 die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
Simon Kelley7de060b2011-08-26 17:24:52 +0100179#endif
180
Simon Kelley824af852008-02-12 20:43:05 +0000181#ifdef HAVE_SOLARIS_NETWORK
182 if (daemon->max_logs != 0)
183 die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
184#endif
185
Simon Kelley572b41e2011-02-18 18:11:18 +0000186#ifdef __ANDROID__
187 if (daemon->max_logs != 0)
188 die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
189#endif
190
Simon Kelley4820dce2012-12-18 18:30:30 +0000191#ifndef HAVE_AUTH
192 if (daemon->authserver)
193 die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
194#endif
195
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100196#ifndef HAVE_LOOP
197 if (option_bool(OPT_LOOP_DETECT))
Simon Kelley360f2512015-03-07 18:28:06 +0000198 die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100199#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100200
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100201 now = dnsmasq_time();
Simon Kelley4f7b3042012-11-28 21:27:02 +0000202
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000203 /* Create a serial at startup if not configured. */
Simon Kelley4f7b3042012-11-28 21:27:02 +0000204 if (daemon->authinterface && daemon->soa_sn == 0)
205#ifdef HAVE_BROKEN_RTC
Simon Kelleyb0ff8582013-02-06 09:57:47 +0000206 die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
Simon Kelley4f7b3042012-11-28 21:27:02 +0000207#else
208 daemon->soa_sn = now;
209#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210
Simon Kelleyff7eea22013-09-04 18:01:38 +0100211#ifdef HAVE_DHCP6
212 if (daemon->dhcp6)
213 {
214 daemon->doing_ra = option_bool(OPT_RA);
Simon Kelley1f776932012-12-16 19:46:08 +0000215
Simon Kelleyff7eea22013-09-04 18:01:38 +0100216 for (context = daemon->dhcp6; context; context = context->next)
Simon Kelley1f776932012-12-16 19:46:08 +0000217 {
Simon Kelleyff7eea22013-09-04 18:01:38 +0100218 if (context->flags & CONTEXT_DHCP)
219 daemon->doing_dhcp6 = 1;
220 if (context->flags & CONTEXT_RA)
221 daemon->doing_ra = 1;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000222#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100223 if (context->flags & CONTEXT_TEMPLATE)
224 die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
Simon Kelleybb86e852012-12-17 22:00:53 +0000225#endif
Simon Kelley1f776932012-12-16 19:46:08 +0000226 }
Simon Kelley1f776932012-12-16 19:46:08 +0000227 }
Simon Kelleyff7eea22013-09-04 18:01:38 +0100228#endif
229
230#ifdef HAVE_DHCP
231 /* Note that order matters here, we must call lease_init before
232 creating any file descriptors which shouldn't be leaked
233 to the lease-script init process. We need to call common_init
234 before lease_init to allocate buffers it uses.*/
235 if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
236 {
237 dhcp_common_init();
238 if (daemon->dhcp || daemon->doing_dhcp6)
239 lease_init(now);
240 }
241
242 if (daemon->dhcp || daemon->relay4)
243 dhcp_init();
244
245# ifdef HAVE_DHCP6
Simon Kelley89500e32013-09-20 16:29:20 +0100246 if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
Simon Kelleyff7eea22013-09-04 18:01:38 +0100247 ra_init(now);
248
249 if (daemon->doing_dhcp6 || daemon->relay6)
250 dhcp6_init();
251# endif
Simon Kelley843c96b2012-02-27 17:42:38 +0000252
Simon Kelley7622fc02009-06-04 20:32:05 +0100253#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100254
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000255#ifdef HAVE_IPSET
256 if (daemon->ipsets)
257 ipset_init();
258#endif
259
Simon Kelley1ee9be42013-12-09 16:50:19 +0000260#if defined(HAVE_LINUX_NETWORK)
Simon Kelley801ca9a2012-03-06 19:30:17 +0000261 netlink_init();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000262#elif defined(HAVE_BSD_NETWORK)
263 route_init();
Simon Kelley801ca9a2012-03-06 19:30:17 +0000264#endif
265
Simon Kelley1ee9be42013-12-09 16:50:19 +0000266 if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
267 die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
268
Simon Kelley115ac3e2013-05-20 11:28:32 +0100269 if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100270 die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
Simon Kelley843c96b2012-02-27 17:42:38 +0000271
Simon Kelley54dd3932012-06-20 11:23:38 +0100272 if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
Simon Kelley5aabfc72007-08-29 11:24:47 +0100273 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100274 create_bound_listeners(1);
Simon Kelley54dd3932012-06-20 11:23:38 +0100275
276 if (!option_bool(OPT_CLEVERBIND))
277 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
278 if (if_tmp->name && !if_tmp->used)
279 die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
Simon Kelley9380ba72012-04-16 14:41:56 +0100280
281#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
282 /* after enumerate_interfaces() */
Simon Kelley3b3f4412013-10-11 16:33:28 +0100283 bound_device = whichdevice();
284
Simon Kelley9380ba72012-04-16 14:41:56 +0100285 if (daemon->dhcp)
286 {
Simon Kelley3b3f4412013-10-11 16:33:28 +0100287 if (!daemon->relay4 && bound_device)
288 {
289 bindtodevice(bound_device, daemon->dhcpfd);
290 did_bind = 1;
291 }
292 if (daemon->enable_pxe && bound_device)
293 {
294 bindtodevice(bound_device, daemon->pxefd);
295 did_bind = 1;
296 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100297 }
298#endif
299
300#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100301 if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
302 {
303 bindtodevice(bound_device, daemon->dhcp6fd);
304 did_bind = 1;
305 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100306#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100307 }
Simon Kelley28866e92011-02-14 20:19:14 +0000308 else
Simon Kelley74c95c22011-10-19 09:33:39 +0100309 create_wildcard_listeners();
Simon Kelley5d162f22012-12-20 14:55:46 +0000310
311#ifdef HAVE_DHCP6
312 /* after enumerate_interfaces() */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100313 if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Simon Kelley5d162f22012-12-20 14:55:46 +0000314 join_multicast(1);
Simon Kelley3511a922013-11-07 10:28:11 +0000315
316 /* After netlink_init() and before create_helper() */
317 lease_make_duid(now);
Simon Kelley5d162f22012-12-20 14:55:46 +0000318#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100319
Simon Kelley824af852008-02-12 20:43:05 +0000320 if (daemon->port != 0)
Simon Kelley82e3f452014-01-31 21:05:48 +0000321 {
322 cache_init();
Simon Kelley193de4a2014-12-10 17:32:16 +0000323
Simon Kelley82e3f452014-01-31 21:05:48 +0000324#ifdef HAVE_DNSSEC
325 blockdata_init();
326#endif
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000327 }
Simon Kelley193de4a2014-12-10 17:32:16 +0000328
Simon Kelley04918052015-01-26 11:23:43 +0000329#ifdef HAVE_INOTIFY
Simon Kelley70d18732015-01-31 19:59:29 +0000330 if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000331 inotify_dnsmasq_init();
332 else
333 daemon->inotifyfd = -1;
Simon Kelley193de4a2014-12-10 17:32:16 +0000334#endif
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000335
Simon Kelley28866e92011-02-14 20:19:14 +0000336 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100337#ifdef HAVE_DBUS
338 {
339 char *err;
340 daemon->dbus = NULL;
341 daemon->watches = NULL;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100342 if ((err = dbus_init()))
343 die(_("DBus error: %s"), err, EC_MISC);
Simon Kelley3d8df262005-08-29 12:19:27 +0100344 }
345#else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100346 die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
Simon Kelley3d8df262005-08-29 12:19:27 +0100347#endif
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100348
Simon Kelley824af852008-02-12 20:43:05 +0000349 if (daemon->port != 0)
350 pre_allocate_sfds();
Simon Kelley1a6bca82008-07-11 11:11:42 +0100351
Simon Kelleyc72daea2012-01-05 21:33:27 +0000352#if defined(HAVE_SCRIPT)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100353 /* Note getpwnam returns static storage */
Simon Kelley843c96b2012-02-27 17:42:38 +0000354 if ((daemon->dhcp || daemon->dhcp6) &&
355 daemon->scriptuser &&
Simon Kelleyc72daea2012-01-05 21:33:27 +0000356 (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100357 {
358 if ((ent_pw = getpwnam(daemon->scriptuser)))
359 {
360 script_uid = ent_pw->pw_uid;
361 script_gid = ent_pw->pw_gid;
362 }
363 else
364 baduser = daemon->scriptuser;
365 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100366#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000367
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
369 baduser = daemon->username;
370 else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
371 baduser = daemon->groupname;
372
373 if (baduser)
374 die(_("unknown user or group: %s"), baduser, EC_BADCONF);
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000375
Simon Kelley1a6bca82008-07-11 11:11:42 +0100376 /* implement group defaults, "dip" if available, or group associated with uid */
377 if (!daemon->group_set && !gp)
378 {
379 if (!(gp = getgrnam(CHGRP)) && ent_pw)
380 gp = getgrgid(ent_pw->pw_gid);
381
382 /* for error message */
383 if (gp)
384 daemon->groupname = gp->gr_name;
385 }
386
387#if defined(HAVE_LINUX_NETWORK)
388 /* determine capability API version here, while we can still
389 call safe_malloc */
390 if (ent_pw && ent_pw->pw_uid != 0)
391 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100392 int capsize = 1; /* for header version 1 */
Simon Kelley3927da42008-07-20 15:10:39 +0100393 hdr = safe_malloc(sizeof(*hdr));
394
Simon Kelley1a6bca82008-07-11 11:11:42 +0100395 /* find version supported by kernel */
396 memset(hdr, 0, sizeof(*hdr));
397 capget(hdr, NULL);
398
399 if (hdr->version != LINUX_CAPABILITY_VERSION_1)
400 {
401 /* if unknown version, use largest supported version (3) */
402 if (hdr->version != LINUX_CAPABILITY_VERSION_2)
403 hdr->version = LINUX_CAPABILITY_VERSION_3;
404 capsize = 2;
405 }
406
407 data = safe_malloc(sizeof(*data) * capsize);
408 memset(data, 0, sizeof(*data) * capsize);
409 }
410#endif
411
Simon Kelley5aabfc72007-08-29 11:24:47 +0100412 /* Use a pipe to carry signals and other events back to the event loop
Simon Kelley1a6bca82008-07-11 11:11:42 +0100413 in a race-free manner and another to carry errors to daemon-invoking process */
414 safe_pipe(pipefd, 1);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100415
416 piperead = pipefd[0];
417 pipewrite = pipefd[1];
418 /* prime the pipe to load stuff first time. */
Simon Kelleye98bd522014-03-28 20:41:23 +0000419 send_event(pipewrite, EVENT_INIT, 0, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100420
421 err_pipe[1] = -1;
Simon Kelley16972692006-10-16 20:04:18 +0100422
Simon Kelley28866e92011-02-14 20:19:14 +0000423 if (!option_bool(OPT_DEBUG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000424 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000425 /* The following code "daemonizes" the process.
426 See Stevens section 12.4 */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100427
Simon Kelley9e038942008-05-30 20:06:34 +0100428 if (chdir("/") != 0)
429 die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
430
Simon Kelley16972692006-10-16 20:04:18 +0100431#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +0000432 if (!option_bool(OPT_NO_FORK))
Simon Kelley3be34542004-09-11 19:12:13 +0100433 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100434 pid_t pid;
435
Simon Kelley1a6bca82008-07-11 11:11:42 +0100436 /* pipe to carry errors back to original process.
437 When startup is complete we close this and the process terminates. */
438 safe_pipe(err_pipe, 0);
439
Simon Kelley7622fc02009-06-04 20:32:05 +0100440 if ((pid = fork()) == -1)
441 /* fd == -1 since we've not forked, never returns. */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000442 send_event(-1, EVENT_FORK_ERR, errno, NULL);
Simon Kelley9e038942008-05-30 20:06:34 +0100443
Simon Kelley5aabfc72007-08-29 11:24:47 +0100444 if (pid != 0)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445 {
446 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000447 char *msg;
448
Simon Kelley1a6bca82008-07-11 11:11:42 +0100449 /* close our copy of write-end */
Simon Kelleyff841eb2015-03-11 21:36:30 +0000450 while (retry_send(close(err_pipe[1])));
Simon Kelley1a6bca82008-07-11 11:11:42 +0100451
452 /* check for errors after the fork */
Simon Kelleyc72daea2012-01-05 21:33:27 +0000453 if (read_event(err_pipe[0], &ev, &msg))
454 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100455
456 _exit(EC_GOOD);
457 }
458
Simon Kelleyff841eb2015-03-11 21:36:30 +0000459 while (retry_send(close(err_pipe[0])));
Simon Kelley1a6bca82008-07-11 11:11:42 +0100460
461 /* NO calls to die() from here on. */
Simon Kelley3be34542004-09-11 19:12:13 +0100462
463 setsid();
Simon Kelley7622fc02009-06-04 20:32:05 +0100464
465 if ((pid = fork()) == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +0000466 send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
Simon Kelley7622fc02009-06-04 20:32:05 +0100467
468 if (pid != 0)
Simon Kelley7cebd202006-05-06 14:13:33 +0100469 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +0100470 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000471#endif
Simon Kelley9e038942008-05-30 20:06:34 +0100472
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000473 /* write pidfile _after_ forking ! */
Simon Kelley1a6bca82008-07-11 11:11:42 +0100474 if (daemon->runfile)
475 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100476 int fd, err = 0;
477
478 sprintf(daemon->namebuff, "%d\n", (int) getpid());
479
480 /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
481 in a directory which is writable by the non-privileged user that dnsmasq runs as. This
482 allows the daemon to delete the file as part of its shutdown. This is a security hole to the
483 extent that an attacker running as the unprivileged user could replace the pidfile with a
484 symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
485
486 The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
487 ensuring that the open() fails should there be any existing file (because the unlink() failed,
488 or an attacker exploited the race between unlink() and open()). This ensures that no symlink
489 attack can succeed.
490
491 Any compromise of the non-privileged user still theoretically allows the pid-file to be
492 replaced whilst dnsmasq is running. The worst that could allow is that the usual
493 "shutdown dnsmasq" shell command could be tricked into stopping any other process.
494
495 Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
496 failure to write the pid-file.
497 */
498
499 unlink(daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100500
Simon Kelley79cfefd2012-09-02 13:29:51 +0100501 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 +0100502 {
Simon Kelley79cfefd2012-09-02 13:29:51 +0100503 /* only complain if started as root */
504 if (getuid() == 0)
505 err = 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100506 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100507 else
508 {
509 if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
510 err = 1;
Simon Kelleyff841eb2015-03-11 21:36:30 +0000511 else
512 {
513 while (retry_send(close(fd)));
514 if (errno != 0)
515 err = 1;
516 }
Simon Kelley79cfefd2012-09-02 13:29:51 +0100517 }
518
519 if (err)
Simon Kelley1a6bca82008-07-11 11:11:42 +0100520 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000521 send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100522 _exit(0);
523 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000524 }
Simon Kelley16972692006-10-16 20:04:18 +0100525 }
526
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100527 log_err = log_start(ent_pw, err_pipe[1]);
528
Simon Kelley28866e92011-02-14 20:19:14 +0000529 if (!option_bool(OPT_DEBUG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100530 {
531 /* open stdout etc to /dev/null */
532 int nullfd = open("/dev/null", O_RDWR);
533 dup2(nullfd, STDOUT_FILENO);
534 dup2(nullfd, STDERR_FILENO);
535 dup2(nullfd, STDIN_FILENO);
536 close(nullfd);
537 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100538
Simon Kelley1a6bca82008-07-11 11:11:42 +0100539 /* if we are to run scripts, we need to fork a helper before dropping root. */
540 daemon->helperfd = -1;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000541#ifdef HAVE_SCRIPT
Simon Kelley52b92f42012-01-22 16:05:15 +0000542 if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
Simon Kelley1a6bca82008-07-11 11:11:42 +0100543 daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
544#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100545
Simon Kelley28866e92011-02-14 20:19:14 +0000546 if (!option_bool(OPT_DEBUG) && getuid() == 0)
Simon Kelley16972692006-10-16 20:04:18 +0100547 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100548 int bad_capabilities = 0;
549 gid_t dummy;
Simon Kelley16972692006-10-16 20:04:18 +0100550
Simon Kelley1a6bca82008-07-11 11:11:42 +0100551 /* remove all supplimentary groups */
552 if (gp &&
553 (setgroups(0, &dummy) == -1 ||
554 setgid(gp->gr_gid) == -1))
555 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000556 send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100557 _exit(0);
558 }
559
Simon Kelley7cebd202006-05-06 14:13:33 +0100560 if (ent_pw && ent_pw->pw_uid != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100561 {
Simon Kelley74c95c22011-10-19 09:33:39 +0100562#if defined(HAVE_LINUX_NETWORK)
Simon Kelley16972692006-10-16 20:04:18 +0100563 /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
Simon Kelley74c95c22011-10-19 09:33:39 +0100564 CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
Simon Kelley54dd3932012-06-20 11:23:38 +0100565 ports because of DAD, or we're doing it dynamically,
566 we need CAP_NET_BIND_SERVICE too. */
567 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100568 data->effective = data->permitted = data->inheritable =
569 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
570 (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
571 else
572 data->effective = data->permitted = data->inheritable =
573 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100574
Simon Kelley16972692006-10-16 20:04:18 +0100575 /* Tell kernel to not clear capabilities when dropping root */
Simon Kelley572b41e2011-02-18 18:11:18 +0000576 if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
Simon Kelley16972692006-10-16 20:04:18 +0100577 bad_capabilities = errno;
Simon Kelley1a6bca82008-07-11 11:11:42 +0100578
Simon Kelley7622fc02009-06-04 20:32:05 +0100579#elif defined(HAVE_SOLARIS_NETWORK)
Simon Kelley824af852008-02-12 20:43:05 +0000580 /* http://developers.sun.com/solaris/articles/program_privileges.html */
581 priv_set_t *priv_set;
582
583 if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
584 priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
585 priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
586 bad_capabilities = errno;
587
588 if (priv_set && bad_capabilities == 0)
589 {
590 priv_inverse(priv_set);
591
592 if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
593 bad_capabilities = errno;
594 }
595
596 if (priv_set)
597 priv_freeset(priv_set);
598
Simon Kelley824af852008-02-12 20:43:05 +0000599#endif
600
Simon Kelley1a6bca82008-07-11 11:11:42 +0100601 if (bad_capabilities != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100602 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000603 send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100604 _exit(0);
Simon Kelley16972692006-10-16 20:04:18 +0100605 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100606
607 /* finally drop root */
608 if (setuid(ent_pw->pw_uid) == -1)
609 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000610 send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100611 _exit(0);
612 }
613
614#ifdef HAVE_LINUX_NETWORK
Simon Kelley54dd3932012-06-20 11:23:38 +0100615 if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
Simon Kelley74c95c22011-10-19 09:33:39 +0100616 data->effective = data->permitted =
617 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
618 else
619 data->effective = data->permitted =
620 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100621 data->inheritable = 0;
622
623 /* lose the setuid and setgid capbilities */
624 if (capset(hdr, data) == -1)
625 {
Simon Kelleyc72daea2012-01-05 21:33:27 +0000626 send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100627 _exit(0);
628 }
629#endif
630
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 }
Simon Kelley849a8352006-06-09 21:02:31 +0100632 }
Simon Kelley16972692006-10-16 20:04:18 +0100633
Simon Kelley16972692006-10-16 20:04:18 +0100634#ifdef HAVE_LINUX_NETWORK
Chen Wei28b879a2015-02-17 22:07:35 +0000635 free(hdr);
636 free(data);
Simon Kelley28866e92011-02-14 20:19:14 +0000637 if (option_bool(OPT_DEBUG))
Simon Kelley572b41e2011-02-18 18:11:18 +0000638 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
Simon Kelley16972692006-10-16 20:04:18 +0100639#endif
Simon Kelley849a8352006-06-09 21:02:31 +0100640
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100641#ifdef HAVE_TFTP
Stefan Tomanek30d08792015-03-31 22:32:11 +0100642 if (option_bool(OPT_TFTP))
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100643 {
644 DIR *dir;
645 struct tftp_prefix *p;
646
647 if (daemon->tftp_prefix)
648 {
649 if (!((dir = opendir(daemon->tftp_prefix))))
650 {
Stefan Tomanek30d08792015-03-31 22:32:11 +0100651 tftp_prefix_missing = 1;
652 if (!option_bool(OPT_TFTP_NO_FAIL))
653 {
654 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
655 _exit(0);
656 }
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100657 }
658 closedir(dir);
659 }
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100660
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100661 for (p = daemon->if_prefix; p; p = p->next)
662 {
Stefan Tomanek30d08792015-03-31 22:32:11 +0100663 p->missing = 0;
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100664 if (!((dir = opendir(p->prefix))))
Stefan Tomanek30d08792015-03-31 22:32:11 +0100665 {
666 p->missing = 1;
667 if (!option_bool(OPT_TFTP_NO_FAIL))
668 {
669 send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
670 _exit(0);
671 }
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100672 }
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100673 closedir(dir);
674 }
675 }
676#endif
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100677
Simon Kelley824af852008-02-12 20:43:05 +0000678 if (daemon->port == 0)
679 my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
680 else if (daemon->cachesize != 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100681 my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000682 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100683 my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
Simon Kelley16972692006-10-16 20:04:18 +0100684
Simon Kelleyf2621c72007-04-29 19:47:21 +0100685 my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
Simon Kelley16972692006-10-16 20:04:18 +0100686
Simon Kelley3d8df262005-08-29 12:19:27 +0100687#ifdef HAVE_DBUS
Simon Kelley28866e92011-02-14 20:19:14 +0000688 if (option_bool(OPT_DBUS))
Simon Kelley3d8df262005-08-29 12:19:27 +0100689 {
690 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100691 my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100692 else
Simon Kelleyf2621c72007-04-29 19:47:21 +0100693 my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
Simon Kelley3d8df262005-08-29 12:19:27 +0100694 }
695#endif
Simon Kelley1a9a3482014-03-05 15:01:08 +0000696
697 if (option_bool(OPT_LOCAL_SERVICE))
698 my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
Simon Kelleydb737462014-01-31 10:32:45 +0000699
Simon Kelley1d97ac42014-01-31 11:12:27 +0000700#ifdef HAVE_DNSSEC
Simon Kelleydb737462014-01-31 10:32:45 +0000701 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleye98bd522014-03-28 20:41:23 +0000702 {
Simon Kelley360f2512015-03-07 18:28:06 +0000703 int rc;
704
705 /* Delay creating the timestamp file until here, after we've changed user, so that
706 it has the correct owner to allow updating the mtime later.
707 This means we have to report fatal errors via the pipe. */
708 if ((rc = setup_timestamp()) == -1)
709 {
710 send_event(err_pipe[1], EVENT_TIME_ERR, errno, daemon->timestamp_file);
711 _exit(0);
712 }
713
Simon Kelleye98bd522014-03-28 20:41:23 +0000714 my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
Simon Kelley360f2512015-03-07 18:28:06 +0000715
Simon Kelleye98bd522014-03-28 20:41:23 +0000716 if (option_bool(OPT_DNSSEC_TIME))
717 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
Simon Kelley360f2512015-03-07 18:28:06 +0000718
719 if (rc == 1)
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000720 my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
Simon Kelleye98bd522014-03-28 20:41:23 +0000721 }
Simon Kelleydb737462014-01-31 10:32:45 +0000722#endif
Simon Kelley3d8df262005-08-29 12:19:27 +0100723
Simon Kelley1a6bca82008-07-11 11:11:42 +0100724 if (log_err != 0)
725 my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
726 daemon->log_file, strerror(log_err));
Simon Kelleydb737462014-01-31 10:32:45 +0000727
Simon Kelleyde379512004-06-22 20:23:33 +0100728 if (bind_fallback)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100729 my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
Simon Kelleydc27e142013-10-16 13:09:53 +0100730
Simon Kelleyf7029f52013-11-21 15:09:09 +0000731 if (option_bool(OPT_NOWILD))
732 warn_bound_listeners();
733
734 warn_int_names();
Simon Kelleyde379512004-06-22 20:23:33 +0100735
Simon Kelley28866e92011-02-14 20:19:14 +0000736 if (!option_bool(OPT_NOWILD))
Simon Kelley26128d22004-11-14 16:43:54 +0000737 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
738 if (if_tmp->name && !if_tmp->used)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100739 my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100740
Simon Kelley28866e92011-02-14 20:19:14 +0000741 if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
Simon Kelley208b65c2006-08-05 21:41:37 +0100742 {
743 if (daemon->resolv_files && !daemon->resolv_files->is_default)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100744 my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100745 daemon->resolv_files = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000746 if (!daemon->servers)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100747 my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
Simon Kelley208b65c2006-08-05 21:41:37 +0100748 }
749
Simon Kelleyf2621c72007-04-29 19:47:21 +0100750 if (daemon->max_logs != 0)
751 my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
Simon Kelley1f776932012-12-16 19:46:08 +0000752
Simon Kelleyf2621c72007-04-29 19:47:21 +0100753
Simon Kelley7622fc02009-06-04 20:32:05 +0100754#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +0000755 for (context = daemon->dhcp; context; context = context->next)
756 log_context(AF_INET, context);
Simon Kelleyc8257542012-03-28 21:15:41 +0100757
Simon Kelleyff7eea22013-09-04 18:01:38 +0100758 for (relay = daemon->relay4; relay; relay = relay->next)
759 log_relay(AF_INET, relay);
760
Simon Kelley1f776932012-12-16 19:46:08 +0000761# ifdef HAVE_DHCP6
762 for (context = daemon->dhcp6; context; context = context->next)
763 log_context(AF_INET6, context);
Simon Kelley52b92f42012-01-22 16:05:15 +0000764
Simon Kelleyff7eea22013-09-04 18:01:38 +0100765 for (relay = daemon->relay6; relay; relay = relay->next)
766 log_relay(AF_INET6, relay);
767
Simon Kelley1f776932012-12-16 19:46:08 +0000768 if (daemon->doing_dhcp6 || daemon->doing_ra)
769 dhcp_construct_contexts(now);
770
771 if (option_bool(OPT_RA))
772 my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
773# endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000774
Simon Kelley3b3f4412013-10-11 16:33:28 +0100775# ifdef HAVE_LINUX_NETWORK
776 if (did_bind)
777 my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
778# endif
779
Simon Kelley8445f5d2012-12-17 21:54:08 +0000780 /* after dhcp_contruct_contexts */
781 if (daemon->dhcp || daemon->doing_dhcp6)
782 lease_find_interfaces(now);
Simon Kelley1f776932012-12-16 19:46:08 +0000783#endif
Simon Kelley52b92f42012-01-22 16:05:15 +0000784
Simon Kelley832af0b2007-01-21 20:01:28 +0000785#ifdef HAVE_TFTP
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000786 if (option_bool(OPT_TFTP))
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100787 {
Stefan Tomanek30d08792015-03-31 22:32:11 +0100788 struct tftp_prefix *p;
Simon Kelley832af0b2007-01-21 20:01:28 +0000789#ifdef FD_SETSIZE
Simon Kelley5aabfc72007-08-29 11:24:47 +0100790 if (FD_SETSIZE < (unsigned)max_fd)
Simon Kelley832af0b2007-01-21 20:01:28 +0000791 max_fd = FD_SETSIZE;
792#endif
793
Simon Kelley7622fc02009-06-04 20:32:05 +0100794 my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
Simon Kelleyf2621c72007-04-29 19:47:21 +0100795 daemon->tftp_prefix ? _("root is ") : _("enabled"),
796 daemon->tftp_prefix ? daemon->tftp_prefix: "",
Simon Kelley28866e92011-02-14 20:19:14 +0000797 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100798
Stefan Tomanek30d08792015-03-31 22:32:11 +0100799 if (tftp_prefix_missing)
800 my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
Stefan Tomanek7aa970e2015-04-01 17:55:07 +0100801
Stefan Tomanek30d08792015-03-31 22:32:11 +0100802 for (p = daemon->if_prefix; p; p = p->next)
803 if (p->missing)
804 my_syslog(MS_TFTP | LOG_WARNING, _("warning: TFTP directory %s inaccessible"), p->prefix);
805
Simon Kelley832af0b2007-01-21 20:01:28 +0000806 /* This is a guess, it assumes that for small limits,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100807 disjoint files might be served, but for large limits,
Simon Kelley832af0b2007-01-21 20:01:28 +0000808 a single file will be sent to may clients (the file only needs
809 one fd). */
810
811 max_fd -= 30; /* use other than TFTP */
812
813 if (max_fd < 0)
814 max_fd = 5;
815 else if (max_fd < 100)
816 max_fd = max_fd/2;
817 else
818 max_fd = max_fd - 20;
Simon Kelley824af852008-02-12 20:43:05 +0000819
820 /* if we have to use a limited range of ports,
821 that will limit the number of transfers */
822 if (daemon->start_tftp_port != 0 &&
823 daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
824 max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000825
826 if (daemon->tftp_max > max_fd)
827 {
828 daemon->tftp_max = max_fd;
Simon Kelley7622fc02009-06-04 20:32:05 +0100829 my_syslog(MS_TFTP | LOG_WARNING,
Simon Kelleyf2621c72007-04-29 19:47:21 +0100830 _("restricting maximum simultaneous TFTP transfers to %d"),
831 daemon->tftp_max);
Simon Kelley832af0b2007-01-21 20:01:28 +0000832 }
833 }
834#endif
835
Simon Kelley1a6bca82008-07-11 11:11:42 +0100836 /* finished start-up - release original process */
837 if (err_pipe[1] != -1)
Simon Kelleyff841eb2015-03-11 21:36:30 +0000838 while (retry_send(close(err_pipe[1])));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000839
Simon Kelley824af852008-02-12 20:43:05 +0000840 if (daemon->port != 0)
841 check_servers();
842
Simon Kelley7cebd202006-05-06 14:13:33 +0100843 pid = getpid();
844
Simon Kelley04918052015-01-26 11:23:43 +0000845#ifdef HAVE_INOTIFY
Simon Kelley193de4a2014-12-10 17:32:16 +0000846 /* Using inotify, have to select a resolv file at startup */
847 poll_resolv(1, 0, now);
848#endif
849
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100850 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000851 {
Simon Kelley16972692006-10-16 20:04:18 +0100852 int maxfd = -1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100853 struct timeval t, *tp = NULL;
Simon Kelley3d8df262005-08-29 12:19:27 +0100854 fd_set rset, wset, eset;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000855
856 FD_ZERO(&rset);
Simon Kelley3d8df262005-08-29 12:19:27 +0100857 FD_ZERO(&wset);
858 FD_ZERO(&eset);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000859
Simon Kelley16972692006-10-16 20:04:18 +0100860 /* if we are out of resources, find how long we have to wait
861 for some to come free, we'll loop around then and restart
862 listening for queries */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100863 if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
Simon Kelley16972692006-10-16 20:04:18 +0100864 {
865 t.tv_usec = 0;
866 tp = &t;
867 }
868
Simon Kelley832af0b2007-01-21 20:01:28 +0000869 /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
870 if (daemon->tftp_trans ||
Simon Kelley28866e92011-02-14 20:19:14 +0000871 (option_bool(OPT_DBUS) && !daemon->dbus))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872 {
Simon Kelley16972692006-10-16 20:04:18 +0100873 t.tv_sec = 0;
874 t.tv_usec = 250000;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100875 tp = &t;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000876 }
Simon Kelley74c95c22011-10-19 09:33:39 +0100877 /* Wake every second whilst waiting for DAD to complete */
878 else if (is_dad_listeners())
879 {
880 t.tv_sec = 1;
881 t.tv_usec = 0;
882 tp = &t;
883 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100884
Simon Kelley832af0b2007-01-21 20:01:28 +0000885#ifdef HAVE_DBUS
Simon Kelley5aabfc72007-08-29 11:24:47 +0100886 set_dbus_listeners(&maxfd, &rset, &wset, &eset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100887#endif
888
Simon Kelley7622fc02009-06-04 20:32:05 +0100889#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +0100890 if (daemon->dhcp || daemon->relay4)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100891 {
892 FD_SET(daemon->dhcpfd, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100893 bump_maxfd(daemon->dhcpfd, &maxfd);
Simon Kelley316e2732010-01-22 20:16:09 +0000894 if (daemon->pxefd != -1)
895 {
896 FD_SET(daemon->pxefd, &rset);
897 bump_maxfd(daemon->pxefd, &maxfd);
898 }
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100899 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100900#endif
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100901
Simon Kelley52b92f42012-01-22 16:05:15 +0000902#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +0100903 if (daemon->doing_dhcp6 || daemon->relay6)
Simon Kelley52b92f42012-01-22 16:05:15 +0000904 {
905 FD_SET(daemon->dhcp6fd, &rset);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000906 bump_maxfd(daemon->dhcp6fd, &maxfd);
Simon Kelley5d71d832012-03-24 14:40:42 +0000907 }
908
Simon Kelley1f776932012-12-16 19:46:08 +0000909 if (daemon->doing_ra)
Simon Kelley5d71d832012-03-24 14:40:42 +0000910 {
911 FD_SET(daemon->icmp6fd, &rset);
912 bump_maxfd(daemon->icmp6fd, &maxfd);
Simon Kelley52b92f42012-01-22 16:05:15 +0000913 }
914#endif
Simon Kelley04918052015-01-26 11:23:43 +0000915
916#ifdef HAVE_INOTIFY
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000917 if (daemon->inotifyfd != -1)
Simon Kelley193de4a2014-12-10 17:32:16 +0000918 {
919 FD_SET(daemon->inotifyfd, &rset);
920 bump_maxfd(daemon->inotifyfd, &maxfd);
921 }
Simon Kelley04918052015-01-26 11:23:43 +0000922#endif
923
924#if defined(HAVE_LINUX_NETWORK)
925 FD_SET(daemon->netlinkfd, &rset);
926 bump_maxfd(daemon->netlinkfd, &maxfd);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000927#elif defined(HAVE_BSD_NETWORK)
928 FD_SET(daemon->routefd, &rset);
929 bump_maxfd(daemon->routefd, &maxfd);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100930#endif
Simon Kelley193de4a2014-12-10 17:32:16 +0000931
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100932 FD_SET(piperead, &rset);
Simon Kelley16972692006-10-16 20:04:18 +0100933 bump_maxfd(piperead, &maxfd);
934
Simon Kelley7622fc02009-06-04 20:32:05 +0100935#ifdef HAVE_DHCP
Simon Kelley1f15b812009-10-13 17:49:32 +0100936# ifdef HAVE_SCRIPT
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937 while (helper_buf_empty() && do_script_run(now));
Simon Kelley16972692006-10-16 20:04:18 +0100938
Simon Kelleya9530962012-03-20 22:07:35 +0000939# ifdef HAVE_TFTP
940 while (helper_buf_empty() && do_tftp_script_run());
941# endif
942
Simon Kelley16972692006-10-16 20:04:18 +0100943 if (!helper_buf_empty())
944 {
945 FD_SET(daemon->helperfd, &wset);
946 bump_maxfd(daemon->helperfd, &maxfd);
947 }
Simon Kelley7622fc02009-06-04 20:32:05 +0100948# else
Simon Kelley5aabfc72007-08-29 11:24:47 +0100949 /* need this for other side-effects */
950 while (do_script_run(now));
Simon Kelleya9530962012-03-20 22:07:35 +0000951
952# ifdef HAVE_TFTP
953 while (do_tftp_script_run());
954# endif
955
Simon Kelley7622fc02009-06-04 20:32:05 +0100956# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +0100957#endif
Simon Kelley7622fc02009-06-04 20:32:05 +0100958
Simon Kelleyf2621c72007-04-29 19:47:21 +0100959 /* must do this just before select(), when we know no
960 more calls to my_syslog() can occur */
961 set_log_writer(&wset, &maxfd);
962
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100963 if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
964 {
965 /* otherwise undefined after error */
966 FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
967 }
968
969 now = dnsmasq_time();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970
Simon Kelleyf2621c72007-04-29 19:47:21 +0100971 check_log_writer(&wset);
Simon Kelley115ac3e2013-05-20 11:28:32 +0100972
973 /* prime. */
974 enumerate_interfaces(1);
975
Simon Kelley74c95c22011-10-19 09:33:39 +0100976 /* Check the interfaces to see if any have exited DAD state
977 and if so, bind the address. */
978 if (is_dad_listeners())
979 {
Simon Kelley115ac3e2013-05-20 11:28:32 +0100980 enumerate_interfaces(0);
Simon Kelley74c95c22011-10-19 09:33:39 +0100981 /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
982 create_bound_listeners(0);
Simon Kelleydc27e142013-10-16 13:09:53 +0100983 warn_bound_listeners();
Simon Kelley74c95c22011-10-19 09:33:39 +0100984 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100985
Simon Kelley1ee9be42013-12-09 16:50:19 +0000986#if defined(HAVE_LINUX_NETWORK)
Simon Kelleyc52e1892010-06-07 22:01:39 +0100987 if (FD_ISSET(daemon->netlinkfd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100988 netlink_multicast();
Simon Kelley1ee9be42013-12-09 16:50:19 +0000989#elif defined(HAVE_BSD_NETWORK)
990 if (FD_ISSET(daemon->routefd, &rset))
Simon Kelleya0358e52014-06-07 13:38:48 +0100991 route_sock();
Simon Kelleyc52e1892010-06-07 22:01:39 +0100992#endif
993
Simon Kelley04918052015-01-26 11:23:43 +0000994#ifdef HAVE_INOTIFY
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000995 if (daemon->inotifyfd != -1 && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check(now))
996 {
997 if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
998 poll_resolv(1, 1, now);
999 }
Simon Kelley193de4a2014-12-10 17:32:16 +00001000#else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001001 /* Check for changes to resolv files once per second max. */
Simon Kelley3d8df262005-08-29 12:19:27 +01001002 /* Don't go silent for long periods if the clock goes backwards. */
Simon Kelley9009d742008-11-14 20:04:27 +00001003 if (daemon->last_resolv == 0 ||
1004 difftime(now, daemon->last_resolv) > 1.0 ||
1005 difftime(now, daemon->last_resolv) < -1.0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001006 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001007 /* poll_resolv doesn't need to reload first time through, since
1008 that's queued anyway. */
Simon Kelley33820b72004-04-03 21:10:00 +01001009
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001010 poll_resolv(0, daemon->last_resolv != 0, now);
1011 daemon->last_resolv = now;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001012 }
Simon Kelley193de4a2014-12-10 17:32:16 +00001013#endif
1014
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001015 if (FD_ISSET(piperead, &rset))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001016 async_event(piperead, now);
Simon Kelley7cebd202006-05-06 14:13:33 +01001017
Simon Kelley3d8df262005-08-29 12:19:27 +01001018#ifdef HAVE_DBUS
1019 /* if we didn't create a DBus connection, retry now. */
Simon Kelley28866e92011-02-14 20:19:14 +00001020 if (option_bool(OPT_DBUS) && !daemon->dbus)
Simon Kelley3d8df262005-08-29 12:19:27 +01001021 {
1022 char *err;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001023 if ((err = dbus_init()))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001024 my_syslog(LOG_WARNING, _("DBus error: %s"), err);
Simon Kelley3d8df262005-08-29 12:19:27 +01001025 if (daemon->dbus)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001026 my_syslog(LOG_INFO, _("connected to system DBus"));
Simon Kelley3d8df262005-08-29 12:19:27 +01001027 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001028 check_dbus_listeners(&rset, &wset, &eset);
Simon Kelley3d8df262005-08-29 12:19:27 +01001029#endif
Simon Kelley824af852008-02-12 20:43:05 +00001030
Simon Kelley5aabfc72007-08-29 11:24:47 +01001031 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001032
1033#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001034 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001035#endif
1036
Simon Kelley7622fc02009-06-04 20:32:05 +01001037#ifdef HAVE_DHCP
Simon Kelleyff7eea22013-09-04 18:01:38 +01001038 if (daemon->dhcp || daemon->relay4)
Simon Kelley316e2732010-01-22 20:16:09 +00001039 {
1040 if (FD_ISSET(daemon->dhcpfd, &rset))
1041 dhcp_packet(now, 0);
1042 if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
1043 dhcp_packet(now, 1);
1044 }
Simon Kelley16972692006-10-16 20:04:18 +01001045
Simon Kelley52b92f42012-01-22 16:05:15 +00001046#ifdef HAVE_DHCP6
Simon Kelleyff7eea22013-09-04 18:01:38 +01001047 if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
Simon Kelley18c63ef2012-05-21 14:34:15 +01001048 dhcp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001049
Simon Kelley1f776932012-12-16 19:46:08 +00001050 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1051 icmp6_packet(now);
Simon Kelley52b92f42012-01-22 16:05:15 +00001052#endif
1053
Simon Kelley1f15b812009-10-13 17:49:32 +01001054# ifdef HAVE_SCRIPT
Simon Kelley16972692006-10-16 20:04:18 +01001055 if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001056 helper_write();
Simon Kelley7622fc02009-06-04 20:32:05 +01001057# endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001058#endif
1059
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001060 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001061}
1062
Simon Kelley3be34542004-09-11 19:12:13 +01001063static void sig_handler(int sig)
1064{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001065 if (pid == 0)
1066 {
Simon Kelley16972692006-10-16 20:04:18 +01001067 /* ignore anything other than TERM during startup
1068 and in helper proc. (helper ignore TERM too) */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001069 if (sig == SIGTERM)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001070 exit(EC_MISC);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001071 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001072 else if (pid != getpid())
Simon Kelley3be34542004-09-11 19:12:13 +01001073 {
Simon Kelley16972692006-10-16 20:04:18 +01001074 /* alarm is used to kill TCP children after a fixed time. */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001075 if (sig == SIGALRM)
Simon Kelley7cebd202006-05-06 14:13:33 +01001076 _exit(0);
Simon Kelley3be34542004-09-11 19:12:13 +01001077 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001078 else
1079 {
1080 /* master process */
1081 int event, errsave = errno;
1082
1083 if (sig == SIGHUP)
1084 event = EVENT_RELOAD;
1085 else if (sig == SIGCHLD)
1086 event = EVENT_CHILD;
1087 else if (sig == SIGALRM)
1088 event = EVENT_ALARM;
1089 else if (sig == SIGTERM)
1090 event = EVENT_TERM;
1091 else if (sig == SIGUSR1)
1092 event = EVENT_DUMP;
1093 else if (sig == SIGUSR2)
1094 event = EVENT_REOPEN;
1095 else
1096 return;
1097
Simon Kelleyc72daea2012-01-05 21:33:27 +00001098 send_event(pipewrite, event, 0, NULL);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001099 errno = errsave;
1100 }
Simon Kelley3be34542004-09-11 19:12:13 +01001101}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001102
Simon Kelley353ae4d2012-03-19 20:07:51 +00001103/* now == 0 -> queue immediate callback */
1104void send_alarm(time_t event, time_t now)
Simon Kelley741c2952012-02-25 13:09:18 +00001105{
Simon Kelley884a6df2012-03-20 16:20:22 +00001106 if (now == 0 || event != 0)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001107 {
Simon Kelley884a6df2012-03-20 16:20:22 +00001108 /* alarm(0) or alarm(-ve) doesn't do what we want.... */
1109 if ((now == 0 || difftime(event, now) <= 0.0))
1110 send_event(pipewrite, EVENT_ALARM, 0, NULL);
1111 else
1112 alarm((unsigned)difftime(event, now));
Simon Kelley353ae4d2012-03-19 20:07:51 +00001113 }
Simon Kelley741c2952012-02-25 13:09:18 +00001114}
1115
Simon Kelley47a95162014-07-08 22:22:02 +01001116void queue_event(int event)
Simon Kelleya0358e52014-06-07 13:38:48 +01001117{
Simon Kelley47a95162014-07-08 22:22:02 +01001118 send_event(pipewrite, event, 0, NULL);
Simon Kelleya0358e52014-06-07 13:38:48 +01001119}
1120
Simon Kelleyc72daea2012-01-05 21:33:27 +00001121void send_event(int fd, int event, int data, char *msg)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001122{
1123 struct event_desc ev;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001124 struct iovec iov[2];
1125
Simon Kelley5aabfc72007-08-29 11:24:47 +01001126 ev.event = event;
1127 ev.data = data;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001128 ev.msg_sz = msg ? strlen(msg) : 0;
1129
1130 iov[0].iov_base = &ev;
1131 iov[0].iov_len = sizeof(ev);
1132 iov[1].iov_base = msg;
1133 iov[1].iov_len = ev.msg_sz;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001134
1135 /* error pipe, debug mode. */
1136 if (fd == -1)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001137 fatal_event(&ev, msg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001138 else
1139 /* pipe is non-blocking and struct event_desc is smaller than
1140 PIPE_BUF, so this either fails or writes everything */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001141 while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001142}
Simon Kelley3d8df262005-08-29 12:19:27 +01001143
Simon Kelleyc72daea2012-01-05 21:33:27 +00001144/* NOTE: the memory used to return msg is leaked: use msgs in events only
1145 to describe fatal errors. */
1146static int read_event(int fd, struct event_desc *evp, char **msg)
1147{
1148 char *buf;
1149
1150 if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
1151 return 0;
1152
1153 *msg = NULL;
1154
1155 if (evp->msg_sz != 0 &&
1156 (buf = malloc(evp->msg_sz + 1)) &&
1157 read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
1158 {
1159 buf[evp->msg_sz] = 0;
1160 *msg = buf;
1161 }
1162
1163 return 1;
1164}
1165
1166static void fatal_event(struct event_desc *ev, char *msg)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001167{
1168 errno = ev->data;
1169
1170 switch (ev->event)
1171 {
1172 case EVENT_DIE:
1173 exit(0);
Simon Kelley7622fc02009-06-04 20:32:05 +01001174
1175 case EVENT_FORK_ERR:
1176 die(_("cannot fork into background: %s"), NULL, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001177
1178 case EVENT_PIPE_ERR:
1179 die(_("failed to create helper: %s"), NULL, EC_MISC);
1180
1181 case EVENT_CAP_ERR:
1182 die(_("setting capabilities failed: %s"), NULL, EC_MISC);
1183
1184 case EVENT_USER_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001185 die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001186
1187 case EVENT_GROUP_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001188 die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001189
1190 case EVENT_PIDFILE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001191 die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001192
1193 case EVENT_LOG_ERR:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001194 die(_("cannot open log %s: %s"), msg, EC_FILE);
1195
1196 case EVENT_LUA_ERR:
1197 die(_("failed to load Lua script: %s"), msg, EC_MISC);
Simon Kelley8b3ae2f2012-06-13 13:43:49 +01001198
1199 case EVENT_TFTP_ERR:
1200 die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
Simon Kelley360f2512015-03-07 18:28:06 +00001201
1202 case EVENT_TIME_ERR:
1203 die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001204 }
1205}
1206
Simon Kelley5aabfc72007-08-29 11:24:47 +01001207static void async_event(int pipe, time_t now)
1208{
1209 pid_t p;
1210 struct event_desc ev;
Simon Kelley7b1eae42014-02-20 13:43:28 +00001211 int i, check = 0;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001212 char *msg;
1213
1214 /* NOTE: the memory used to return msg is leaked: use msgs in events only
1215 to describe fatal errors. */
1216
1217 if (read_event(pipe, &ev, &msg))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001218 switch (ev.event)
1219 {
1220 case EVENT_RELOAD:
Simon Kelleye98bd522014-03-28 20:41:23 +00001221#ifdef HAVE_DNSSEC
1222 if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
1223 {
1224 my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
1225 reset_option_bool(OPT_DNSSEC_TIME);
1226 }
1227#endif
1228 /* fall through */
1229
1230 case EVENT_INIT:
Simon Kelley5aabfc72007-08-29 11:24:47 +01001231 clear_cache_and_reload(now);
Simon Kelleye98bd522014-03-28 20:41:23 +00001232
Simon Kelley7b1eae42014-02-20 13:43:28 +00001233 if (daemon->port != 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001234 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00001235 if (daemon->resolv_files && option_bool(OPT_NO_POLL))
1236 {
1237 reload_servers(daemon->resolv_files->name);
1238 check = 1;
1239 }
1240
1241 if (daemon->servers_file)
1242 {
1243 read_servers_file();
1244 check = 1;
1245 }
1246
1247 if (check)
1248 check_servers();
Simon Kelley5aabfc72007-08-29 11:24:47 +01001249 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001250
Simon Kelley7622fc02009-06-04 20:32:05 +01001251#ifdef HAVE_DHCP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001252 rerun_scripts();
Simon Kelley7622fc02009-06-04 20:32:05 +01001253#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001254 break;
1255
1256 case EVENT_DUMP:
Simon Kelley824af852008-02-12 20:43:05 +00001257 if (daemon->port != 0)
1258 dump_cache(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001259 break;
1260
1261 case EVENT_ALARM:
Simon Kelley7622fc02009-06-04 20:32:05 +01001262#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001263 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001264 {
1265 lease_prune(NULL, now);
1266 lease_update_file(now);
1267 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001268#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001269 else if (daemon->doing_ra)
Simon Kelley353ae4d2012-03-19 20:07:51 +00001270 /* Not doing DHCP, so no lease system, manage alarms for ra only */
1271 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001272#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001273#endif
Simon Kelley5aabfc72007-08-29 11:24:47 +01001274 break;
1275
1276 case EVENT_CHILD:
1277 /* See Stevens 5.10 */
1278 while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
1279 if (p == -1)
1280 {
1281 if (errno != EINTR)
1282 break;
1283 }
1284 else
1285 for (i = 0 ; i < MAX_PROCS; i++)
1286 if (daemon->tcp_pids[i] == p)
1287 daemon->tcp_pids[i] = 0;
1288 break;
1289
1290 case EVENT_KILLED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001291 my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001292 break;
1293
1294 case EVENT_EXITED:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001295 my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001296 break;
1297
1298 case EVENT_EXEC_ERR:
Simon Kelley9e038942008-05-30 20:06:34 +01001299 my_syslog(LOG_ERR, _("failed to execute %s: %s"),
1300 daemon->lease_change_command, strerror(ev.data));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001301 break;
1302
Simon Kelley1a6bca82008-07-11 11:11:42 +01001303 /* necessary for fatal errors in helper */
Simon Kelleyc72daea2012-01-05 21:33:27 +00001304 case EVENT_USER_ERR:
Simon Kelley1a6bca82008-07-11 11:11:42 +01001305 case EVENT_DIE:
Simon Kelleyc72daea2012-01-05 21:33:27 +00001306 case EVENT_LUA_ERR:
1307 fatal_event(&ev, msg);
Simon Kelley9e038942008-05-30 20:06:34 +01001308 break;
1309
Simon Kelley5aabfc72007-08-29 11:24:47 +01001310 case EVENT_REOPEN:
1311 /* Note: this may leave TCP-handling processes with the old file still open.
1312 Since any such process will die in CHILD_LIFETIME or probably much sooner,
1313 we leave them logging to the old file. */
1314 if (daemon->log_file != NULL)
1315 log_reopen(daemon->log_file);
1316 break;
Simon Kelleya0358e52014-06-07 13:38:48 +01001317
1318 case EVENT_NEWADDR:
1319 newaddress(now);
1320 break;
Simon Kelley47a95162014-07-08 22:22:02 +01001321
1322 case EVENT_NEWROUTE:
1323 resend_query();
1324 /* Force re-reading resolv file right now, for luck. */
1325 poll_resolv(0, 1, now);
1326 break;
1327
Simon Kelley5aabfc72007-08-29 11:24:47 +01001328 case EVENT_TERM:
1329 /* Knock all our children on the head. */
1330 for (i = 0; i < MAX_PROCS; i++)
1331 if (daemon->tcp_pids[i] != 0)
1332 kill(daemon->tcp_pids[i], SIGALRM);
1333
Simon Kelleyc72daea2012-01-05 21:33:27 +00001334#if defined(HAVE_SCRIPT)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001335 /* handle pending lease transitions */
1336 if (daemon->helperfd != -1)
1337 {
1338 /* block in writes until all done */
1339 if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
1340 fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
1341 do {
1342 helper_write();
1343 } while (!helper_buf_empty() || do_script_run(now));
Simon Kelleyff841eb2015-03-11 21:36:30 +00001344 while (retry_send(close(daemon->helperfd)));
Simon Kelley5aabfc72007-08-29 11:24:47 +01001345 }
1346#endif
1347
1348 if (daemon->lease_stream)
1349 fclose(daemon->lease_stream);
Simon Kelley73a08a22009-02-05 20:28:08 +00001350
1351 if (daemon->runfile)
1352 unlink(daemon->runfile);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001353
1354 my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
1355 flush_log();
1356 exit(EC_GOOD);
1357 }
1358}
1359
Simon Kelley47a95162014-07-08 22:22:02 +01001360static void poll_resolv(int force, int do_reload, time_t now)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001361{
1362 struct resolvc *res, *latest;
1363 struct stat statbuf;
1364 time_t last_change = 0;
1365 /* There may be more than one possible file.
1366 Go through and find the one which changed _last_.
1367 Warn of any which can't be read. */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001368
Simon Kelley28866e92011-02-14 20:19:14 +00001369 if (daemon->port == 0 || option_bool(OPT_NO_POLL))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001370 return;
1371
Simon Kelley5aabfc72007-08-29 11:24:47 +01001372 for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
1373 if (stat(res->name, &statbuf) == -1)
1374 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001375 if (force)
1376 {
1377 res->mtime = 0;
1378 continue;
1379 }
1380
Simon Kelley5aabfc72007-08-29 11:24:47 +01001381 if (!res->logged)
1382 my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
1383 res->logged = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001384
1385 if (res->mtime != 0)
1386 {
1387 /* existing file evaporated, force selection of the latest
1388 file even if its mtime hasn't changed since we last looked */
1389 poll_resolv(1, do_reload, now);
1390 return;
1391 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001392 }
1393 else
1394 {
1395 res->logged = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001396 if (force || (statbuf.st_mtime != res->mtime))
1397 {
1398 res->mtime = statbuf.st_mtime;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001399 if (difftime(statbuf.st_mtime, last_change) > 0.0)
1400 {
1401 last_change = statbuf.st_mtime;
1402 latest = res;
1403 }
1404 }
1405 }
1406
1407 if (latest)
1408 {
1409 static int warned = 0;
1410 if (reload_servers(latest->name))
1411 {
1412 my_syslog(LOG_INFO, _("reading %s"), latest->name);
1413 warned = 0;
1414 check_servers();
Simon Kelley28866e92011-02-14 20:19:14 +00001415 if (option_bool(OPT_RELOAD) && do_reload)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001416 clear_cache_and_reload(now);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001417 }
1418 else
1419 {
1420 latest->mtime = 0;
1421 if (!warned)
1422 {
1423 my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
1424 warned = 1;
1425 }
1426 }
1427 }
1428}
1429
1430void clear_cache_and_reload(time_t now)
Simon Kelley3d8df262005-08-29 12:19:27 +01001431{
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001432 (void)now;
1433
Simon Kelley824af852008-02-12 20:43:05 +00001434 if (daemon->port != 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01001435 cache_reload();
Simon Kelley824af852008-02-12 20:43:05 +00001436
Simon Kelley7622fc02009-06-04 20:32:05 +01001437#ifdef HAVE_DHCP
Simon Kelley1f776932012-12-16 19:46:08 +00001438 if (daemon->dhcp || daemon->doing_dhcp6)
Simon Kelley3d8df262005-08-29 12:19:27 +01001439 {
Simon Kelley28866e92011-02-14 20:19:14 +00001440 if (option_bool(OPT_ETHERS))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001441 dhcp_read_ethers();
Simon Kelley824af852008-02-12 20:43:05 +00001442 reread_dhcp();
Simon Kelley04918052015-01-26 11:23:43 +00001443#ifdef HAVE_INOTIFY
Simon Kelley70d18732015-01-31 19:59:29 +00001444 set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001445#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001446 dhcp_update_configs(daemon->dhcp_conf);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001447 lease_update_from_configs();
1448 lease_update_file(now);
Simon Kelley353ae4d2012-03-19 20:07:51 +00001449 lease_update_dns(1);
Simon Kelley3d8df262005-08-29 12:19:27 +01001450 }
Simon Kelley843c96b2012-02-27 17:42:38 +00001451#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001452 else if (daemon->doing_ra)
Simon Kelley2021c662012-05-07 16:43:21 +01001453 /* Not doing DHCP, so no lease system, manage
1454 alarms for ra only */
1455 send_alarm(periodic_ra(now), now);
Simon Kelley843c96b2012-02-27 17:42:38 +00001456#endif
Simon Kelley7622fc02009-06-04 20:32:05 +01001457#endif
Simon Kelley3d8df262005-08-29 12:19:27 +01001458}
1459
Simon Kelley5aabfc72007-08-29 11:24:47 +01001460static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
Simon Kelley3be34542004-09-11 19:12:13 +01001461{
1462 struct serverfd *serverfdp;
1463 struct listener *listener;
Simon Kelley824af852008-02-12 20:43:05 +00001464 int wait = 0, i;
Simon Kelley832af0b2007-01-21 20:01:28 +00001465
1466#ifdef HAVE_TFTP
1467 int tftp = 0;
1468 struct tftp_transfer *transfer;
1469 for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
1470 {
1471 tftp++;
1472 FD_SET(transfer->sockfd, set);
1473 bump_maxfd(transfer->sockfd, maxfdp);
1474 }
1475#endif
1476
Simon Kelley16972692006-10-16 20:04:18 +01001477 /* will we be able to get memory? */
Simon Kelley824af852008-02-12 20:43:05 +00001478 if (daemon->port != 0)
Simon Kelley3a237152013-12-12 12:15:50 +00001479 get_new_frec(now, &wait, 0);
Simon Kelley16972692006-10-16 20:04:18 +01001480
Simon Kelley3be34542004-09-11 19:12:13 +01001481 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1482 {
1483 FD_SET(serverfdp->fd, set);
Simon Kelley16972692006-10-16 20:04:18 +01001484 bump_maxfd(serverfdp->fd, maxfdp);
Simon Kelley3be34542004-09-11 19:12:13 +01001485 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001486
1487 if (daemon->port != 0 && !daemon->osport)
1488 for (i = 0; i < RANDOM_SOCKS; i++)
1489 if (daemon->randomsocks[i].refcount != 0)
1490 {
1491 FD_SET(daemon->randomsocks[i].fd, set);
1492 bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
1493 }
1494
Simon Kelley3be34542004-09-11 19:12:13 +01001495 for (listener = daemon->listeners; listener; listener = listener->next)
1496 {
Simon Kelley16972692006-10-16 20:04:18 +01001497 /* only listen for queries if we have resources */
Simon Kelley824af852008-02-12 20:43:05 +00001498 if (listener->fd != -1 && wait == 0)
Simon Kelley16972692006-10-16 20:04:18 +01001499 {
1500 FD_SET(listener->fd, set);
1501 bump_maxfd(listener->fd, maxfdp);
1502 }
1503
1504 /* death of a child goes through the select loop, so
1505 we don't need to explicitly arrange to wake up here */
Simon Kelley824af852008-02-12 20:43:05 +00001506 if (listener->tcpfd != -1)
1507 for (i = 0; i < MAX_PROCS; i++)
1508 if (daemon->tcp_pids[i] == 0)
1509 {
1510 FD_SET(listener->tcpfd, set);
1511 bump_maxfd(listener->tcpfd, maxfdp);
1512 break;
1513 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001514
Simon Kelley832af0b2007-01-21 20:01:28 +00001515#ifdef HAVE_TFTP
1516 if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
1517 {
1518 FD_SET(listener->tftpfd, set);
1519 bump_maxfd(listener->tftpfd, maxfdp);
1520 }
1521#endif
1522
1523 }
1524
Simon Kelley16972692006-10-16 20:04:18 +01001525 return wait;
Simon Kelley3be34542004-09-11 19:12:13 +01001526}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001527
Simon Kelley5aabfc72007-08-29 11:24:47 +01001528static void check_dns_listeners(fd_set *set, time_t now)
Simon Kelley3be34542004-09-11 19:12:13 +01001529{
1530 struct serverfd *serverfdp;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001531 struct listener *listener;
1532 int i;
1533
Simon Kelley832af0b2007-01-21 20:01:28 +00001534 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1535 if (FD_ISSET(serverfdp->fd, set))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001536 reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
1537
1538 if (daemon->port != 0 && !daemon->osport)
1539 for (i = 0; i < RANDOM_SOCKS; i++)
1540 if (daemon->randomsocks[i].refcount != 0 &&
1541 FD_ISSET(daemon->randomsocks[i].fd, set))
1542 reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001543
1544 for (listener = daemon->listeners; listener; listener = listener->next)
1545 {
Simon Kelley824af852008-02-12 20:43:05 +00001546 if (listener->fd != -1 && FD_ISSET(listener->fd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001547 receive_query(listener, now);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001548
Simon Kelley832af0b2007-01-21 20:01:28 +00001549#ifdef HAVE_TFTP
1550 if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001551 tftp_request(listener, now);
Simon Kelley59353a62004-11-21 19:34:28 +00001552#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001553
Simon Kelley824af852008-02-12 20:43:05 +00001554 if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
Simon Kelley832af0b2007-01-21 20:01:28 +00001555 {
Simon Kelley22ce5502013-01-22 13:53:04 +00001556 int confd, client_ok = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001557 struct irec *iface = NULL;
1558 pid_t p;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001559 union mysockaddr tcp_addr;
1560 socklen_t tcp_len = sizeof(union mysockaddr);
1561
1562 while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
Simon Kelley832af0b2007-01-21 20:01:28 +00001563
Simon Kelley46b06652013-02-04 21:47:59 +00001564 if (confd == -1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001565 continue;
Simon Kelley76dd75d2013-05-23 10:04:25 +01001566
Simon Kelley46b06652013-02-04 21:47:59 +00001567 if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
1568 {
Simon Kelleyff841eb2015-03-11 21:36:30 +00001569 while (retry_send(close(confd)));
Simon Kelley46b06652013-02-04 21:47:59 +00001570 continue;
1571 }
Simon Kelley76dd75d2013-05-23 10:04:25 +01001572
1573 /* Make sure that the interface list is up-to-date.
1574
1575 We do this here as we may need the results below, and
1576 the DNS code needs them for --interface-name stuff.
Simon Kelley46b06652013-02-04 21:47:59 +00001577
Simon Kelley76dd75d2013-05-23 10:04:25 +01001578 Multiple calls to enumerate_interfaces() per select loop are
1579 inhibited, so calls to it in the child process (which doesn't select())
1580 have no effect. This avoids two processes reading from the same
1581 netlink fd and screwing the pooch entirely.
1582 */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001583
Simon Kelley76dd75d2013-05-23 10:04:25 +01001584 enumerate_interfaces(0);
1585
1586 if (option_bool(OPT_NOWILD))
1587 iface = listener->iface; /* May be NULL */
1588 else
1589 {
1590 int if_index;
1591 char intr_name[IF_NAMESIZE];
1592
1593 /* if we can find the arrival interface, check it's one that's allowed */
1594 if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
1595 indextoname(listener->tcpfd, if_index, intr_name))
1596 {
1597 struct all_addr addr;
1598 addr.addr.addr4 = tcp_addr.in.sin_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001599#ifdef HAVE_IPV6
Simon Kelley76dd75d2013-05-23 10:04:25 +01001600 if (tcp_addr.sa.sa_family == AF_INET6)
1601 addr.addr.addr6 = tcp_addr.in6.sin6_addr;
Simon Kelleye25db1f2013-01-29 22:10:26 +00001602#endif
Simon Kelley76dd75d2013-05-23 10:04:25 +01001603
1604 for (iface = daemon->interfaces; iface; iface = iface->next)
1605 if (iface->index == if_index)
1606 break;
1607
1608 if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
1609 client_ok = 0;
1610 }
1611
1612 if (option_bool(OPT_CLEVERBIND))
1613 iface = listener->iface; /* May be NULL */
1614 else
1615 {
1616 /* Check for allowed interfaces when binding the wildcard address:
1617 we do this by looking for an interface with the same address as
1618 the local address of the TCP connection, then looking to see if that's
1619 an allowed interface. As a side effect, we get the netmask of the
1620 interface too, for localisation. */
1621
1622 for (iface = daemon->interfaces; iface; iface = iface->next)
1623 if (sockaddr_isequal(&iface->addr, &tcp_addr))
1624 break;
1625
1626 if (!iface)
1627 client_ok = 0;
1628 }
1629 }
1630
Simon Kelley22ce5502013-01-22 13:53:04 +00001631 if (!client_ok)
Simon Kelley832af0b2007-01-21 20:01:28 +00001632 {
1633 shutdown(confd, SHUT_RDWR);
Simon Kelleyff841eb2015-03-11 21:36:30 +00001634 while (retry_send(close(confd)));
Simon Kelley832af0b2007-01-21 20:01:28 +00001635 }
1636#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001637 else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001638 {
1639 if (p != -1)
1640 {
1641 int i;
1642 for (i = 0; i < MAX_PROCS; i++)
1643 if (daemon->tcp_pids[i] == 0)
1644 {
1645 daemon->tcp_pids[i] = p;
1646 break;
1647 }
1648 }
Simon Kelleyff841eb2015-03-11 21:36:30 +00001649 while (retry_send(close(confd)));
Simon Kelley25cf5e32015-01-09 15:53:03 +00001650
1651 /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
1652 daemon->log_id += TCP_MAX_QUERIES;
Simon Kelley832af0b2007-01-21 20:01:28 +00001653 }
1654#endif
1655 else
1656 {
1657 unsigned char *buff;
1658 struct server *s;
1659 int flags;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001660 struct in_addr netmask;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001661 int auth_dns;
Simon Kelley52d4abf2012-03-21 21:39:48 +00001662
1663 if (iface)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001664 {
1665 netmask = iface->netmask;
1666 auth_dns = iface->dns_auth;
1667 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001668 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001669 {
1670 netmask.s_addr = 0;
1671 auth_dns = 0;
1672 }
Simon Kelley52d4abf2012-03-21 21:39:48 +00001673
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001674#ifndef NO_FORK
1675 /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
1676 terminate the process. */
Simon Kelley28866e92011-02-14 20:19:14 +00001677 if (!option_bool(OPT_DEBUG))
Simon Kelley832af0b2007-01-21 20:01:28 +00001678 alarm(CHILD_LIFETIME);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001679#endif
1680
Simon Kelley832af0b2007-01-21 20:01:28 +00001681 /* start with no upstream connections. */
1682 for (s = daemon->servers; s; s = s->next)
Simon Kelley7cebd202006-05-06 14:13:33 +01001683 s->tcpfd = -1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001684
1685 /* The connected socket inherits non-blocking
1686 attribute from the listening socket.
1687 Reset that here. */
1688 if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
1689 fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
1690
Simon Kelley4f7b3042012-11-28 21:27:02 +00001691 buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
Simon Kelley7cebd202006-05-06 14:13:33 +01001692
Simon Kelley832af0b2007-01-21 20:01:28 +00001693 shutdown(confd, SHUT_RDWR);
Simon Kelleyff841eb2015-03-11 21:36:30 +00001694 while (retry_send(close(confd)));
Simon Kelley832af0b2007-01-21 20:01:28 +00001695
1696 if (buff)
1697 free(buff);
1698
1699 for (s = daemon->servers; s; s = s->next)
1700 if (s->tcpfd != -1)
1701 {
1702 shutdown(s->tcpfd, SHUT_RDWR);
Simon Kelleyff841eb2015-03-11 21:36:30 +00001703 while (retry_send(close(s->tcpfd)));
Simon Kelley832af0b2007-01-21 20:01:28 +00001704 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001705#ifndef NO_FORK
Simon Kelley28866e92011-02-14 20:19:14 +00001706 if (!option_bool(OPT_DEBUG))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001707 {
1708 flush_log();
1709 _exit(0);
1710 }
Simon Kelley7cebd202006-05-06 14:13:33 +01001711#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001712 }
1713 }
1714 }
Simon Kelley3be34542004-09-11 19:12:13 +01001715}
1716
Simon Kelley7622fc02009-06-04 20:32:05 +01001717#ifdef HAVE_DHCP
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001718int make_icmp_sock(void)
1719{
Simon Kelley7cebd202006-05-06 14:13:33 +01001720 int fd;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001721 int zeroopt = 0;
1722
1723 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
1724 {
Simon Kelley7cebd202006-05-06 14:13:33 +01001725 if (!fix_fd(fd) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001726 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
1727 {
1728 close(fd);
1729 fd = -1;
1730 }
1731 }
1732
1733 return fd;
1734}
1735
Simon Kelley5aabfc72007-08-29 11:24:47 +01001736int icmp_ping(struct in_addr addr)
Simon Kelley3be34542004-09-11 19:12:13 +01001737{
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001738 /* Try and get an ICMP echo from a machine. */
Simon Kelley3be34542004-09-11 19:12:13 +01001739
1740 /* Note that whilst in the three second wait, we check for
Simon Kelley832af0b2007-01-21 20:01:28 +00001741 (and service) events on the DNS and TFTP sockets, (so doing that
Simon Kelley3be34542004-09-11 19:12:13 +01001742 better not use any resources our caller has in use...)
1743 but we remain deaf to signals or further DHCP packets. */
1744
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001745 int fd;
Simon Kelley3be34542004-09-11 19:12:13 +01001746 struct sockaddr_in saddr;
1747 struct {
1748 struct ip ip;
1749 struct icmp icmp;
1750 } packet;
1751 unsigned short id = rand16();
1752 unsigned int i, j;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001753 int gotreply = 0;
Simon Kelley3be34542004-09-11 19:12:13 +01001754 time_t start, now;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001755
Simon Kelley824af852008-02-12 20:43:05 +00001756#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001757 if ((fd = make_icmp_sock()) == -1)
1758 return 0;
1759#else
1760 int opt = 2000;
1761 fd = daemon->dhcp_icmp_fd;
1762 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1763#endif
1764
Simon Kelley3be34542004-09-11 19:12:13 +01001765 saddr.sin_family = AF_INET;
1766 saddr.sin_port = 0;
1767 saddr.sin_addr = addr;
1768#ifdef HAVE_SOCKADDR_SA_LEN
1769 saddr.sin_len = sizeof(struct sockaddr_in);
1770#endif
1771
1772 memset(&packet.icmp, 0, sizeof(packet.icmp));
1773 packet.icmp.icmp_type = ICMP_ECHO;
1774 packet.icmp.icmp_id = id;
1775 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
1776 j += ((u16 *)&packet.icmp)[i];
1777 while (j>>16)
1778 j = (j & 0xffff) + (j >> 16);
1779 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
1780
Simon Kelleyff841eb2015-03-11 21:36:30 +00001781 while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
1782 (struct sockaddr *)&saddr, sizeof(saddr))));
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001783
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001784 for (now = start = dnsmasq_time();
1785 difftime(now, start) < (float)PING_WAIT;)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001786 {
1787 struct timeval tv;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001788 fd_set rset, wset;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001789 struct sockaddr_in faddr;
Simon Kelley16972692006-10-16 20:04:18 +01001790 int maxfd = fd;
Simon Kelley3d8df262005-08-29 12:19:27 +01001791 socklen_t len = sizeof(faddr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001792
1793 tv.tv_usec = 250000;
1794 tv.tv_sec = 0;
1795
1796 FD_ZERO(&rset);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001797 FD_ZERO(&wset);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001798 FD_SET(fd, &rset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001799 set_dns_listeners(now, &rset, &maxfd);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001800 set_log_writer(&wset, &maxfd);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001801
1802#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001803 if (daemon->doing_ra)
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001804 {
1805 FD_SET(daemon->icmp6fd, &rset);
1806 bump_maxfd(daemon->icmp6fd, &maxfd);
1807 }
1808#endif
1809
Simon Kelleyf2621c72007-04-29 19:47:21 +01001810 if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
1811 {
1812 FD_ZERO(&rset);
1813 FD_ZERO(&wset);
1814 }
1815
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001816 now = dnsmasq_time();
Simon Kelleyf2621c72007-04-29 19:47:21 +01001817
1818 check_log_writer(&wset);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001819 check_dns_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001820
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001821#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +00001822 if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
1823 icmp6_packet(now);
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001824#endif
1825
Simon Kelley832af0b2007-01-21 20:01:28 +00001826#ifdef HAVE_TFTP
Simon Kelley5aabfc72007-08-29 11:24:47 +01001827 check_tftp_listeners(&rset, now);
Simon Kelley832af0b2007-01-21 20:01:28 +00001828#endif
1829
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001830 if (FD_ISSET(fd, &rset) &&
1831 recvfrom(fd, &packet, sizeof(packet), 0,
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001832 (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
1833 saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
1834 packet.icmp.icmp_type == ICMP_ECHOREPLY &&
1835 packet.icmp.icmp_seq == 0 &&
1836 packet.icmp.icmp_id == id)
1837 {
1838 gotreply = 1;
1839 break;
1840 }
1841 }
1842
Simon Kelley824af852008-02-12 20:43:05 +00001843#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelleyff841eb2015-03-11 21:36:30 +00001844 while (retry_send(close(fd)));
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001845#else
Simon Kelley3be34542004-09-11 19:12:13 +01001846 opt = 1;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001847 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
1848#endif
1849
Simon Kelley3be34542004-09-11 19:12:13 +01001850 return gotreply;
1851}
Simon Kelley7622fc02009-06-04 20:32:05 +01001852#endif
Simon Kelley0a852542005-03-23 20:28:59 +00001853
1854