相关文章推荐

Repository files navigation

开发工具

  • Windows 11
  • IntelliJ IDEA 2023.2.1
  • jpcap
  • 设计思路及使用说明

    基于多线程的网络抓包程序的实现思路

  • 获取网络接口列表,以网络接口为单位进行抓包。
  • 创建线程池,每个线程代表一个网络接口和一个分析包的线程,线程池容量就等于网络接口数量+1。
  • 根据用户选中的接口,执行线程池里面的线程进行抓包,将抓到的包存入一个队列。
  • 分析线程对队列里面抓到的包进行逐个处理、分析,目前仅支持分析IP、TCP、UDP三种包。
  • 其中,每次用户点击开始抓包按钮,都会从线程池取出一个用于抓包的线程;但是分析包的线程只有在程序启动的时候创建,这个线程将处理整个程序运行过程中抓到的全部包
  • 图形化界面的设计及使用介绍

    布局如图所示,现介绍使用方法:

    choose device:

  • 为一个选项框,里面列出了获取到的所有网络接口。
  • 选择一个选项可以对特定接口进行抓包,选择all表示对全部接口进行抓包;选择choose a device表示先暂停不抓包。
  • 选择选项的时候抓包处于暂停状态
  • start按钮:

  • 点击start后程序会先清除当前抓到的所有包的记录,然后对所选接口进行抓包。
  • clear按钮:

  • 清除抓包记录
  • filter:

  • 过滤器,要求输入大写字符串
  • 目前仅支持输入IP、TCP、UDP、SRC+IP地址、DST+IP地址。分别表示只抓某个类型的包和只抓源/目的为指定IP地址的包
  • 输入过滤条件之后要重新选择接口并按start,过滤条件才可生效
  • 抓包展示表格部分:

  • time stamp:表示时间戳,保留两位小数单位为ms
  • src ip:表示源IP地址
  • dst ip:表示目的IP地址
  • protocol:表示协议类型
  • length:表示包数据部分的长度
  • info:表示包的重要信息
  • IP:TTL、identification、version
  • TCP:ACK、SEQ、DST_PORT、SRC_PORT
  • UDP:上层协议、DST_IP、SRC_PORT
  • public static String selectedOption:表示用户在filter输入的内容,因为设置为全局变量,因此如果在抓包过程中改变这个值也是支持的
  • public static volatile boolean isRunning:表示程序是否结束,初始为true,在程序退出时执行的关闭逻辑被设为false,目的是保证执行AnalyzePacket()任务的线程安全退出
  • public static BlockingQueue packetQueue = new LinkedBlockingQueue<>():存包的队列,保证全局且线程安全
  • window.chooseDevice.addActionListener:监听用户选的网卡是哪个
  • window.startBtn.addActionListener:监听用户是否点击开始按钮,根据用户选择的网卡从线程池启动线程
  • window.clearBtn.addActionListener:监听用户是否要清空屏幕
  • NPCWindow.table.getSelectionModel().addListSelectionListener:根据用户选择的表项(包),来显示包的数据部分的字节和字符串
  • Runtime.getRuntime().addShutdownHook:启动一个新线程用于执行程序退出的逻辑,使用 shutdown 和 awaitTermination 来优雅地关闭线程池,确保所有线程在程序关闭时正确终止
  • private void clearTable()

  • 当用户点击clear按钮时清空抓包展示表项
  • 清空packetQueue
  • private void AnalyzePacket()

  • 用来分析包的函数
  • 将packetQueue里面的包取出来进行分析
  • private void NetworkPacketCap(NetworkInterface device)

  • 对device这个网络接口进行抓包,将抓到的包放入packetQueue
  • 显示status的信息
  • class PacketHandler implements PacketReceiver

    这是用于抓包、处理包的类,与Main在同一个包内,其作用有:

  • 根据包的类型处理包
  • 将处理包得到的信息显示在图形化界面上
  • 将包里面的二进制流转换为16进制和String
  • public void receivePacket (Packet packet)
  • 取得filter里面的字段,并根据过滤条件来过滤包
  • 对每个包单独处理,获取包展示表项需要的所有信息并将其加入表的数据集
  • 在控制台打印出包数据部分的16进制和String
  • public void addToTable(String time, String srcip, String dstip, String pro, String len, String info, String dataByte, String dataStr)
  • 为包展示表格添加一行表项,表项内容即为传入的参数
  • public String toCharString(byte[] dataByte)
  • 将包的数据部分由二进制字节数组转换为String
  • public String toHexString(byte[] dataByte)
  • 将包的数据部分由二进制字节数组转换为16进制字符串
  • public String inferProtocol(int sourcePort, int destinationPort, String str)
  • 根据源端口和目标端口推断包的上层协议
  • 目前仅能知道HTTP、HTTPS、DNS三种
  • public class NPCWindow extends JFrame

    JFrame 是Java Swing库中的一个类,用于创建图形用户界面(GUI)应用程序的顶层窗口。NPCWindow是它的子类

    作用:构造、整合图形化界面

  • public NPCWindow()
  • 显示图形化窗口
  • public static JTextField getFilterField()
  • 获取filter示例
  • public void createNewWindow()
  • 规定窗口大小
  • 将窗口的各个部分整合在一起,包括之前图示中的所有部分
  • class PanelStyle

    用于设置图形化窗口各个部件的类,与NPCWindow在同一个包内

    作用:详细设置图形化界面的每个部分

  • public void setTopPanel(NPCWindow window)
  • 设置顶部面板的样式
  • 创建choose a device选项框并规定它的长度和内容
  • 创建start、clear按钮并规定它的长度
  • 创建filter输入框并规定它的长度
  • 如果选择了对所有的网卡进行抓包,就从线程池为每一个网卡分配一个线程,该线程执行mainObj.NetworkPacketCap(device)函数,表示对该device进行抓包。这个线程的主要作用就是抓包,并且将抓到的包放入线程安全的队列packetQueue

    创建分析包的线程,该线程只有在用户启动程序时创建,在程序退出时被回收。这个线程的主要作用就是取出packetQueue里面的包,并将其交给PacketHandler类来分析包。相当于所有抓包线程抓到的包都将由这一个线程来处理。

    最核心的就是这段代码:

    window.startBtn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            for (NetworkInterface device : devices) {
                if (selectedOption.equals(device.name + " - " + device.description) || selectedOption.equals("all")) {
                    // 改变这个值使得当前线程可以结束
                    isCapturing = false;
                    if (!selectedOption.equals("all")) {
                        // 等待一段时间,以确保之前的抓包线程能够结束
                        try {
                            Thread.sleep(1000); // 1秒钟
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                    // 提交任务给线程池执行
                    threadPool.submit(() -> mainObj.NetworkPacketCap(device));
    // 创建处理包的线程
    threadPool.submit(() -> mainObj.AnalyzePacket());
     
    推荐文章