A certain engineer "COMPLEX"

.NETでパケットキャプチャを試してみる Pcap.Net編 第1回

前回は下準備でした。

Introduction


まずは、Pcap.Netを入手します。
Nugetにパッケージはありますが、公式では無い様子。
githubに公式ページがありますが、そこでNugetについて言及が無いので、野良配布でしょう。
なので、githubのリリースページから最新版を入手します。

PcapDotNet/Pcap.Net
Pcap.Net - .NET wrapper for WinPcap written in C++/CLI and C#, which features almost all WinPcap features and includes a packet interpretation framework.

注意して欲しいのは、解凍後の中身にx86版とx64版が存在することです。
正確には、

  • PcapDotNet.Core.dll
  • PcapDotNet.Core.Extensions.dll

の2つが、x86またはx64でビルドされており、残りはAnyでビルドされています。
つまり、配布時には、これらを切り替えて実行フォルダに配置しないと System.BadImageFormatException で落ちます。
そのため、ソリューションの構成にAnyは含みませんが、参照dllはやむなくx64のPcap.Netを参照しています。
実行時にdllを適切に配置すれば良いのですが、若干気持ち悪いかな...

ソースは下記になります

Source


いつも通り、簡単にMVVMを使用して簡単なプロジェクトを作成します。
ネットワークアダプタを選択するリストボックス、選択したリストボックスに流れるHTTPトラフィックを表示するグリッドマップ、キャプチャの開始ボタンを備えています。
Xaml側は省略します。

Pcap.Netのライブラリは、sln ファイルと同じ階層にあるlibフォルダに、下記のように配置してください。

  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Base.dll
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Base.pdb
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Base.xml
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.dll
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.Extensions.dll
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.Extensions.pdb
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.Extensions.XML
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.pdb
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Core.xml
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Packets.dll
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Packets.pdb
  • \lib\PcapDotNet\PcapDotNet.Binaries.1.0.4.x64\PcapDotNet.Packets.xml

IPacketCaptureService

まず、DI(依存性注入)のため、パケットキャプチャを担当するinterfaceを定義します。
Pcap.Netとの依存性を極力減らすために、入出力の型もinterfaceに限定しています。
つまり、interface実装側で具象クラスを生成しますが、サービスの利用側は実際の型を意識しなくて済むので、依存性を断ち切れます。

IPacketCaptureDeviceModel

IPacketCaptureService.GetAllDevices の戻りの要素である、ネットワークキャプチャデバイスを表現します。
このinterfaceからパケットのキャプチャの開始、停止を指示します。

IPacketModel

パケットデータを表現します。
今回は、送信元アドレス、送信先アドレス、パケット長、送受信日時のみ用意します。

PacketCaptureService

今回の肝です。
型をネストしているのは、型の情報を外部が知る必要は無いですし、無関係のクラスが型を使用しないようにすることを意識させやすくするためです。
まぁprivateだからアクセスできませんが。
必要な情報は、interfaceを経由し、Pcap.Netの具体的なデータにアクセスします。

StartCapture が重要です。
LivePacketDevice.Openでパケットのキャプチャを開始するオブジェクトを取得します。
その後、フィルターを設定し、IPかつTCPかつHTTP以外を弾きます。
最後に、PacketCommunicator.ReceivePackets で、コールバック関数を指定してキャプチャを開始します。
注意してほしいのは、このメソッドはスレッドをブロックします。
よって、Taskによる非同期実行しています。
本当は、StartCaptureをasyncすれば良かったのですが、これで動くので良いです。

停止は、PacketCommunicator.Break を呼びます。
ただし、Task内で、InvalidOpeationExceptionを投げる原因がわかりませんので、try-catchで囲っています。
キャプチャ中に停止しているのが不味いのだと思いますが...

テスト


実際に実行してみます。
お好きなキャプチャデバイスを選択してStart Captureを押下することでキャプチャが実行されます。
HTTPのみ許容しているので、Webブラウザでどこかにアクセスしてみてください。

ちょっとマウスカーソルが途中でどこか行ったのは、Webブラウザを操作しに行ったからです。

Conclusion


簡単にキャプチャできました。
フィルタ条件が若干覚えないといけないですが、このあたりを自分が理解できやすいUIにすることで、グッと使いやすくなると思います。

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/WPF.Pcap.Net1

コメントを残す

メールアドレスが公開されることはありません。

%d人のブロガーが「いいね」をつけました。