connect.c: Try to connect to other host addresses than just the first

When one host has multiple addresses returned by `getaddrinfo` try not just
the first address. The scenario where the first address is wrong but the
second is good was failing, because the second address was never tried.
This applies to ipv6 as well as to ipv4 addresses.
As the implementation uses non-blocking sockets it may return EINPROGRESS
when error happened as well as just "non-blocking" statement. The socket
can not be queried for status code to determine the error if any, because it
requires calling blocking functions.

Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Norbert Pocs
2023-05-16 15:03:39 +02:00
parent c4a00ee430
commit 1c0b8f624e

View File

@@ -168,7 +168,7 @@ static int set_tcp_nodelay(socket_t socket)
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
const char *bind_addr, int port)
{
socket_t s = -1;
socket_t s = -1, first = -1;
int rc;
struct addrinfo *ai = NULL;
struct addrinfo *itr = NULL;
@@ -258,12 +258,22 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
errno = 0;
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
ssh_set_error(session, SSH_FATAL,
"Failed to connect: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
ssh_connect_socket_close(s);
s = -1;
if (rc == -1) {
if ((errno != 0) && (errno != EINPROGRESS)) {
ssh_set_error(session, SSH_FATAL,
"Failed to connect: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
ssh_connect_socket_close(s);
s = -1;
} else {
if (first == -1) {
first = s;
} else { /* errno == EINPROGRESS */
/* save only the first "working" socket */
ssh_connect_socket_close(s);
s = -1;
}
}
continue;
}
@@ -272,6 +282,12 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
freeaddrinfo(ai);
/* first let's go through all the addresses looking for immediate
* connection, otherwise return the first address without error or error */
if (s == -1) {
s = first;
}
return s;
}