2022年9月12日月曜日

magick packet

 


https://irukanobox.blogspot.com/2017/08/raspberry-pipython3pc.html  参照

Raspberry PiとPython3でPCを起動する

多くのPCにはWake On LAN(WOL)という機能があって、ネットワーク越しにマジックパケットという指定のパケットを送ると、PCの電源を入れることができる。Raspberry PiからPython3でマジックパケットを送り、Windows10 PCの電源を入れてみる。

Raspberry PiのOSはRaspbian Jessie、Python3のバージョンは以下の通り。


Windows機側でWOLを有効にするにはBIOS/UEFIとOSのLANコントローラドライバの設定が必要で、その方法についてはWake On LANでコンピュータを起動する を参照。

マジックパケットというのは、6個の0xFFとパケットを受信する側のMACアドレス16個からなる計102バイトのデータを含むパケット。MACアドレスがAA:BB:CC:11:22:33の場合、FFFFFFFFFFFFAABBCC11223344AABBCC...のようなイメージになるが、実際はバイナリデータなので、Python3のprintで出力すると、「b'\xff\xff\xff\xff\xff\xff\xaa\xbb\xcc\x11"3\xaa\xbb\xcc\x11"3\xaa\xbb\xcc...」のように、\x~とASCII文字が混在したものになる。

パケットの送り方は特に決まっていないが、UDPとブロードキャスト、ポート番号は7か9を使うのが一般的らしい。ブロードキャストアドレスには、255.255.255.255とIPアドレスのホスト部のビットがすべて1のアドレスがあるが、ルータを越える必要がなければ255.255.255.255で問題ないので、ここでは255.255.255.255を使う。

MACアドレスがAA:BB:CC:11:22:33の端末にマジックパケットを送るPython3のコード。
sample.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import socket
import binascii
 
# MACアドレス
MACADDR = 'AA:BB:CC:11:22:33'
# ブロードキャストアドレス
BCADDR = '255.255.255.255'
# 宛先ポート番号
PORT = 7
 
macstr = ''.join(MACADDR.split(':'))
mdata = 'FF' * 6 + macstr * 16
# 16進数表記の文字列を表すバイナリデータに変換
mdata = binascii.unhexlify(mdata)
 
# ソケットの作成
# 第一引数: アドレス (およびプロトコル) ファミリーを示す定数
# socket.AF_INETのときは(host, port)
# 第二引数: ソケットタイプ、UDPならSOCK_DGRAM、TCPならSOCK_STREAM
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
# ブロードキャストを使用するための設定
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
 
# ソケットにデータを送信
s.sendto(mdata, (BCADDR, PORT))
 
s.close()

Windows PCをスリープ状態にして、Raspberry PiのPython3で上記スクリプトを実行すると、Windows PCがスリープからめでたく復帰。

LANコントローラによっては、シャットダウンした状態でもマジックパケットを受け取れるものもあるらしいが、残念ながら家のPCではできなかった。

MACアドレスを引数として渡せるようにして、MACアドレスチェックを追加したスクリプトを作成。(2017.9.30)
"""
Send magic(WOL) packet
"""
import socket
import binascii
import sys
import re
# Broadcast address
BCADDR = '255.255.255.255'
# Port
PORT = 7
def macstr(macaddr):
"""
Check the validity of the MAC address
"""
if len(macaddr) == 17:
maclist = macaddr.split(':')
if len(maclist) == 6:
if len(list(filter(lambda x: re.match('^[0-9a-fA-F]{2}', x), maclist))) == 6:
return ''.join(maclist)
print('Invalid MAC address: ' + macaddr)
exit()
def main():
params = sys.argv
if len(params) != 2:
print('Usage: python3 wol.py [MAC address]')
print('e.g.')
print('python3 wol.py AA:BB:CC:11:22:33')
exit()
mdata = 'FF' * 6 + macstr(params[1]) * 16
print('Sending a magic packet to ' + params[1])
# Convert into binary data represented by hexadecimal string
mdata = binascii.unhexlify(mdata)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(mdata, (BCADDR, PORT))
s.close()
if __name__ == '__main__':
main()
view rawwol.py hosted with ❤ by GitHub