1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using SharpPcap;
6
7 namespace TestConsole
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 //显示SharpPcap版本
14 string ver = SharpPcap.Version.VersionString;
15 Console.WriteLine("SharpPcap {0}", ver);
16
17 //获取网络设备
18 var devices = LivePcapDeviceList.Instance;
19 if (devices.Count < 1)
20 {
21 Console.WriteLine("找不到网络设备");
22 return;
23 }
24 Console.WriteLine();
25 Console.WriteLine("以下是目前本计算机上的活动网络设备:");
26 Console.WriteLine("----------------------------------------------------");
27 Console.WriteLine();
28 int i = 0;
29 foreach (LivePcapDevice dev in devices)
30 {
31 Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
32 i++;
33 }
34
35 //选择要监听的网络设备
36 Console.WriteLine();
37 Console.Write("-- 请选择一个需要监听的网络设备: ");
38 i = int.Parse(Console.ReadLine());
39 LivePcapDevice device = devices[i];
40
41 Console.Write("-- 请选择操作:监听通讯[C/c],多线程监听通讯[T/t],监听统计[F/f],发送随机数据包[S/s]? ");
42 string resp = Console.ReadLine().ToUpper();
43
44 while (!(resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T") || resp.StartsWith("S")))
45 {
46 resp = Console.ReadLine().ToUpper();
47 }
48
49 try
50 {
51 if (resp.StartsWith("C") || resp.StartsWith("F") || resp.StartsWith("T"))
52 {
53 //监听过滤条件
54 string filter = "ip and tcp";
55
56 //连接设备
57 System.Threading.Thread backgroundThread = null;
58 int readTimeoutMilliseconds = 1000;
59 if (resp.StartsWith("F"))
60 {
61 device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
62 device.SetFilter(filter);
63 device.Mode = CaptureMode.Statistics; //抓包统计
64 device.OnPcapStatistics += new StatisticsModeEventHandler(device_OnPcapStatistics); //抓包统计回调事件
65 }
66 else if (resp.StartsWith("C"))
67 {
68 device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
69 device.SetFilter(filter);
70 device.Mode = CaptureMode.Packets; //抓数据包
71 showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情
72 device.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival); //抓数据包回调事件
73 }
74 else
75 {
76 backgroundThread = new System.Threading.Thread(BackgroundThread);
77 backgroundThread.Start();
78 device.Open();
79 device.SetFilter(filter);
80 device.Mode = CaptureMode.Packets; //抓数据包
81 showDetails = resp.EndsWith("-A"); //当抓数据包时,检查是否要查看详情
82 device.OnPacketArrival += new PacketArrivalEventHandler(device_OnThreadPacketArrival); //抓数据包回调事件
83 }
84
85 Console.WriteLine();
86 Console.WriteLine("-- 当前TCPdump过滤条件: /{0}/", filter);
87 Console.WriteLine("-- 正在监听设备 {0}, 按 '回车' 键以停止监听...", device.Description);
88
89 //开始监听
90 device.StartCapture();
91
92 //停止监听
93 Console.ReadLine();
94 device.StopCapture();
95 Console.WriteLine("-- 停止监听.");
96
97 if (backgroundThread != null)
98 {
99 BackgroundThreadStop = true;
100 backgroundThread.Join();
101 }
102 }
103 else if (resp.StartsWith("S"))
104 {
105 //连接设备
106 device.Open();
107
108 //生成随机数据包
109 byte[] bytes = GetRandomPacket();
110
111 try
112 {
113 //发送数据
114
115 device.SendPacket(bytes);
116 SendQueue squeue = new SendQueue(2000);
117 Console.WriteLine("-- 单个数据包发送成功.");
118
119 for (int j = 0; j < 10; j++)
120 {
121 if (!squeue.Add(bytes))
122 {
123 Console.WriteLine("-- 警告: 队列大小不足以存放所有数据包,将只发送部分数据包.");
124 break;
125 }
126 }
127 device.SendQueue(squeue, SendQueueTransmitModes.Synchronized);
128 Console.WriteLine("-- 数据包队列发送完毕.");
129 }
130 catch (Exception e)
131 {
132 Console.WriteLine("-- " + e.Message);
133 }
134 }
135 }
136 catch (Exception e)
137 {
138 Console.WriteLine("-- " + e.Message);
139 }
140 finally
141 {
142 if (device.Opened)
143 {
144 //断开设备连接
145 Console.WriteLine(device.Statistics().ToString());
146 device.Close();
147 Console.WriteLine("-- 断开设备连接.");
148 Console.Write("按 '回车' 键以退出...");
149 Console.Read();
150 }
151 }
152 }
153
154 static bool showDetails = false; //查看详情的参数
155 /// <summary>
156 /// 抓包方法
157 /// </summary>
158 private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
159 {
160 PcapPorcessContext(e.Packet);
161 }
162
163 private static void PcapPorcessContext(PacketDotNet.RawPacket pPacket)
164 {
165 var time = pPacket.Timeval.Date;
166 var len = pPacket.Data.Length;
167 var layer = pPacket.LinkLayerType;
168
169 Console.WriteLine("{0}:{1}:{2},{3} Len={4} Layer={5}",
170 time.Hour, time.Minute, time.Second, time.Millisecond, len, layer);
171
172 var packet = PacketDotNet.Packet.ParsePacket(pPacket); //Raw基础包对象
173
174 if (layer == PacketDotNet.LinkLayers.Ethernet) //以太网包
175 {
176 var ethernetPacket = (PacketDotNet.EthernetPacket)packet;
177 System.Net.NetworkInformation.PhysicalAddress srcMac = ethernetPacket.SourceHwAddress;
178 System.Net.NetworkInformation.PhysicalAddress destMac = ethernetPacket.DestinationHwAddress;
179
180 Console.WriteLine("MAC:{0} -> {1}", srcMac, destMac);
181 if (showDetails) Console.WriteLine("Ethernet packet: " + ethernetPacket.ToColoredString(false));
182 }
183 var ipPacket = PacketDotNet.IpPacket.GetEncapsulated(packet); //IP包
184 if (ipPacket != null)
185 {
186 System.Net.IPAddress srcIp = ipPacket.SourceAddress;
187 System.Net.IPAddress destIp = ipPacket.DestinationAddress;
188
189 Console.WriteLine("IP: {0} -> {1}", srcIp, destIp);
190 if (showDetails) Console.WriteLine("IP packet: " + ipPacket.ToColoredString(false));
191
192 var tcpPacket = PacketDotNet.TcpPacket.GetEncapsulated(packet); //TCP包
193 if (tcpPacket != null)
194 {
195 int srcPort = tcpPacket.SourcePort;
196 int destPort = tcpPacket.DestinationPort;
197
198 Console.WriteLine("TCP Port: {0} -> {1}", srcPort, destPort);
199 if (showDetails) Console.WriteLine("TCP packet: " + tcpPacket.ToColoredString(false));
200 }
201
202 var udpPacket = PacketDotNet.UdpPacket.GetEncapsulated(packet); //UDP包
203 if (udpPacket != null)
204 {
205 int srcPort = udpPacket.SourcePort;
206 int destPort = udpPacket.DestinationPort;
207
208 Console.WriteLine("UDP Port: {0} -> {1}", srcPort, destPort);
209 if (showDetails) Console.WriteLine("UDP packet: " + udpPacket.ToColoredString(false));
210 }
211 }
212 }
213
214 static ulong oldSec = 0;
215 static ulong oldUsec = 0;
216 /// <summary>
217 /// 抓包统计方法
218 /// </summary>
219 private static void device_OnPcapStatistics(object sender, StatisticsModeEventArgs e)
220 {
221 // 计算统计心跳间隔
222 ulong delay = (e.Statistics.Timeval.Seconds - oldSec) * 1000000 - oldUsec + e.Statistics.Timeval.MicroSeconds;
223
224 // 获取 Bits per second
225 ulong bps = ((ulong)e.Statistics.RecievedBytes * 8 * 1000000) / delay;
226 /* ^ ^
227 | |
228 | |
229 | |
230 converts bytes in bits -- |
231 |
232 delay is expressed in microseconds --
233 */
234
235 // 获取 Packets per second
236 ulong pps = ((ulong)e.Statistics.RecievedPackets * 1000000) / delay;
237
238 // 将时间戳装换为易读格式
239 var ts = e.Statistics.Timeval.Date.ToLongTimeString();
240
241 // 输出统计结果
242 Console.WriteLine("{0}: bps={1}, pps={2}", ts, bps, pps);
243
244 //记录本次统计时间戳,以用于下次统计计算心跳间隔
245 oldSec = e.Statistics.Timeval.Seconds;
246 oldUsec = e.Statistics.Timeval.MicroSeconds;
247 }
248
249 /// <summary>
250 /// 生成一个大小为200的随机数据包
251 /// </summary>
252 private static byte[] GetRandomPacket()
253 {
254 byte[] packet = new byte[200];
255 Random rand = new Random();
256 rand.NextBytes(packet);
257 return packet;
258 }
259
260 /// <summary>
261 /// 生成一个大小为98的数据包
262 /// </summary>
263 private static byte[] GetPacket()
264 {
265 byte[] packet = new byte[]
266 {
267 0x00,0x02,0x65,0x11,0xa6,0x05, //srcMac
268 0x00,0x1b,0x38,0xa5,0xc2,0x40, //destMac
269 0x08,0x00, //Type Ip
270 0x45, //Version 4
271 0x00, //Differentiated Services Field 分隔符
272 0x00,0x54, //Total Length 84
273 0x43,0x08, //Identification 校验位
274 0x40,0x00, //Fragment offset 片偏移
275 0x80, //Time to live 生存时间
276 0x06, //Protocol TCP
277 0x40,0x00, //Header checksum 报头校验和
278 0xc0,0xa8,0x00,0x71, //srcIP
279 0xc0,0xa8,0x00,0x6a, //destIP
280 0x26,0x8e, //srcPort
281 0x04,0x04, //destPort
282 0x5b,0x0c,0x5e,0xc7, //Sequence number 序号
283 0xca,0xf9,0x1b,0xb1, //Acknowledgement number 应答号
284 0x80, //Header Length 32
285 0x18, //Flags [PSH,ACK]
286 0x41,0x10, //Window size
287 0x82,0x72, //Checksum 校验和
288 0x01, //Options NOP
289 0x01, //Options NOP
290 0x08,0x0a,0x00,0x00,0xac,0x4c,0x00,0x41,0x50,0xaa, //Options Timestamps
291 0x21, //Data Start 这之后是我这个项目中的服务器和终端通讯的特有的附加数据
292 0x0a, //Command
293 0x00,0x00, //CID
294 0x01,0x00,0x00,0x00, //TID
295 0x00,0x00,0x00,0x00, //Param1
296 0x00,0x00,0x00,0x00, //Param2
297 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //Param3
298 0x30,0x30,0x30,0x30, //ErrorCode
299 0x00,0x00,0xec,0x00 //ExtraData
300 };
301 return packet;
302 }
303
304 private static DateTime LastStatisticsOutput = DateTime.Now;
305 private static TimeSpan LastStatisticsInterval = new TimeSpan(0, 0, 2);
306 private static void device_OnThreadPacketArrival(object sender, CaptureEventArgs e)
307 {
308 //输出设备通讯统计信息
309 var Now = DateTime.Now;
310 var interval = Now - LastStatisticsOutput;
311 if (interval > LastStatisticsInterval)
312 {
313 Console.WriteLine("Device Statistics: " + ((LivePcapDevice)e.Device).Statistics());
314 LastStatisticsOutput = Now;
315 }
316
317 lock (QueueLock)
318 {
319 PacketQueue.Add(e.Packet); //将捕获到的数据包加入处理队列
320 }
321 }
322
323 /// <summary>
324 /// 多线程处理数据包队列
325 /// </summary>
326 private static void BackgroundThread()
327 {
328 while (!BackgroundThreadStop)
329 {
330 bool shouldSleep = true;
331
332 lock (QueueLock)
333 {
334 if (PacketQueue.Count != 0)
335 {
336 shouldSleep = false;
337 }
338 }
339
340 if (shouldSleep)
341 {
342 System.Threading.Thread.Sleep(250);
343 }
344 else //处理队列
345 {
346 List<PacketDotNet.RawPacket> ourQueue; //本线程待处理队列
347 lock (QueueLock)
348 {
349 ourQueue = PacketQueue;
350 PacketQueue = new List<PacketDotNet.RawPacket>();
351 }
352
353 Console.WriteLine("BackgroundThread: Local Queue Count is {0}", ourQueue.Count);
354
355 foreach (var packet in ourQueue)
356 {
357 PcapPorcessContext(packet);
358 }
359 }
360 }
361 }
362 private static bool BackgroundThreadStop = false; //线程停止标识
363 private static object QueueLock = new object(); //线程锁变量
364 private static List<PacketDotNet.RawPacket> PacketQueue = new List<PacketDotNet.RawPacket>(); //待处理数据包队列
365 }
366 }