网络远程唤醒 WOL Magic Packet【转】
转自:https://www.cnblogs.com/dcb3688/p/4608063.html
Magic Packet
Magic Packet白皮书介绍:
The basic technical details of Magic Packet Technologyare simple and easy to understand. There is also a sec-ond set of details, which will be implementation spe-cific. In other words, silicon- or gate-levelimplementations of Magic Packet Technology may dif-fer from AMD\’s approach and be completely interoper-able, as long as the basic feature set is maintained.
https://wenku.baidu.com/view/d5a3282e453610661ed9f487.html
AMD公司出的网络唤醒协议,即发送远程唤醒数据包,Magic Packet虽然只是AMD公司所开发的一项技术,但是受到了几乎所有网卡制造商的支持,因此,大多数流行网卡都能与之很好地兼容。(2010年后生产的主板)
WOL原理
WOL(Wake on Lan),即局域网唤醒,从根本上来说是硬件设备提供的一项管理功能,该功能可以当电脑处于关机或休眠状态时,通过给网卡发送特定的数据包从而命令网卡向主板发送开机指令,进而实现上电开机.可见,网络唤醒需要硬件(主要是主板和网卡)的支持.
硬件设置
进入BIOS,将“Power Management Setup”中的“Wake Up On LAN”或“Resume by LAN”项设置为“Enable”或“On”,类似于这样,因为主板不一样,BIOS设置位置有可能有差异
比如我的主板设置是在:Setting-Advanced-Wake up event setup – Resume By PCI-E Device 设置为Enable.
有的人说还要设置boot的第一启动项为network,我试过不需要滴!
软件设置
BIOS设置好了,硬件已经满足条件了,然后需要OS级别的软件设置
Windows设置:
设备管理器-网卡设备-属性-高级, 在列表里能找到“Wakeup Capabilities(唤醒功能)”设置值为“MagicPacket”或”Both”.
Linux设置:
先通过 ifconfig 查看要wol的网卡.
这里需要说下,好多网友说没有eth0, 对! 我也没有这个网卡的信息,因为你用的肯定是Ubuntu的衍生版,在Ubuntu 16.04之后以太网卡名称由eth0,变成了enp3s0,还有systemd替换掉了initd来引导系统,参考: Linux网卡命名enp3s0说明
用ethtool命令 打印网卡信息
sudo ethtool enp3s0
打印结果:
....
....
Supports Wake-on: pumbg Wake-on: g Current message level: 0x00000033 (51) drv probe ifdown ifup
Wake-on 参数:
d 表示禁用disable
g表示启用great
如果wake-on参数为d就要启用wol, 启用命令:
sudo ethtool -s enp3s0 wol g
必须要用sudo 管理员权限否则会提示: Cannot get current wake-on-lan settings: Operation not permitted
-s 参数是修改以太网设备设置
supports wake-on 中的参数
p Wake on phy activity |
获取MAC地址
Windows 直接在网络设备-属性里面, linux使用ifconfig 命令查看
例如linux:
enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.213 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::a680:65a4:a006:5bbc prefixlen 64 scopeid 0x20<link> ether d8:cb:8a:3f:32:d2 txqueuelen 1000 (以太网) RX packets 890331 bytes 1003253740 (1.0 GB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 555010 bytes 73345907 (73.3 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
网络唤醒
到这;已经有了BIOS的支持,有了OS wake-on的支持,又知道了MAC地址,说明被控制(唤醒)机已经Ready了.
局域网唤醒
现在我们需要局域网的电脑或者设备去访问,访问不是随随便便访问的,因为Magic Packet是一种协议规则,必须要用规则发送,关于规则可看下一个段落解析Magic Packet包
我们用GUI工具去访问,常用的WOL工具有
WakeOnLanGui
下载地址:https://www.depicus.com/wake-on-lan/wake-on-lan-gui
WakeMeOnLan
下载地址:http://wakemeonlan.findmysoft.com
参数IP地址,MAC地址,任意一个端口号,IP地址也可以直接填写255.255.255.255
Linux下我没有找到GUI工具,只有wakeonlan命令了
sudo apt install wakeonlan
唤醒目标主机:
wakeonlan d8:cb:8a:3f:32:d2
输出:
Sending magic packet to 255.255.255.255:9 with d8:cb:8a:3f:32:d2
局域网手机唤醒
在同一个局域网下,手机也可以唤醒目标主机
Android APP:
Wake On Lan
下载地址:https://dl.iplaysoft.com/files/3869.html
iphone APP:
RemoteBoot
下载地址:appstore自己搜…..
准备放大招了!!!!!
互联网远程唤醒
虽然 WOL (Wake on Lan) 网络唤醒原本的设计就是 LAN 局域网环境下使用的,但其实我们也是可以想办法让其在 WAN 广域网 (即互联网) 下使用——Wake On Wan。这样,在公司唤醒家里的电脑(在家唤醒公司电脑………..)
第一步:设置端口映射(虚拟服务器)
因为广域网不知道我们局域网内对应的主机是哪一个,所以只访问外网的IP不会把Magic Packet包发到局域网指定的电脑上.我们需要路由器端口映射的支持
登陆路由器找到 传输控制-NAT设置-虚拟服务器
路由器必须为顶级路由而非二级即二级以下
如果路由器LAN设置的是DHCP动态分配IP,有可能这次分配的局域网IP与重启之后局域网IP不统一(如果设备少于DHCP分配区间,IP会一直续租), 所以最好做一个静态地址分配或者IP与MAC绑定.
对于外网,如果IP是运营商固定IP可以直接使用公网IP,如果非固定IP(自动获取IP与PPPoE拨号)可以通过花生壳进行DDNS动态域名解析.使用动态域名替代公网IP.
第二步:查看公网IP
通过站长工具 http://ip.chinaz.com/ 查看对应公网IP
第三步:网络访问目标
OK! 此时,可以通过手机APP进行互联网的唤醒了,关闭WiFi,打开4G.好吧,不关WiFi也行.
当我们按BOOT时,就会通过公网IP端口映射到指定的主机,发送Magic Packet包唤醒电脑.
depicus 提供了在线远程唤醒 (现在貌似唤不起来了!!!)
https://www.depicus.com/wake-on-lan/woli
网站这样解释:
Wake on Lan Magic Packets can be sent over the Internet – why not try waking up one of your machines with our free Wake On Wan Service. Want a quick way to use this page ?
Bookmark https://www.depicus.com/wake-on-lan/woli?m=001143BDA600&i=82.110.108.30&s=255.255.255.255&p=4321 will get you straight there without the need to press those pesky send buttons.
换句话说,我们可以不用下载APP,只要保存一个书签,当需要的时候访问书签即可.
https://www.depicus.com/wake-on-lan/woli?m=d8cb8a3f32d2&i=58.37.39.82&s=255.255.255.255&p=4321
TeamViewer 自带Lan网络唤醒
在TeamViewer-其他-常规-网络设置中就有自带的Lan网络唤醒
填写公共地址IP或端口映射对应的NAT网址,手机端TeamViewer登陆对应的账户,当主机关机时我们就可以通过手机端TeamViewer唤醒电脑
解析Magic Packet包
我们已经知道,Magic Packet是一种协议规则,必须遵从规则发送,Magic Packet的包格式很简单,首先是六个FF,然后是重复十六次待唤醒电脑的MAC
FF FF FF FF FF FF d8 cb 8a 3f 32 d2 d8 cb 8a 3f 32 d2 .......
理论上可以在任意网络封包中打包Magic Packet,不过一般选择UDP或IPX
Python代码:
#!/usr/bin/env python # -*- encoding: utf-8 -*- """ Small module for use with the wake on lan protocol. """ from __future__ import absolute_import from __future__ import unicode_literals import argparse import socket import struct import re BROADCAST_IP = \'255.255.255.255\' DEFAULT_PORT = 9 def create_magic_packet(macaddress): """ Create a magic packet. A magic packet is a packet that can be used with the for wake on lan protocol to wake up a computer. The packet is constructed from the mac address given as a parameter. Args: macaddress (str): the mac address that should be parsed into a magic packet. """ if len(macaddress) == 12: pass elif len(macaddress) == 17: sep = macaddress[2] macaddress = macaddress.replace(sep, \'\') else: raise ValueError(\'Incorrect MAC address format\') # Pad the synchronization stream data = b\'FFFFFFFFFFFF\' + (macaddress * 16).encode() send_data = b\'\' # Split up the hex values in pack for i in range(0, len(data), 2): send_data += struct.pack(b\'B\', int(data[i: i + 2], 16)) return send_data def send_magic_packet(*macs, **kwargs): """ Wake up computers having any of the given mac addresses. Wake on lan must be enabled on the host device. Args: macs (str): One or more macaddresses of machines to wake. Keyword Args: ip_address (str): the ip address of the host to send the magic packet to (default "255.255.255.255") port (int): the port of the host to send the magic packet to (default 9) """ packets = [] ip = kwargs.pop(\'ip_address\', BROADCAST_IP) port = kwargs.pop(\'port\', DEFAULT_PORT) for k in kwargs: raise TypeError(\'send_magic_packet() got an unexpected keyword \' \'argument {!r}\'.format(k)) for mac in macs: packet = create_magic_packet(mac) packets.append(packet) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 如果输入的是域名,将域名转换为IP ipv4_regex = re.compile(r\'(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\',re.IGNORECASE) if not ipv4_regex.match(ip): ip=socket.gethostbyname(ip) sock.connect((ip, port)) for packet in packets: sock.send(packet) sock.close() print(\'sent to \'+ip) def main(argv=None): """ Run wake on lan as a CLI application. """ parser = argparse.ArgumentParser( description=\'Wake one or more computers using the wake on lan\' \' protocol.\') parser.add_argument( \'macs\', metavar=\'mac address\', nargs=\'+\', help=\'The mac addresses or of the computers you are trying to wake.\') parser.add_argument( \'-i\', metavar=\'ip\', default=BROADCAST_IP, help=\'The ip address of the host to send the magic packet to.\' \' (default {})\'.format(BROADCAST_IP)) parser.add_argument( \'-p\', metavar=\'port\', type=int, default=DEFAULT_PORT, help=\'The port of the host to send the magic packet to (default 9)\') args = parser.parse_args(argv) send_magic_packet(*args.macs, ip_address=args.i, port=args.p) if __name__ == \'__main__\': # pragma: nocover main()
terminal执行:
python3 WakeOnWan.py -i test.tpddns.cn -p 9 d8:cb:8a:3f:32:d2
python3 WakeOnWan.py -i 192.168.1.105 -p 9 d8:cb:8a:3f:32:d2
C++ 代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> void fill_magic_buf(void *magic_buf, void *mac) { int i; char *ptr; ptr = magic_buf; memset(ptr, 0xFF, 6); ptr += 6; for(i = 0; i < 16; ++i) { memcpy(ptr, mac, 6); ptr += 6; } } void usage(void) { printf("usage...\n"); } int main(int argc, char **argv) { int s; int packet_num = 10; char c; unsigned char mac[6] = {0x00, 0x1A, 0x92, 0xE5, 0x1B, 0xA7}; char dstip[256] = "192.168.9.180"; int port = 9; struct sockaddr_in address; char magic_buf[6 + 6 * 16] = {0}; daemon(0,0); /* run in background */ while((c = getopt(argc, argv, "d:m:p:")) != -1) { switch(c) { case \'d\': strcpy(dstip, optarg); break; case \'m\': sscanf(optarg, "%x:%x:%x:%x:%x:%x", (unsigned int*)&mac[0], (unsigned int*)&mac[1], (unsigned int*)&mac[2], (unsigned int*)&mac[3], (unsigned int*)&mac[4], (unsigned int*)&mac[5]); break; case \'p\': port = atoi(optarg); break; default: usage(); return -1; } } s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) { perror("Opening socket"); exit(EXIT_FAILURE); } memset(&address, 0, sizeof(struct sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(dstip); address.sin_port = htons(port); fill_magic_buf(magic_buf, mac); /* ten packets. TODO: use ping to check whether the destination is on or else. */ while (packet_num-- > 0) { if (sendto(s, magic_buf, sizeof(magic_buf), 0, (struct sockaddr *)&address, sizeof(address)) < 0) { printf("sendto\n"); exit(EXIT_FAILURE); } sleep(1); } exit(EXIT_SUCCESS); }
注意事项
1: 如果电脑非正常关机(比如按Power键来强制关机)还是无法WOL的,只有正常关机后,网卡仍会处于活动状态可以接收网络数据
2:如果是外网IP访问,路由器做端口映射必须要是顶级接入的路由器,因为二级以下NAT只能在是内网映射
3:Linux设置wol的时候,重启后enp3s0的设置又恢复Wake-on: d 状态, 写个脚本让开机执行 (Ubuntu18.04已修复)
在~/.profile 文件中添加
.config/wol.sh
wol.sh
#!/bin/sh echo "12345678" | sudo -S ethtool -s enp3s0 wol g
-S表示bash脚本免输密码,参考: bash脚本,自动输入sudo的密码