コントローラを直接指定してWOLを発行したい
WOLの仕様は以下(WireSharkのWiki)とか。
要はパケット内に
- 0xffを6つ
- その後に対象のMACアドレスを16個並べる
で普通は起きます。ポートとかは関係なくパターンの一致で見れば良いという事もあり、ハードで検出させて割り込み出すとかもまーやれるのかなこれだという感じです。
で、これを送出する場合はUDPパケット作ってでやるのが簡単だと思います。そういうツールもあるみたいですが、私がざっと調べた限りIPアドレスで指定させる物が多かったです。これだとIPアドレスを適当にして発行とかが厳しくなります。なのでコントローラを直接指定して送るやり方を実装してみました。
Scapy
Scapyを使ってWOLパケットの生成と送信を行います。Scapy自体は前にもチラッと書いてます。以下
環境
- Mac OS 10.14.4
- Python3.7
あとScapyを使ってます。恐らくLinux系でも動くのではないかと思います。
参考にさせて頂いたサイト
以下のコードを参考というか、これらをベースに切った貼ったした感じです。ありがとうございました!
-
koさんのブログ
-
thinkAmiさんのブログ
https://irukanobox.blogspot.com/2017/08/raspberry-pipython3pc.html
コード
実際にどうやってるかはもうコード見た方が早くて、以下です。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from scapy.all import *
import binascii
# ----> ここを適切に設定してください。
# 制御対象。これは本物を指定してあげて下さい。
TARGET_MAC_ADDRESS = "11:22:33:44:55:66"
# パケットに乗せるIPアドレス。これは何でも良いです。
IP_ADDRESS = "66.77.88.99"
# パケットを創出するコントローラ。これも本物を指定してあげて下さい。
PCAP_ifname = "en0"
# <----- ここまで
def issue_WOL():
'''
まずはペイロードを作ります。コード見ると分かりますが、
以下のPassword (optional)を省いたものを作っているだけです。
https://wiki.wireshark.org/WakeOnLAN
'''
synchronization_stream = b"\xff" * 16
mac_bin = binascii.unhexlify("".join(TARGET_MAC_ADDRESS.split(":")))
payload = synchronization_stream + mac_bin * 16
'''
上記のpayloadを送るWOLパケットをUDPとして生成します。
'''
ether_layer = Ether(dst=TARGET_MAC_ADDRESS)
ip_layer = IP(dst=IP_ADDRESS)
udp_layer = UDP(sport=44444,dport=33333) # 適当
raw_layer = Raw(load=payload) # ペイロードはbytesで指定すればよしなにしてくれます
wol_packet = ether_layer / ip_layer / udp_layer / raw_layer
'''
生パケ送るだけで良いのでLayer2が使えます。
この時にコントローラを指定すれば、そこから出してくれるはず…
'''
sendp(wol_packet, iface=PCAP_ifname)
print ("sent WOL ", TARGET_MAC_ADDRESS, IP_ADDRESS)
if __name__ == "__main__":
issue_WOL()
使い方としては、TARGET_MAC_ADDRESS 、IP_ADDRESS、PCAP_ifnameを自分の環境や対象に合わせて書きかえて、本コードを実行すればWOLパケットが出ていくはずです(sudo が必要)。
IP_ADDRESSは別に今の対象アドレスがどうとか考えなくても良いです。実際、メチャメチャなアドレスを指定しても以下のように届きます(対向のWireSharkで確認)。レイヤー2から行けるので、コントローラを直接しているためです。
以上です。ま、scapyを使えばそんなに難しくはなかったです
(と書きつつ上記でいうRaw(load= ...で指定するデータの型式で結構自分はハマりましたが)