Java之Pcap文件解析(三:解析文件)

前言

数据结构已经定义好了,那么现在就开始正式解析Pcap文件了。
注:以下仅贴出核心代码,项目全部代码会在文章结尾处给出下载链接

解析Pcap文件

1 读取整个Pcap文件到内存

FileInputStream fis = null;
    try {
        fis = new FileInputStream(pcap);
        int m = fis.read(file_header);
        //....
    } catch // .....

2 读取文件头

/**
     * 读取 pcap 文件头
     */
    public PcapFileHeader parseFileHeader(byte[] file_header) throws IOException {
        PcapFileHeader fileHeader = new PcapFileHeader();
        byte[] buff_4 = new byte[4];    // 4 字节的数组
        byte[] buff_2 = new byte[2];    // 2 字节的数组

        int offset = 0;
        for (int i = 0; i < 4; i ++) {
            buff_4[i] = file_header[i + offset];
        }
        offset += 4;
        int magic = DataUtils.byteArrayToInt(buff_4);
        fileHeader.setMagic(magic);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = file_header[i + offset];
        }
        offset += 2;
        short magorVersion = DataUtils.byteArrayToShort(buff_2);
        fileHeader.setMagorVersion(magorVersion);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = file_header[i + offset];
        }
        offset += 2;
        short minorVersion = DataUtils.byteArrayToShort(buff_2);
        fileHeader.setMinorVersion(minorVersion);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = file_header[i + offset];
        }
        offset += 4;
        int timezone = DataUtils.byteArrayToInt(buff_4);
        fileHeader.setTimezone(timezone);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = file_header[i + offset];
        }
        offset += 4;
        int sigflags = DataUtils.byteArrayToInt(buff_4);
        fileHeader.setSigflags(sigflags);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = file_header[i + offset];
        }
        offset += 4;
        int snaplen = DataUtils.byteArrayToInt(buff_4);
        fileHeader.setSnaplen(snaplen);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = file_header[i + offset];
        }
        offset += 4;
        int linktype = DataUtils.byteArrayToInt(buff_4);
        fileHeader.setLinktype(linktype);

//      LogUtils.printObjInfo(fileHeader);

        return fileHeader;
    }

3 读取数据头

/**
     * 读取数据包头
     */
    public PcapDataHeader parseDataHeader(byte[] data_header){
        byte[] buff_4 = new byte[4];
        PcapDataHeader dataHeader = new PcapDataHeader();
        int offset = 0;
        for (int i = 0; i < 4; i ++) {
            buff_4[i] = data_header[i + offset];
        }
        offset += 4;
        int timeS = DataUtils.byteArrayToInt(buff_4);
        dataHeader.setTimeS(timeS);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = data_header[i + offset];
        }
        offset += 4;
        int timeMs = DataUtils.byteArrayToInt(buff_4);
        dataHeader.setTimeMs(timeMs);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = data_header[i + offset];
        }
        offset += 4;
        // 得先逆序在转为 int
        DataUtils.reverseByteArray(buff_4);
        int caplen = DataUtils.byteArrayToInt(buff_4);
        dataHeader.setCaplen(caplen);
//      LogUtils.printObj("数据包实际长度", dataHeader.getCaplen());

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = data_header[i + offset];
        }
        offset += 4;
        //      int len = DataUtils.byteArrayToInt(buff_4);
        DataUtils.reverseByteArray(buff_4);
        int len = DataUtils.byteArrayToInt(buff_4);
        dataHeader.setLen(len);

//      LogUtils.printObjInfo(dataHeader);

        return dataHeader;
    }

读取数据头后,我们将整个数据存入 content 字节数组中,方便以后的解析

private byte[] content;
content = new byte[dataHeader.getCaplen()];

4 读取数据帧

数据帧数据对我们没啥用,不做过多解析

/**
     * 读取 Pcap 数据帧
     * @param fis
     */
    public void readPcapDataFrame(byte[] content) {
        PcapDataFrame dataFrame = new PcapDataFrame();
        int offset = 12;
        byte[] buff_2 = new byte[2];
        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        short frameType = DataUtils.byteArrayToShort(buff_2);
        dataFrame.setFrameType(frameType);

//      LogUtils.printObjInfo(dataFrame);
    }

5 读取IP头

private IPHeader readIPHeader(byte[] content) {
        int offset = 14;
        IPHeader ip = new IPHeader();

        byte[] buff_2 = new byte[2];
        byte[] buff_4 = new byte[4];

        byte varHLen = content[offset ++];              // offset = 15
//      LogUtils.printByteToBinaryStr("varHLen", varHLen);
        if (varHLen == 0) {
            return null;
        }

        ip.setVarHLen(varHLen);

        byte tos = content[offset ++];                  // offset = 16
        ip.setTos(tos);

        for (int i = 0; i < 2; i ++) {      
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 18
        short totalLen = DataUtils.byteArrayToShort(buff_2);
        ip.setTotalLen(totalLen);

        for (int i = 0; i < 2; i ++) {          
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 20
        short id = DataUtils.byteArrayToShort(buff_2);
        ip.setId(id);

        for (int i = 0; i < 2; i ++) {                  
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 22
        short flagSegment = DataUtils.byteArrayToShort(buff_2);
        ip.setFlagSegment(flagSegment);

        byte ttl = content[offset ++];                  // offset = 23
        ip.setTtl(ttl);

        byte protocol = content[offset ++];             // offset = 24
        ip.setProtocol(protocol);

        for (int i = 0; i < 2; i ++) {                  
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 26
        short checkSum = DataUtils.byteArrayToShort(buff_2);
        ip.setCheckSum(checkSum);

        for (int i = 0; i < 4; i ++) {                  
            buff_4[i] = content[i + offset];
        }
        offset += 4;                                    // offset = 30
        int srcIP = DataUtils.byteArrayToInt(buff_4);
        ip.setSrcIP(srcIP);

        // 拼接出 SourceIP
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            builder.append((int) (buff_4[i] & 0xff));
            builder.append(".");
        }
        builder.deleteCharAt(builder.length() - 1);
        String sourceIP = builder.toString();
        protocolData.setSrcIP(sourceIP);

        for (int i = 0; i < 4; i ++) {      
            buff_4[i] = content[i + offset];
        }
        offset += 4;                                    // offset = 34
        int dstIP = DataUtils.byteArrayToInt(buff_4);
        ip.setDstIP(dstIP);

        // 拼接出 DestinationIP
        builder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            builder.append((int) (buff_4[i] & 0xff));
            builder.append(".");
        }
        builder.deleteCharAt(builder.length() - 1);
        String destinationIP = builder.toString();
        protocolData.setDesIP(destinationIP);

//      LogUtils.printObjInfo(ip);

        return ip;
    }

6 读取TCP头

private TCPHeader readTCPHeader(byte[] content2, int offset) {
        byte[] buff_2 = new byte[2];
        byte[] buff_4 = new byte[4];

        TCPHeader tcp = new TCPHeader();

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
//          LogUtils.printByteToBinaryStr("TCP: buff_2[" + i + "]", buff_2[i]);
        }
        offset += 2;                                    // offset = 36
        short srcPort = DataUtils.byteArrayToShort(buff_2);
        tcp.setSrcPort(srcPort);

        String sourcePort = validateData(srcPort);
        protocolData.setSrcPort(sourcePort);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 38
        short dstPort = DataUtils.byteArrayToShort(buff_2);
        tcp.setDstPort(dstPort);

        String desPort = validateData(dstPort);
        protocolData.setDesPort(desPort);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = content[i + offset];
        }
        offset += 4;                                    // offset = 42
        int seqNum = DataUtils.byteArrayToInt(buff_4);
        tcp.setSeqNum(seqNum);

        for (int i = 0; i < 4; i ++) {
            buff_4[i] = content[i + offset];
        }
        offset += 4;                                    // offset = 46
        int ackNum = DataUtils.byteArrayToInt(buff_4);
        tcp.setAckNum(ackNum);

        byte headerLen = content[offset ++];            // offset = 47
        tcp.setHeaderLen(headerLen);

        byte flags = content[offset ++];                // offset = 48
        tcp.setFlags(flags);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 50
        short window = DataUtils.byteArrayToShort(buff_2);
        tcp.setWindow(window);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 52
        short checkSum = DataUtils.byteArrayToShort(buff_2);
        tcp.setCheckSum(checkSum);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 54
        short urgentPointer = DataUtils.byteArrayToShort(buff_2);
        tcp.setUrgentPointer(urgentPointer);

//      LogUtils.printObj("tcp.offset", offset);
        data_offset = offset;
//      LogUtils.printObjInfo(tcp);

        return tcp;
    }

7 读取UDP头

private UDPHeader readUDPHeader(byte[] content, int offset) {
        byte[] buff_2 = new byte[2];

        UDPHeader udp = new UDPHeader();
        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
//          LogUtils.printByteToBinaryStr("UDP: buff_2[" + i + "]", buff_2[i]);
        }
        offset += 2;                                    // offset = 36
        short srcPort = DataUtils.byteArrayToShort(buff_2);
        udp.setSrcPort(srcPort);

        String sourcePort = validateData(srcPort);
        protocolData.setSrcPort(sourcePort);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 38
        short dstPort = DataUtils.byteArrayToShort(buff_2);
        udp.setDstPort(dstPort);

        String desPort = validateData(dstPort);
        protocolData.setDesPort(desPort);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 40
        short length = DataUtils.byteArrayToShort(buff_2);
        udp.setLength(length);

        for (int i = 0; i < 2; i ++) {
            buff_2[i] = content[i + offset];
        }
        offset += 2;                                    // offset = 42
        short checkSum = DataUtils.byteArrayToShort(buff_2);
        udp.setCheckSum(checkSum);

//      LogUtils.printObj("udp.offset", offset );
//      LogUtils.printObjInfo(udp);
        data_offset = offset;

        return udp;
    }

创建文件

解析完毕后,就得将数据写入文件了

/**
     * 创建文件
     * @param protocolData
     */
    public void createFiles(ProtocolData protocolData) {
        String protocol = "TCP";
        String suffix = ".pcap";
        if (protocolData.getProtocolType() == ProtocolType.UDP) {
            protocol = "UDP";
        }  else if (protocolData.getProtocolType() == ProtocolType.OTHER) {
            return;
        }
        String filename = protocol + "[" + protocolData.getSrcIP() + "]"
                                   + "[" + protocolData.getSrcPort() + "]"
                                   + "[" + protocolData.getDesIP() + "]"
                                   + "[" + protocolData.getDesPort() + "]";

        String reverseFilename = protocol + "[" + protocolData.getDesIP() + "]"
                                          + "[" + protocolData.getDesPort() + "]"
                                          + "[" + protocolData.getSrcIP() + "]"
                                          + "[" + protocolData.getSrcPort() + "]";
        boolean isReverse = false;

        boolean append = false;
        // 判断是否已经包含该五元组
        if (filenames.contains(filename)) {
            append = true;
//          LogUtils.printObj(filename + "已存在...");
        } else {
            append = false;
//          LogUtils.printObj(filename + "不存在...");

            // 将源IP、源Port和目的IP、目的Port 调换顺序,查看该文件是否存在,若存在,则追加
            if (filenames.contains(reverseFilename)) {
                append = true;
                isReverse = true;
                filename = reverseFilename;
//              LogUtils.printObj("rf: " + reverseFilename + "已存在...");
            } else {
                filenames.add(filename);
            }

        }

        filename = DataUtils.validateFilename(filename);
        String pathname = savePath + "\\" + protocol + "\\" + filename + suffix;

        /*
         * 数据负载信息
         */
        int data_size = content.length - data_offset;
//      LogUtils.printObj("数据负载长", data_size);
        data_content = new byte[data_size];
        for (int i = 0; i < data_size; i ++) {
            data_content[i] = content[i + data_offset];
        }
        String pathname_data = savePath + "\\" + protocol + "\\数据负载提取结果\\" + filename + ".pcap.txt";

        try {
            File file = new File(pathname);
            FileOutputStream fos = new FileOutputStream(file, append);

            File data_file = new File(pathname_data);
            FileOutputStream fos_data = new FileOutputStream(data_file, append);

            if (!append) {  // 若 append 为 true,表明文件已经存在,追加
                // 1. 写入文件头
                fos.write(file_header);

                String[] data = new String[2];
                data[0] = filename;
                data[1] = pathname;
                datas.add(data);
                super.setChanged();                             // 通知观察者
                super.notifyObservers(datas);                   // 传递数据给观察者

                // 不存在,则说明该记录尚未添加
                String logPath = savePath + "\\" + protocol + "\\" + protocol + ".txt";
                FileUtils.writeLineToFile(filename, new File(logPath), true);
            }

            // 2. 写入 Pcap 数据头
//          LogUtils.printObj("data_header.length", data_header.length);
            fos.write(data_header);
            // 3. 写入数据
//          LogUtils.printObj("content.length", content.length);
            fos.write(content);

            // 写入数据负载信息
            fos_data.write(data_content);

            // 4. 关闭流
            FileUtils.closeStream(null, fos);
            FileUtils.closeStream(null, fos_data);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 

    }

项目代码下载PcapAnalyzer

前往 bascker/javaworld 获取更多 Java 知识

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
### 回答1: Java可以利用第三方库Jpcap解析pcap文件的五元组信息。在使用Jpcap之前,需要先下载和安装Jpcap库。 首先,我们需要创建一个能够读取pcap文件的Capture对象。代码如下: `Capture capture = new Capture();` 然后,我们需要设置Capture对象的文件路径,指定pcap文件所在的位置。代码如下: `capture.openFile("filepath.pcap");` 接下来,我们可以通过循环遍历Capture对象的包,获取每个包的五元组信息。代码如下: ``` while(capture.getNextPacket() != null){ byte[] packet = capture.getPacket(); //解析五元组信息 //...代码 } ``` 在循环内部,我们可以利用Jpcap库提供的方法来解析包的五元组信息。五元组信息包括源IP地址、目标IP地址、源端口号、目标端口号和传输协议。具体解析方法如下: ``` Packet packet = new Packet(packet, Packet.PROTOCOL_IP); if (packet instanceof IPPacket) { IPPacket ipPacket = (IPPacket) packet; String sourceIP = ipPacket.getSourceAddress(); String destinationIP = ipPacket.getDestinationAddress(); int sourcePort = 0; int destinationPort = 0; if (packet instanceof TCPPacket) { TCPPacket tcpPacket = (TCPPacket) packet; sourcePort = tcpPacket.getSourcePort(); destinationPort = tcpPacket.getDestinationPort(); } else if (packet instanceof UDPPacket) { UDPPacket udpPacket = (UDPPacket) packet; sourcePort = udpPacket.getSourcePort(); destinationPort = udpPacket.getDestinationPort(); } String transportProtocol = ipPacket.protocolDescription; //打印五元组信息 System.out.println("源IP地址:" + sourceIP + ",目标IP地址:" + destinationIP + ",源端口号:" + sourcePort + ",目标端口号:" + destinationPort + ",传输协议:" + transportProtocol); } ``` 通过以上代码,我们可以获取pcap文件中每个包的五元组信息,并打印出来。 最后,记得在程序结束后关闭Capture对象,释放资源。代码如下: `capture.close();` 以上是Java解析pcap文件五元组信息的基本步骤和代码实现。通过利用Jpcap库,我们可以方便地获取pcap文件中的五元组信息,进行进一步的网络分析和处理。 ### 回答2: PCAP文件是一种常用的网络数据捕获文件格式,它可以用来存储网络数据包。在网络分析和安全领域中,解析PCAP文件的五元组信息非常重要。 五元组信息指的是TCP/IP协议栈中的五个重要参数,即源IP地址、目的IP地址、源端口号、目的端口号和协议类型。解析PCAP文件的五元组信息可以帮助我们分析网络通信的源和目的,识别网络中的主机和服务等。 对于Java程序来说,解析PCAP文件的五元组信息可以通过使用相关的库和API实现。以下是一个简单的示例代码,展示了如何使用开源库jpcap解析PCAP文件中的五元组信息: ```java import jpcap.*; import jpcap.packet.*; public class PCAPParser { public static void main(String[] args) throws Exception { // 打开PCAP文件 NetworkInterface[] devices = JpcapCaptor.getDeviceList(); JpcapCaptor captor = JpcapCaptor.openFile("filename.pcap"); // 逐个解析数据包 while (true) { Packet packet = captor.getPacket(); if (packet == null) break; // 获取五元组信息 if (packet instanceof IPPacket) { IPPacket ipPacket = (IPPacket) packet; String sourceIP = ipPacket.src_ip.getHostAddress(); String destinationIP = ipPacket.dst_ip.getHostAddress(); int sourcePort = 0; int destinationPort = 0; if (ipPacket instanceof TCPPacket) { TCPPacket tcpPacket = (TCPPacket) ipPacket; sourcePort = tcpPacket.src_port; destinationPort = tcpPacket.dst_port; } else if (ipPacket instanceof UDPPacket) { UDPPacket udpPacket = (UDPPacket) ipPacket; sourcePort = udpPacket.src_port; destinationPort = udpPacket.dst_port; } String protocol = ipPacket.protocolDescription; // 输出五元组信息 System.out.println("Source IP: " + sourceIP); System.out.println("Destination IP: " + destinationIP); System.out.println("Source Port: " + sourcePort); System.out.println("Destination Port: " + destinationPort); System.out.println("Protocol: " + protocol); System.out.println("--------------------------"); } } // 关闭PCAP文件 captor.close(); } } ``` 以上代码使用jpcap库读取并解析PCAP文件中的数据包。通过遍历数据包,我们使用IPPacket类获取源IP地址、目的IP地址和协议类型。之后,根据具体的协议类型,我们使用TCPPacket或UDPPacket类获取源端口号和目的端口号。 最后,输出五元组信息供进一步的分析和使用。这样,我们就可以使用Java解析PCAP文件中的五元组信息了。当然,解析PCAP文件还涉及到其他的一些操作,比如过滤、统计等,可以根据具体需求进行扩展和处理。 ### 回答3: Java解析pcap文件五元组信息的过程如下: pcap文件是一种网络数据包捕获文件格式,它记录了在计算机网络中传输的数据包的原始内容和元数据。五元组是识别网络数据流的关键信息,包括源IP地址、目标IP地址、源端口号、目标端口号和传输协议。 1. 打开pcap文件:使用Java文件操作类库打开pcap文件,并读取其中的数据包内容和元数据。 2. 解析数据包:遍历pcap文件中的数据包,使用Java的网络协议解析库对每个数据包进行解析。这个过程中可以获取到数据包的源IP地址、目标IP地址、源端口号、目标端口号和传输协议。 3. 保存五元组信息:将每个数据包中解析得到的五元组信息存储在一个数据结构中,比如使用Java的列表或映射等。 4. 分析五元组信息:对保存的五元组信息进行分析,可以统计每个五元组出现的次数,找出频率最高的五元组,或者进行其他复杂的网络分析。 通过以上步骤,使用Java可以很方便地解析pcap文件中的五元组信息。这些信息对于网络安全研究、网络流量监控和网络性能优化等领域都非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bascker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值