2008-12-23

MagicPacketを送るJAVAプログラム

外から Wake on Lan で PC を起動する試み…失敗でした の続き

匿名さんからルータのDHCPリース情報があればNATで直接クライアントPCのIPアドレスにWOLパケットを送れるのではないかとコメントがついていまして、試していなかったとコメント返したのですが…

よくよく考えたら最初に潰してました

いや、やったこと全てメモに残さないからこういう事になるんですけどね…

そもそもクライアントPCのIPアドレスは固定でないとアドレス変換の変換先が決まらないので、DHCPを使うなら固定IPの予約を入れておく必要があります。
なので、リース期間も何もないんですよ~

で、予想どおりと言いますか、クライアントPCのIPアドレスに変換する設定ではNATでの破棄はおこらないものの、クライアントPCまでパケットは届きません。
DHCPの情報とARPテーブルは連動していないようです。
なんとなくですが、これは連動しない実装が正解なんじゃないでしょうか?

ちなみにPCの電源を落とした直後であればちゃんと起動します。
これはARPのキャッシュが残っているからでしょう。

色々試してみるのにブロードキャストアドレス以外にMagicPacketを送る適当なツールが見あたらなかったのでJAVAで作って見ました。
ちなみに私はJAVAのお作法などに詳しくないため(というか全く知らない)おかしなところがあるかもしれません。

ファイルにしないでコードをここに直接乗せるのはファイルのアップロード先を確保するのが面倒だからです。
てなわけで、確認のために使ったJAVAプログラムは以下の通り。

ファイル名:JAVACUIWOL.java
//
// JAVACUIWOL.java
// JAVACUIWOL
//
// Created by nova on 08/12/20.
// Copyright (c) 2008 nova. All rights reserved.
//
import java.util.*;
import java.io.*;
import java.net.*;

public class JAVACUIWOL {
public static final int DEFAULT_PORT = 9; //デフォルトポートは9とする
public static void main (String args[]) {
try {
// 引数の数をチェック
if (args.length != 2) {
throw new IllegalArgumentException("引数の数が不正です");
}
String argHostStr = args[0];
String argMacStr = args[1];

// 引数からMACアドレスを取得する
byte[] macBytes = getMacBytes(argMacStr);

// 引数からIPアドレスを取得する
SocketAddress socketAddress = getHostSocketAddress(argHostStr);

// Magic Packet を作成する
byte[] magicPacketBytes = new byte[6 + 16 * macBytes.length];
for (int i = 0; i < 6; i++) {
magicPacketBytes[i] = (byte) 0xff;
}
for (int i = 6; i < magicPacketBytes.length; i += macBytes.length) {
System.arraycopy(macBytes, 0, magicPacketBytes, i, macBytes.length);
}

// Magic Packet を送信する
DatagramPacket packet = new DatagramPacket(magicPacketBytes, magicPacketBytes.length, socketAddress);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
socket.close();

// 終了メッセージ
System.out.println(socketAddress + " へ Magic Packet を送信しました");
}
catch (Exception e) {
System.out.println("エラーが発生しました:" + e);
System.out.println("");
System.out.println("使い方");
System.out.println(" : java -cp JAVACUIWOL.jar JAVACUIWOL <host name>[:<port no>] <mac address<");
System.out.println("LAN上のPCを起動する場合にはブロードキャストアドレスで送ります");
System.out.println(" : java -cp JAVACUIWOL.jar JAVACUIWOL 192.168.0.255 01-23-45-67-89-AB");
System.out.println("DynDNSなどを使ってルータに送信する場合はホスト名でも送る事が出来ます");
System.out.println(" : java -cp JAVACUIWOL.jar JAVACUIWOL example.com 01-23-45-67-89-AB");
System.out.println("ポートの指定も可能です(デフォルトはUDP9)");
System.out.println(" : java -cp JAVACUIWOL.jar JAVACUIWOL example.com:9 01-23-45-67-89-AB");
System.exit(1);
}
}

private static byte[] getMacBytes(String argMacStr) throws IllegalArgumentException {
// MACアドレスの文字列を6個に区切る
String[] macHexStrs;
if (argMacStr.length() == 12) {
macHexStrs = new String[6];
for (int i = 0; i < 6; i++) {
macHexStrs[i] = argMacStr.substring(i*2, i*2+1);
}
}
else if (argMacStr.length() == 17) {
macHexStrs = argMacStr.split("(\\:|\\-)");
if (macHexStrs.length != 6) {
throw new IllegalArgumentException("MACアドレスの形式が不正です");
}
}
else {
throw new IllegalArgumentException("MACアドレスの形式が不正です");
}

// MACアドレスをバイト配列に変換する
byte[] macBytes = new byte[6];
try {
for (int i = 0; i < 6; i++) {
macBytes[i] = (byte) Integer.parseInt(macHexStrs[i], 16);
}
}
catch (NumberFormatException e) {
throw new IllegalArgumentException("MACアドレスの形式が不正です");
}
return macBytes;
}

private static SocketAddress getHostSocketAddress(String argHostStr) throws IllegalArgumentException {
String[] hostStrs = argHostStr.split(":");
String hostName;
int portNo;
SocketAddress sa;

if (hostStrs.length == 1 ) {
hostName = hostStrs[0];
portNo = DEFAULT_PORT;
}
else if (hostStrs.length == 2) {
hostName = hostStrs[0];
try {
portNo = Integer.parseInt(hostStrs[1]);
}
catch (NumberFormatException e) {
throw new IllegalArgumentException("ホストのポート指定が不正です");
}
}
else {
throw new IllegalArgumentException("ホスト名の指定が不正です");
}

try {
sa = new InetSocketAddress(hostName, portNo);
return sa;
}
catch (Exception e) {
throw new IllegalArgumentException("ホスト名の指定が不正です");
}
}
}

使い方はテキストエディタで JAVACUIWOL.java を作成し、
javac JAVACUIWOL.java

で、コンパイル
java JAVACUIWOL <ホスト名> <MACアドレス>

で実行です。

恥ずかしい間違いを犯していなければよいのですが…自信ないなぁorz

0 件のコメント: