• 使用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;
    }
    }

  • 相关阅读:
    most-wanted-letter
    non-unique-elements
    python组建之paramiko的简介和简单使用
    Android平台使用termux,随时随地写代码
    发现生活中数学的美,然后记录下来
    别再用Microsoft Office,改为WPS或者Latex
    office2016 vol 中文版本
    Office 2016 英文版(VOL版)下载
    选择好用的生产力工具
    使用windows(win7和win10),最好用chocolatey
  • 原文地址:https://www.cnblogs.com/wudingfeng/p/1916931.html
Copyright © 2020-2023  润新知