PCAP (Packet Capture) 是網路封包擷取的標準檔案格式。本文提供一組純 Java 實作的 PCAP 解析器,無需第三方庫即可讀取全域標頭、封包記錄標頭與封包資料,適合嵌入式環境或不想引入龐大依賴的專案。
InputStream 回傳 Pcap 物件。PcapHeader 與 List<PcapData>。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...
}
}
0xA1B2C3D4 確認;若為 0xD4C3B2A1 則為小端序,需調整轉換邏輯。1 (Ethernet)、101 (Raw IP)、113 (Linux cooked)、105 (802.11)。解析封包負載前必須先判斷鏈路層封裝格式。jNetPcap 或 Pcap4J 進行深度協定解析 (TCP 重組、HTTP 解碼等)。文中包含 Pcap, PcapHeader, PcapData 完整 Getter/Setter 與 toString() 實作,可直接複製使用。