diff --git a/src/common/common/defaults.h b/src/common/common/defaults.h new file mode 100644 index 00000000..17d761d7 --- /dev/null +++ b/src/common/common/defaults.h @@ -0,0 +1,31 @@ +/* + * 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_COMMON_DEFAULTS_H +#define GUAC_COMMON_DEFAULTS_H + +/** + * The default number of seconds to wait after sending the Wake-on-LAN packet + * for the destination host to start responding. + */ +#define GUAC_WOL_DEFAULT_BOOT_WAIT_TIME 60 + + +#endif /* GUAC_COMMON_DEFAULTS_H */ + diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index a6240802..ad7d7c9d 100644 --- a/src/libguac/Makefile.am +++ b/src/libguac/Makefile.am @@ -69,7 +69,9 @@ libguacinc_HEADERS = \ guacamole/user.h \ guacamole/user-constants.h \ guacamole/user-fntypes.h \ - guacamole/user-types.h + guacamole/user-types.h \ + guacamole/wol.h \ + guacamole/wol-constants.h noinst_HEADERS = \ id.h \ @@ -104,7 +106,8 @@ libguac_la_SOURCES = \ user.c \ user-handlers.c \ user-handshake.c \ - wait-fd.c + wait-fd.c \ + wol.c # Compile WebP support if available if ENABLE_WEBP diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h new file mode 100644 index 00000000..215e6b88 --- /dev/null +++ b/src/libguac/guacamole/wol-constants.h @@ -0,0 +1,51 @@ +/* + * 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_WOL_CONSTANTS_H +#define GUAC_WOL_CONSTANTS_H + +/** + * Header file that provides constants and defaults related to libguac + * Wake-on-LAN support. + * + * @file wol-constants.h + */ + +/** + * The value for the local IPv4 broadcast address. + */ +#define GUAC_WOL_LOCAL_IPV4_BROADCAST "255.255.255.255" + +/** + * The size of the magic Wake-on-LAN packet to send to wake a remote host. This + * consists of 6 bytes of 0xFF, and then the MAC address repeated 16 times. + * https://en.wikipedia.org/wiki/Wake-on-LAN#Magic_packet + */ +#define GUAC_WOL_PACKET_SIZE 102 + +/** + * The port number that the magic packet should contain as the destination. In + * reality this doesn't matter all that much, since the packet is not usually + * processed by a full IP stack, but defining one is considered a standard + * practice. + */ +#define GUAC_WOL_PORT 9 + +#endif /* GUAC_WOL_CONSTANTS_H */ + diff --git a/src/libguac/guacamole/wol.h b/src/libguac/guacamole/wol.h new file mode 100644 index 00000000..cdbb7391 --- /dev/null +++ b/src/libguac/guacamole/wol.h @@ -0,0 +1,52 @@ +/* + * 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_WOL_H +#define GUAC_WOL_H + +/** + * Header that provides functions and structures related to Wake-on-LAN + * support in libguac. + * + * @file wol.h + */ + +#include "wol-constants.h" + +/** + * 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. + * + * @return + * Zero if the packet is successfully sent to the destination; non-zero + * if the packet cannot be sent. + */ +int guac_wol_wake(const char* mac_addr, const char* broadcast_addr); + +#endif /* GUAC_WOL_H */ + diff --git a/src/libguac/wol.c b/src/libguac/wol.c new file mode 100644 index 00000000..b8e5e687 --- /dev/null +++ b/src/libguac/wol.c @@ -0,0 +1,150 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "guacamole/wol.h" + +/** + * Generate the magic Wake-on-LAN (WoL) packet for the specified MAC address + * and place it in the character array. + * + * @param packet + * The character array that will contain the generated packet. + * + * @param mac_address + * The unsigned int representation of the MAC address to place in the packet. + */ +static void __guac_wol_create_magic_packet(unsigned char packet[], + unsigned int mac_address[]) { + + int i; + unsigned char mac[6]; + + /* Concurrently fill the first part of the packet with 0xFF, and copy the + MAC address from the int array to the char array. */ + for (i = 0; i < 6; i++) { + packet[i] = 0xFF; + mac[i] = mac_address[i]; + } + + /* Copy the MAC address contents into the char array that is storing + the rest of the packet. */ + for (i = 1; i <= 16; i++) { + memcpy(&packet[i * 6], &mac, 6 * sizeof(unsigned char)); + } + +} + +/** + * Send the magic Wake-on-LAN (WoL) packet to the specified broadcast address, + * returning the number of bytes sent, or zero if any error occurred and nothing + * was sent. + * + * @param broadcast_addr + * The broadcast address to which to send the magic WoL packet. + * + * @param packet + * The magic WoL packet to send. + * + * @return + * The number of bytes sent, or zero if nothing could be sent. + */ +static ssize_t __guac_wol_send_packet(const char* broadcast_addr, + unsigned char packet[]) { + + struct sockaddr_in wol_dest; + int wol_socket; + + /* Determine the IP version, starting with IPv4. */ + wol_dest.sin_port = htons(GUAC_WOL_PORT); + wol_dest.sin_family = AF_INET; + if (inet_pton(AF_INET, broadcast_addr, &(wol_dest.sin_addr)) == 0) { + wol_dest.sin_family = AF_INET6; + if (inet_pton(AF_INET6, broadcast_addr, &(wol_dest.sin_addr)) == 0) + return 0; + } + + /* Set up socket for IPv4 broadcast. */ + if (wol_dest.sin_family == AF_INET) { + int wol_bcast = 1; + wol_socket = socket(AF_INET, SOCK_DGRAM, 0); + + /* Attempt to set broadcast; exit with error if this fails. */ + if (setsockopt(wol_socket, SOL_SOCKET, SO_BROADCAST, &wol_bcast, + sizeof(wol_bcast)) < 0) { + close(wol_socket); + return 0; + } + } + + /* Set up socket for IPv6 multicast. */ + else { + wol_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + /* Stick to a single hop for now. */ + int hops = 1; + + if (setsockopt(wol_socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, + sizeof(hops))) { + close(wol_socket); + return 0; + } + } + + /* Send the packet and return number of bytes sent. */ + int bytes = sendto(wol_socket, packet, GUAC_WOL_PACKET_SIZE, 0, + (struct sockaddr*) &wol_dest, sizeof(wol_dest)); + close(wol_socket); + return bytes; + +} + +int guac_wol_wake(const char* mac_addr, const char* broadcast_addr) { + + unsigned char wol_packet[GUAC_WOL_PACKET_SIZE]; + unsigned int dest_mac[6]; + + /* Parse mac address and return with error if parsing fails. */ + if (sscanf(mac_addr, "%x:%x:%x:%x:%x:%x", + &(dest_mac[0]), &(dest_mac[1]), &(dest_mac[2]), + &(dest_mac[3]), &(dest_mac[4]), &(dest_mac[5])) != 6) { + return -1; + } + + /* Generate the magic packet. */ + __guac_wol_create_magic_packet(wol_packet, dest_mac); + + /* Send the packet and record bytes sent. */ + int bytes_sent = __guac_wol_send_packet(broadcast_addr, wol_packet); + + /* Return 0 if bytes were sent, otherwise return an error. */ + if (bytes_sent) + return 0; + + return -1; +} \ No newline at end of file diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index 0988632b..ca69b459 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -344,7 +345,7 @@ static int guac_rdp_handle_connection(guac_client* client) { /* Init random number generator */ srandom(time(NULL)); - + /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { rdp_client->recording = guac_common_recording_create(client, @@ -529,6 +530,20 @@ void* guac_rdp_client_thread(void* data) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; + /* If Wake-on-LAN is enabled, try to wake. */ + if (settings->wol_send_packet) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request. */ + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr)) + return NULL; + + /* If wait time is specified, sleep for that amount of time. */ + if (settings->wol_wait_time > 0) + guac_timestamp_msleep(settings->wol_wait_time * 1000); + } + /* If audio enabled, choose an encoder */ if (settings->audio_enabled) { diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index ef7221b8..381ec303 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -17,6 +17,7 @@ * under the License. */ +#include "common/defaults.h" #include "common/string.h" #include "config.h" #include "resolution.h" @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -117,6 +119,11 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "disable-copy", "disable-paste", + + "wol-send-packet", + "wol-mac-addr", + "wol-broadcast-addr", + "wol-wait-time", NULL }; @@ -580,6 +587,34 @@ enum RDP_ARGS_IDX { * using the clipboard. By default, clipboard access is not blocked. */ IDX_DISABLE_PASTE, + + /** + * Whether or not to send the magic Wake-on-LAN (WoL) packet to the host + * prior to attempting to connect. Non-zero values will enable sending + * the WoL packet, while zero will disable this functionality. By default + * the WoL packet is not sent. + */ + IDX_WOL_SEND_PACKET, + + /** + * The MAC address to put in the magic WoL packet for the host that should + * be woken up. + */ + IDX_WOL_MAC_ADDR, + + /** + * The broadcast address to which to send the magic WoL packet to wake up + * the remote host. + */ + IDX_WOL_BROADCAST_ADDR, + + /** + * The amount of time, in seconds, to wait after sending the WoL packet + * before attempting to connect to the host. This should be a reasonable + * amount of time to allow the remote host to fully boot and respond to + * network connection requests. The default amount of time is 60 seconds. + */ + IDX_WOL_WAIT_TIME, RDP_ARGS_COUNT }; @@ -1071,6 +1106,37 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, 0); + + /* Parse Wake-on-LAN (WoL) settings */ + settings->wol_send_packet = + guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_WOL_SEND_PACKET, 0); + + if (settings->wol_send_packet) { + + /* If WoL has been requested but no MAC address given, log a warning. */ + if(strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) { + guac_user_log(user, GUAC_LOG_WARNING, "WoL requested but no MAC ", + "address specified. WoL will not be sent."); + settings->wol_send_packet = 0; + } + + /* Parse the WoL MAC address. */ + settings->wol_mac_addr = + guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_WOL_MAC_ADDR, NULL); + + /* Parse the WoL broadcast address. */ + settings->wol_broadcast_addr = + guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST); + + /* Parse the WoL wait time. */ + settings->wol_wait_time = + guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv, + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); + + } /* Success */ return settings; @@ -1133,6 +1199,9 @@ void guac_rdp_settings_free(guac_rdp_settings* settings) { /* Free load balancer information string */ free(settings->load_balance_info); + + free(settings->wol_mac_addr); + free(settings->wol_broadcast_addr); /* Free settings structure */ free(settings); diff --git a/src/protocols/rdp/settings.h b/src/protocols/rdp/settings.h index c39c7345..5fa18396 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -565,6 +565,29 @@ typedef struct guac_rdp_settings { * the connection broker, if a connection broker is being used. */ char* load_balance_info; + + /** + * Whether or not to send a magic WoL packet to wake up the host before + * trying to connect. Zero will disable sending the packet, non-zero + * values will trigger sending the packet. + */ + int wol_send_packet; + + /** + * The mac address to put in the magic WoL packet. + */ + char* wol_mac_addr; + + /** + * The broadcast address to send the magic WoL packet to. + */ + char* wol_broadcast_addr; + + /** + * The amount of time to wait after sending the magic WoL packet before + * continuing the connection. + */ + int wol_wait_time; } guac_rdp_settings; diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 35f3b067..9539d033 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -20,9 +20,11 @@ #include "config.h" #include "client.h" +#include "common/defaults.h" #include "settings.h" #include +#include #include #include @@ -66,6 +68,10 @@ const char* GUAC_SSH_CLIENT_ARGS[] = { "timezone", "disable-copy", "disable-paste", + "wol-send-packet", + "wol-mac-addr", + "wol-broadcast-addr", + "wol-wait-time", NULL }; @@ -287,6 +293,34 @@ enum SSH_ARGS_IDX { * the clipboard. By default, clipboard access is not blocked. */ IDX_DISABLE_PASTE, + + /** + * Whether the magic WoL packet should be sent prior to starting the + * connection. If set to "true", the system will attempt to send the WoL + * packet and wait for the host to wake up. By default the WoL packet + * is not sent. + */ + IDX_WOL_SEND_PACKET, + + /** + * The MAC address to put in the magic WoL packet to wake the remote system. + * By default no MAC address is specified. If WoL is enabled by a MAC + * address is not provided a warning will be logged and the WoL packet will + * not be sent. + */ + IDX_WOL_MAC_ADDR, + + /** + * The broadcast address to which to send the magic WoL packet to wake the + * remote system. + */ + IDX_WOL_BROADCAST_ADDR, + + /** + * The amount of time to wait after sending the magic WoL packet prior to + * continuing the connection attempt. + */ + IDX_WOL_WAIT_TIME, SSH_ARGS_COUNT }; @@ -475,6 +509,33 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, false); + + /* Parse Wake-on-LAN (WoL) parameters. */ + settings->wol_send_packet = + guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_WOL_SEND_PACKET, false); + + if (settings->wol_send_packet) { + + if (strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) { + guac_user_log(user, GUAC_LOG_WARNING, "WoL was enabled, but no ", + "MAC address was provide. WoL will not be sent."); + settings->wol_send_packet = false; + } + + settings->wol_mac_addr = + guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_WOL_MAC_ADDR, NULL); + + settings->wol_broadcast_addr = + guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST); + + settings->wol_wait_time = + guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); + + } /* Parsing was successful */ return settings; @@ -520,6 +581,10 @@ void guac_ssh_settings_free(guac_ssh_settings* settings) { /* Free the client timezone. */ free(settings->timezone); + + /* Free Wake-on-LAN settings. */ + free(settings->wol_mac_addr); + free(settings->wol_broadcast_addr); /* Free overall structure */ free(settings); diff --git a/src/protocols/ssh/settings.h b/src/protocols/ssh/settings.h index 5e79d39a..d106b0a7 100644 --- a/src/protocols/ssh/settings.h +++ b/src/protocols/ssh/settings.h @@ -286,6 +286,26 @@ typedef struct guac_ssh_settings { * The client timezone to pass to the remote system. */ char* timezone; + + /** + * Whether or not to send the Wake-on-LAN magic packet. + */ + bool wol_send_packet; + + /** + * The MAC address to put in the magic WoL packet for the host to wake. + */ + char* wol_mac_addr; + + /** + * The broadcast address to which to send the magic WoL packet. + */ + char* wol_broadcast_addr; + + /** + * The amount of time to wait for the system to wake after sending the packet. + */ + int wol_wait_time; } guac_ssh_settings; diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 9ec9bbe4..03f5b0b6 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,20 @@ void* ssh_client_thread(void* data) { pthread_t input_thread; + /* If Wake-on-LAN is enabled, attempt to wake. */ + if (settings->wol_send_packet) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request. */ + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr)) + return NULL; + + /* If wait time is specified, sleep for that amount of time. */ + if (settings->wol_wait_time > 0) + guac_timestamp_msleep(settings->wol_wait_time * 1000); + } + /* Init SSH base libraries */ if (guac_common_ssh_init(client)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index e72359c9..8b537de4 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -19,9 +19,11 @@ #include "config.h" +#include "common/defaults.h" #include "settings.h" #include +#include #include #include @@ -57,6 +59,10 @@ const char* GUAC_TELNET_CLIENT_ARGS[] = { "login-failure-regex", "disable-copy", "disable-paste", + "wol-send-packet", + "wol-mac-addr", + "wol-broadcast-addr", + "wol-wait-time", NULL }; @@ -231,6 +237,31 @@ enum TELNET_ARGS_IDX { * the clipboard. By default, clipboard access is not blocked. */ IDX_DISABLE_PASTE, + + /** + * Whether to send the magic Wake-on-LAN (WoL) packet. If set to "true" + * the WoL packet will be sent prior to attempting to connect to the remote + * host. By default the WoL packet will not be sent. + */ + IDX_WOL_SEND_PACKET, + + /** + * The MAC address to put in the magic WoL packet to wake the remote host. + * There is no default value, and if WoL is enabled but the MAC address + * is not provided, a warning will be logged and no packet will be sent. + */ + IDX_WOL_MAC_ADDR, + + /** + * The broadcast address to which to send the magic WoL packet. + */ + IDX_WOL_BROADCAST_ADDR, + + /** + * The amount of time, in seconds, to wait after the magic WoL packet is + * sent before continuing the connection attempt. + */ + IDX_WOL_WAIT_TIME, TELNET_ARGS_COUNT }; @@ -453,6 +484,37 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, false); + + /* Parse Wake-on-LAN (WoL) settings */ + settings->wol_send_packet = + guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv, + IDX_WOL_SEND_PACKET, false); + + if (settings->wol_send_packet) { + + /* If WoL has been enabled but no MAC provided, log warning and disable. */ + if(strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) { + guac_user_log(user, GUAC_LOG_WARNING, "Wake on LAN was requested, ", + "but no MAC address was specified. WoL will not be sent."); + settings->wol_send_packet = false; + } + + /* Parse the WoL MAC address. */ + settings->wol_mac_addr = + guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + IDX_WOL_MAC_ADDR, NULL); + + /* Parse the WoL broadcast address. */ + settings->wol_broadcast_addr = + guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv, + IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST); + + /* Parse the WoL wait time. */ + settings->wol_wait_time = + guac_user_parse_args_int(user, GUAC_TELNET_CLIENT_ARGS, argv, + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); + + } /* Parsing was successful */ return settings; diff --git a/src/protocols/telnet/settings.h b/src/protocols/telnet/settings.h index 691669cb..dfaaa97b 100644 --- a/src/protocols/telnet/settings.h +++ b/src/protocols/telnet/settings.h @@ -256,6 +256,30 @@ typedef struct guac_telnet_settings { * The terminal emulator type that is passed to the remote system. */ char* terminal_type; + + /** + * Whether or not to send the magic Wake-on-LAN (WoL) packet prior to + * continuing the connection. + */ + bool wol_send_packet; + + /** + * The MAC address to put in the magic WoL packet for the remote host to + * wake. + */ + char* wol_mac_addr; + + /** + * The broadcast address to which to send the magic WoL packet to wake + * the remote host. + */ + char* wol_broadcast_addr; + + /** + * The number of seconds to wait after sending the magic WoL packet before + * continuing the connection. + */ + int wol_wait_time; } guac_telnet_settings; diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 5a5ca303..8d8d4398 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -556,6 +557,20 @@ void* guac_telnet_client_thread(void* data) { pthread_t input_thread; char buffer[8192]; int wait_result; + + /* If Wake-on-LAN is enabled, attempt to wake. */ + if (settings->wol_send_packet) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request. */ + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr)) + return NULL; + + /* If wait time is specified, sleep for that amount of time. */ + if (settings->wol_wait_time > 0) + guac_timestamp_msleep(settings->wol_wait_time * 1000); + } /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 76b03650..c64c73af 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -20,9 +20,11 @@ #include "config.h" #include "client.h" +#include "common/defaults.h" #include "settings.h" #include +#include #include #include @@ -82,6 +84,11 @@ const char* GUAC_VNC_CLIENT_ARGS[] = { "create-recording-path", "disable-copy", "disable-paste", + + "wol-send-packet", + "wol-mac-addr", + "wol-broadcast-addr", + "wol-wait-time", NULL }; @@ -332,6 +339,31 @@ enum VNC_ARGS_IDX { * using the clipboard. By default, clipboard access is not blocked. */ IDX_DISABLE_PASTE, + + /** + * Whether to send the magic Wake-on-LAN (WoL) packet to wake the remote + * host prior to attempting to connect. If set to "true" the packet will + * be sent. By default the packet will not be sent. + */ + IDX_WOL_SEND_PACKET, + + /** + * The MAC address to place in the magic WoL packet to wake the remote host. + * If WoL is requested but this is not provided a warning will be logged + * and the WoL packet will not be sent. + */ + IDX_WOL_MAC_ADDR, + + /** + * The broadcast packet to which to send the magic WoL packet. + */ + IDX_WOL_BROADCAST_ADDR, + + /** + * The number of seconds to wait after sending the magic WoL packet before + * attempting to connect to the remote host. + */ + IDX_WOL_WAIT_TIME, VNC_ARGS_COUNT }; @@ -549,6 +581,37 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, settings->disable_paste = guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, IDX_DISABLE_PASTE, false); + + /* Parse Wake-on-LAN (WoL) settings */ + settings->wol_send_packet = + guac_user_parse_args_boolean(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_WOL_SEND_PACKET, false); + + if (settings->wol_send_packet) { + + /* If WoL has been enabled but no MAC provided, log warning and disable. */ + if(strcmp(argv[IDX_WOL_MAC_ADDR], "") == 0) { + guac_user_log(user, GUAC_LOG_WARNING, "Wake on LAN was requested, ", + "but no MAC address was specified. WoL will not be sent."); + settings->wol_send_packet = false; + } + + /* Parse the WoL MAC address. */ + settings->wol_mac_addr = + guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_WOL_MAC_ADDR, NULL); + + /* Parse the WoL broadcast address. */ + settings->wol_broadcast_addr = + guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_WOL_BROADCAST_ADDR, GUAC_WOL_LOCAL_IPV4_BROADCAST); + + /* Parse the WoL wait time. */ + settings->wol_wait_time = + guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv, + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); + + } return settings; diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h index f2205fb6..8d5659ef 100644 --- a/src/protocols/vnc/settings.h +++ b/src/protocols/vnc/settings.h @@ -269,6 +269,31 @@ typedef struct guac_vnc_settings { * as passwords, credit card numbers, etc. */ bool recording_include_keys; + + /** + * Whether or not to send the magic Wake-on-LAN (WoL) packet prior to + * trying to connect to the remote host. By default this will not be sent. + * If this option is enabled but a MAC address is not provided a warning will + * be logged and the packet will not be sent. + */ + bool wol_send_packet; + + /** + * The MAC address to place in the magic WoL packet to wake the remote host. + */ + char* wol_mac_addr; + + /** + * The broadcast address to which to send the magic WoL packet to wake + * the remote host. + */ + char* wol_broadcast_addr; + + /** + * The number of seconds after sending the magic WoL packet to wait before + * attempting to connect to the remote host. + */ + int wol_wait_time; } guac_vnc_settings; diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index b88f7945..31d97022 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -238,6 +239,20 @@ void* guac_vnc_client_thread(void* data) { guac_vnc_client* vnc_client = (guac_vnc_client*) client->data; guac_vnc_settings* settings = vnc_client->settings; + /* If Wake-on-LAN is enabled, attempt to wake. */ + if (settings->wol_send_packet) { + guac_client_log(client, GUAC_LOG_DEBUG, "Sending Wake-on-LAN packet, " + "and pausing for %d seconds.", settings->wol_wait_time); + + /* Send the Wake-on-LAN request. */ + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr)) + return NULL; + + /* If wait time is specified, sleep for that amount of time. */ + if (settings->wol_wait_time > 0) + guac_timestamp_msleep(settings->wol_wait_time * 1000); + } + /* Configure clipboard encoding */ if (guac_vnc_set_clipboard_encoding(client, settings->clipboard_encoding)) { guac_client_log(client, GUAC_LOG_INFO, "Using non-standard VNC "