summaryrefslogtreecommitdiff
path: root/src/dnsmasq.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dnsmasq.c')
-rw-r--r--src/dnsmasq.c211
1 files changed, 128 insertions, 83 deletions
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 2306c48..602daed 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ struct daemon *daemon;
static volatile pid_t pid = 0;
static volatile int pipewrite;
-static int set_dns_listeners(time_t now);
+static void set_dns_listeners(void);
static void check_dns_listeners(time_t now);
static void sig_handler(int sig);
static void async_event(int pipe, time_t now);
@@ -109,7 +109,6 @@ int main (int argc, char **argv)
daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
- daemon->addrbuff = safe_malloc(ADDRSTRLEN);
if (option_bool(OPT_EXTRALOG))
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
@@ -135,6 +134,13 @@ int main (int argc, char **argv)
}
#endif
+#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
+ /* CONNTRACK UBUS code uses this buffer, so if not allocated above,
+ we need to allocate it here. */
+ if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename)
+ daemon->workspacename = safe_malloc(MAXDNAME);
+#endif
+
#ifdef HAVE_DHCP
if (!daemon->lease_file)
{
@@ -205,8 +211,13 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_CONNTRACK
- if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
- die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
+ if (option_bool(OPT_CONNTRACK))
+ {
+ if (daemon->query_port != 0 || daemon->osport)
+ die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
+
+ need_cap_net_admin = 1;
+ }
#else
if (option_bool(OPT_CONNTRACK))
die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
@@ -237,9 +248,16 @@ int main (int argc, char **argv)
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
#endif
+ /* Handle only one of min_port/max_port being set. */
+ if (daemon->min_port != 0 && daemon->max_port == 0)
+ daemon->max_port = MAX_PORT;
+
+ if (daemon->max_port != 0 && daemon->min_port == 0)
+ daemon->min_port = MIN_PORT;
+
if (daemon->max_port < daemon->min_port)
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
-
+
now = dnsmasq_time();
if (daemon->auth_zones)
@@ -390,8 +408,16 @@ int main (int argc, char **argv)
if (daemon->port != 0)
{
cache_init();
-
blockdata_init();
+ hash_questions_init();
+
+ /* Scale random socket pool by ftabsize, but
+ limit it based on available fds. */
+ daemon->numrrand = daemon->ftabsize/2;
+ if (daemon->numrrand > max_fd/3)
+ daemon->numrrand = max_fd/3;
+ /* safe_malloc returns zero'd memory */
+ daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd));
}
#ifdef HAVE_INOTIFY
@@ -415,8 +441,6 @@ int main (int argc, char **argv)
#ifdef HAVE_DBUS
{
char *err;
- daemon->dbus = NULL;
- daemon->watches = NULL;
if ((err = dbus_init()))
die(_("DBus error: %s"), err, EC_MISC);
}
@@ -427,8 +451,9 @@ int main (int argc, char **argv)
if (option_bool(OPT_UBUS))
#ifdef HAVE_UBUS
{
- daemon->ubus = NULL;
- ubus_init();
+ char *err;
+ if ((err = ubus_init()))
+ die(_("UBus error: %s"), err, EC_MISC);
}
#else
die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
@@ -980,7 +1005,7 @@ int main (int argc, char **argv)
a single file will be sent to may clients (the file only needs
one fd). */
- max_fd -= 30; /* use other than TFTP */
+ max_fd -= 30 + daemon->numrrand; /* use other than TFTP */
if (max_fd < 0)
max_fd = 5;
@@ -1010,7 +1035,7 @@ int main (int argc, char **argv)
close(err_pipe[1]);
if (daemon->port != 0)
- check_servers();
+ check_servers(0);
pid = getpid();
@@ -1025,16 +1050,10 @@ int main (int argc, char **argv)
while (1)
{
- int t, timeout = -1;
+ int timeout = -1;
poll_reset();
- /* if we are out of resources, find how long we have to wait
- for some to come free, we'll loop around then and restart
- listening for queries */
- if ((t = set_dns_listeners(now)) != 0)
- timeout = t * 1000;
-
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
if (daemon->tftp_trans ||
(option_bool(OPT_DBUS) && !daemon->dbus))
@@ -1044,15 +1063,18 @@ int main (int argc, char **argv)
else if (is_dad_listeners())
timeout = 1000;
+ set_dns_listeners();
+
#ifdef HAVE_DBUS
- set_dbus_listeners();
+ if (option_bool(OPT_DBUS))
+ set_dbus_listeners();
#endif
-
+
#ifdef HAVE_UBUS
if (option_bool(OPT_UBUS))
set_ubus_listeners();
#endif
-
+
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->relay4)
{
@@ -1172,28 +1194,44 @@ int main (int argc, char **argv)
#ifdef HAVE_DBUS
/* if we didn't create a DBus connection, retry now. */
- if (option_bool(OPT_DBUS) && !daemon->dbus)
+ if (option_bool(OPT_DBUS))
{
- char *err;
- if ((err = dbus_init()))
- my_syslog(LOG_WARNING, _("DBus error: %s"), err);
- if (daemon->dbus)
- my_syslog(LOG_INFO, _("connected to system DBus"));
+ if (!daemon->dbus)
+ {
+ char *err = dbus_init();
+
+ if (daemon->dbus)
+ my_syslog(LOG_INFO, _("connected to system DBus"));
+ else if (err)
+ {
+ my_syslog(LOG_ERR, _("DBus error: %s"), err);
+ reset_option_bool(OPT_DBUS); /* fatal error, stop trying. */
+ }
+ }
+
+ check_dbus_listeners();
}
- check_dbus_listeners();
#endif
#ifdef HAVE_UBUS
+ /* if we didn't create a UBus connection, retry now. */
if (option_bool(OPT_UBUS))
- {
- /* if we didn't create a UBus connection, retry now. */
- if (!daemon->ubus)
- {
- ubus_init();
- }
+ {
+ if (!daemon->ubus)
+ {
+ char *err = ubus_init();
- check_ubus_listeners();
- }
+ if (daemon->ubus)
+ my_syslog(LOG_INFO, _("connected to system UBus"));
+ else if (err)
+ {
+ my_syslog(LOG_ERR, _("UBus error: %s"), err);
+ reset_option_bool(OPT_UBUS); /* fatal error, stop trying. */
+ }
+ }
+
+ check_ubus_listeners();
+ }
#endif
check_dns_listeners(now);
@@ -1426,7 +1464,7 @@ static void async_event(int pipe, time_t now)
}
if (check)
- check_servers();
+ check_servers(0);
}
#ifdef HAVE_DHCP
@@ -1625,7 +1663,7 @@ static void poll_resolv(int force, int do_reload, time_t now)
{
my_syslog(LOG_INFO, _("reading %s"), latest->name);
warned = 0;
- check_servers();
+ check_servers(0);
if (option_bool(OPT_RELOAD) && do_reload)
clear_cache_and_reload(now);
}
@@ -1668,11 +1706,12 @@ void clear_cache_and_reload(time_t now)
#endif
}
-static int set_dns_listeners(time_t now)
+static void set_dns_listeners(void)
{
struct serverfd *serverfdp;
struct listener *listener;
- int wait = 0, i;
+ struct randfd_list *rfl;
+ int i;
#ifdef HAVE_TFTP
int tftp = 0;
@@ -1685,66 +1724,68 @@ static int set_dns_listeners(time_t now)
}
#endif
- /* will we be able to get memory? */
- if (daemon->port != 0)
- get_new_frec(now, &wait, NULL);
-
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
poll_listen(serverfdp->fd, POLLIN);
- if (daemon->port != 0 && !daemon->osport)
- for (i = 0; i < RANDOM_SOCKS; i++)
- if (daemon->randomsocks[i].refcount != 0)
- poll_listen(daemon->randomsocks[i].fd, POLLIN);
-
+ for (i = 0; i < daemon->numrrand; i++)
+ if (daemon->randomsocks[i].refcount != 0)
+ poll_listen(daemon->randomsocks[i].fd, POLLIN);
+
+ /* Check overflow random sockets too. */
+ for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
+ poll_listen(rfl->rfd->fd, POLLIN);
+
+ /* check to see if we have free tcp process slots. */
+ for (i = MAX_PROCS - 1; i >= 0; i--)
+ if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
+ break;
+
for (listener = daemon->listeners; listener; listener = listener->next)
{
- /* only listen for queries if we have resources */
- if (listener->fd != -1 && wait == 0)
+ if (listener->fd != -1)
poll_listen(listener->fd, POLLIN);
-
- /* death of a child goes through the select loop, so
- we don't need to explicitly arrange to wake up here */
- if (listener->tcpfd != -1)
- for (i = 0; i < MAX_PROCS; i++)
- if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
- {
- poll_listen(listener->tcpfd, POLLIN);
- break;
- }
-
+
+ /* Only listen for TCP connections when a process slot
+ is available. Death of a child goes through the select loop, so
+ we don't need to explicitly arrange to wake up here,
+ we'll be called again when a slot becomes available. */
+ if (listener->tcpfd != -1 && i >= 0)
+ poll_listen(listener->tcpfd, POLLIN);
+
#ifdef HAVE_TFTP
/* tftp == 0 in single-port mode. */
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
poll_listen(listener->tftpfd, POLLIN);
#endif
-
}
if (!option_bool(OPT_DEBUG))
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pipes[i] != -1)
poll_listen(daemon->tcp_pipes[i], POLLIN);
-
- return wait;
}
static void check_dns_listeners(time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
+ struct randfd_list *rfl;
int i;
int pipefd[2];
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN))
- reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
+ reply_query(serverfdp->fd, now);
- if (daemon->port != 0 && !daemon->osport)
- for (i = 0; i < RANDOM_SOCKS; i++)
- if (daemon->randomsocks[i].refcount != 0 &&
- poll_check(daemon->randomsocks[i].fd, POLLIN))
- reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
+ for (i = 0; i < daemon->numrrand; i++)
+ if (daemon->randomsocks[i].refcount != 0 &&
+ poll_check(daemon->randomsocks[i].fd, POLLIN))
+ reply_query(daemon->randomsocks[i].fd, now);
+
+ /* Check overflow random sockets too. */
+ for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
+ if (poll_check(rfl->rfd->fd, POLLIN))
+ reply_query(rfl->rfd->fd, now);
/* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
@@ -1773,7 +1814,16 @@ static void check_dns_listeners(time_t now)
tftp_request(listener, now);
#endif
- if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
+ /* check to see if we have a free tcp process slot.
+ Note that we can't assume that because we had
+ at least one a poll() time, that we still do.
+ There may be more waiting connections after
+ poll() returns then free process slots. */
+ for (i = MAX_PROCS - 1; i >= 0; i--)
+ if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
+ break;
+
+ if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
{
int confd, client_ok = 1;
struct irec *iface = NULL;
@@ -1863,7 +1913,6 @@ static void check_dns_listeners(time_t now)
close(pipefd[0]);
else
{
- int i;
#ifdef HAVE_LINUX_NETWORK
/* The child process inherits the netlink socket,
which it never uses, but when the parent (us)
@@ -1883,13 +1932,9 @@ static void check_dns_listeners(time_t now)
read_write(pipefd[0], &a, 1, 1);
#endif
- for (i = 0; i < MAX_PROCS; i++)
- if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
- {
- daemon->tcp_pids[i] = p;
- daemon->tcp_pipes[i] = pipefd[0];
- break;
- }
+ /* i holds index of free slot */
+ daemon->tcp_pids[i] = p;
+ daemon->tcp_pipes[i] = pipefd[0];
}
close(confd);
@@ -2068,7 +2113,7 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
poll_reset();
if (fd != -1)
poll_listen(fd, POLLIN);
- set_dns_listeners(now);
+ set_dns_listeners();
set_log_writer();
#ifdef HAVE_DHCP6