From 3d4a27607d89288e20dadfb106583f4c7333173a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 15 Mar 2020 12:21:30 -0400 Subject: [PATCH] GUACAMOLE-513: Implement settings and code for Wake-on-LAN support. --- src/libguac/Makefile.am | 7 +- src/libguac/guacamole/wol-constants.h | 43 +++++++++ src/libguac/guacamole/wol.h | 56 +++++++++++ src/libguac/wol.c | 128 ++++++++++++++++++++++++++ src/protocols/rdp/rdp.c | 10 +- src/protocols/rdp/settings.c | 68 ++++++++++++++ src/protocols/rdp/settings.h | 23 +++++ src/protocols/ssh/settings.c | 64 +++++++++++++ src/protocols/ssh/settings.h | 20 ++++ src/protocols/ssh/ssh.c | 8 ++ src/protocols/telnet/settings.c | 61 ++++++++++++ src/protocols/telnet/settings.h | 24 +++++ src/protocols/telnet/telnet.c | 8 ++ src/protocols/vnc/settings.c | 31 +++++++ src/protocols/vnc/settings.h | 25 +++++ src/protocols/vnc/vnc.c | 8 ++ 16 files changed, 581 insertions(+), 3 deletions(-) create mode 100644 src/libguac/guacamole/wol-constants.h create mode 100644 src/libguac/guacamole/wol.h create mode 100644 src/libguac/wol.c diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index a6240802..68d80278 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..6d005466 --- /dev/null +++ b/src/libguac/guacamole/wol-constants.h @@ -0,0 +1,43 @@ +/* + * 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 default broadcast address to which Wake-on-LAN packets will be sent + * if one is not specified. + */ +#define GUAC_WOL_DEFAULT_BROADCAST "255.255.255.255" + +/** + * 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_WAIT_TIME 60 + +#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..e2dc5d99 --- /dev/null +++ b/src/libguac/guacamole/wol.h @@ -0,0 +1,56 @@ +/* + * 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. + * + * @param wait_time + * The number of seconds to pause after sending the 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, + const int wait_time); + +#endif /* __GUAC_WOL_H */ + diff --git a/src/libguac/wol.c b/src/libguac/wol.c new file mode 100644 index 00000000..4bdc0488 --- /dev/null +++ b/src/libguac/wol.c @@ -0,0 +1,128 @@ +/* + * 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[]) { + + int wol_bcast = 1; + struct sockaddr_in wol_dest; + int wol_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + /* Attempt to set broadcast; exit with error if this fails. */ + if (setsockopt(wol_socket, SOL_SOCKET, SO_BROADCAST, &wol_bcast, sizeof(wol_bcast)) < 0) { + return 0; + } + + /* Set server endpoint to the broadcast address. */ + wol_dest.sin_family = AF_INET; + wol_dest.sin_port = htons(9); + wol_dest.sin_addr.s_addr = inet_addr(broadcast_addr); + + /* Send the packet and return number of bytes sent. */ + return sendto(wol_socket, &packet, sizeof(unsigned char) * 102, 0, + (struct sockaddr*) &wol_dest, sizeof(wol_dest)); + +} + +int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, + const int wait_time) { + + unsigned char wol_packet[102]; + 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); + + /* Sleep for the specified amount of time to wait for the remote + host to boot. */ + sleep(wait_time); + + /* 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 9388d0cd..0e22084c 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,13 @@ 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) { + if(guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, + settings->wol_wait_time)) + return NULL; + } + /* 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 117b50bf..3c692556 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,11 @@ const char* GUAC_RDP_CLIENT_ARGS[] = { "disable-copy", "disable-paste", + + "wol-send-packet", + "wol-mac-addr", + "wol-broadcast-addr", + "wol-wait-time", NULL }; @@ -550,6 +556,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 }; @@ -1022,6 +1056,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_DEFAULT_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_WAIT_TIME); + + } /* Success */ return settings; @@ -1084,6 +1149,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 e4c579ed..3f4e9585 100644 --- a/src/protocols/rdp/settings.h +++ b/src/protocols/rdp/settings.h @@ -535,6 +535,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 7dab3215..679545f8 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -23,6 +23,7 @@ #include "settings.h" #include +#include #include #include @@ -64,6 +65,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 }; @@ -273,6 +278,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 }; @@ -451,6 +484,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_DEFAULT_BROADCAST); + + settings->wol_wait_time = + guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv, + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_WAIT_TIME); + + } /* Parsing was successful */ return settings; @@ -496,6 +556,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 bab21bdf..e38c998b 100644 --- a/src/protocols/ssh/settings.h +++ b/src/protocols/ssh/settings.h @@ -272,6 +272,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 89572050..4349c38f 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,13 @@ void* ssh_client_thread(void* data) { pthread_t input_thread; + /* If Wake-on-LAN is enabled, attempt to wake. */ + if (settings->wol_send_packet) { + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, + settings->wol_wait_time)) + return NULL; + } + /* 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..2fca8fed 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -22,6 +22,7 @@ #include "settings.h" #include +#include #include #include @@ -57,6 +58,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 +236,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 +483,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_DEFAULT_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_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..5a739621 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,13 @@ 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) { + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, + settings->wol_wait_time)) + return NULL; + } /* 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 21f64057..2ac33b9f 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -23,6 +23,7 @@ #include "settings.h" #include +#include #include #include @@ -80,6 +81,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 }; @@ -318,6 +324,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 }; diff --git a/src/protocols/vnc/settings.h b/src/protocols/vnc/settings.h index 34c08ec9..b51a5a0f 100644 --- a/src/protocols/vnc/settings.h +++ b/src/protocols/vnc/settings.h @@ -255,6 +255,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 f33b267a..be0ee5b2 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,13 @@ 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) { + if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, + settings->wol_wait_time)) + return NULL; + } + /* Configure clipboard encoding */ if (guac_vnc_set_clipboard_encoding(client, settings->clipboard_encoding)) { guac_client_log(client, GUAC_LOG_INFO, "Using non-standard VNC "