Skip to content

Commit

Permalink
GUACAMOLE-600: Merge support for setting SSH and SFTP timeouts.
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-jumper authored Aug 26, 2024
2 parents e42def8 + 7d0b76b commit f50ccf6
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 26 deletions.
6 changes: 5 additions & 1 deletion src/common-ssh/common-ssh/ssh.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ void guac_common_ssh_uninit();
*
* @param user
* 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
* How frequently the connection should send keepalive packets, in
Expand All @@ -138,7 +142,7 @@ void guac_common_ssh_uninit();
*/
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
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);

/**
Expand Down
10 changes: 8 additions & 2 deletions src/common-ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@
#include <openssl/err.h>
#include <openssl/ssl.h>

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef LIBSSH2_USES_GCRYPT
Expand Down Expand Up @@ -408,10 +414,10 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)

guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
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) {

int fd = guac_socket_tcp_connect(hostname, port);
int fd = guac_socket_tcp_connect(hostname, port, timeout);
if (fd < 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Failed to open TCP connection to %s on %s.", hostname, port);
Expand Down
5 changes: 4 additions & 1 deletion src/libguac/guacamole/socket-tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,13 @@
* @param port
* The TCP port to which to attempt to connect.
*
* @param timeout
* The number of seconds to try the TCP connection before timing out.
*
* @return
* A valid socket if the connection succeeds, or a negative integer if it
* fails.
*/
int guac_socket_tcp_connect(const char* hostname, const char* port);
int guac_socket_tcp_connect(const char* hostname, const char* port, const int timeout);

#endif // __GUAC_SOCKET_TCP_H
6 changes: 6 additions & 0 deletions src/libguac/guacamole/wol-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
*/
#define GUAC_WOL_DEFAULT_CONNECT_RETRIES 5

/**
* The default number of seconds for the connection timeout when attempting
* to connect to the remote system to see if it is awake.
*/
#define GUAC_WOL_DEFAULT_CONNECTION_TIMEOUT 10

/**
* The value for the local IPv4 broadcast address.
*/
Expand Down
6 changes: 5 additions & 1 deletion src/libguac/guacamole/wol.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,18 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr,
* @param port
* The TCP port of the remote system on which the connection will be
* attempted after the system has been woken.
*
* @param timeout
* The number of seconds to wait when attempting the connection to the
* remote system when checking to see if it is awake.
*
* @return
* Zero if the packet is successfully sent to the destination; non-zero
* if the packet cannot be sent.
*/
int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr,
const unsigned short udp_port, int wait_time, int retries,
const char* hostname, const char* port);
const char* hostname, const char* port, const int timeout);

#endif /* GUAC_WOL_H */

30 changes: 24 additions & 6 deletions src/libguac/socket-tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#include "guacamole/socket.h"

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>

int guac_socket_tcp_connect(const char* hostname, const char* port) {
int guac_socket_tcp_connect(const char* hostname, const char* port, const int timeout) {

int retval;

Expand Down Expand Up @@ -73,15 +75,31 @@ int guac_socket_tcp_connect(const char* hostname, const char* port) {
return fd;
}

/* Connect */
if (connect(fd, current_address->ai_addr,
current_address->ai_addrlen) == 0) {
/* Set socket to non-blocking */
fcntl(fd, F_SETFL, O_NONBLOCK);

/* Done if successful connect */
break;
/* Set up timeout. */
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);

struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;

/* Connect and wait for timeout */
if (connect(fd, current_address->ai_addr, current_address->ai_addrlen) < 0) {
guac_error = GUAC_STATUS_REFUSED;
guac_error_message = "Unable to connect via socket.";
close(fd);
break;
}

/* Check for the connection and break if successful */
if (select(fd + 1, NULL, &fdset, NULL, &tv) > 0)
break;

/* Connection not successful - free resources and go to the next address. */
close(fd);
current_address = current_address->ai_next;

Expand Down
6 changes: 3 additions & 3 deletions src/libguac/wol.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr,

int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr,
const unsigned short udp_port, int wait_time, int retries,
const char* hostname, const char* port) {
const char* hostname, const char* port, const int timeout) {

/* Attempt to connect, first. */
int sockfd = guac_socket_tcp_connect(hostname, port);
int sockfd = guac_socket_tcp_connect(hostname, port, timeout);

/* If connection succeeds, no need to wake the system. */
if (sockfd > 0) {
Expand All @@ -225,7 +225,7 @@ int guac_wol_wake_and_wait(const char* mac_addr, const char* broadcast_addr,
/* Try to connect on the specified TCP port and hostname or IP. */
for (int i = 0; i < retries; i++) {

sockfd = guac_socket_tcp_connect(hostname, port);
sockfd = guac_socket_tcp_connect(hostname, port, timeout);

/* Connection succeeded - close socket and exit. */
if (sockfd > 0) {
Expand Down
7 changes: 4 additions & 3 deletions src/protocols/rdp/rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,8 @@ void* guac_rdp_client_thread(void* data) {
settings->wol_wait_time,
GUAC_WOL_DEFAULT_CONNECT_RETRIES,
settings->hostname,
(const char *) str_port)) {
(const char *) str_port,
GUAC_WOL_DEFAULT_CONNECTION_TIMEOUT)) {
guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet, or server failed to wake up.");
guac_mem_free(str_port);
return NULL;
Expand Down Expand Up @@ -815,8 +816,8 @@ void* guac_rdp_client_thread(void* data) {
/* Attempt SSH connection */
rdp_client->sftp_session =
guac_common_ssh_create_session(client, settings->sftp_hostname,
settings->sftp_port, rdp_client->sftp_user, settings->sftp_server_alive_interval,
settings->sftp_host_key, NULL);
settings->sftp_port, rdp_client->sftp_user, settings->sftp_timeout,
settings->sftp_server_alive_interval, settings->sftp_host_key, NULL);

/* Fail if SSH connection does not succeed */
if (rdp_client->sftp_session == NULL) {
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/rdp/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
"sftp-hostname",
"sftp-host-key",
"sftp-port",
"sftp-timeout",
"sftp-username",
"sftp-password",
"sftp-private-key",
Expand Down Expand Up @@ -461,6 +462,12 @@ enum RDP_ARGS_IDX {
*/
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
* SFTP. If blank, the username provided for the RDP user will be used.
Expand Down Expand Up @@ -1098,6 +1105,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
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 */
settings->sftp_username =
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
Expand Down
11 changes: 11 additions & 0 deletions src/protocols/rdp/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
*/
#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".
*/
Expand Down Expand Up @@ -462,6 +467,12 @@ typedef struct guac_rdp_settings {
*/
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
* SFTP.
Expand Down
11 changes: 11 additions & 0 deletions src/protocols/ssh/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
"hostname",
"host-key",
"port",
"timeout",
"username",
"password",
GUAC_SSH_ARGV_FONT_NAME,
Expand Down Expand Up @@ -99,6 +100,11 @@ enum SSH_ARGS_IDX {
*/
IDX_PORT,

/**
* The timeout of the connection attempt, in seconds. Optional.
*/
IDX_TIMEOUT,

/**
* The name of the user to login as. Optional.
*/
Expand Down Expand Up @@ -454,6 +460,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
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 */
settings->read_only =
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/ssh/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
*/
#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.
*/
Expand Down Expand Up @@ -69,6 +75,12 @@ typedef struct guac_ssh_settings {
*/
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,
* this will be NULL.
Expand Down
10 changes: 6 additions & 4 deletions src/protocols/ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ void* ssh_client_thread(void* data) {
settings->wol_wait_time,
GUAC_WOL_DEFAULT_CONNECT_RETRIES,
settings->hostname,
settings->port)) {
settings->port,
settings->timeout)) {
guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server.");
return NULL;
}
Expand Down Expand Up @@ -336,7 +337,8 @@ void* ssh_client_thread(void* data) {

/* Open SSH session */
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);
if (ssh_client->session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */
Expand Down Expand Up @@ -387,8 +389,8 @@ void* ssh_client_thread(void* data) {
guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
ssh_client->sftp_session =
guac_common_ssh_create_session(client, settings->hostname,
settings->port, ssh_client->user, settings->server_alive_interval,
settings->host_key, NULL);
settings->port, ssh_client->user, settings->timeout,
settings->server_alive_interval, settings->host_key, NULL);
if (ssh_client->sftp_session == NULL) {
/* Already aborted within guac_common_ssh_create_session() */
return NULL;
Expand Down
5 changes: 3 additions & 2 deletions src/protocols/telnet/telnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ static telnet_t* __guac_telnet_create_session(guac_client* client) {
guac_telnet_client* telnet_client = (guac_telnet_client*) client->data;
guac_telnet_settings* settings = telnet_client->settings;

int fd = guac_socket_tcp_connect(settings->hostname, settings->port);
int fd = guac_socket_tcp_connect(settings->hostname, settings->port, settings->timeout);

/* Open telnet session */
telnet_t* telnet = telnet_init(__telnet_options, __guac_telnet_event_handler, 0, client);
Expand Down Expand Up @@ -511,7 +511,8 @@ void* guac_telnet_client_thread(void* data) {
settings->wol_wait_time,
GUAC_WOL_DEFAULT_CONNECT_RETRIES,
settings->hostname,
settings->port)) {
settings->port,
settings->timeout)) {
guac_client_log(client, GUAC_LOG_ERROR, "Failed to send WOL packet or connect to remote server.");
return NULL;
}
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/vnc/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = {
"sftp-hostname",
"sftp-host-key",
"sftp-port",
"sftp-timeout",
"sftp-username",
"sftp-password",
"sftp-private-key",
Expand Down Expand Up @@ -241,6 +242,12 @@ enum VNC_ARGS_IDX {
*/
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
* SFTP.
Expand Down Expand Up @@ -576,6 +583,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
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 */
settings->sftp_username =
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
Expand Down
Loading

0 comments on commit f50ccf6

Please sign in to comment.