Wake on Lan のマジックパケットを送信するプログラムを Rust で実装した
Wake on Lan とは
Wake on Lan は、コンピュータネットワークに特定のパケットを送信させることにより、そのパケットの内容に該当するコンピュータが自ら電源を投入させる仕組みです(参考 : Wikipedia)
Wake on Lan を使用することで、遠隔でコンピュータの電源を入れることができるようになります。
送信する「特定のパケット」を マジックパケット といいます。
マジックパケットは FF:FF:FF:FF:FF:FF
に続けて起動したい装置の MAC アドレスを16回繰り返したデータパターンのパケットです。
例えば、起動したい装置の MAC アドレスが EE:EE:EE:00:00:01
の場合、マジックパケットは以下のようになります。
FF:FF:FF:FF:FF:FF
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
EE:EE:EE:00:00:01
マジックパケットをブロードキャストアドレスの UDPのポート9 に送ることで、指定した MAC アドレスのコンピュータの電源を入れることができます。
(電源を投入される PC が Wake on Lan に対応している必要があります)
プログラムの説明
今回は以下の処理を行う Rust のプログラムを作成しました。
- MAC アドレスを受け取る
- マジックパケットを生成
- UDP の 9 番ポートに送信
作成したプログラムは以下のリポジトリにあります。
作成したプログラムの説明を記載します。
MAC アドレスを受け取る
MAC アドレスは clap を使用して、コマンドライン引数で受け取るようにしました。
Cargo.toml の dependencies に clap を指定します。
clap のバージョンはプログラム作成時(2025/03)の最新バージョンです。
[dependencies]
clap = { version = "4.5.31", features = ["derive"] }
ソースコードは以下のようになりました。
use clap::Parser;
// コマンドライン引数の定義
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
struct Args {
/// MAC ADDRESS
#[arg(value_name = "MAC_ADDRESS")]
mac_address: String,
}
マジックパケットを生成
関数 parse_mac_address
で &str
で受け取った MAC アドレスを 16 進数に変換します。
関数 create_magic_packet
で parse_mac_address
を 16 回実行します。
// MAC アドレスを受け取り、その MAC アドレスに対応するマジックパケットを生成する
fn create_magic_packet(mac_address: &str) -> Result<Vec<u8>, ParseIntError> {
// FF:FF:FF:FF:FF:FF という 6 バイトのヘッダを生成
let mut magic_packet: Vec<u8> = vec![0xff; 6];
// MAC アドレスを 16 回繰り返して追加する
for _ in 0..16 {
let parsed_address: Vec<u8> = parse_mac_address(mac_address)?;
magic_packet.extend_from_slice(&parsed_address);
}
Ok(magic_packet)
}
// MAC アドレスを 16 進数のベクタに変換する
fn parse_mac_address(mac_address: &str) -> Result<Vec<u8>, ParseIntError> {
let mut parsed: Vec<u8> = Vec::new();
for octet in mac_address.split(":") {
parsed.push(u8::from_str_radix(octet, 16)?);
}
Ok(parsed)
}
マジックパケットを UDP の ポート9に送信
以下の関数でマジックパケットを送信します。
// マジックパケットをブロードキャストアドレスの udp のポート9に送信する
fn send_magic_packet(magic_packet: Vec<u8>) -> Result<usize, std::io::Error> {
let socket: UdpSocket = UdpSocket::bind("0.0.0.0:0")?;
socket.set_broadcast(true)?;
socket.send_to(&magic_packet, "255.255.255.255:9")
}
main 関数
上記の関数を順に実行します。
fn main() {
// コマンドライン引数をパースし、MAC アドレスを取得する
let args = Args::parse();
let mac_address: String = args.mac_address;
// マジックパケットを生成する
let magic_packet: Vec<u8> = match create_magic_packet(&mac_address) {
Ok(packet) => packet,
Err(e) => { // エラーは表示して、プログラムを終了する
eprintln!("Error: {}", e);
return;
}
};
// マジックパケットを送信する
match send_magic_packet(magic_packet) {
Ok(_) => println!("Magic Packet sent to {mac_address}"),
Err(e) => eprintln!("Error: {}", e)
}
}
以下のメッセージが出て、指定した MAC アドレスのコンピュータに電源が入れば成功です。
Magic Packet sent to <指定した MAC アドレス>
Discussion