GUACAMOLE-600: Add support for setting SSH and SFTP timeouts.

This commit is contained in:
Virtually Nick 2023-02-16 16:52:23 -05:00
parent 47b9360d46
commit fbb257da69
11 changed files with 110 additions and 13 deletions

View File

@ -115,6 +115,10 @@ void guac_common_ssh_uninit();
* @param user * @param user
* The user to authenticate as, once connected. * The user to authenticate as, once connected.
* *
* @param timeout
* The number of seconds to attempt to connect to the SSH server before
* timing out.
*
* @param keepalive * @param keepalive
* How frequently the connection should send keepalive packets, in * How frequently the connection should send keepalive packets, in
* seconds. Zero disables keepalive packets, and 2 is the minimum * seconds. Zero disables keepalive packets, and 2 is the minimum
@ -138,7 +142,7 @@ void guac_common_ssh_uninit();
*/ */
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, const char* hostname, const char* port, guac_common_ssh_user* user,
int keepalive, const char* host_key, int timeout, int keepalive, const char* host_key,
guac_ssh_credential_handler* credential_handler); guac_ssh_credential_handler* credential_handler);
/** /**

View File

@ -33,6 +33,7 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
@ -40,6 +41,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
@ -405,7 +407,7 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, const char* hostname, const char* port, guac_common_ssh_user* user,
int keepalive, const char* host_key, int timeout, int keepalive, const char* host_key,
guac_ssh_credential_handler* credential_handler) { guac_ssh_credential_handler* credential_handler) {
int retval; int retval;
@ -453,17 +455,39 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
return NULL; return NULL;
} }
/* Connect */ /* Set socket to non-blocking */
if (connect(fd, current_address->ai_addr, fcntl(fd, F_SETFL, O_NONBLOCK);
current_address->ai_addrlen) == 0) {
/* Set up timeout. */
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
struct timeval tv;
tv.tv_sec = timeout; /* 10 second timeout */
tv.tv_usec = 0;
/* Connect and wait for timeout */
connect(fd, current_address->ai_addr, current_address->ai_addrlen);
retval = select(fd + 1, NULL, &fdset, NULL, &tv);
/* Timeout has occured - log the failure and move to the next address. */
if (retval == 0) {
guac_client_log(client, GUAC_LOG_DEBUG,
"Timeout connecting to host %s, port %s",
connected_address, connected_port);
continue;
}
/* Connection is successful - log it and break the loop. */
else if (retval > 0) {
guac_client_log(client, GUAC_LOG_DEBUG, guac_client_log(client, GUAC_LOG_DEBUG,
"Successfully connected to host %s, port %s", "Successfully connected to host %s, port %s",
connected_address, connected_port); connected_address, connected_port);
/* Done if successful connect */ /* Done if successful connect */
break; break;
} }
/* Otherwise log information regarding bind failure */ /* Otherwise log information regarding bind failure */

View File

@ -776,8 +776,8 @@ void* guac_rdp_client_thread(void* data) {
/* Attempt SSH connection */ /* Attempt SSH connection */
rdp_client->sftp_session = rdp_client->sftp_session =
guac_common_ssh_create_session(client, settings->sftp_hostname, guac_common_ssh_create_session(client, settings->sftp_hostname,
settings->sftp_port, rdp_client->sftp_user, settings->sftp_server_alive_interval, settings->sftp_port, rdp_client->sftp_user, settings->sftp_timeout,
settings->sftp_host_key, NULL); settings->sftp_server_alive_interval, settings->sftp_host_key, NULL);
/* Fail if SSH connection does not succeed */ /* Fail if SSH connection does not succeed */
if (rdp_client->sftp_session == NULL) { if (rdp_client->sftp_session == NULL) {

View File

@ -101,6 +101,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
"sftp-hostname", "sftp-hostname",
"sftp-host-key", "sftp-host-key",
"sftp-port", "sftp-port",
"sftp-timeout",
"sftp-username", "sftp-username",
"sftp-password", "sftp-password",
"sftp-private-key", "sftp-private-key",
@ -435,6 +436,12 @@ enum RDP_ARGS_IDX {
*/ */
IDX_SFTP_PORT, IDX_SFTP_PORT,
/**
* The number of seconds to attempt to connect to the SSH server before
* timing out.
*/
IDX_SFTP_TIMEOUT,
/** /**
* The username to provide when authenticating with the SSH server for * The username to provide when authenticating with the SSH server for
* SFTP. If blank, the username provided for the RDP user will be used. * SFTP. If blank, the username provided for the RDP user will be used.
@ -1051,6 +1058,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_SFTP_PORT, "22"); IDX_SFTP_PORT, "22");
/* SFTP timeout */
settings->sftp_timeout =
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
IDX_SFTP_TIMEOUT, RDP_DEFAULT_SFTP_TIMEOUT);
/* Username for SSH/SFTP authentication */ /* Username for SSH/SFTP authentication */
settings->sftp_username = settings->sftp_username =
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,

View File

@ -38,6 +38,11 @@
*/ */
#define RDP_DEFAULT_PORT 3389 #define RDP_DEFAULT_PORT 3389
/**
* The default SFTP connection timeout, in seconds.
*/
#define RDP_DEFAULT_SFTP_TIMEOUT 10
/** /**
* The default RDP port used by Hyper-V "VMConnect". * The default RDP port used by Hyper-V "VMConnect".
*/ */
@ -440,6 +445,12 @@ typedef struct guac_rdp_settings {
*/ */
char* sftp_port; char* sftp_port;
/**
* The number of seconds to attempt to connect to the SSH server before
* timing out.
*/
int sftp_timeout;
/** /**
* The username to provide when authenticating with the SSH server for * The username to provide when authenticating with the SSH server for
* SFTP. * SFTP.

View File

@ -37,6 +37,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
"hostname", "hostname",
"host-key", "host-key",
"port", "port",
"timeout",
"username", "username",
"password", "password",
GUAC_SSH_ARGV_FONT_NAME, GUAC_SSH_ARGV_FONT_NAME,
@ -95,6 +96,11 @@ enum SSH_ARGS_IDX {
*/ */
IDX_PORT, IDX_PORT,
/**
* The timeout of the connection attempt, in seconds. Optional.
*/
IDX_TIMEOUT,
/** /**
* The name of the user to login as. Optional. * The name of the user to login as. Optional.
*/ */
@ -429,6 +435,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_PORT, GUAC_SSH_DEFAULT_PORT); IDX_PORT, GUAC_SSH_DEFAULT_PORT);
/* Parse the timeout value. */
settings->timeout =
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_TIMEOUT, GUAC_SSH_DEFAULT_TIMEOUT);
/* Read-only mode */ /* Read-only mode */
settings->read_only = settings->read_only =
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,

View File

@ -32,6 +32,12 @@
*/ */
#define GUAC_SSH_DEFAULT_PORT "22" #define GUAC_SSH_DEFAULT_PORT "22"
/**
* The default number of seconds to attempt a connection to the SSH/SFTP
* server before giving up.
*/
#define GUAC_SSH_DEFAULT_TIMEOUT 10
/** /**
* The filename to use for the typescript, if not specified. * The filename to use for the typescript, if not specified.
*/ */
@ -69,6 +75,12 @@ typedef struct guac_ssh_settings {
*/ */
char* port; char* port;
/**
* The number of seconds to attempt to connect to the SSH server before
* timing out.
*/
int timeout;
/** /**
* The name of the user to login as, if any. If no username is specified, * The name of the user to login as, if any. If no username is specified,
* this will be NULL. * this will be NULL.

View File

@ -288,7 +288,8 @@ void* ssh_client_thread(void* data) {
/* Open SSH session */ /* Open SSH session */
ssh_client->session = guac_common_ssh_create_session(client, ssh_client->session = guac_common_ssh_create_session(client,
settings->hostname, settings->port, ssh_client->user, settings->server_alive_interval, settings->hostname, settings->port, ssh_client->user,
settings->timeout, settings->server_alive_interval,
settings->host_key, guac_ssh_get_credential); settings->host_key, guac_ssh_get_credential);
if (ssh_client->session == NULL) { if (ssh_client->session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */ /* Already aborted within guac_common_ssh_create_session() */
@ -340,8 +341,8 @@ void* ssh_client_thread(void* data) {
guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP..."); guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
ssh_client->sftp_session = ssh_client->sftp_session =
guac_common_ssh_create_session(client, settings->hostname, guac_common_ssh_create_session(client, settings->hostname,
settings->port, ssh_client->user, settings->server_alive_interval, settings->port, ssh_client->user, settings->timeout,
settings->host_key, NULL); settings->server_alive_interval, settings->host_key, NULL);
if (ssh_client->sftp_session == NULL) { if (ssh_client->sftp_session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */ /* Already aborted within guac_common_ssh_create_session() */
return NULL; return NULL;

View File

@ -66,6 +66,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = {
"sftp-hostname", "sftp-hostname",
"sftp-host-key", "sftp-host-key",
"sftp-port", "sftp-port",
"sftp-timeout",
"sftp-username", "sftp-username",
"sftp-password", "sftp-password",
"sftp-private-key", "sftp-private-key",
@ -228,6 +229,12 @@ enum VNC_ARGS_IDX {
*/ */
IDX_SFTP_PORT, IDX_SFTP_PORT,
/**
* The number of seconds to attempt to connect to the SFTP server before
* timing out.
*/
IDX_SFTP_TIMEOUT,
/** /**
* The username to provide when authenticating with the SSH server for * The username to provide when authenticating with the SSH server for
* SFTP. * SFTP.
@ -519,6 +526,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
IDX_SFTP_PORT, "22"); IDX_SFTP_PORT, "22");
/* SFTP connection timeout */
settings->sftp_timeout =
guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
IDX_SFTP_TIMEOUT, GUAC_VNC_DEFAULT_SFTP_TIMEOUT);
/* Username for SSH/SFTP authentication */ /* Username for SSH/SFTP authentication */
settings->sftp_username = settings->sftp_username =
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,

View File

@ -30,6 +30,11 @@
*/ */
#define GUAC_VNC_DEFAULT_RECORDING_NAME "recording" #define GUAC_VNC_DEFAULT_RECORDING_NAME "recording"
/**
* The default number of seconds to attempt to connect to the SFTP server.
*/
#define GUAC_VNC_DEFAULT_SFTP_TIMEOUT 10
/** /**
* VNC-specific client data. * VNC-specific client data.
*/ */
@ -173,6 +178,11 @@ typedef struct guac_vnc_settings {
*/ */
char* sftp_port; char* sftp_port;
/**
* The number of seconds to attempt to connect to the SFTP server.
*/
int sftp_timeout;
/** /**
* The username to provide when authenticating with the SSH server for * The username to provide when authenticating with the SSH server for
* SFTP. * SFTP.

View File

@ -376,8 +376,8 @@ void* guac_vnc_client_thread(void* data) {
/* Attempt SSH connection */ /* Attempt SSH connection */
vnc_client->sftp_session = vnc_client->sftp_session =
guac_common_ssh_create_session(client, settings->sftp_hostname, guac_common_ssh_create_session(client, settings->sftp_hostname,
settings->sftp_port, vnc_client->sftp_user, settings->sftp_server_alive_interval, settings->sftp_port, vnc_client->sftp_user, settings->sftp_timeout,
settings->sftp_host_key, NULL); settings->sftp_server_alive_interval, settings->sftp_host_key, NULL);
/* Fail if SSH connection does not succeed */ /* Fail if SSH connection does not succeed */
if (vnc_client->sftp_session == NULL) { if (vnc_client->sftp_session == NULL) {