A certain engineer "COMPLEX"

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

前回はPcap.Netでキャプチャを実施しました。

Introduction


今回はSharpPcapを使います。ライセンスはLGPLです。

sharppcap - Fully managed, cross platform (Windows, Mac, Linux) .NET library for capturing packets

Nugetにパッケージはありますが、またも公式では無い様子。
githubに公式ページがありますが、Nugetについて言及が無いので、野良配布でしょう。
なので、githubのリリースページから最新版を入手します。
2017年3月末時点で4.2.0が最新版です。

Pcap.Netとは異なり、バイナリにx86版とx64版はありません。

  • SharpPcap.dll
  • PacketDotNet.dll

なので、前回と違って気にすることは少ないです。
また、SharpPcapはPacket.Netというライブラリに依存しています。こちらもLGPLです。

今回のソースは下記になります

Sample source code for Demonstration, Experiment and Test - takuya-takeuchi/Demo

Source


前回と同じ、Xamlです。
また、前回はinterfaceを駆使しているため、編集するソースは1ファイルだけになります。
実装をinterfaceで分離したかいがありました。

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

  • lib\SharpPcap-4.2.0\Release\SharpPcap.dll
  • lib\SharpPcap-4.2.0\Release\PacketDotNet.dll

PacketCaptureService

前回のソースを基準にしますので、interfaceは一切変更しません。
Pcap.NetのクラスをSharpPcapのクラスに置換したりするだけです。
修正ファイルは、PacketCaptureService.cs のみです。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PacketDotNet;
using SharpPcap;
using WPF.PacketCapture.Models.Interfaces;
using WPF.PacketCapture.Services.Interfaces;

namespace WPF.PacketCapture.Services
{

public sealed class PacketCaptureService : IPacketCaptureService
{

#region Methods

public IEnumerable<IPacketCaptureDeviceModel> GetAllDevices()
{
return CaptureDeviceList.Instance.Select(device => new PacketCaptureDeviceModel(device));
}

#endregion

private sealed class PacketCaptureDeviceModel : IPacketCaptureDeviceModel
{

#region Events

public event EventHandler<IPacketModel> PacketReceived;

#endregion

#region Fields

private readonly ICaptureDevice _Device;

private Task _Task;

#endregion

#region Constructors

public PacketCaptureDeviceModel(ICaptureDevice device)
{
this._Device = device;
this._Device.OnPacketArrival += this.OnPacketReceived;
}

#endregion

#region Properties

public string Description => this._Device.Description;

public string Name => this._Device.Name;

#endregion

#region Methods

public void StartCapture()
{
this._Device.StopCapture();

// read timeout
var timeout = 1000;
this._Device.Open(DeviceMode.Promiscuous, timeout);
this._Device.Filter = "ip and tcp and port http";

this._Task?.Dispose();
this._Task = Task.Run(() =>
{
try
{
this._Device.StartCapture();
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
}

public void StopCapture()
{
try
{
// 停止時に例外を投げるが原因が不明
this._Device.StopCapture();
}
catch (Exception e)
{
Console.WriteLine(e);
}

this._Task?.Dispose();
}

#region Helper Methods

private void OnPacketReceived(object sender, CaptureEventArgs captureEventArgs)
{
this.PacketReceived?.Invoke(this, new PacketModel(captureEventArgs.Packet));
}

#endregion

#endregion
}

private sealed class PacketModel : IPacketModel
{

#region Fields

private readonly Packet _Packet;

private readonly RawCapture _RawCapture;

#endregion

#region Constructors

public PacketModel(RawCapture rawPacket)
{
this._RawCapture = rawPacket;
this._Packet = Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
}

#endregion

#region Properties

public string Destination => (this._Packet.PayloadPacket as IPv4Packet)?.DestinationAddress?.ToString();

public int Length => this._Packet.Bytes.Length;

public DateTime Timestamp => this._RawCapture.Timeval.Date;

public string Source => (this._Packet.PayloadPacket as IPv4Packet)?.SourceAddress?.ToString();

#endregion

}

}

}

Pcap.Netと異なり、DestnationやSourceを取得する際に、型のキャストが必要になるのが面倒かな。
パケットはデータリンク層かもしれないので、アドレスがない可能性があるのはわかりますが。
フィルタの構文はPcap.Netと同じです。
これは、WinPcapを使っているためです。

テスト


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

Conclusion


今回も簡単にキャプチャできました。
基本的にWinPcapのラッパーなので、似た使い方になるので、移植も簡単でしたね。

Source Code

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

コメントを残す

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

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