From 3d4a27607d89288e20dadfb106583f4c7333173a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 15 Mar 2020 12:21:30 -0400 Subject: [PATCH 1/8] 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 " From 3dc25915177121fe8816a2da424be4c5876fb49a Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 18 Mar 2020 14:16:40 -0400 Subject: [PATCH 2/8] GUACAMOLE-513: Add debug logging for sending WoL. --- src/protocols/rdp/rdp.c | 2 ++ src/protocols/ssh/ssh.c | 2 ++ src/protocols/telnet/telnet.c | 2 ++ src/protocols/vnc/vnc.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index 0e22084c..c79909ca 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -532,6 +532,8 @@ void* guac_rdp_client_thread(void* data) { /* 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); if(guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, settings->wol_wait_time)) return NULL; diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 4349c38f..7dd462f3 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -204,6 +204,8 @@ void* ssh_client_thread(void* data) { /* 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); if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, settings->wol_wait_time)) return NULL; diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 5a739621..5bfb7b69 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -560,6 +560,8 @@ void* guac_telnet_client_thread(void* data) { /* 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); if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, settings->wol_wait_time)) return NULL; diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index be0ee5b2..2ca1ec86 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -241,6 +241,8 @@ void* guac_vnc_client_thread(void* data) { /* 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); if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, settings->wol_wait_time)) return NULL; From 45e46bd245c90654f8aedcfcfcac1a827186b6a0 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 18 Mar 2020 14:49:42 -0400 Subject: [PATCH 3/8] GUACAMOLE-513: Move sleep to protocol implementations; update comments and headers. --- src/libguac/guacamole/wol-constants.h | 9 +++++---- src/libguac/guacamole/wol.h | 12 ++++-------- src/libguac/wol.c | 7 +------ src/protocols/rdp/rdp.c | 9 +++++++-- src/protocols/ssh/ssh.c | 9 +++++++-- src/protocols/telnet/telnet.c | 9 +++++++-- src/protocols/vnc/vnc.c | 9 +++++++-- 7 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 6d005466..358d26b0 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef __GUAC_WOL_CONSTANTS_H -#define __GUAC_WOL_CONSTANTS_H +#ifndef GUAC_WOL_CONSTANTS_H +#define GUAC_WOL_CONSTANTS_H /** * Header file that provides constants and defaults related to libguac @@ -29,7 +29,8 @@ /** * The default broadcast address to which Wake-on-LAN packets will be sent - * if one is not specified. + * if one is not specified, which is the special value for the IPv4 local + * network broadcast. */ #define GUAC_WOL_DEFAULT_BROADCAST "255.255.255.255" @@ -39,5 +40,5 @@ */ #define GUAC_WOL_DEFAULT_WAIT_TIME 60 -#endif /* __GUAC_WOL_CONSTANTS_H */ +#endif /* GUAC_WOL_CONSTANTS_H */ diff --git a/src/libguac/guacamole/wol.h b/src/libguac/guacamole/wol.h index e2dc5d99..cdbb7391 100644 --- a/src/libguac/guacamole/wol.h +++ b/src/libguac/guacamole/wol.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef __GUAC_WOL_H -#define __GUAC_WOL_H +#ifndef GUAC_WOL_H +#define GUAC_WOL_H /** * Header that provides functions and structures related to Wake-on-LAN @@ -42,15 +42,11 @@ * @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); +int guac_wol_wake(const char* mac_addr, const char* broadcast_addr); -#endif /* __GUAC_WOL_H */ +#endif /* GUAC_WOL_H */ diff --git a/src/libguac/wol.c b/src/libguac/wol.c index 4bdc0488..c2b76660 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -97,8 +97,7 @@ static ssize_t __guac_wol_send_packet(const char* broadcast_addr, } -int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, - const int wait_time) { +int guac_wol_wake(const char* mac_addr, const char* broadcast_addr) { unsigned char wol_packet[102]; unsigned int dest_mac[6]; @@ -116,10 +115,6 @@ int guac_wol_wake(const char* mac_addr, const char* broadcast_addr, /* 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; diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index c79909ca..c6e1d08c 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -534,9 +534,14 @@ void* guac_rdp_client_thread(void* data) { 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); - if(guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - 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 */ diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 7dd462f3..d9a8c0c0 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -206,9 +206,14 @@ void* ssh_client_thread(void* data) { 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); - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - 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 */ diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 5bfb7b69..8d8d4398 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -562,9 +562,14 @@ void* guac_telnet_client_thread(void* data) { 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); - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - 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 */ diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 2ca1ec86..e5bd2eeb 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -243,9 +243,14 @@ void* guac_vnc_client_thread(void* data) { 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); - if (guac_wol_wake(settings->wol_mac_addr, settings->wol_broadcast_addr, - 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 */ From 0feda1fa2f9d8311cf4a27bc0d16dd62bdc7eb32 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 18 Mar 2020 15:34:01 -0400 Subject: [PATCH 4/8] GUACAMOLE-513: Make packet size a constant. --- src/libguac/guacamole/wol-constants.h | 7 +++++++ src/libguac/wol.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 358d26b0..48e470c3 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -40,5 +40,12 @@ */ #define GUAC_WOL_DEFAULT_WAIT_TIME 60 +/** + * 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 + #endif /* GUAC_WOL_CONSTANTS_H */ diff --git a/src/libguac/wol.c b/src/libguac/wol.c index c2b76660..2bf706a1 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -99,7 +99,7 @@ static ssize_t __guac_wol_send_packet(const char* broadcast_addr, int guac_wol_wake(const char* mac_addr, const char* broadcast_addr) { - unsigned char wol_packet[102]; + unsigned char wol_packet[GUAC_WOL_PACKET_SIZE]; unsigned int dest_mac[6]; /* Parse mac address and return with error if parsing fails. */ From a0d4bacbc6ceddb5e9e995093f607267a25c2cdd Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 18 Mar 2020 20:31:02 -0400 Subject: [PATCH 5/8] GUACAMOLE-513: Support determining IPv4 or IPv6. --- src/libguac/guacamole/wol-constants.h | 8 ++++++ src/libguac/wol.c | 41 ++++++++++++++++++++------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 48e470c3..8e5fb4e4 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -47,5 +47,13 @@ */ #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 it is considered a pretty standard + * practice. + */ +#define GUAC_WOL_PORT 9 + #endif /* GUAC_WOL_CONSTANTS_H */ diff --git a/src/libguac/wol.c b/src/libguac/wol.c index 2bf706a1..fc9d8a2a 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -77,22 +77,43 @@ static void __guac_wol_create_magic_packet(unsigned char packet[], 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); + int wol_socket; - /* 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; + /* 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 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); + /* 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) + 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))) + return 0; + } /* Send the packet and return number of bytes sent. */ - return sendto(wol_socket, &packet, sizeof(unsigned char) * 102, 0, + return sendto(wol_socket, packet, GUAC_WOL_PACKET_SIZE, 0, (struct sockaddr*) &wol_dest, sizeof(wol_dest)); } From 02a72917429296978a5570b453040dd7a17012e7 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 15 Apr 2020 09:42:22 -0400 Subject: [PATCH 6/8] GUACAMOLE-513: Adjust names of constants and fix style. --- src/libguac/Makefile.am | 4 ++-- src/libguac/guacamole/wol-constants.h | 12 +++++------ src/protocols/rdp/settings.c | 4 ++-- src/protocols/ssh/settings.c | 4 ++-- src/protocols/telnet/settings.c | 4 ++-- src/protocols/vnc/settings.c | 31 +++++++++++++++++++++++++++ 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index 68d80278..ad7d7c9d 100644 --- a/src/libguac/Makefile.am +++ b/src/libguac/Makefile.am @@ -69,8 +69,8 @@ libguacinc_HEADERS = \ guacamole/user.h \ guacamole/user-constants.h \ guacamole/user-fntypes.h \ - guacamole/user-types.h \ - guacamole/wol.h \ + guacamole/user-types.h \ + guacamole/wol.h \ guacamole/wol-constants.h noinst_HEADERS = \ diff --git a/src/libguac/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 8e5fb4e4..6f27dd07 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -28,17 +28,15 @@ */ /** - * The default broadcast address to which Wake-on-LAN packets will be sent - * if one is not specified, which is the special value for the IPv4 local - * network broadcast. + * The value for the local IPv4 broadcast address. */ -#define GUAC_WOL_DEFAULT_BROADCAST "255.255.255.255" +#define GUAC_WOL_LOCAL_IPV4_BROADCAST "255.255.255.255" /** - * The default number of seconds to wait after sending the Wake-on-LAN packet + * The 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 +#define GUAC_WOL_BOOT_WAIT_TIME 60 /** * The size of the magic Wake-on-LAN packet to send to wake a remote host. This @@ -50,7 +48,7 @@ /** * 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 it is considered a pretty standard + * processed by a full IP stack, but defining one is considered a standard * practice. */ #define GUAC_WOL_PORT 9 diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 3c692556..7c4b23cb 100644 --- a/src/protocols/rdp/settings.c +++ b/src/protocols/rdp/settings.c @@ -1079,12 +1079,12 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, /* 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); + 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_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_BOOT_WAIT_TIME); } diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index 679545f8..c76feaeb 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -504,11 +504,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, settings->wol_broadcast_addr = guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, - IDX_WOL_BROADCAST_ADDR, GUAC_WOL_DEFAULT_BROADCAST); + 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_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_BOOT_WAIT_TIME); } diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index 2fca8fed..63f68d17 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -506,12 +506,12 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, /* 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); + 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_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_BOOT_WAIT_TIME); } diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 2ac33b9f..847f6733 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -558,6 +558,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_BOOT_WAIT_TIME); + + } return settings; From df8030d9bb2d045265f6a965efb06b98423ce3c2 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 7 Jun 2020 20:27:42 -0400 Subject: [PATCH 7/8] GUACAMOLE-513: Implement defaults header for protocol constants. --- src/common/common/defaults.h | 31 +++++++++++++++++++++++++++ src/libguac/guacamole/wol-constants.h | 6 ------ src/protocols/rdp/settings.c | 3 ++- src/protocols/ssh/settings.c | 3 ++- src/protocols/telnet/settings.c | 3 ++- src/protocols/vnc/settings.c | 3 ++- 6 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 src/common/common/defaults.h 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/guacamole/wol-constants.h b/src/libguac/guacamole/wol-constants.h index 6f27dd07..215e6b88 100644 --- a/src/libguac/guacamole/wol-constants.h +++ b/src/libguac/guacamole/wol-constants.h @@ -32,12 +32,6 @@ */ #define GUAC_WOL_LOCAL_IPV4_BROADCAST "255.255.255.255" -/** - * The number of seconds to wait after sending the Wake-on-LAN packet - * for the destination host to start responding. - */ -#define GUAC_WOL_BOOT_WAIT_TIME 60 - /** * 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. diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c index 7c4b23cb..0f47f6e2 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" @@ -1084,7 +1085,7 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user, /* 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_BOOT_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); } diff --git a/src/protocols/ssh/settings.c b/src/protocols/ssh/settings.c index c76feaeb..5e798178 100644 --- a/src/protocols/ssh/settings.c +++ b/src/protocols/ssh/settings.c @@ -20,6 +20,7 @@ #include "config.h" #include "client.h" +#include "common/defaults.h" #include "settings.h" #include @@ -508,7 +509,7 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user, settings->wol_wait_time = guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv, - IDX_WOL_WAIT_TIME, GUAC_WOL_BOOT_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); } diff --git a/src/protocols/telnet/settings.c b/src/protocols/telnet/settings.c index 63f68d17..8b537de4 100644 --- a/src/protocols/telnet/settings.c +++ b/src/protocols/telnet/settings.c @@ -19,6 +19,7 @@ #include "config.h" +#include "common/defaults.h" #include "settings.h" #include @@ -511,7 +512,7 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user, /* 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_BOOT_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); } diff --git a/src/protocols/vnc/settings.c b/src/protocols/vnc/settings.c index 847f6733..8ca7e463 100644 --- a/src/protocols/vnc/settings.c +++ b/src/protocols/vnc/settings.c @@ -20,6 +20,7 @@ #include "config.h" #include "client.h" +#include "common/defaults.h" #include "settings.h" #include @@ -586,7 +587,7 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user, /* 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_BOOT_WAIT_TIME); + IDX_WOL_WAIT_TIME, GUAC_WOL_DEFAULT_BOOT_WAIT_TIME); } From 2aa2ccc90cec2201f369c70537b66509bfbca5ce Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Sun, 7 Jun 2020 20:33:19 -0400 Subject: [PATCH 8/8] GUACAMOLE-513: Properly close WOL socket. --- src/libguac/wol.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libguac/wol.c b/src/libguac/wol.c index fc9d8a2a..b8e5e687 100644 --- a/src/libguac/wol.c +++ b/src/libguac/wol.c @@ -96,8 +96,10 @@ static ssize_t __guac_wol_send_packet(const char* broadcast_addr, /* Attempt to set broadcast; exit with error if this fails. */ if (setsockopt(wol_socket, SOL_SOCKET, SO_BROADCAST, &wol_bcast, - sizeof(wol_bcast)) < 0) + sizeof(wol_bcast)) < 0) { + close(wol_socket); return 0; + } } /* Set up socket for IPv6 multicast. */ @@ -108,13 +110,17 @@ static ssize_t __guac_wol_send_packet(const char* broadcast_addr, int hops = 1; if (setsockopt(wol_socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, - sizeof(hops))) + sizeof(hops))) { + close(wol_socket); return 0; + } } /* Send the packet and return number of bytes sent. */ - return sendto(wol_socket, packet, GUAC_WOL_PACKET_SIZE, 0, + int bytes = sendto(wol_socket, packet, GUAC_WOL_PACKET_SIZE, 0, (struct sockaddr*) &wol_dest, sizeof(wol_dest)); + close(wol_socket); + return bytes; }