首先用到PacketDotNet,SharpPcap这两个DLL,工具Ethereal可以分析包内容
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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;
}
}