从外部WAN唤醒计算机
不久前,我在谷歌的帮助下写了一个小脚本,用来唤醒我网络中的电脑。这个脚本是这样的:
exec /usr/bin/python -x "$0" "$@"
#
node_lst = [
'srv1 0a:1b:8c:0d:2e:7f',
'srv2 0A-0B-4C-8D-CE:3F',
]
#
import os,sys,string,commands
import struct, socket
import re,random
retval = 0
mac_addr = "mac_addr.txt"
X = '([a-zA-Z0-9]{2}[:|\-|.]?){5}[a-zA-Z0-9]{2}'
S = re.compile(r'\s+')
mmap = {}
## First argument 'None' in str.translate is new in 2.6.
## Previously, it was a string of 256 characters
if sys.version_info < (2, 6):
f1_arg = ''.join(chr(i) for i in xrange(256))
else:
f1_arg = None
## broadcast address
sysOS = "uname -s"
BSD = "ifconfig | grep -w broadcast | cut -d\ -f 6"
LNX = "ip -o addr show | grep -w inet | grep -e eth | cut -d\ -f 9"
#
if commands.getoutput(sysOS) == "Linux":
bCast = commands.getoutput(LNX)
elif commands.getoutput(sysOS) == "Darwin":
bCast = commands.getoutput(BSD)
else:
print "System not supported!!"
sys_exit()
def WakeOnLan(mac_address):
## Building the Wake-On-LAN "Magic Packet"...
## Pad the synchronization stream.
data = ''.join(['FFFFFFFFFFFF', mac_address * 20])
msg = ''
## Split up the hex values and pack.
for i in range(0, len(data), 2):
msg = ''.join([msg, struct.pack('B', int(data[i: i + 2], 16))])
## ...and send it to the broadcast address using UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(msg, (bCast, 9))
s.close()
def sys_exit():
sys.stdout.flush()
sys.exit(1)
## check if hostname is provided
if len(sys.argv) != 2:
print "Usage: %s <hostname>" % sys.argv[0]
sys_exit()
for i in node_lst:
# strip off everything from first "#" [if] found
i = i.split('#',1)[0]
if not re.search(X, i):
continue
h = S.split(i,1)[0] ## host name
m = S.split(i,1)[-1] ## MAC address
mmap[h] = m.strip('\t|" "')
for j, k in mmap.iteritems():
if sys.argv[1] == j:
if not re.search(X.replace('zA-Z','fA-F'), k):
print "Invalid MAC address [",k,"]; nothing to do!!"
sys_exit()
else:
WakeOnLan(k.translate(f1_arg,':.-'))
print "WOL request has been sent to %s [%s]" % (j,k)
break
else:
print "Host [%s] doesn't exist!!" % sys.argv[1]
sys_exit()
这个脚本在我家网络内部(也就是局域网)运行得很好。请问我该如何修改这个脚本,让它在局域网外也能工作呢?有没有什么想法或建议?谢谢!!
2 个回答
1
把你的路由器设置成,能够把10个不连续的端口上的数据包转发到你家网络里的某台机器上。
想个办法,比如用格林威治标准时间(GMT)加上一个哈希值,来生成端口触发的顺序。
在你家网络里的电脑上,运行一个Python程序(可以用scappy库),让它监听一系列的SYN数据包。
这个监听的代码大概就像下面的tcpdump语法:
sudo tcpdump -ni eth0 'tcp[tcpflags] & (tcp-syn) !=0'
它只捕捉SYN数据包。
你的程序就静静地待着,等着正确的SYN序列。当它收到这个序列时,就会运行你的唤醒脚本。
就这样。
如果你不想打开端口,你的脚本可以改成去访问一个远程网站,等待网站内容的变化。或者监听通过电子邮件获取的邮件。
如果想得更花哨一点,你还可以做一些有趣的事情,比如打开灯或者启动电视。
1
这是不可能的,因为WOL(唤醒局域网)数据包是广播数据包(因为你不知道要发给谁)。家里的路由器,尤其是网络服务提供商(ISP)或网络路由器,会丢弃所有广播数据包。否则,每次你运行这个脚本时,互联网上的所有电脑都会收到你的数据包,这样就会造成很多混乱。
当然,你可以做的是写一个小程序,让它在你想要唤醒所有电脑的那个网络里的一台电脑上运行,然后让这个程序发送一个WOL数据包。不过,这样的话,就需要一台始终保持开机并且能上网的电脑。