Wake on LAN してみる Part 4 (SOCKS5 を越えて)

Wake on LAN をしてみる Part 2』 で Wake on LANJavaFX で実装する方法について書いた。
未だ完成には いたらないのものの、とりあえず、居間にいながらにして 別の部屋にある Linux サーバの電源の ON/OFF を行えるぐらいにはなった。

とりあえず、当初の目的は十分達成できたので 後は適当に画面を作れば 何となくアプリケーションは完成するはずだったのだが...

人間の欲望というのは恐ろしいもので、これだけ便利だと 居間からだけではなく、 会社からも ON/OFF できるようにしたくなる。
ネットワークにつながっていれば どこからでも一緒でしょ!! なんて言う甘い考えで試してみることに...

会社のデスクから 自宅の PC を起動するためには 会社の PC から自宅のプライベートネットワークに マジックパケットをブロードキャストしなくてはならない。
しかも

  • 自宅のルータ
  • 会社のプロキシ
という大きな壁を2つも越えて...
こんな感じで...
会社PC ----> [会社のプロキシ] ---- インターネット ----> [自宅のルータ] ----> 自宅PC
巷で ルータ越え とか プロキシ越え とか言われているやつ。

前者は利用しているルータにもよるが、大抵の場合 ルータの設定を変更するだけでなんとかなるはず...
もし、不幸にも なんともならなかったら、そんな ルータ は買い替えてしまえばよい。
で、実際何を設定すれば良いかと言うと

任意のポートに送信されてきた UDP のパケットを プライベートネットワークのブロードキャストアドレス宛に転送する
ように設定するだけで良い。
例えば、
5555 -- 転送 --> 192.168.0.255:5555
のように設定すると...
ルータの 5555 ポート (5555 でなくてもよい) 宛に マジックパケットを送信するだけで ルータが勝手にプライベートネットワークに ブロードキャストしてくれる。

早速、自宅のルータでも設定してみたのだが、なんと!!
『IP アドレス は 255 より小さな値でなければなりません。』とか言われて 255 への転送を許可してくれない。
確かに、下手に ブロードキャストアドレスに転送できてしまったら Smurf 攻撃の踏み台にされかねないので、しかたがないのだが...
とは言え、簡単にはあきらめられないので、試しに サブネットマスクを 255.255.255.128 に変更してみた。
これは、単にブロードキャストアドレスの4バイト目を 255 以外にしてみれば 良いんじゃない という安易な考えだったのだが...
なんと!!

5555 -- 転送 --> 192.168.0.127:5555
という感じで ブロードキャストアドレス 192.168.0.127 に転送するように設定できた。
家庭用ルータなんてこんなもんなんだね。^^;)

と言うことで...
早速 Linux サーバが起動されるかテストしてみたが、 もちろん問題なく起動してくれた。
ちなみに ルータのグローバルアドレスは 大抵 DHCP で割り当てられているので、 固定のドメイン名でアクセスできるように ダイナミックDNS に登録しておけば完璧だ。
これで 公衆無線LANからなら どこからでも 自宅のサーバを起動することができてとっても便利だ。

これで1つ目の壁は無事乗り越えることができたのだが...
会社から 自宅の Linux サーバを立ち上げるには まだもう一つ超えなくてはならない 『プロキシ』 という壁がある。
通常、JavaFXJava Web Start や Applet として起動するため アプリケーション側で プロキシ のことを気にする必要はない。
Java Preferences でプロキシの設定ができるからである。ちなみに 通常は システムの設定がそのまま利用される。
しかし、これは HTTP 等の TCP に限った話だ。 TCP については J2SE 5.0 で プロキシをサポートするようになったのだが、UDP については Java 6 でもサポートされていない。(詳細は こちら)

プロキシには HTTP や SOCKS など いくつかの種類があるが UDP で利用できるプロキシは SOCKS5 以外にない。
SOCKS5 は rfc1928 でちゃんとスペックが決まっているので、自前で実装することもできるのだが...
google で検索したら jsocks という Java のライブラリが見つかったので それを使うことにした。
JSch もそうだが 既存の Java のライブラリがそのまま利用できるのは JavaFX のメリットの一つでもある。
このライブラリには SOCKS5 のプロキシ経由で UDP パケットを送信するための Socks5DatagramSocket というクラスが用意されている。
使い方は いたって簡単だ。以下のように 通常の DatagramSocket の代わりに使うだけ...

import java.lang.Integer.parseInt;
import java.net.DatagramSocket;

import socks.Socks5DatagramSocket;
import socks.Socks5Proxy;

// 起動する PC の NIC の MAC アドレス
public var macAddress = "aa:bb:cc:dd:ee:ff"

// マジックパケットの送信先ホスト名 (ルータのダイナミックDNSのドメイン名)
public var host = "host.to.wake.on.lan";

// マジックパケットの送信先ポート (ルータのポート)
public var port = 5555;

// SOCKS5 プロキシサーバのホスト名 又は IPアドレス
def proxyHost = "socks5.proxy";

// SOCKS5 プロキシサーバのポート番号
def proxyPort = 1080;
   

// マジックパケット
def magicPacket = [
    for (i in [1..6]) { 0xff }
    for (i in [1..16], b in macAddress.split("-|:")) { parseInt(b, 16) }
];

// プロキシサーバ
def proxy = new Socks5Proxy(proxyHost, proxyPort);
proxy.resolveAddrLocally(false);

// マジックパケットを任意のポートにブロードキャストするための UDPデータグラムパケット
// ここでは送信先のホスト名は指定してはいけない。
// プロキシの内側のネットワークでは外部のネットワークの名前解決ができない場合があるため...
def packet = new DatagramPacket(magicPacket, sizeof magicPacket, null, port);

// プロキシサーバ経由で マジックパケット 送信
def socket = new Socks5DatagramSocket(proxy, 0, null);
socket.send(packet, host);  // ここでホスト名を指定する。

Wake on LAN をしてみる Part 2』 のサンプルコードと見比べても そんなに違いはない。
たったこれだけのコードでプロキシを越えられるなんて少し拍子抜けしてしまったが...
これで いざというときに 会社から自宅の PC を起動することができてしまう。
なんて幸せなんだろう...
プロキシを越えられる WOL のアプリケーションは見たことがないので これはなかなかおもしろいかもしれない。

今回は起動だけしか試せなかったが 同様にサーバを停止することだってできるはずである。
これについては またの機会ということで...