1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-12-24 19:37:49 +03:00

tests: retry KEX failures when using the WinCNG backend

Twice. This tests are flaky and we haven't figured out why. In the
meantime use this workaround to test and log these issues, but also
ensure that CI run aren't flagged red because of it.

Also:
- kex: add debug message when hostkey `sig_verify` fails,
  to help tracking WinCNG KEX failures.
- test_ssh2: also add retry logic.
  I'm not quite sure this is correct. Please let me know.
- session_fixture: bump up `src_path` slots to fit retries and show
  message when hitting the limit.
- session_fixture: clear `kbd_password` static variable after use.
- session_fixture: close and deinit socket after use.
- session_fixture: deinit libssh2 after use.

Ref: #804 #846 #979 #1012 #1015

Cherry-picked from #1017
Closes #1023
This commit is contained in:
Viktor Szakats
2023-04-28 23:24:26 +00:00
parent d70919fb00
commit bc120a343b
7 changed files with 105 additions and 27 deletions

View File

@@ -352,6 +352,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session,
/* Wait for KEX reply */
struct string_buf buf;
size_t host_key_len;
int err;
rc = _libssh2_packet_require(session, packet_type_reply,
&exchange_state->s_packet,
@@ -619,10 +620,17 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session,
_libssh2_sha_algo_ctx_final(sha_algo_value, exchange_hash_ctx,
exchange_state->h_sig_comp);
if(session->hostkey->
sig_verify(session, exchange_state->h_sig,
exchange_state->h_sig_len, exchange_state->h_sig_comp,
digest_len, &session->server_hostkey_abstract)) {
err = session->hostkey->sig_verify(session,
exchange_state->h_sig,
exchange_state->h_sig_len,
exchange_state->h_sig_comp,
digest_len,
&session->server_hostkey_abstract);
if(err) {
_libssh2_debug((session, LIBSSH2_TRACE_KEX,
"Failed hostkey sig_verify(): %s: %d",
session->hostkey->name, err));
ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
"Unable to verify hostkey signature "
"DH-SHA");

View File

@@ -420,6 +420,18 @@ cleanup:
return ret;
}
static void close_socket_to_container(libssh2_socket_t sock)
{
if(sock != LIBSSH2_INVALID_SOCKET) {
shutdown(sock, 2 /* SHUT_RDWR */);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
}
}
static char *running_container_id = NULL;
int start_openssh_fixture(void)
@@ -463,3 +475,8 @@ libssh2_socket_t open_socket_to_openssh_server(void)
{
return open_socket_to_container(running_container_id);
}
void close_socket_to_openssh_server(libssh2_socket_t sock)
{
close_socket_to_container(sock);
}

View File

@@ -41,6 +41,7 @@
int start_openssh_fixture(void);
void stop_openssh_fixture(void);
libssh2_socket_t open_socket_to_openssh_server(void);
void close_socket_to_openssh_server(libssh2_socket_t sock);
int openssh_fixture_have_docker(void);
#endif

View File

@@ -39,16 +39,39 @@
int main(void)
{
int exit_code = 1;
int skipped;
LIBSSH2_SESSION *session = start_session_fixture(&skipped);
if(session) {
exit_code = (test(session) == 0) ? 0 : 1;
}
else if(skipped) {
fprintf(stderr, "Test skipped.\n");
exit_code = 0;
}
stop_session_fixture();
int exit_code;
int retries = 0, retry = 0;
#ifdef LIBSSH2_WINCNG
/* FIXME: Retry tests with WinCNG due to flakiness in hostkey
verification: https://github.com/libssh2/libssh2/issues/804 */
retries += 2;
#endif
do {
int skipped, rc;
LIBSSH2_SESSION *session = start_session_fixture(&skipped, &rc);
if(session) {
exit_code = (test(session) == 0) ? 0 : 1;
}
else if(skipped) {
fprintf(stderr, "Test skipped.\n");
exit_code = 0;
}
else {
exit_code = 1;
}
stop_session_fixture();
if(exit_code == 0 ||
#ifdef LIBSSH2_WINCNG
rc != LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE ||
#endif
++retry > retries) {
break;
}
fprintf(stderr, "Test failed (%d)! Retrying... %d / %d\n",
rc, retry, retries);
} while(1);
return exit_code;
}

View File

@@ -65,16 +65,16 @@ static int connect_to_server(void)
int rc;
connected_socket = open_socket_to_openssh_server();
if(connected_socket == LIBSSH2_INVALID_SOCKET) {
return -1;
return LIBSSH2_ERROR_SOCKET_NONE;
}
rc = libssh2_session_handshake(connected_session, connected_socket);
if(rc) {
print_last_session_error("libssh2_session_handshake");
return -1;
return libssh2_session_last_errno(connected_session);
}
return 0;
return LIBSSH2_ERROR_NONE;
}
static void setup_fixture_workdir(void)
@@ -117,7 +117,7 @@ static char const *skip_crypt[] = {
NULL
};
LIBSSH2_SESSION *start_session_fixture(int *skipped)
LIBSSH2_SESSION *start_session_fixture(int *skipped, int *err)
{
int rc;
@@ -125,6 +125,7 @@ LIBSSH2_SESSION *start_session_fixture(int *skipped)
const char *mac = getenv("FIXTURE_TEST_MAC");
*skipped = 0;
*err = LIBSSH2_ERROR_NONE;
if(crypt) {
char const * const *cr;
@@ -192,7 +193,8 @@ LIBSSH2_SESSION *start_session_fixture(int *skipped)
libssh2_session_set_blocking(connected_session, 1);
rc = connect_to_server();
if(rc) {
if(rc != LIBSSH2_ERROR_NONE) {
*err = rc;
return NULL;
}
@@ -221,13 +223,17 @@ void stop_session_fixture(void)
if(connected_session) {
libssh2_session_disconnect(connected_session, "test ended");
libssh2_session_free(connected_session);
shutdown(connected_socket, 2);
connected_session = NULL;
}
else {
fprintf(stderr, "Cannot stop session - none started\n");
}
close_socket_to_openssh_server(connected_socket);
connected_socket = LIBSSH2_INVALID_SOCKET;
libssh2_exit();
stop_openssh_fixture();
}
@@ -236,7 +242,7 @@ void stop_session_fixture(void)
* variable, if found. It does so in a way that avoids leaking memory by using
* a fixed number of static buffers.
*/
#define NUMPATHS 3
#define NUMPATHS 32
const char *srcdir_path(const char *file)
{
#ifdef WIN32
@@ -246,6 +252,9 @@ const char *srcdir_path(const char *file)
#endif
static int curpath;
char *p = getenv("srcdir");
if(curpath >= NUMPATHS) {
fprintf(stderr, "srcdir_path ran out of filepath slots.\n");
}
assert(curpath < NUMPATHS);
if(p) {
/* Ensure the final string is nul-terminated on Windows */
@@ -315,6 +324,8 @@ int test_auth_keyboard(LIBSSH2_SESSION *session, int flags,
(unsigned int)strlen(username),
kbd_callback);
kbd_password = NULL;
if((flags & TEST_AUTH_SHOULDFAIL) != 0) {
if(rc == 0) {
fprintf(stderr, "Keyboard-interactive auth succeeded "

View File

@@ -42,7 +42,7 @@
#include "libssh2_priv.h"
LIBSSH2_SESSION *start_session_fixture(int *skipped);
LIBSSH2_SESSION *start_session_fixture(int *skipped, int *err);
void stop_session_fixture(void);
void print_last_session_error(const char *function);
const char *srcdir_path(const char *file);

View File

@@ -133,10 +133,28 @@ int main(int argc, char *argv[])
libssh2_session_set_blocking(session, 1);
rc = libssh2_session_handshake(session, sock);
if(rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
goto shutdown;
{
int retries = 0, retry = 0;
#ifdef LIBSSH2_WINCNG
/* FIXME: Retry tests with WinCNG due to flakiness in hostkey
verification: https://github.com/libssh2/libssh2/issues/804 */
retries += 2;
#endif
do {
rc = libssh2_session_handshake(session, sock);
if(rc == 0) {
break;
}
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
if(
#ifdef LIBSSH2_WINCNG
rc != LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE ||
#endif
++retry > retries) {
break;
}
fprintf(stderr, "Retrying... %d / %d\n", retry, retries);
} while(1);
}
/* At this point we have not yet authenticated. The first thing to do