如何使用python代码通过互联网唤醒局域网?

sho*_*key 3 openwrt wake-on-lan router python3

我的家庭网络图很简单,如下所示:

internet       --> Optical modem --> router      --> pc1 ,pc2
111.111.111.111--> 192.168.1.1   -->192.168.31.1 --> 192.168.31.144,192.168.31.173
Run Code Online (Sandbox Code Playgroud)

ISP提供一个静态ip,假设它是111.111.111.111,光调制解调器的ip地址是192.168.1.1,路由器的ip地址是192.168.31.1,pc1的ip地址是,pc2的192.168.31.144ip地址是192.168.31.173,pc1的mac地址xx.xx.xx.xx

openwrt是我的路由器上运行,将在路由器和防火墙开放某个端口转发规则:

forwarding rule
name        protocl       outer port    inner IP address   inner port 
wakeonwan   UDP           9             192.168.31.144      9
ssh         TCP and UDP   10000         192.168.31.1        22
Run Code Online (Sandbox Code Playgroud)

并在openwrt中绑定ip地址和mac:

ip address               mac               interface
192.168.31.144           xx.xx.xx.xx       ??
Run Code Online (Sandbox Code Playgroud)

从以下选项中选择哪个界面?

在此处输入图片说明

远程登录我的路由器:

ssh root@111.111.111.111 -p 10000
Run Code Online (Sandbox Code Playgroud)

从路由器发出 wol 命令:

/usr/bin/wol -i 192.168.31.255 xx.xx.xx.xx
Run Code Online (Sandbox Code Playgroud)

pc1 可以从路由器唤醒!
关闭 pc1,使用以下 python 代码从 pc2 唤醒它wakeonlan.py

from wakeonlan import send_magic_packet
send_magic_packet('xx.xx.xx.xx')
Run Code Online (Sandbox Code Playgroud)

python3 wakeonlan.py在pc2中执行命令可以成功唤醒我的pc1。

python3 wakeonwan.py远程执行命令(例如——在我公司的电脑中)无法唤醒我的 pc1。

cat wakeonwan.py
mac = "xx.xx.xx.xx"
target_ip = "111.111.111.111"
from wakeonlan import send_magic_packet
send_magic_packet(mac, ip_address=target_ip,port=9)
Run Code Online (Sandbox Code Playgroud)

它没有遇到错误,为什么pc1无法唤醒wakeonwan.py
让我们用 lib-- 来做paramiko

pip install paramiko
Run Code Online (Sandbox Code Playgroud)

艾特wakeonwan-paramiko.py

import paramiko
from contextlib import contextmanager
host = '111.111.111.111'
username = 'root'
password = 'password'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(host, username=username, password=password,port=10000)
stdin, stdout, stderr = ssh.exec_command("/usr/bin/wol -i 192.168.31.255 xx:xx:xx:xx")
ssh.close()
Run Code Online (Sandbox Code Playgroud)

python3 wakeonwan-paramiko.py可以从外网唤醒我的家用电脑,我觉得编辑wakeonwan.py远程唤醒电脑更简单吗?
如何解决?

tel*_*coM 5

从本地网络之外发送 Wake-on-LAN 数据包的棘手部分是让路由器将数据包发送到本地网络,以便完全被动的 PC1 可以接收它。

魔术数据包寻址到路由器的外部 IP 地址,这使其成为单播数据包。路由器中的转发规则将目标PC自己的IP地址指定为内部IP地址。因此,按照转发单播流量的标准程序,路由器将首先发出 ARP 请求以找出目标 PC 的 MAC 地址……但没有得到答复,因为目标 PC 已关闭。等待 LAN 唤醒数据包的网络接口处于低功耗仅接收模式:它通常无法响应 ARP 请求。

当 ARP 请求失败时,路由器可能会发回一个 ICMP 错误数据包,指示“主机无法访问”……但 Python 唤醒兰模块似乎没有处理此类错误响应的设施,即使假设 ICMP 消息没有得到在返回的路上被偏执防火墙过滤掉。

将 MAC 地址嵌入到魔术数据包负载中这一事实无济于事,因为路由器既不知道也不关心这一点。对于路由器来说,魔术包只是另一个 TCP 或 UDP 数据包,将像往常一样进行处理。

您必须配置转发规则,将魔术数据包发送到内部网络的广播地址,以使其成为广播。这样,路由器在将数据包传递到内部网络之前不需要进行 ARP 查询。因此,如果您的内部网络的掩码是 255.255.255.0,那么您应该使用 192.168.31.255 作为转发规则中的内部 IP 地址。

但是......正如@AB 在评论中提到的,基于 Linux 的路由器通常不喜欢将单播转换为广播,所以这种方法可能行不通。

另一种解决方案是将目标 PC 的静态 ARP 表条目添加到路由器的 ARP 表中,这样它就不需要进行 ARP 查询,而可以继续将数据包转发到内部网络。

通过快速源代码检查,wakeonlan python 模块似乎使用 SOCK_DGRAM,这意味着它使用 UDP。因此,您应该能够将转发规则从“TCP 和 UDP”更改为“仅 UDP”。