mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Further optimisation of --port-limit.
No longer try and fail to open every port when the port range is in complete use; go straight to re-using an existing socket. Die at startup if port range is smaller than --port-limit, since the code behaves badly in this case.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
|
||||
@@ -266,6 +266,10 @@ int main (int argc, char **argv)
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->max_port != 0 &&
|
||||
daemon->max_port - daemon->min_port + 1 < daemon->randport_limit)
|
||||
die(_("port_limit must not be larger than available port range"), NULL, EC_BADCONF);
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
if (daemon->auth_zones)
|
||||
|
||||
@@ -2435,6 +2435,21 @@ static int random_sock(struct server *s)
|
||||
|
||||
if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
|
||||
{
|
||||
/* We need to set IPV6ONLY so we can use the same ports
|
||||
for IPv4 and IPV6, otherwise, in restriced port situations,
|
||||
we can end up with all our available ports in use for
|
||||
one address family, and the other address family cannot be used. */
|
||||
if (s->source_addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
int opt = 1;
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
|
||||
return fd;
|
||||
|
||||
@@ -2479,9 +2494,22 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
{
|
||||
static int finger = 0;
|
||||
int i, j = 0;
|
||||
int ports_full = 0;
|
||||
struct randfd_list **up, *rfl, *found, **found_link;
|
||||
struct randfd *rfd = NULL;
|
||||
int fd = 0;
|
||||
int ports_avail = 0;
|
||||
|
||||
/* We can't have more randomsocks for this AF available than ports in our port range,
|
||||
so check that here, to avoid trying and failing to bind every port
|
||||
in local_bind(), called from random_sock(). The actual check is below when
|
||||
ports_avail != 0 */
|
||||
if (daemon->max_port != 0)
|
||||
{
|
||||
ports_avail = daemon->max_port - daemon->min_port + 1;
|
||||
if (ports_avail >= SMALL_PORT_RANGE)
|
||||
ports_avail = 0;
|
||||
}
|
||||
|
||||
/* If server has a pre-allocated fd, use that. */
|
||||
if (serv->sfd)
|
||||
@@ -2508,20 +2536,36 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
|
||||
return found->rfd->fd;
|
||||
}
|
||||
|
||||
/* check for all available ports in use. */
|
||||
if (ports_avail != 0)
|
||||
{
|
||||
int ports_inuse;
|
||||
|
||||
for (ports_inuse = 0, i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
daemon->randomsocks[i].serv->source_addr.sa.sa_family == serv->source_addr.sa.sa_family &&
|
||||
++ports_inuse >= ports_avail)
|
||||
{
|
||||
ports_full = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* limit the number of sockets we have open to avoid starvation of
|
||||
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount == 0)
|
||||
{
|
||||
if ((fd = random_sock(serv)) != -1)
|
||||
{
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->serv = serv;
|
||||
rfd->fd = fd;
|
||||
rfd->refcount = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!ports_full)
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount == 0)
|
||||
{
|
||||
if ((fd = random_sock(serv)) != -1)
|
||||
{
|
||||
rfd = &daemon->randomsocks[i];
|
||||
rfd->serv = serv;
|
||||
rfd->fd = fd;
|
||||
rfd->refcount = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* No good existing. Need new link. */
|
||||
if ((rfl = daemon->rfl_spare))
|
||||
|
||||
@@ -1371,7 +1371,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
or both are set. Otherwise use the OS's random ephemeral port allocation by
|
||||
leaving port == 0 and tries == 1 */
|
||||
ports_avail = daemon->max_port - daemon->min_port + 1;
|
||||
tries = (ports_avail < 30) ? ports_avail : 100;
|
||||
tries = (ports_avail < SMALL_PORT_RANGE) ? ports_avail : 100;
|
||||
port = htons(daemon->min_port + (rand16() % ports_avail));
|
||||
}
|
||||
|
||||
@@ -1401,7 +1401,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
return 0;
|
||||
|
||||
/* For small ranges, do a systematic search, not a random one. */
|
||||
if (ports_avail < 30)
|
||||
if (ports_avail < SMALL_PORT_RANGE)
|
||||
{
|
||||
unsigned short hport = ntohs(port);
|
||||
if (hport++ == daemon->max_port)
|
||||
|
||||
Reference in New Issue
Block a user