包捕获(或数据包嗅探)是收集数据,通过特定的网络接口将所有数据包的过程。在我们的应用程序捕获网络数据包是一个强大的能力,它可以让我们写网络监控,数据包分析器和安全工具。本的libpcap库和基于UNIX系统WinPcap的用于Windows是最广泛使用的数据包捕获驱动程序监视API提供低级别的网络。其中应用程序使用的libpcap / WinPcap的包捕获子系统为是著名的tcpdump的和Wireshark的。
在这篇文章中,我们将介绍SharpPcap WinPcap的从您的。NET应用程序。)NET程序集(库接口与libpcap的或并会给你一个详细的方案编制教程教你如何使用。
背景
塔米尔加尔在2004年左右开始的SharpPcap项目。他想用在。NET应用WinPcap而在他的大学最后项目的工作。该项目涉及VoIP流量分析和解码,他想继续用C#编码具有省时,如垃圾收集功能简单。 WinPcap的API的访问似乎从净是相当流行的要求,他发现在CodeProject上的一些网站,让您做到这一点有益的项目。:
数据包捕获和分析仪 原始套接字捕获使用C#
与WinPcap的包嗅探功能移植到。NET库
第一个项目是一个伟大的空灵。NET的克隆,让您获取和分析大量的数据包的协议类型。然而,随着这个项目的几个问题使它几乎不可能得到在其他。NET应用程序共享。首先,作者没有提供用于捕获,可以通过其他。NET应用程序中使用任何通用的API包。他没有单独的UI代码和他的分析和捕获的代码,使他的捕捉代码类依赖于图形用户界面,如ListView操作。其次,由于某些原因,笔者选择了重新实现在C#由他本人,而不是仅仅WinPcap的包装他们的部分职能。这意味着他的应用程序无法利用新的WinPcap的版本的硬编码的优势,因为他在他的WinPcap的应用程序的某些版本。
第二个和第三个物品的包装项目为WinPcap的好开始,但他们没有提供一些重要的WinPcap的功能,如离线pcap的文件处理和应用内核级数据包过滤器,以及最重要的是他们提供了这样的分析没有协议分析器类包。这两个项目没有张贴的文章,以自己的库的源代码,让其他人一起延长他们的工作和增加新功能和新的数据包分析器类。
因此,塔米尔决定开始他对自己的图书馆工作。在1.x系列的几个版本发布。发展放缓对2007年年中时,在1.x系列的最后一个版本发布时,SharpPcap 1.6.2。
克里斯摩根发生在2008年11月超过SharpPcap发展。从那时起SharpPcap主要内部已重写和API改进。
2010年2月下旬,SharpPcap 3.0被释放。此版本是一个重写SharpPcap的数据包分析器。分组分析功能被打破,进入一个新的图书馆,Packet.Net。 SharpPcap注意到与libpcap的/ WinPcap的包和Packet.Net注意到接口解剖和创造护理照顾。对Packet.Net的建筑的细节将在本教程的后面讨论。
SharpPcap v3.5版本发布了2月1 ,2011年。 3.5版本包含重大的空气污染指数的变化
日
以及WinPcap的远程采集和支持AirPcap。
关于SharpPcap
的目的SharpPcap是提供一个框架NET应用程序捕获,注资。和分析网络数据包。
SharpPcap是公开和积极发展同它的源代码和文件发布在SourceForge托管。源代码补丁,以改善或解决问题欢迎通过sharppcap开发者邮件列表。错误报告,功能要求和其他查询正在积极回答问题的论坛和跟踪支持,所以如果你有任何问题请与库随时问。
SharpPcap是一个完全跨平台的库管理。同一程序集运行在微软的。NET以及单在32位和64位平台。
下面的列表说明了目前SharpPcap功能支持:
单一组件的Microsoft。NET和 Mono平台上的Windows(32位或64位)和Linux
(32或64位)和 Mac。
高性能 - SharpPcap可以捕捉足够快跟上>的3MB / s的传输速率高达SCP的 WinPcap的扩展部分支持:
o 设置内核缓冲区大小 o 注射用的数据包发送队列。
o 收集在一个特定的网络接口的网络统计
AirPcap支持
枚举和显示有关Windows机器上的物理网络接口的细节。 捕获低级别的网络数据包将通过给定的接口。 分析和解析以下协议:
o 以太网
o 血清瘦素(Linux的熟食方式采集) o ARP(地址解析协议) o IP(因特网协议):
IPv4的 IPv6的
o TCP(传输控制协议) o UDP(用户数据报协议)
o ICMP协议(Internet控制消息协议):
ICMPv4 ICMPv6报
o IGMPv2的 o PPPoE协议 o 和平之路 o LLDP功能
o 唤醒局域网(网络唤醒)
在给定接口注入的低级别的网络数据包。 处理(阅读和写作)离线数据包捕获文件。 检索的数据包接收适配器统计对比下降
请检查项目主页主页最新的更新和bug修复。
SharpPcap架构
SharpPcap具有层状结构,在顶层的类,所有设备的工作:
CaptureDeviceList -检索系统名单上的所有设备
OfflineCaptureDevice -文件读取装置从一个pcap的捕捉 ICaptureDevice -所有的捕捉设备有ICaptureDevice接口
该命名空间的布局层次:
libpcap的
o LibPcapLiveDevice -一个ICaptureDevice
o LibPcapLiveDeviceList -检索一个名单LibPcapLiveDevice设备(其
中包括pcap的/ WinPcap的和airpcap设备)
WinPcap的
o WinPcapDeviceList -检索一个名单WinPcapDevices(其中包括
WinPcap的和airpcap设备)
o WinPcapDevice -阿LibPcapLiveDevice额外WinPcap的功能和接
口
AirPcap
o AirPcapDeviceList -检索一个名单AirPcapDevices o AirPcapDevice -阿WinPcapDevice额外AirPcap功能和接口
CaptureDeviceList返回一个设备清单完全分化。这意味着每个ICaptureDevice由
归国CaptureDeviceList要么是LibPcapLiveDevice,一WinPcapDevice或AirPcapDevice。这使您可以检索整个列表的设备和差异化在每个设备类型看。如果你想获得一个特定的特定类型的设备只,你可以使用一个*DeviceList类。
Collapse | Copy Code
/ /检索所有捕获设备 = CaptureDeviceList VaR的装置; / /类型的区分依据 的foreach(ICaptureDevice dev的设备中) { 如果(dev 是 AirPcapDevice) { / /过程作为AirPcapDevice } 否则如果(dev 是 WinPcapDevice) { / /过程作为WinPcapDevice } 否则如果(dev 是 LibPcapLiveDevice) { / /过程作为LibPcapLiveDevice } } Collapse | Copy Code / /只检索WinPcap的(和AirPcap设备) = AirPcapDeviceList VaR的装置; 的foreach(AirPcapDevice dev的设备中) { / /处理该AirPcap设备 } Packet.Net结构和用法
Packet.Net切换从2.x到SharpPcap继承模型的嵌套包之一。所有的数据包包含一个
Packet PayloadPacket属性和一个Byte[] PayloadData财产。一个或多个这些都
不能有效。以太网上的TCP数据包捕获的可能EthernetPacket“ - > IPv4包 - >”TCP数据包。在Packet.Net时,TCP数据包可能被访问一样
capturedPacket.PayloadPacket.PayloadPacket而是要帮助用户从static GetEncapsulsted()方法被添加,因此用户可以做的var tcpPacket = TcpPacket.GetEncapsulated(capturedPacket);。
该GetEncapsulated()方法是很聪明,设计工作在许多不同的情况。
UdpPacket.GetEncapsulated()将返回EthernetPacket UDP包的数据包,包括“ - >
IP数据包” - > UdpPacket或Linux熟捕捉- >“知识产权” - > UdpPacket或
EthernetPacket - >“的PPPoE - >”和平之路“ - >知识产权 - >”UdpPacket。我们建议使用GetEncapsulated()方法来检索子数据包。 随着Packet.Net,建设包是这样的:
Collapse | Copy Code 使用 PacketDotNet; ushort的 tcpSourcePort = 123; ushort的 tcpDestinationPort = 321; 风险 tcpPacket = 新 TcpPacket(tcpSourcePort,tcpDestinationPort); 风险 ipSourceAddress = System.Net.IPAddress.Parse(“192.168.1.1”); 风险 ipDestinationAddress = System.Net.IPAddress.Parse(“192.168.1.2”); 风险 ipPacket = 新 IPv4Packet(ipSourceAddress,ipDestinationAddress); 风险 sourceHwAddress =“90-90-90-90-90-90”; 风险 ethernetSourceHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(sourceHwAddress); 风险 destinationHwAddress =“80-80-80-80-80-80”; 风险 ethernetDestinationHwAddress = / /注意:使用EthernetPacketType.None说明了以太网 / /协议类型的更新是基于数据包有效载荷 / /分配给特定的以太网包 风险 ethernetPacket = 新 EthernetPacket(ethernetSourceHwAddress, ethernetDestinationHwAddress, EthernetPacketType.None); / /现在所有的数据包缝在一起 ipPacket.PayloadPacket = tcpPacket; ethernetPacket.PayloadPacket = ipPacket; / /并打印出包地看到,它看上去就像我们希望它 Console.WriteLine(ethernetPacket.ToString()); / /要检索的字节表示这个新创建 / / EthernetPacket使用属性的字节 字节 [] packetBytes = ethernetPacket.Bytes; System.Net.NetworkInformation.PhysicalAddress.Parse(destinationHwAddress); SharpPcap教程:一步步教您使用SharpPcap
例子可以发现,在示例/包目录源。
本教程的文本,这是直接取自WinPcap的的官方教程,但修改以显示C#中使用SharpPcap库。所有的例子可以下载连同SharpPcap此网页的源代码从顶部。如果您是Windows上运行,WinPcap的库必须安装运行的例子,然后再尝试任何这些,所以请下载并安装最新版本的WinPcap的的下载页面。如果Mac运行在Unix / Linux /时,libpcap库必须安装使用你的系统软件管理系统。
涵盖以下主题在这方面与在括号中的实例名称教程:
1. 获取设备列表(例1)
2. 打开适配器并捕获数据包(示例3) 3. 4)捕获的数据包,但无事件(例 4. 过滤流量(例5) 5. 解读包(例6)
6. 脱机处理转储文件(例8) 7. 发送数据包(例9)
8. 发送队列(例10) - WinPcap的唯一
9. 11)收集统计数据在网络上的流量(例如- WinPcap的唯一 10. 后台处理数据包队列-高封包捕获率
获取设备列表(例如,在源码包1) 通常,第一个事,一个SharpPcap为基础的应用程序是得到一个连接的网络适配器的列表。 SharpPcap提供了一个类,CaptureDeviceList用于这一目的。这个类是一个单实例,持有型缓存网络适配器列表ICaptureDevice。特别是,Name和Description属性包含人类可读的名称和描述,分别对相应的设备。下面的C#示例显示了如何检索适配器列表和打印在屏幕上,印刷错误,如果没有适配器发现: Collapse | Copy Code / /打印SharpPcap版本 字符串版本= SharpPcap.Version.VersionString; Console.WriteLine(“{0} SharpPcap,Example1.IfList.cs”,版本); / /检索设备列表 CaptureDeviceList设备= CaptureDeviceList.Instance; / /如果没有设备被发现打印错误 如果(devices.Count“1) { Console.WriteLine(“设备不被发现本机”); 返回 ; } Console.WriteLine(“\\ n以下是机器设备可以用这样的:”); Console.WriteLine(“--------------------------------------------- ------- \\ ñ“); / /打印出可用的网络设备 的foreach(ICaptureDevice dev的设备中) Console.WriteLine(“{0} \\ N”的,dev.ToString()); Console.Write(“点击'输入'退出...”); Console.ReadLine(); 上述应用程序的输出会是这样的: Collapse | Copy Code ç:\\ sharppcap \\实例\\ Example1.IfList \\ bin \\目录调试“> Example1.IfList.exe SharpPcap 3.5.0.0,Example1.IfList.cs 以下是这台机器上的设备可供选择: -------------------------------------------------- - 接口:名称:\\ Device \\ NPF_ {D8B7C9B2 - D53D - 45DA - ACF0 - 2E2116F97314} 的FriendlyName:局域网连接2 描述:英特尔(R)PRO/1000 MT台式机适配器 地址: 地址:为fe80::b444:92d8:c882:8227 网络掩码: Broadaddr: 地址: 地址:10.0.2.15 网络掩码:255.255.255.0 Broadaddr:255.255.255.255 地址: 地址:硬件地址:0800276AC792 标志:0 按'Enter'键退出... 打开一个适配器和捕获数据包(例如,在源码包3)
现在,我们已经看到了如何获得一个适配器一起玩,让我们开始真正的工作,打开适配器并捕获一些交通。在本节中,我们将编写一个程序,打印一些通过适配器每个数据包信息流。 该函数打开一个捕获装置是Open()重载是如下一些论据:
Open()
Open(DeviceMode mode)
Open(DeviceMode mode, int read_timeout)
以上两个论点值得一些进一步的解释。 DeviceMode:在正常模式(DeviceMode.Normal),网络适配器只捕获的数据包直接解决它;在网络上的其他主机的数据包交换的被忽略。相反,当适配器(处于混杂模式DeviceMode.Promiscuous),它捕获所有的数据包不管是不是注定它或。这意味着,在共同的媒介(如非交换以太网),libpcap的/ WinPcap的将能够捕捉到其他主机的数据包。混杂模式是应用程序的默认大多数捕捉,所以我们能够例如它在以下方面:。注意混杂模式,可以通过网络检测手段,如果你是在混杂模式捕获您可能能够被检测到其他实体在网络上。搜索“发现混杂”通过获取更多信息网上搜索引擎。 read_timeout:指定读取超时毫秒,在。一个读了适配器(例如,使用GetNextPacket()函数)将总是返回后read_timeout毫秒,即使没有数据包网络可从。read_timeout还定义统计报告之间的间隔如果适配器模式在统计(见在网络流量收集统计数据的部分)。设置read_timeout以0表示没有超时,数据包到达一个适配器上的阅读永远不会返回,如果没有。甲-1方超时而导致适配器读取上总是立即返回。 下面的例子显示了使用OnPacketArrival事件接收数据包。我们创建一个事件处理程序被称为每当一个新的包是经历ICaptureDevice: Collapse | Copy Code / /提取设备的清单 ICaptureDevice设备=器件[我]; / /注册的处理函数的 / /'包到来的事件 device.OnPacketArrival + = 新 SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival); / /打开设备捕捉 诠释 readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous,readTimeoutMilliseconds); Console.WriteLine(“ - ...监听{0},按'回车'停止”, device.Description); / /开始捕获过程 device.StartCapture(); / /等待'回车'从用户。 Console.ReadLine(); / /停止捕获过程 device.StopCapture(); / /关闭pcap的设备 device.Close(); 这里是我们的包处理程序的执行情况: Collapse | Copy Code / / / <摘要> / / /打印的时间和长度分别获得分组 / / / 摘要> 私有静态无效 device_OnPacketArrival(对象发件人,CaptureEventArgs包) { DateTime的时间= packet.Timeval.Date; 诠释长度= packet.Data.Length; Console.WriteLine(“{0}:{1}:{2},{3} {4}长度=” time.Hour,time.Minute,time.Second,time.Millisecond,len个); } 一旦适配器被打开,可以开始捕捉与StartCapture()或Capture(int packetCount)功能。这两个函数非常相似,所不同的是StartCapture()是一个非阻断功能,启动新的线程捕获进程A,而Capture(int packetCount)直至块packetCount包已被抓获。当使用StartCapture()我们应该以后调用StopCapture()终止捕获过程。为了捕捉下去,调用Capture()方法。
这些功能都需要一个用于处理数据包的事件处理程序调用它们前登记。此事件处理程序调用
ICaptureDevice为每个新的网络数据包,并接收来自发送者对象,调用该处理程序(即ICaptureDevice对象)和实际收到的Packet,包括所有的协议头。请注意该帧的CRC
通常不会在报文中,因为它是由框架验证后的网络适配器中删除。还要注意的是大多数适配器丢弃错误的CRC,所以WinPcap的包(因此SharpPcap)通常无法捕捉他们。
该Packet类表示一个通用分组网络捕捉到的。每一个这样的数据包有一个PcapHeader的TIMESTAMP属性包含了捕获的数据包的长度和捕获)的有关数据包信息(例如。上面的例子中提取和长度从每一个时间戳Packet对象,并打印在屏幕上。
请注意,处理程序代码是由所谓的ICaptureDevice,因此,用户应用程序没有在它的直接控制。另一种方法是使用GetNextPacket()函数,它在未来的一段介绍。
如果没有事件处理程序(例如,在源码包4)捕获数据包
在本节中的示例程序中的行为完全像前面的示例,但它使用
ICaptureDevice.GetNextPacket()事件处理方法,而不是注册一个。该
OnPacketArrival事件是一个很好的做法,可在一次捕捉设备从几个不错的选择在这样一
些情况,因为当。但是,处理回调有时并不实用 - 它往往使得程序更加复杂,特别是在多线程应用程序的情况。在这种情况下,GetNextPacket()检索直接调用一个包,一-使用GetNextPacket()数据包只收到当程序员想用它们。在下面的程序,我们重新使用以前的示例中的事件处理程序代码和移动循环它成一个函数调用后立即在主要以GetNextPacket() 注意:下面的例子将退出如果MS超时到期的1000网络上没有数据包: Collapse | Copy Code / /提取设备的清单 ICaptureDevice设备=器件[我]; / /打开设备捕捉 诠释 readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous,readTimeoutMilliseconds); Console.WriteLine(); Console.WriteLine(“ - }...\"监听{0, device.Description); 分组包= 0; / /保存捕获数据包使用GetNextPacket() 而((包= device.GetNextPacket())!= 空) { / /打印的时间和收到的每个数据包的长度 DateTime的时间= packet.PcapHeader.Date; 诠释长度= packet.PcapHeader.PacketLength; Console.WriteLine(“{0}:{1}:{2},{3} {4}长度=” time.Hour,time.Minute,time.Second, time.Millisecond,len个); } / /关闭pcap的设备 device.Close(); Console.WriteLine(“ -捕捉停止,装置关闭。”); 过滤交通(例如在源码包5)
由libpcap和WinPcap的提供了最强大的功能之一就是过滤引擎。它提供了非常有效的方式来接收网络流量的子集。 WinPcap的和libpcap拥有一个完整的编译器,它接受一个string包含一个高层次的布尔(过滤器)的表达,并产生一个低级别的字节代码,可以通过数据包捕获驱动程序解释的过滤器的发动机。作为tcpdump的布尔语法)表达式的语法(也称为被广泛用于许多应用的libpcap和WinPcap的除外。你可以找到它的规格在WinPcap的文档页面,或者如果您运行的是通过Linux的人pcap的过滤器'。
该Filter属性相关联过滤器,捕捉器。一旦Filter设置,相关的过滤器将被应用到所有的数据包来自于网络,所有的符合性的数据包(即包为其布尔表达式的值为true)将实际复制到应用程序。下面的代码演示如何编译和设置过滤器。 请注意的libpcap / WinPcap的的表达式编译器要求掩码由ICaptureDevice传递连同过滤器,因为编译器创建的一些过滤器需要它。然而SharpPcap需要通过自动提取从适配器掩码它照顾我们。 该过滤器的表达我们在下面的代码片段使用“IP和TCP”,这意味着“只保留数据包是IPv4和TCP和提供这些应用程序”: Collapse | Copy Code / /打开设备捕捉 诠释 readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous,readTimeoutMilliseconds); / / tcpdump的过滤器,只捕获的TCP / IP数据包 字符串过滤=“IP和TCP”; device.Filter =过滤器; Console.WriteLine(); Console.WriteLine(“ -下tcpdump的过滤器将被应用于:\\”{0} \\“”, 过滤器); Console.WriteLine(“ - ...监听{0},按'回车'停止”, device.Description); / /开始捕获数据包无限期 device.Capture(); / /关闭pcap的设备 / /(注:这条线将永远不会被调用,因为 / /我们捕捉无限期 device.Close(); 口译(在源代码包示例6)包
现在,我们能够捕捉和过滤网络流量,我们希望把我们的知识,可以用一个简单的“真实世界”的申请。在这一课,我们将采取从前面的代码,并使用这些作品建立一个更加有用的程序。当前计划的主要目的是展示如何捕获的数据包的协议头可以解析和解释。由此产生的程序,名字叫
DumpTCP,打印网络摘要对我们的TCP流量。我选择了解析和显示TCP协议(UDP的例子,
而不是在原来的教程贴),因为它是一个更加有趣比UDP和SharpPcap它不需要太多的编码解析。
Collapse | Copy Code
/ / / <摘要> / / /打印的时间,长度,源IP, / / /源端口,DST的IP和端口的DST / / /为每个TCP / IP数据包在网络上收到 / / / 摘要> 私有静态无效 device_OnPacketArrival( 对象发件人,CaptureEventArgs五) { 风险值的TCP = TcpPacket.GetEncapsulated(e.Packet); 如果(技术合作计划!= 空) { DateTime的时间= e.Packet.Timeval.Date; 诠释长度= e.Packet.Data.Length; 串 srcIp = tcp.SourceAddress; 串 dstIp = tcp.DestinationAddress; Console.WriteLine(“{0}:{1}:{2},{3} {4}长度=” time.Hour,time.Minute,time.Second, time.Millisecond,len个); Console.WriteLine(e.Packet.ToString()); } } 如果你在看一个UDP的例子原WinPcap教程,你将看到它是多么复杂的报文解析(虽然UDP是一个简单的TCP解析位比在我们的例子)提供直接从数据字节的原始WinPcap的库。幸运的是,SharpPcap提供了一些有用的数据包进行分析一些常见的协议(例如TCP,UDP和ICMP和其他)类。这些分析类是直接的C#最初是从翻译JPcap,一个libpcap的Java包装/ WinPcap的类似SharpPcap,但已作出重大改变,使他们更好地适应。NET中。所有代码的数据包解析和生成可以发现,在PacketDotNet命名空间中PacketDotNet大会。 正如你可以看到,在我们的包处理,我们首先尝试提取的TCP报文的那包就行了捕获封装。如果一个人发现了,它应该是唯一的选择,因为我们的TCP数据包过滤器,我们就可以访问其属性。如果我们也希望看到的IP数据包通过这些属性是可以访问var ip = IpPacket.GetEncapsulated(e.Packet); Collapse | Copy Code 可用设备: ------------------ 1)英特尔(R)PRO/1000吨移动连接 (微软的数据包调度程序) - 请选择一个设备捕捉:1 - 英特尔听力(R)的PRO/1000吨移动连接 - (微软的数据包调度程序)... 1:18:17,675长度= 123 66.102.7.147:80 - >“10.21.98.21:43501 1:18:17,675长度= 80 10.21.98.21:43501 - >“66.102.7.147:80 1:18:17,919长度= 54 66.102.7.147:80 - >“10.21.98.21:43501 最后三个行,每行代表一个不同的数据包。 脱机处理转储文件(例如,在源码包8) 在本节中,我们将学习如何处理数据包捕获到一个文件(转储到文件)。 Libpcap的/ WinPcap的提供内置的保存到一个文件中的网络通信功能和读取的转储内容 - 这部分将教你如何完成与SharpPcap这一点。为转储文件的格式是libpcap的一个。这种格式包含了二进制数据捕获的数据包的形式,广泛应用于许多网络工具,包括的wireshark,windump,tcpdump和snort的使用标准。因此,任何转储文件中,我们创建使用SharpPcap可与上述工具和其他人可以通过这些工具创建的文件SharpPcap打开任何打开。 保存数据包转储文件 首先,让我们来看看如何写libpcap文件格式的数据包。下面的示例捕获从选定的接口的数据包并将其保存在一个文件的名称是由用户提供他们: Collapse | Copy Code Console.Write(“ -请输入输出文件名:”); 串 capFile = Console.ReadLine(); ICaptureDevice设备= CaptureDeviceList.Instance [我]; / /注册的处理函数的'包到来的事件 device.OnPacketArrival + = 新 SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival); / /打开设备捕捉 诠释 readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous,readTimeoutMilliseconds); / /打开或创建一个捕获输出文件 device.DumpOpen(capFile); Console.WriteLine(); Console.WriteLine(“ - ...监听{0},按'按Ctrl - c'来退出” device.Description); / /开始捕获无限期 device.Capture(); / /关闭pcap的设备 / /(注:这条线将永远不会被调用,因为 / /我们永远捕捉 device.Close(); 这里是包处理程序,将每一个收到的数据包转储到文件中: Collapse | Copy Code / / / <摘要> / / /每次接收的数据包转储到一个pcap的文件 / / / 摘要 私有静态无效device_OnPacketArrival( 对象发件人,CaptureEventArgs包) { ICaptureDevice设备=(ICaptureDevice)寄件人; / /如果设备有一个转储文件打开 如果(device.DumpOpened) { / /数据包转储到文件 device.Dump(包); Console.WriteLine(“数据包转储到文件中。”); } } 正如你可以看到,该方案的结构非常相似,我们在前面的章节中看到的。区别是:
调用device.DumpOpen( capFile )发出一旦接口被打开。此调用打开与接口转储文件和关联。
数据包写入该文件以device.Dump( packet )处理程序调用的数据包。请注意一个使用发送者的对象参数传递给包处理程序回调是投ICaptureDevice。
从转储文件中读数据包 现在,我们有一个转储文件可用,我们可以尝试读取其内容。下面的代码打开一个WinPcap的/ libpcap的转储文件并显示文件中的每个数据包。该SharpPcap.OfflineCaptureDevice(capFile)类是一个ICaptureDevice对象,表示脱机捕获文件,我们读到,那么通常OnPacketArrival事件中使用的数据包按顺序。正如你可以看到,从脱机阅读捕获数据包几乎是相同的,以期得到一个物理接口它们: Collapse | Copy Code Console.Write(“ -请输入一个输入捕捉文件名:”); 串 capFile = Console.ReadLine(); ICaptureDevice装置; 尝试 { / /得到一个脱机文件pcap的设备 设备= 新 OfflineCaptureDevice(capFile); / /打开设备捕捉 device.Open(); } 赶上(例外五) { Console.WriteLine(e.Message); 返回 ; } / /注册的处理函数的'包到来的事件 device.OnPacketArrival + = 新 SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival); Console.WriteLine(); Console.WriteLine(“ -捕获'{0}',按'按Ctrl - C'退出...” capFile); / /开始捕获的数据包数量不定 device.Capture(); / /关闭pcap的设备 device.Close(); Console.WriteLine(“ -文件结束为止。”); 发送数据包(例如,在源码包9) 最简单的方法来发送一个数据包显示在下面的代码片段。开业后适配器,SendPacket调用来发送一个手工制作的数据包。SendPacket作为参数的字节数组或Packet对象,它包含的数据被发送。请注意,缓冲区发送到网络中,它已收到。这意味着应用程序必须创建正确的协议头,以送一些有意义的事: Collapse | Copy Code / /打开设备 device.Open(); / /生成一个随机分组 字节 []字节= GetRandomPacket(); 尝试 { / /发送数据包的网络设备出 device.SendPacket(字节); Console.WriteLine(“ -包发送成功。”); } 赶上(例外五) { Console.WriteLine(“ - ”+ e.Message); } / /关闭pcap的设备 device.Close(); Console.WriteLine(“ -设备关闭。”); 发送队列 - WinPcap的专用的扩展(例如,在源码包10)
虽然SendPacket提供了一个简单而直接的方法来发送一个数据包,发送队列提供了一个先进,强大和优化机制,寄包集合。发送队列是一个一将数据包发送到网络变量的容器。它有大小,它代表的字节可以存储的最大数量。
由于SendQueue WinPcap的具体功能是,作者建议的SharpPcap基准特定使用您的发送队列发送数据包,以确定如果损失跨平台支持的使用效率是值得的补充。一句老话,“避免过早优化”应该慎重考虑。
SharpPcap代表发送队列使用SendQueue类,这是通过指定构造队列的大小,新的发送。 一旦发送队列的创建,SendQueue.Add()可以被调用时,添加一个数据包的发送队列。这个函数接受一个PcapHeader与数据包的时间戳和长度和一个缓冲或Packet分组数据对象持有的。这些参数是由收到相同的OnPacketArrival事件,因此排队一个数据包从刚刚抓获了一名或读文件是传递参数的问题这些SendQueue.Add()
要发送发送队列,SharpPcap提供WinPcapDevice.SendQueue(SendQueue q,
SendQueueTransmitModes transmitMode)功能。请注意第二个参数:如果
SendQueueTransmitModes.Synchronized,发送将被同步,即数据包的相对时间戳
将得到尊重。此操作需要非凡的CPU数量,因为同步需要在内核中使用“忙等待”循环赶车。尽管这个操作是相当的CPU密集型的,它往往在非常高的精度的数据包传输的结果(经常在以下几微秒)。
请注意,转递发送队列WinPcapDevice.SendQueue()能更有效的不是执行一系列
ICaptureDevice.SendPacket()由于发送量在内核队列缓冲交换机数量急剧减少的情
况。
当不再需要排队,它可以被删除的SendQueue.Dispose()是释放所有的队列发送缓冲区与。 下一个程序显示了如何使用发送队列。它打开通过创建一个捕获文件OfflineCaptureDevice()那么它存储文件的数据包从发送到正确分配队列。在这一点上,它传输队列同步。 请注意,链路层的转储文件是比一的接口,将数据包发送使用PcapDevice.DataLink财产,并打印一个警告,如果它们是不同的-这是很重要的捕获文件的链接层是作为适配器的,否则传输链路层一样是毫无意义的: Collapse | Copy Code ICaptureDevice装置; 尝试 { / /得到一个脱机文件pcap的设备 设备= 新 OfflineCaptureDevice(capFile); / /打开设备捕捉 device.Open(); } 赶上(例外五) { Console.WriteLine(e.Message); 返回 ; } Console.Write(“排队包...”); / /分配一个新的发送队列 SendQueue squeue = 新 SendQueue ((int)的((OfflineCaptureDevice)设备)PcapFileSize。); 分组包; 尝试 { / /遍历所有数据包中的文件,并添加到队列 而((包= device.GetNextPacket())!= 空) { 如果(!squeue.Add(包)) { Console.WriteLine(“警告:数据包缓冲区太小,”+ “并非所有的数据包将被发送。”); 打破 ; } } } 赶上(例外五) { Console.WriteLine(e.Message); 返回 ; } Console.WriteLine(“行”); Console.WriteLine(); Console.WriteLine(“以下设备机可在本:”); Console.WriteLine(“--------------------------------------------- -------\"); Console.WriteLine(); 诠释我= 0; = CaptureDeviceList.Instance VaR的装置; / /打印出所有可用的设备 的foreach(ICaptureDevice dev的设备中) { Console.WriteLine(“{0}){1}”,我dev.Description); 我+ +; } Console.WriteLine(); Console.Write(“ -请选择一个设备,传送关于:”); 我= 整数)。解析(Console.ReadLine(); 。器件[我]开放(); 串分别; 如果(器件[我]。PcapDataLink!= device.PcapDataLink) { Console.Write(“警告:捕获数据链的”+ “不同于接口一个选定, continue? [YES|no]\" ); resp = Console.ReadLine().ToLower(); if ((resp!= \" \" )&&(!resp.StartsWith( \" y\" ))) { Console.WriteLine( \" Cancelled by user!\" ); devices[i].Close(); 返回 ; } } // Close the offline device device.Close(); // find the network device for sending the packets we read device = devices[i]; Console.Write( \" This will transmit all queued packets through\" + \" this device, continue? [YES|no]\" ); resp = Console.ReadLine().ToLower(); if ((resp!= \" \" )&&( !resp.StartsWith( \" y\" ))) { Console.WriteLine( \" Cancelled by user!\" ); 返回 ; } 尝试 { Console.Write( \" Sending packets...\" ); int sent = device.SendQueue(squeue, SendQueueTransmitModes.Synchronized); Console.WriteLine( \" Done!\" ); if (sent < squeue.CurrentLength) { Console.WriteLine( \" An error occurred sending the packets: {0}. \" + \" Only {1} bytes were sent\\n\" , device.LastError, sent); } } catch (Exception e) { Console.WriteLine( \" Error: \" +e.Message ); } // Free the queue squeue.Dispose(); Console.WriteLine( \" -- Queue is disposed.\" ); // Close the pcap device device.Close(); Console.WriteLine( \" -- Device closed.\" ); Gathering Statistics on the Network Traffic - WinPcap Only (Example 11 in the Source Package) Adapter statistics are available by calling the ICaptureDevice.Statistics property. The Statistics property is supported by all ICaptureDevice types. WinPcap has a statistics extension that provides statistics callbacks that can be more efficient than retrieving device statistics over and over. WinPcap's statistical engine makes use of the kernel-level packet filter to efficiently classify the incoming packet. You can take a look at the NPF driver internals manual if you want to learn more about the details. In order to use this feature, the programmer must open an adapter and put it in statistical mode. This can be done by setting the PcapDevice.Mode property. In particular, the PcapDevice.Mode property should be set to CaptureMode.Statistics . With the statistical mode, making an application that monitors the TCP traffic load is a matter of a few lines of code. The following sample shows how to do this: Collapse | Copy Code // Register our handler function to the // 'winpcap statistics' event device.OnPcapStatistics += new WinPcap.StatisticsModeEventHandler(device_OnPcapStatistics); // Open the device for capturing int readTimeoutMilliseconds = 1000 ; device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds); // Handle TCP packets only device.Filter = \" tcp\" ; // Set device to statistics mode device.Mode = CaptureMode.Statistics; Console.WriteLine(); Console.WriteLine( \" -- Gathering statistics on \\\"{0}\\\ hit 'Enter' to stop...\" , device.Description); // Start the capturing process device.StartCapture(); // Wait for 'Enter' from the user. Console.ReadLine(); // Stop the capturing process device.StopCapture(); // Close the pcap device device.Close(); Console.WriteLine( \" Capture stopped, device closed.\" ); And our event handler will print the statistics: Collapse | Copy Code static int oldSec = 0 ; static int oldUsec = 0 ; /// < summary > /// Gets a pcap stat object and calculate bps and pps /// < / summary > private static void device_OnPcapStatistics( object sender, StatisticsModeEventArgs statistics) { // Calculate the delay in microseconds // from the last sample. // This value is obtained from the timestamp // that's associated with the sample. int delay = (statistics.Seconds - oldSec) * 1000000 - oldUsec + statistics.MicroSeconds; /* Get the number of Bits per second */ long bps = (statistics.RecievedBytes * 8 * 1000000 ) / delay; /* ^ ^ | | | | | | converts bytes in bits ----- | delay is expressed in microseconds --------- * / // Get the number of Packets per second long pps = (statistics.RecievedPackets * 1000000 ) / delay; // Convert the timestamp to readable format string ts = statistics.Date.ToLongTimeString(); // Print Statistics Console.WriteLine( \" {0}: bps={1}, pps={2}\" , ts, bps, pps); // store current timestamp oldSec = statistics.Seconds; oldUsec = statistics.MicroSeconds; } Note that this example is by far more efficient than a program that captures the packets in the traditional way and calculates statistics at the user-level. Statistical mode requires minimum amount of data copies and context switches and therefore the CPU is optimized. Moreover, a very small amount of memory is required. The downside is that if your application uses statistical mode, it will only work with WinPcap on Windows. Queuing Packets for Background Processing - High Packet Rate Capture (Example QueuingPacketsForBackgroundProcessing in the Source Package) Packet rates can exceed the rate at which they can be processed by the callback routines. This can occur if the packet processing code is time intensive, such as writing to disk, or if the packet processing code is performing advanced logic. Sometimes it is possible to reduce packet rates by applying bnf filters, but in other cases these filters can be complex. If packet rates only exceed the rate of processing for short periods of time, it is possible to simply defer packet processing until periods of less activity. One technique for this is to queue the packets and process them in a background thread as shown in this example. Collapse | Copy Code 使用系统; 使用 System.Collections.Generic; using SharpPcap; namespace QueuingPacketsForBackgroundProcessing { /// < summary > /// Basic capture example showing simple queueing for background processing /// < / summary > public class MainClass { /// < summary > /// When true the background thread will terminate /// < / summary > /// < param name=\"args\" > /// A < see cref=\"System.String\" / > /// < / param > private static bool BackgroundThreadStop = false ; /// < summary > /// Object that is used to prevent two threads from accessing /// PacketQueue at the same time /// < / summary > /// < param name=\"args\" > /// A < see cref=\"System.String\" / > /// < / param > private static object QueueLock = new object (); /// < summary > /// The queue that the callback thread puts packets in. Accessed by /// the background thread when QueueLock is held /// < / summary > private static List 因篇幅问题不能全部显示,请点此查看更多更全内容