首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 解析 PCAP 封包檔案完整實作範例

     編輯:Java 相關知識

Java 解析 PCAP 封包檔案完整實作範例

PCAP (Packet Capture) 是網路封包擷取的標準檔案格式。本文提供一組純 Java 實作的 PCAP 解析器,無需第三方庫即可讀取全域標頭、封包記錄標頭與封包資料,適合嵌入式環境或不想引入龐大依賴的專案。

架構設計

  • PcapParser:靜態解析入口,讀取 InputStream 回傳 Pcap 物件。
  • Pcap:容器類別,持有 PcapHeader 與 List<PcapData>。
  • PcapHeader:全域檔案標頭 (Magic Number、版本、時區、鏈路類型等)。
  • PcapData:單一封包記錄 (時間戳、擷取長度、原始長度、原始資料)。

核心解析邏輯 (PcapParser.unpack)

public static Pcap unpack(InputStream is) throws IOException {
    Pcap pcap = new Pcap();
    byte[] buf4 = new byte[4];
    byte[] buf2 = new byte[2];

    // 1. 讀取全域標頭 (24 bytes)
    PcapHeader header = new PcapHeader();
    readFully(is, buf4); header.setMagic(reverseInt(buf4));       // 0xA1B2C3D4
    readFully(is, buf2); header.setMagorVersion(reverseShort(buf2));
    readFully(is, buf2); header.setMinorVersion(reverseShort(buf2));
    readFully(is, buf4); header.setTimezone(reverseInt(buf4));
    readFully(is, buf4); header.setSigflags(reverseInt(buf4));
    readFully(is, buf4); header.setSnaplen(reverseInt(buf4));
    readFully(is, buf4); header.setLinktype(reverseInt(buf4));    // 1 = Ethernet
    pcap.setHeader(header);

    // 2. 循環讀取封包記錄
    List packets = new ArrayList<>();
    while (true) {
        int n = is.read(buf4);
        if (n != 4) break; // EOF
        PcapData data = new PcapData();
        data.setTimeSec(reverseInt(buf4));      // 秒
        readFully(is, buf4); data.setTimeUsec(reverseInt(buf4)); // 微秒
        readFully(is, buf4); data.setCapturedLen(reverseInt(buf4)); // 擷取長度
        readFully(is, buf4); data.setOriginalLen(reverseInt(buf4)); // 原始長度

        byte[] content = new byte[data.getCapturedLen()];
        readFully(is, content);
        data.setContent(content);
        packets.add(data);
    }
    pcap.setData(packets);
    return pcap;
}

// 輔助:確保讀滿指定位元組
private static void readFully(InputStream is, byte[] buf) throws IOException {
    int offset = 0;
    while (offset < buf.length) {
        int r = is.read(buf, offset, buf.length - offset);
        if (r == -1) throw new EOFException();
        offset += r;
    }
}

// 大端序轉換 (PCAP 檔案採用大端序)
private static int reverseInt(byte[] b) { ... }
private static short reverseShort(byte[] b) { ... }

使用範例

try (InputStream is = getClass().getResourceAsStream("/capture.pcap")) {
    Pcap pcap = PcapParser.unpack(is);
    System.out.println("Linktype: " + pcap.getHeader().getLinktype());
    System.out.println("Packets: " + pcap.getData().size());
    
    // 取得第一個封包的 IP 負載 (跳過 14 字節 Ethernet + 20 字節 IP = 34, 視協定而定)
    if (!pcap.getData().isEmpty()) {
        byte[] raw = pcap.getData().get(0).getContent();
        byte[] payload = Arrays.copyOfRange(raw, 34, raw.length);
        // 進一步解析 TCP/UDP...
    }
}

關鍵細節補充

  • 位元組序:標準 PCAP 檔案為大端序 (Big Endian),Magic Number 0xA1B2C3D4 確認;若為 0xD4C3B2A1 則為小端序,需調整轉換邏輯。
  • 鏈路類型 (Linktype):常見值 1 (Ethernet)、101 (Raw IP)、113 (Linux cooked)、105 (802.11)。解析封包負載前必須先判斷鏈路層封裝格式。
  • 大檔案處理:採用流式讀取避免 OOM,若需隨機存取可建立索引檔。
  • 擴充性:可整合 jNetPcap 或 Pcap4J 進行深度協定解析 (TCP 重組、HTTP 解碼等)。

完整類別定義參考

文中包含 Pcap, PcapHeader, PcapData 完整 Getter/Setter 與 toString() 實作,可直接複製使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved