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-1686: Make WOL functionality capable of testing connectivity to the server. #470

Merged
merged 5 commits into from
May 22, 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
82 changes: 4 additions & 78 deletions src/common-ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <guacamole/client.h>
#include <guacamole/fips.h>
#include <guacamole/mem.h>
#include <guacamole/socket-tcp.h>
#include <guacamole/string.h>
#include <libssh2.h>

Expand All @@ -34,15 +35,11 @@
#include <openssl/err.h>
#include <openssl/ssl.h>

#include <errno.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/socket.h>
#include <unistd.h>

#ifdef LIBSSH2_USES_GCRYPT
Expand Down Expand Up @@ -414,81 +411,10 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
int keepalive, const char* host_key,
guac_ssh_credential_handler* credential_handler) {

int retval;

int fd;
struct addrinfo* addresses;
struct addrinfo* current_address;

char connected_address[1024];
char connected_port[64];

struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP
};

/* Get addresses connection */
if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) {
int fd = guac_socket_tcp_connect(hostname, port);
if (fd < 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Error parsing given address or port: %s",
gai_strerror(retval));
return NULL;
}

/* Attempt connection to each address until success */
current_address = addresses;
while (current_address != NULL) {

/* Resolve hostname */
if ((retval = getnameinfo(current_address->ai_addr,
current_address->ai_addrlen,
connected_address, sizeof(connected_address),
connected_port, sizeof(connected_port),
NI_NUMERICHOST | NI_NUMERICSERV)))
guac_client_log(client, GUAC_LOG_DEBUG,
"Unable to resolve host: %s", gai_strerror(retval));

/* Get socket */
fd = socket(current_address->ai_family, SOCK_STREAM, 0);
if (fd < 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to create socket: %s", strerror(errno));
freeaddrinfo(addresses);
return NULL;
}

/* Connect */
if (connect(fd, current_address->ai_addr,
current_address->ai_addrlen) == 0) {

guac_client_log(client, GUAC_LOG_DEBUG,
"Successfully connected to host %s, port %s",
connected_address, connected_port);

/* Done if successful connect */
break;

}

/* Otherwise log information regarding bind failure */
guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to "
"host %s, port %s: %s",
connected_address, connected_port, strerror(errno));

close(fd);
current_address = current_address->ai_next;

}

/* Free addrinfo */
freeaddrinfo(addresses);

/* If unable to connect to anything, fail */
if (current_address == NULL) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
"Unable to connect to any addresses.");
"Failed to open TCP connection to %s on %s.", hostname, port);
return NULL;
}

Expand Down
2 changes: 2 additions & 0 deletions src/libguac/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ libguacinc_HEADERS = \
guacamole/socket-constants.h \
guacamole/socket.h \
guacamole/socket-fntypes.h \
guacamole/socket-tcp.h \
guacamole/socket-types.h \
guacamole/stream.h \
guacamole/stream-types.h \
Expand Down Expand Up @@ -128,6 +129,7 @@ libguac_la_SOURCES = \
socket-broadcast.c \
socket-fd.c \
socket-nest.c \
socket-tcp.c \
socket-tee.c \
string.c \
timestamp.c \
Expand Down
44 changes: 44 additions & 0 deletions src/libguac/guacamole/socket-tcp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#ifndef __GUAC_SOCKET_TCP_H
#define __GUAC_SOCKET_TCP_H

#include "config.h"

#include <stddef.h>

/**
* Given a hostname or IP address and port, attempt to connect to that
* system, returning an open socket if the connection succeeds, or a negative
* value if it fails. If it fails the errno variable will be set.
*
* @param hostname
* The hostname or IP address to which to attempt connections.
*
* @param port
* The TCP port to which to attempt to connect.
*
* @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);

#endif // __GUAC_SOCKET_TCP_H
18 changes: 18 additions & 0 deletions src/libguac/guacamole/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@
#include <stddef.h>
#include <string.h>

/**
* Convert the provided unsigned integer into a string, returning the number of
* characters written into the destination string, or a negative value if an
* error occurs.
*
* @param dest
* The destination string to copy the data into, which should already be
* allocated and at a size that can handle the string representation of the
* inteer.
*
* @param integer
* The unsigned integer to convert to a string.
*
* @return
* The number of characters written into the dest string.
*/
int guac_itoa(char* restrict dest, unsigned int integer);

/**
* Copies a limited number of bytes from the given source string to the given
* destination buffer. The resulting buffer will always be null-terminated,
Expand Down
6 changes: 6 additions & 0 deletions src/libguac/guacamole/wol-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
* @file wol-constants.h
*/

/**
* The default number of times to retry a connection to a server after waking
* the server with a WOL packet before giving up.
*/
#define GUAC_WOL_DEFAULT_CONNECT_RETRIES 5

/**
* The value for the local IPv4 broadcast address.
*/
Expand Down
40 changes: 40 additions & 0 deletions src/libguac/guacamole/wol.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,45 @@
int guac_wol_wake(const char* mac_addr, const char* broadcast_addr,
const unsigned short udp_port);

/**
* Send the wake-up packet to the specified destination, returning zero if the
* wake was sent successfully, or non-zero if an error occurs sending the
* wake packet. Note that the return value does not specify whether the
* system actually wakes up successfully, only whether or not the packet
* is transmitted.
*
* @param mac_addr
* The MAC address to place in the magic Wake-on-LAN packet.
*
* @param broadcast_addr
* The broadcast address to which to send the magic Wake-on-LAN packet.
*
* @param udp_port
* The UDP port to use when sending the WoL packet.
*
* @param wait_time
* The number of seconds to wait between connection attempts after the WOL
* packet has been sent.
*
* @param retries
* The number of attempts to make to connect to the system before giving up
* on the connection.
*
* @param hostname
* The hostname or IP address of the system that has been woken up and to
* to which the connection will be attempted.
*
* @param port
* The TCP port of the remote system on which the connection will be
* attempted after the system has been woken.
*
* @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);

#endif /* GUAC_WOL_H */

102 changes: 102 additions & 0 deletions src/libguac/socket-tcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#include "config.h"
#include "guacamole/error.h"
#include "guacamole/socket.h"

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

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

int retval;

int fd = EBADFD;
struct addrinfo* addresses;
struct addrinfo* current_address;

char connected_address[1024];
char connected_port[64];

struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP
};

/* Get addresses for requested hostname and port. */
if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) {
guac_error = GUAC_STATUS_INVALID_ARGUMENT;
guac_error_message = "Error parsing address or port.";
return retval;
}

/* Attempt connection to each address until success */
current_address = addresses;
while (current_address != NULL) {

/* Resolve hostname */
if ((retval = getnameinfo(current_address->ai_addr,
current_address->ai_addrlen,
connected_address, sizeof(connected_address),
connected_port, sizeof(connected_port),
NI_NUMERICHOST | NI_NUMERICSERV))) {

guac_error = GUAC_STATUS_INVALID_ARGUMENT;
guac_error_message = "Error resolving host.";
continue;
}

/* Get socket */
fd = socket(current_address->ai_family, SOCK_STREAM, 0);
if (fd < 0) {
freeaddrinfo(addresses);
return fd;
}

/* Connect */
if (connect(fd, current_address->ai_addr,
current_address->ai_addrlen) == 0) {

/* Done if successful connect */
break;

}

close(fd);
current_address = current_address->ai_next;

}

/* Free addrinfo */
freeaddrinfo(addresses);

/* If unable to connect to anything, set error status. */
if (current_address == NULL) {
guac_error = GUAC_STATUS_REFUSED;
guac_error_message = "Unable to connect to remote host.";
}

/* Return the fd, or the error message if the socket connection failed. */
return fd;

}
15 changes: 15 additions & 0 deletions src/libguac/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "guacamole/mem.h"

#include <stddef.h>
#include <stdio.h>
#include <string.h>

/**
Expand All @@ -44,6 +45,20 @@
*/
#define REMAINING(n, length) (((n) < (length)) ? 0 : ((n) - (length)))

int guac_itoa(char* restrict dest, unsigned int integer) {

/* Determine size of string. */
int str_size = snprintf(dest, 0, "%i", integer);
necouchman marked this conversation as resolved.
Show resolved Hide resolved

/* If an error occurs, just return that and skip the conversion. */
if (str_size < 0)
return str_size;

/* Do the conversion and return. */
return snprintf(dest, (str_size + 1), "%i", integer);

}

size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n) {

#ifdef HAVE_STRLCPY
Expand Down
Loading
Loading