Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -222,7 +222,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 @@ -725,7 +725,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 @@ -823,8 +824,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 @@ -104,6 +104,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 @@ -454,6 +455,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 @@ -1086,6 +1093,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 @@ -38,6 +38,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 @@ -452,6 +457,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 @@ -67,6 +67,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 @@ -233,6 +234,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 @@ -563,6 +570,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
Loading