前回は下準備でした。
Introduction
まずは、Pcap.Netを入手します。
Nugetにパッケージはありますが、公式では無い様子。
githubに公式ページがありますが、そこでNugetについて言及が無いので、野良配布でしょう。
なので、githubのリリースページから最新版を入手します。
注意して欲しいのは、解凍後の中身に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実装側で具象クラスを生成しますが、サービスの利用側は実際の型を意識しなくて済むので、依存性を断ち切れます。
1 | using System.Collections.Generic; |
IPacketCaptureDeviceModel
IPacketCaptureService.GetAllDevices の戻りの要素である、ネットワークキャプチャデバイスを表現します。
このinterfaceからパケットのキャプチャの開始、停止を指示します。
1 | using System; |
IPacketModel
パケットデータを表現します。
今回は、送信元アドレス、送信先アドレス、パケット長、送受信日時のみ用意します。
1 | using System; |
PacketCaptureService
今回の肝です。
型をネストしているのは、型の情報を外部が知る必要は無いですし、無関係のクラスが型を使用しないようにすることを意識させやすくするためです。
まぁprivateだからアクセスできませんが。
必要な情報は、interfaceを経由し、Pcap.Netの具体的なデータにアクセスします。
1 | using System; |
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/06_WPF.Pcap.Net1