C# + SharpPcap を使って、他の端末のWakeOnLANやシャットダウンをしてみる

最近開発で使う端末が増えたのですが、その分各端末を手動で起動・シャットダウンするのが手間になりました。


そのため、WakeOnLANやシャットダウンができるツールを探してみたところ、いろいろとありました。
ただ、C#でネットワーク周りのコードを書いたことがなかったため、どんな書き方をするんだろうと自作してみることにしました。



Wake On LAN部分

Wake On LANで使うマジックパケットの仕様は以下の通りでした。
Wake-on-LAN - Wikipedia


今回はDHCPを使っている端末も含まれていたため、起動させたい端末のMACアドレスを知るために以下の変換を行うことにしました。

  1. ホスト名→IPアドレスの変換
  2. IPアドレスMACアドレスの変換


ホスト名→IPアドレスの変換は、.NETの以下のメソッドを使えばできました。

System.Net.Dns.GetHostAddresses(hostName)


IPアドレス→ホスト名の変換も.NETにあるのかなと思っていましたが、自分の端末のインタフェースは

System.Net.NetworkInformation.NetworkInterface.GetPhysicalAddress()

で取得できるものの、自分以外の端末のMACアドレスは取得することができないようでした。


他の方法を探してみたものの、

  • System.ManagementScopeを使う
  • arp.exeを使う
  • Win32APIを使う

と少々敷居が高そうだったので、ライブラリを探してみたところ、「SharpPcap」がありました。
SharpPcap プロジェクト日本語トップページ - SourceForge.JP


SharpPcapでは、

など、必要なことができそうだったので、これを使うことにしました。
c# - How to send a WOL package(or anything at all) through a nic which has no IP address? - Stack Overflow



シャットダウン部分

.NETでは機能が見当たりませんでしたので、他の方法を探してみました。
.net - How to shutdown the computer from C# - Stack Overflow


いろいろとあるのですが、結局お手軽な「shutdown」コマンドを使うことにしました。



環境

公式サイトよりダウンロード・インストールします。
WinPcap · Download


インストールしていない場合、実行時に以下のエラーとなりました。

ハンドルされていない例外: System.DllNotFoundException: DLL 'wpcap' を読み込めません:指定されたモジュールが見つかりません。 (HRESULT からの例外:0x8007007E)
  • SharpPcap 4.2.0

NuGetにてインストールすれば、依存しているものも入ります*1

  • Command Line Parser Library 1.9.71

コマンドライン引数の扱いを容易にするため、NuGetにてインストールします。



悩んだことなど

有効なネットワークインタフェースの判定

ネットワークインターフェースは、

SharpPcap.LibPcap.LibPcapLiveDeviceList.Instance

にて取得することができましたが、仮想環境とかを作っていると複数のインタフェースが取得できます。そのため、どれを有効なものと判断するか迷いました。


ただ、手元の環境ではデフォルトゲートウェイが設定されているかどうかで判断できそうだったので、それを採用しました。他の環境では異なると思いますが...



SharpPcapでのMACアドレス収集

ARP.Resolve()メソッドを使えば、対象のIPアドレスからMACアドレスを取得できます。
SharpPcap.ARP


なお、ARPを利用していることから、シャットダウン中の端末のMACアドレスは収集できませんでした。



対象端末を記載したファイルについて

いろいろとありますが、xmlだと手軽に記載できなかったので、お手軽なcsvファイルを使うことにしました。


NuGetの利用

今回初めてNuGet(NuGet 2.8)を使いました。
GitHubのVisualStudio向け.gitignoreを入れてGitHubへとcommit・pushした後、cloneしてみました。


ソリューションを開いた当初は、

参照コンポーネント 'CommandLIne' が見つかりませんでした
参照コンポーネント 'PacketDotNet' が見つかりませんでした
参照コンポーネント 'SharpPcap' が見つかりませんでした

という警告がでたものの、そのままビルドしてみたところ、

ファイル packages.configに一覧表示されているNuGetパッケージを復元しています

と表示され、必要なNuGetパッケージはすべて復元され、ビルドも正常に終わりました。


なお、デスクトップアプリだったせいか、NuGet.Configが無くてもパッケージは復元されました。
NuGet 2.7 と Visual Studio におけるパッケージ復元機能の強化 - THE TRUTH IS OUT THERE - Site Home - MSDN Blogs



ソースコード

GitHubに上げておきました。
thinkAmi/WakeOnLAN-Shutdown · GitHub




グループポリシーオブジェクトのローカルコンピューターポリシーにある「スクリプト(スタートアップ/シャットダウン)」などに仕込むことで、自分の端末と連動して起動/シャットダウンができるようになりました。



*1:似たパッケージとしてSharp_Pcapというものがあったものの、正確なのはSharpPcap