Python2 + Scapyでマジックパケットを作成し、Wake on LANをしてみた

今まで、遠隔からPCの電源を入れる場合、Wake on LAN 用のツールを使っていました。
Wake-on-LAN - Wikipedia

 
そこで今回、ScapyでWake on LANマジックパケットを作ってみて、ツールの代替となるかを試してみました。

 

目次

 

環境

ネットワーク構成
-----------------------------------------
Raspberry Pi 2 Model B
(`eth0` : オンボードLANアダプタ)
-----------------------------------------
|
|
-----------------------------------------
スイッチングハブ
-----------------------------------------
|
|
-----------------------------------------
(外付けUSB有線LANアダプタ)
Windows10
(オンボードLANアダプタ)
-----------------------------------------

 

ネットワークアダプタ設定

明示的に設定したネットワークアダプタ設定です。

なお、以降の表記は

とします。

機器 アダプタ IPアドレス DGW DNS
ラズパイ eth0 192.168.10.50/24 192.168.10.1 192.168.10.1
X201s USB有線 192.168.10.201/24 192.168.10.1 192.168.10.1
X201s オンボード DHCP DHCP DHCP

 

各機器の構成

以前、ブリッジやルータを自作した時と同じ構成です。

 

Wake on LANができる環境を調査

Wake on LANができる環境を調査するため、いろいろと試してみましたので、それらのメモを残します。

 

試してみたこと
[NG] Macからマジックパケットを送信できるか

当初MacからWiFi経由でマジックパケットを送信しようとしましたが、手元の環境が良くないのか、MacからX201sへのWake on LANは成功しませんでした。

そのため、今回はMacからマジックパケットを送信するのはあきらめました。

 

[NG] Wake on LANでラズパイを起動できるか

Wake on LANでラズパイを起動してみようと思いました。

しかし、以下にある通り、Wake on LANではラズパイは起動しないことが分かりました。

 
そのため、Wake on LANでラズパイを起動することもあきらめました。

 

[NG] Wake on LAN + オンボードLANアダプタで、Windows10のX201sを起動できるか

元々、X201sではWake on LANができそうでした。ただ、Windows10のX201sで試してみたところ、起動しませんでした。

そのため、Windows10版向けのLANアダプタドライバを探してみました。

すると、LenovoではX201sがEOL扱いとなっており、Windows10版のドライバ提供はありませんでした。
Device Drivers File Matrices - ThinkPad X201s

 
そのため、Windows10のX201sのオンボードLANアダプタを使ってWake on LANすることもあきらめました。

 

[OK] X201s + 外付けUSB有線LANアダプタで起動するか

X201sに外付けUSB有線LANアダプタのLUA4-U3-AGTをつないでみたところ、アダプタのプロパティに Wake on LAN関係の設定がありました。

そこで、それらの設定を有効化後、X201sのLUA4-U3-AGT宛にマジックパケットを送信したところ、Wake on LANができました。

そのため、

の構成で試すことにしました。

 

Wake on LANするための設定

今回、LUA4-U3-AGTでWake on LANするため、LUA4-U3-AGTの アダプターのプロパテイ > ネットワークタブの構成ボタン > 電源の管理タブ より

  • このデバイスで、コンピューターのスタンバイ状態を解除できるようにする
  • Magic Packet でのみ、コンピューターのスタンバイ状態を解除できるようにする

の2つにチェックを入れました。

 
一方、オンボードのLANアダプタではなかったせいか、

  • BIOSWake on LAN設定を無効
    • Config > Network > Wake On LAN[Disabled] にする
  • 高速スタートアップを有効化
    • コントロールパネル > 電源オプション > システム設定(電源ボタンの動作を選択する) > 現在利用可能ではない設定を変更します > 高速スタートアップを有効にする のチェックを入れたまま

としても、Wake on LANができました。

 
ただ、スリープ状態の時はWake on LANできましたが、電源OFFの時はできませんでした。

とはいえ、今回はWake on LANができればよかったので、電源OFFの時の対応は気にしないことにしました。

 

Scapyでマジックパケットを送信する

マジックパケットのフォーマットについて

以下を参考にしました。

 

ScapyでUDPデータを設定する方法について

マジックパケットを送信するにはUDPでデータを送信する必要があります。

そのため、方法を調べてみたところ、Rawクラスを使い、データ部分は decode('hex') すれば良さそうでした。
scapy command for defining the data part of udp packet - Stack Overflow

 
なお、 decode('hex') はPython2系のみ利用可能ですが、今回使うScapyはPython2なため、気にしないことにしました。
How to create python bytes object from long hex string? - Stack Overflow

 

ソースコード全体

wake_on_lan.py

# -*- coding: utf-8 -*-
# from scapy.allでも良い
from scapy.sendrecv import sendp
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP, Raw


# 必要に応じて、宛先のMACアドレスに変更する
TARGET_MAC_ADDRESS = '88:xx:xx:xx:xx:xx'

PREFIX_PAYLOAD = 'ff' * 6
BROADCAST_MAC_ADDRESS = 'FF:FF:FF:FF:FF:FF'
LIMITED_BROADCAST_IP_ADDRESS = '255.255.255.255'


def send_magic_packet():
    # マジックパケットの仕様に従い、文字列でペイロードを準備
    str_payload = PREFIX_PAYLOAD + (TARGET_MAC_ADDRESS.replace(':', '') * 16)
    hex_payload = str_payload.decode('hex')

    ether_layer = Ether(dst=BROADCAST_MAC_ADDRESS)
    ip_layer = IP(dst=LIMITED_BROADCAST_IP_ADDRESS)
    udp_layer = UDP()
    raw_layer = Raw(load=hex_payload)
    magic_packet = ether_layer / ip_layer / udp_layer / raw_layer

    # ブリッジやルータと異なり、戻りパケットの受け取りは不要
    # そのため、sendp()関数でL2パケットを送信するだけで良い
    sendp(magic_packet)


if __name__ == '__main__':
    send_magic_packet()

 

実行結果

X201sをスリープにした後、上記スクリプトを実行してみたところ、

pi@raspberrypi:~/scapy_sample/wol $ sudo python wake_on_lan.py
.
Sent 1 packets.

X201sが起動しました。

これにより、Scapyでマジックパケットが正しく作成・送信できたと分かりました。

 

ソースコード

GitHubに上げました。wol/wake_on_lan.py が今回のファイルです。
https://github.com/thinkAmi-sandbox/scapy-sample