给guacamole添加WOL ether-wake功能,支持局域网唤醒

去年12月搭建了guacamole实现了网页方式rdp,rdp对象是跑在虚拟机里的win10,最近发现如果用物理机当rdp client时,如果物理机休眠了,rdp就不可能起作用了。

有些网友说win10支持局域网读写访问时自动唤醒机器,具体方法搜了下,一堆不知所云的东西,主板bios里也翻了一遍,调整了几个参数也没有效果

偶然发现,我这块主板(ga h110tn-e)居然不支持WOL发魔术包的方式唤醒,必须用ether-wake包,这点从google paly上下载的wake-on-lan apk和openwrt上的luci app上都得到了证实

既然是这样,只能曲线救国了,rdp之前先想办法局域网唤醒

查看了guacamole文档,是支持wol的,这样就省了不少事,配置相关参数后,不出意外,wol无法唤醒我这块主板,配置文件如下:

下一步就是为guacamole添加ether-wake功能

参考了busybox中的代码,很容易就添加了ether-wake函数,代码如下:

guacamole-server\src\libguac\wol.c


#include <netinet/ether.h>
#include <linux/if.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>

/**
 * Generate the WoL ether wake 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_ether_wake_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++) {
        mac[i] = mac_address[i];
    }
    
    /* Copy the MAC address contents into the char array that is storing
     the first 12 byte packet. */
    for (i = 0; i < 2; i++) {
        memcpy(&packet[i * 6], &mac, 6 * sizeof(unsigned char));
    }
    
    unsigned char* pkt = packet;
    pkt += 12;

    *pkt++ = 0x08; /* 12 */ /* Or 0x0806 for ARP, 0x8035 for RARP */
    *pkt++ = 0x42; /* 13 */
    
    memset(pkt, 0xff, 6); /* 14 */
    
    for (i = 0; i < 16; ++i) {
        pkt += 6;
        memcpy(pkt, &mac, 6); /* 20,26,32,... */
    }
}


static ssize_t __guac_ether_wake_send_packet(unsigned char packet[],const char *ifname) {
    struct sockaddr_ll wol_dest;
    int wol_socket;

    /* Set up the socket */
    wol_socket = socket(PF_PACKET, SOCK_RAW, 0);
    
    /* If socket open fails, bail out. */
    if (wol_socket < 0) {
        guac_error = GUAC_STATUS_SEE_ERRNO;
        guac_error_message = "Failed to open socket to send WOL:ether-wake packet";
        return 0;
    }
    

    memset(&wol_dest, 0, sizeof(wol_dest));
    wol_dest.sll_family = AF_PACKET;
    struct ifreq ifr;
    strcpy(ifr.ifr_name, ifname);
    ioctl(wol_socket, SIOCGIFINDEX, &ifr);
    wol_dest.sll_ifindex = ifr.ifr_ifindex;
    /* The manual page incorrectly claims the address must be filled.
           We do so because the code may change to match the docs. */
    wol_dest.sll_halen = ETH_ALEN;
    memcpy(wol_dest.sll_addr, packet, ETH_ALEN);
        
    /* Send the packet and return number of bytes sent. */
    int bytes = sendto(wol_socket, packet, GUAC_ETHER_WAKE_PACKET_SIZE, 0,
            (struct sockaddr*) &wol_dest, sizeof(wol_dest));
    close(wol_socket);
    return bytes;
}

int guac_ether_wake(const char* mac_addr, const char* if_name) {
    
    unsigned char ether_wake_packet[GUAC_ETHER_WAKE_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) {
        guac_error = GUAC_STATUS_INVALID_ARGUMENT;
        guac_error_message = "Invalid argument for WOL:ether-wake MAC address";
        return -1;
    }
    
    /* Generate the magic packet. */
    __guac_ether_wake_create_magic_packet(ether_wake_packet, dest_mac);
    
    /* Send the packet and record bytes sent. */
    int bytes_sent = __guac_ether_wake_send_packet(ether_wake_packet, if_name);
    
    /* Return 0 if bytes were sent, otherwise return an error. */
    if (bytes_sent)
        return 0;
    
    return -1;
}




如上是核心的几个构造和发socke包函数,剩下的就是把guac_ether_wake函数添加到rdp.c中,这样在网页中点击rdp设备前就能优先发wol包唤醒设备了。

guac_ether_wake函数需要指定网卡名称,所以增加了一个rdp的配置参数,允许用户自定义网卡名字,效果如下

最后说明下,为了保证唤醒成功,没有移除原有的magic package,相当于ether-wake和magic package同时发送,确保唤醒成功 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值