DNS_Mgr: Replace ares_fds() with ares_getsock()

On Slack, a user reported "fortify source" aborts within ares_fds() due
to the FDs used by c-ares exceeding 1024 and thereby larger than the
maximum fd value that a fd_set can hold.

Switch to ares_get_socks() and poll() to avoid this.

Closes #3309.

(cherry picked from commit c4c4a23bfd)
This commit is contained in:
Arne Welzel 2023-09-25 10:11:14 +02:00 committed by Tim Wojtulewicz
parent 526e0ae0ad
commit 7291ac4f26

View file

@ -6,7 +6,7 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/select.h> #include <sys/poll.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -994,23 +994,54 @@ void DNS_Mgr::Resolve()
{ {
int nfds = 0; int nfds = 0;
struct timeval *tvp, tv; struct timeval *tvp, tv;
fd_set read_fds, write_fds; struct pollfd pollfds[ARES_GETSOCK_MAXNUM];
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
tv.tv_sec = DNS_TIMEOUT; tv.tv_sec = DNS_TIMEOUT;
tv.tv_usec = 0; tv.tv_usec = 0;
for ( int i = 0; i < MAX_PENDING_REQUESTS; i++ ) for ( int i = 0; i < MAX_PENDING_REQUESTS; i++ )
{ {
FD_ZERO(&read_fds); int nfds = 0;
FD_ZERO(&write_fds); int bitmap = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
nfds = ares_fds(channel, &read_fds, &write_fds);
for ( int i = 0; i < ARES_GETSOCK_MAXNUM; i++ )
{
bool rd = ARES_GETSOCK_READABLE(bitmap, i);
bool wr = ARES_GETSOCK_WRITABLE(bitmap, i);
if ( rd || wr )
{
pollfds[nfds].fd = socks[i];
pollfds[nfds].events = rd ? POLLIN : 0;
pollfds[nfds].events |= wr ? POLLOUT : 0;
++nfds;
}
}
// Do we have any sockets that are read or writable?
if ( nfds == 0 ) if ( nfds == 0 )
break; break;
// poll() timeout is in milliseconds.
tvp = ares_timeout(channel, &tv, &tv); tvp = ares_timeout(channel, &tv, &tv);
int res = select(nfds, &read_fds, &write_fds, NULL, tvp); int timeout_ms = tvp->tv_sec * 1000 + tvp->tv_usec / 1000;
if ( res >= 0 )
ares_process(channel, &read_fds, &write_fds); int res = poll(pollfds, nfds, timeout_ms);
if ( res > 0 )
{
for ( int i = 0; i < nfds; i++ )
{
int rdfd = pollfds[i].revents | POLLIN ? pollfds[i].fd : ARES_SOCKET_BAD;
int wrfd = pollfds[i].revents | POLLOUT ? pollfds[i].fd : ARES_SOCKET_BAD;
if ( rdfd != ARES_SOCKET_BAD || wrfd != ARES_SOCKET_BAD )
ares_process_fd(channel, rdfd, wrfd);
}
}
else if ( res == 0 )
// Do timeout processing when poll() timed out.
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
} }
} }
@ -1444,11 +1475,16 @@ double DNS_Mgr::GetNextTimeout()
if ( asyncs_pending == 0 ) if ( asyncs_pending == 0 )
return -1; return -1;
fd_set read_fds, write_fds; int nfds = 0;
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
int bitmap = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
for ( int i = 0; i < ARES_GETSOCK_MAXNUM; i++ )
{
if ( ARES_GETSOCK_READABLE(bitmap, i) || ARES_GETSOCK_WRITABLE(bitmap, i) )
++nfds;
}
FD_ZERO(&read_fds); // Do we have any sockets that are read or writable?
FD_ZERO(&write_fds);
int nfds = ares_fds(channel, &read_fds, &write_fds);
if ( nfds == 0 ) if ( nfds == 0 )
return -1; return -1;