什么是SharpPcap
最近嘛,要写各种课设,计网也要
课设就算了,里面还有一个网络编程
要求捕获些IP数据报,并输出些IP数据报里面的一些数据
然后一看要求,霍,好家伙,能用C#,那就简单了
说回正题,要了解什么是SharpPcap,就要先了解WinPcapWinPcap是在windows下抓包的工具集合,相当于一个抓包的api
有了这个,我们就不需要直接与网卡打交道了,要抓包,直接调WinPcap提供的api
SharpPcap就是把这些api打包成C#的形式,让我们可用在C#中方便的抓包
安装
这个就很简单了,直接到Nuget包管理器里面安装就是了
(@ 24-01-11)
其实应该用NPcap的,这个比较新,WinPcap有点老了
WinPcap调用不了无线网卡
这两个SharpPcap都可以调用
NPcap下载
在写代码前,还要检查下又没有安装过WinPcap,没有的话会找不到捕获的设备
WinPcap下载
这个也是装上就完事了
写代码
需要注意的是,SharpPcap貌似重构过好多次,我看到的使用范例有好几版
但都没用,最后还是靠我自己反编译看的
(GitHub那里的范例也是不能直接用的)
总之,我这里用的是6.2.5的版本,别的版本我不管
丢一段代码,里面带着详细的注释(这段代码也是我计网课设网络编程的代码)
(@ 24-01-11)
稍微修改下,原来的代码在处理标识符的逻辑点问题
(转成BitArray会出现高低位顺序的问题)
using System;
using SharpPcap;
using PacketDotNet;
using System.Collections;
namespace Test
{
public class Program
{
static void Main()
{
CaptureDeviceList devices = CaptureDeviceList.Instance;//获取所有可用的设备
if (devices.Count < 1)
{
Console.WriteLine("No devices were found on this machine");
return;
}//没有就直接退出了
Console.WriteLine("\nThe following devices are available on this machine:");
Console.WriteLine("----------------------------------------------------\n");
for (int i = 0; i < devices.Count; i++)
{
Console.WriteLine($"index:{i}|{devices[i].Description}\n");
}//输出可用的设备及其编号
string num = Console.ReadLine();//获取用户输入的编号
ICaptureDevice device = devices[int.Parse(num)];//获取对应的设备对象
device.Open(DeviceModes.Promiscuous, 10000);//准备启动设备
string filter = "ip";
device.Filter = filter;//设置过滤器为ip数据报
device.OnPacketArrival += Device_OnPacketArrival;//设置收到包后的回调方法
device.StartCapture();//开始捕捉
Console.ReadLine();
device.StopCapture();//如果按下任意键,终止捕捉
device.Close();//释放设备
}
private static void Device_OnPacketArrival(object sender, PacketCapture e)
{
var ip = e.GetPacket().GetPacket().Extract<IPPacket>();//把捕捉到的包转换成ip数据报
//因为库里没有处理标识符和片偏移的逻辑,这里要自己写处理逻辑
var s = new BitArray(new byte[] { ip.HeaderData[5], ip.HeaderData[4] });//获取第5第6字节的数据
var symbol = new BitArray(new byte[] { ip.HeaderData[7], ip.HeaderData[6] });//获取第7第8字节的数据
Console.WriteLine();
Console.WriteLine($"Version:\t{ip.Version}");
Console.WriteLine($"Length:\t\t{ip.TotalLength}");
Console.WriteLine($"Serial:\t\t{BitArrayToInt(s, 0, 15)}");
Console.WriteLine($"DF:\t\t{symbol[14]}");
Console.WriteLine($"MF:\t\t{symbol[13]}");
Console.WriteLine($"Offest:\t\t{BitArrayToInt(symbol, 0, 12)}");
Console.WriteLine($"From:\t\t{ip.SourceAddress}");
Console.WriteLine($"To:\t\t{ip.DestinationAddress}");
Console.WriteLine($"Protocol:\t{ip.Protocol}");
for (int i = 0; i < ip.HeaderData.Length; i++)
{
if (ip.HeaderData[i] < 16)
{
Console.Write("0{0:X} ", ip.HeaderData[i]);
}
else
{
Console.Write("{0:X} ", ip.HeaderData[i]);
}
if (i % 4 == 3)
{
Console.WriteLine();
}
}
Console.WriteLine();
}
static int BitArrayToInt(BitArray bitArray, int head, int end)//只是个把二进制数组转换成数字的方法
{
int a = 0;
for (int i = head; i <= end; i++)
{
if (bitArray[i])
{
a += 1;
}
a *= 2;
}
return a;
}
}
}
实际上确实就这么一段代码就够了
里面的注释也已经点明了具体的功能
需要注意的是,这里通过事件机制来处理收到包的情况
也就是这一句
device.OnPacketArrival += Device_OnPacketArrival;//设置收到包后的回调方法
在device收到数据报后,会触发OnPacketArrival事件
然后就可用用事件那一套机制来处理收到的包了,也就是这一段代码
private static void Device_OnPacketArrival(object sender, PacketCapture e)
{
var ip = e.GetPacket().GetPacket().Extract<IPPacket>();//把捕捉到的包转换成ip数据报
//因为库里没有处理标识符和片偏移的逻辑,这里要自己写处理逻辑
var s = new BitArray(new byte[] { ip.HeaderData[5], ip.HeaderData[4] });//获取第5第6字节的数据
var symbol = new BitArray(new byte[] { ip.HeaderData[7], ip.HeaderData[6] });//获取第7第8字节的数据
Console.WriteLine();
Console.WriteLine($"Version:\t{ip.Version}");
Console.WriteLine($"Length:\t\t{ip.TotalLength}");
Console.WriteLine($"Serial:\t\t{BitArrayToInt(s, 0, 15)}");
Console.WriteLine($"DF:\t\t{symbol[14]}");
Console.WriteLine($"MF:\t\t{symbol[13]}");
Console.WriteLine($"Offest:\t\t{BitArrayToInt(symbol, 0, 12)}");
Console.WriteLine($"From:\t\t{ip.SourceAddress}");
Console.WriteLine($"To:\t\t{ip.DestinationAddress}");
Console.WriteLine($"Protocol:\t{ip.Protocol}");
for (int i = 0; i < ip.HeaderData.Length; i++)
{
if (ip.HeaderData[i] < 16)
{
Console.Write("0{0:X} ", ip.HeaderData[i]);
}
else
{
Console.Write("{0:X} ", ip.HeaderData[i]);
}
if (i % 4 == 3)
{
Console.WriteLine();
}
}
Console.WriteLine();
}
这里的e就是捕获到的包,然后就可用进行一系列的处理了