使用sharppcap抓数据包

首先用到PacketDotNet,SharpPcap这两个DLL,工具Ethereal可以分析包内容

代码
class Program
{
static bool showDetails = false; //查看详情的参数
private static bool BackgroundThreadStop = false; //线程停止标识
private static object QueueLock = new object(); //线程锁变量
private static List<PacketDotNet.RawPacket> PacketQueue = new List<PacketDotNet.RawPacket>(); //待处理数据包队列

static void Main(string[] args)
{
//显示SharpPcap版本
string ver = SharpPcap.Version.VersionString;
Console.WriteLine(
"SharpPcap {0}", ver);

//获取网络设备
var devices = LivePcapDeviceList.Instance;
if (devices.Count < 1)
{
Console.WriteLine(
"找不到网络设备");
return;
}
Console.WriteLine();
Console.WriteLine(
"以下是目前本计算机上的活动网络设备:");
Console.WriteLine(
"----------------------------------------------------");
Console.WriteLine();
int i = 0;
foreach (LivePcapDevice dev in devices)
{
Console.WriteLine(
"{0}) {1} {2}", i, dev.Name, dev.Description);
i
++;
}

//选择要监听的网络设备
Console.WriteLine();
Console.WriteLine(
"--选择一个需要监听的网络设备--");
i
= int.Parse(Console.ReadLine());
LivePcapDevice device
= devices[i];
Console.Write(
"-- 请选择操作:监听通讯[C/c],多线程监听通讯[T/t],监听统计[F/f],发送随机数据包[S/s]? ");
string resp = Console.ReadLine().ToUpper();
while (!(resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T") || resp.StartsWith("S")))
{
resp
= Console.ReadLine().ToUpper();
}

try
{
if (resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T"))
{
//监听过滤条件
string filter = "ip and tcp";

//连接设备
System.Threading.Thread backgroundThread = null;
int readTimeoutMilliseconds = 1000;
if (resp.StartsWith("F"))
{
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
device.Filter
=filter;
device.Mode
= CaptureMode.Statistics; //抓包统计
device.OnPacketArrival+= new PacketArrivalEventHandler(device_OnPacketArrival); //抓数据包回调事件
device.OnPcapStatistics += new StatisticsModeEventHandler(device_OnPcapStatistics); //抓包统计回调事件
}
else if (resp.StartsWith("C"))
{
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
device.Filter
= filter;
device.Mode
= CaptureMode.Packets; //抓包数据
showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情
device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival); //抓数据包回调事件
}
else if (resp.StartsWith("T"))
{
backgroundThread
= new System.Threading.Thread(BackgroundThread);
backgroundThread.Start();
device.Open();
device.Filter
= filter;
device.Mode
= CaptureMode.Packets; //抓数据包
showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情
device.OnPacketArrival += new PacketArrivalEventHandler(device_OnThreadPacketArrival); //抓数据包回调事件
}

Console.WriteLine();
Console.WriteLine(
"-- 当前TCPdump过滤条件: \"{0}\"", filter);
Console.WriteLine(
"-- 正在监听设备 {0}, 按 '回车' 键以停止监听...", device.Description);

//开始监听
device.StartCapture();

//停止监听
Console.ReadLine();
device.StopCapture();
Console.WriteLine(
"-- 停止监听.");

if (backgroundThread != null)
{
BackgroundThreadStop
= true;
backgroundThread.Join();
}
}
else if (resp.StartsWith("S"))
{
//连接设备
device.Open();

//生成随机数据包
byte[] bytes = GetRandomPacket();

try
{
//发送数据
device.SendPacket(bytes);
SendQueue squeue
= new SendQueue(2000);
Console.WriteLine(
"-- 单个数据包发送成功.");

for (int j = 0; j < 10; j++)
{
if (!squeue.Add(bytes))
{
Console.WriteLine(
"-- 警告: 队列大小不足以存放所有数据包,将只发送部分数据包.");
break;
}
}
device.SendQueue(squeue, SendQueueTransmitModes.Synchronized);
Console.WriteLine(
"-- 数据包队列发送完毕.");
}
catch (Exception e)
{
Console.WriteLine(
"-- -- -- " + e.Message);
}
}
}
catch (Exception e)
{
Console.WriteLine(
"-- -- -- " + e.Message);
}
finally
{
if (device.Opened)
{
//断开设备连接
Console.WriteLine(device.Statistics().ToString());
device.Close();
Console.WriteLine(
"--断开设备连接");
Console.Write(
"按 '回车' 键以退出...");
Console.Read();
}
}


Console.Read();
}

/// <summary>
/// 抓包方法
/// </summary>
static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
PcapPorcessContext(e.Packet);
}

private static void PcapPorcessContext(PacketDotNet.RawPacket pPacket)
{
var time
= pPacket.Timeval.Date;
var len
= pPacket.Data.Length;
var layer
= pPacket.LinkLayerType;

Console.WriteLine(
"{0}:{1}:{2},{3} 长度={4} 第几层={5}",
time.Hour, time.Minute, time.Second, time.Millisecond, len, layer);

Console.WriteLine(
"content is {0}", Encoding.ASCII.GetString(pPacket.Data));

var packet
= PacketDotNet.Packet.ParsePacket(pPacket); //Raw基础包对象

if (layer == PacketDotNet.LinkLayers.Ethernet) //以太网包
{
var ethernetPacket
= (PacketDotNet.EthernetPacket)packet;
System.Net.NetworkInformation.PhysicalAddress srcMac
= ethernetPacket.SourceHwAddress;
System.Net.NetworkInformation.PhysicalAddress destMac
= ethernetPacket.DestinationHwAddress;
Console.WriteLine(
"MAC:{0} -> {1}", srcMac, destMac);
if (showDetails)
Console.WriteLine(
"以太网包: " + ethernetPacket.ToColoredString(false));
}
var ipPacket
= PacketDotNet.IpPacket.GetEncapsulated(packet); //ip包
if (ipPacket != null)
{
System.Net.IPAddress srcIp
= ipPacket.SourceAddress;
System.Net.IPAddress destIp
= ipPacket.DestinationAddress;

Console.WriteLine(
"IP: {0} -> {1}", srcIp, destIp);
if (showDetails) Console.WriteLine("IP packet: " + ipPacket.ToColoredString(false));

var tcpPacket
= PacketDotNet.TcpPacket.GetEncapsulated(packet); //TCP包
if (tcpPacket != null)
{
int srcPort = tcpPacket.SourcePort;
int destPort = tcpPacket.DestinationPort;

Console.WriteLine(
"TCP Port: {0} -> {1}", srcPort, destPort);
if (showDetails) Console.WriteLine("TCP packet: " + tcpPacket.ToColoredString(false));
}

var udpPacket
= PacketDotNet.UdpPacket.GetEncapsulated(packet); //UDP包
if (udpPacket != null)
{
int srcPort = udpPacket.SourcePort;
int destPort = udpPacket.DestinationPort;

Console.WriteLine(
"UDP Port: {0} -> {1}", srcPort, destPort);
if (showDetails) Console.WriteLine("UDP packet: " + udpPacket.ToColoredString(false));
}
}
}

static ulong oldSec = 0;
static ulong oldUsec = 0;
/// <summary>
/// 抓包统计方法
/// </summary>
static void device_OnPcapStatistics(object sender, StatisticsModeEventArgs e)
{
// 计算统计心跳间隔
ulong delay = (e.Statistics.Timeval.Seconds - oldSec) * 1000000 - oldUsec + e.Statistics.Timeval.MicroSeconds;

// 获取 Bits per second
ulong bps = ((ulong)e.Statistics.RecievedBytes * 8 * 1000000) / delay;
/* ^ ^
| |
| |
| |
converts bytes in bits -- |
|
delay is expressed in microseconds --
*/

// 获取 Packets per second
ulong pps = ((ulong)e.Statistics.RecievedPackets * 1000000) / delay;

// 将时间戳装换为易读格式
var ts = e.Statistics.Timeval.Date.ToLongTimeString();

// 输出统计结果
Console.WriteLine("{0}: bps={1}, pps={2}", ts, bps, pps);

//记录本次统计时间戳,以用于下次统计计算心跳间隔
oldSec = e.Statistics.Timeval.Seconds;
oldUsec
= e.Statistics.Timeval.MicroSeconds;
}

/// <summary>
///
/// </summary>
private static DateTime LastStatisticsOutput = DateTime.Now;
private static TimeSpan LastStatisticsInterval = new TimeSpan(0, 0, 2);
static void device_OnThreadPacketArrival(object sender, CaptureEventArgs e)
{
//输出设备通讯统计信息
var Now = DateTime.Now;
var interval
= Now - LastStatisticsOutput;
if (interval > LastStatisticsInterval)
{
Console.WriteLine(
"Device Statistics: " + ((LivePcapDevice)e.Device).Statistics());
LastStatisticsOutput
= Now;
}

lock (QueueLock)
{
PacketQueue.Add(e.Packet);
//将捕获到的数据包加入处理队列
}
}

/// <summary>
/// 多线程处理数据包队列
/// </summary>
private static void BackgroundThread()
{
while (!BackgroundThreadStop)
{
bool shouldSleep = true;

lock (QueueLock)
{
if (PacketQueue.Count != 0)
{
shouldSleep
= false;
}
}

if (shouldSleep)
{
System.Threading.Thread.Sleep(
250);
}
else //处理队列
{
List
<PacketDotNet.RawPacket> ourQueue; //本线程待处理队列
lock (QueueLock)
{
ourQueue
= PacketQueue;
PacketQueue
= new List<PacketDotNet.RawPacket>();
}

Console.WriteLine(
"BackgroundThread: Local Queue Count is {0}", ourQueue.Count);

foreach (var packet in ourQueue)
{
PcapPorcessContext(packet);
}
}
}
}

/// <summary>
/// 生成一个大小为200的随机数据包
/// </summary>
private static byte[] GetRandomPacket()
{
byte[] packet = new byte[200];
Random rand
= new Random();
rand.NextBytes(packet);
return packet;
}
}

原文地址:https://www.cnblogs.com/wudingfeng/p/1916931.html