PCAP (named after libpcap / winpcap) is a popular format for saving network traffic grabbed by network sniffers. It is typically produced by tools like tcpdump or Wireshark.
This page hosts a formal specification of .pcap / .pcapdump file format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3
local class = require("class")
require("kaitaistruct")
local enum = require("enum")
local utils = require("utils")
local stringstream = require("string_stream")
require("packet_ppi")
require("ethernet_frame")
--
-- PCAP (named after libpcap / winpcap) is a popular format for saving
-- network traffic grabbed by network sniffers. It is typically
-- produced by tools like [tcpdump](https://www.tcpdump.org/) or
-- [Wireshark](https://www.wireshark.org/).
-- See also: Source (https://wiki.wireshark.org/Development/LibpcapFileFormat)
Pcap = class.class(KaitaiStruct)
Pcap.Linktype = enum.Enum {
null_linktype = 0,
ethernet = 1,
exp_ethernet = 2,
ax25 = 3,
pronet = 4,
chaos = 5,
ieee802_5 = 6,
arcnet_bsd = 7,
slip = 8,
ppp = 9,
fddi = 10,
redback_smartedge = 32,
ppp_hdlc = 50,
ppp_ether = 51,
symantec_firewall = 99,
atm_rfc1483 = 100,
raw = 101,
c_hdlc = 104,
ieee802_11 = 105,
atm_clip = 106,
frelay = 107,
loop = 108,
enc = 109,
netbsd_hdlc = 112,
linux_sll = 113,
ltalk = 114,
econet = 115,
ipfilter = 116,
pflog = 117,
cisco_ios = 118,
ieee802_11_prism = 119,
aironet_header = 120,
ip_over_fc = 122,
sunatm = 123,
rio = 124,
pci_exp = 125,
aurora = 126,
ieee802_11_radiotap = 127,
tzsp = 128,
arcnet_linux = 129,
juniper_mlppp = 130,
juniper_mlfr = 131,
juniper_es = 132,
juniper_ggsn = 133,
juniper_mfr = 134,
juniper_atm2 = 135,
juniper_services = 136,
juniper_atm1 = 137,
apple_ip_over_ieee1394 = 138,
mtp2_with_phdr = 139,
mtp2 = 140,
mtp3 = 141,
sccp = 142,
docsis = 143,
linux_irda = 144,
ibm_sp = 145,
ibm_sn = 146,
user0 = 147,
user1 = 148,
user2 = 149,
user3 = 150,
user4 = 151,
user5 = 152,
user6 = 153,
user7 = 154,
user8 = 155,
user9 = 156,
user10 = 157,
user11 = 158,
user12 = 159,
user13 = 160,
user14 = 161,
user15 = 162,
ieee802_11_avs = 163,
juniper_monitor = 164,
bacnet_ms_tp = 165,
ppp_pppd = 166,
juniper_pppoe = 167,
juniper_pppoe_atm = 168,
gprs_llc = 169,
gpf_t = 170,
gpf_f = 171,
gcom_t1e1 = 172,
gcom_serial = 173,
juniper_pic_peer = 174,
erf_eth = 175,
erf_pos = 176,
linux_lapd = 177,
juniper_ether = 178,
juniper_ppp = 179,
juniper_frelay = 180,
juniper_chdlc = 181,
mfr = 182,
juniper_vp = 183,
a429 = 184,
a653_icm = 185,
usb_freebsd = 186,
bluetooth_hci_h4 = 187,
ieee802_16_mac_cps = 188,
usb_linux = 189,
can20b = 190,
ieee802_15_4_linux = 191,
ppi = 192,
ieee802_16_mac_cps_radio = 193,
juniper_ism = 194,
ieee802_15_4_withfcs = 195,
sita = 196,
erf = 197,
raif1 = 198,
ipmb_kontron = 199,
juniper_st = 200,
bluetooth_hci_h4_with_phdr = 201,
ax25_kiss = 202,
lapd = 203,
ppp_with_dir = 204,
c_hdlc_with_dir = 205,
frelay_with_dir = 206,
lapb_with_dir = 207,
ipmb_linux = 209,
flexray = 210,
most = 211,
lin = 212,
x2e_serial = 213,
x2e_xoraya = 214,
ieee802_15_4_nonask_phy = 215,
linux_evdev = 216,
gsmtap_um = 217,
gsmtap_abis = 218,
mpls = 219,
usb_linux_mmapped = 220,
dect = 221,
aos = 222,
wihart = 223,
fc_2 = 224,
fc_2_with_frame_delims = 225,
ipnet = 226,
can_socketcan = 227,
ipv4 = 228,
ipv6 = 229,
ieee802_15_4_nofcs = 230,
dbus = 231,
juniper_vs = 232,
juniper_srx_e2e = 233,
juniper_fibrechannel = 234,
dvb_ci = 235,
mux27010 = 236,
stanag_5066_d_pdu = 237,
juniper_atm_cemic = 238,
nflog = 239,
netanalyzer = 240,
netanalyzer_transparent = 241,
ipoib = 242,
mpeg_2_ts = 243,
ng40 = 244,
nfc_llcp = 245,
pfsync = 246,
infiniband = 247,
sctp = 248,
usbpcap = 249,
rtac_serial = 250,
bluetooth_le_ll = 251,
wireshark_upper_pdu = 252,
netlink = 253,
bluetooth_linux_monitor = 254,
bluetooth_bredr_bb = 255,
bluetooth_le_ll_with_phdr = 256,
profibus_dl = 257,
pktap = 258,
epon = 259,
ipmi_hpm_2 = 260,
zwave_r1_r2 = 261,
zwave_r3 = 262,
wattstopper_dlm = 263,
iso_14443 = 264,
rds = 265,
usb_darwin = 266,
openflow = 267,
sdlc = 268,
ti_lln_sniffer = 269,
loratap = 270,
vsock = 271,
nordic_ble = 272,
docsis31_xra31 = 273,
ethernet_mpacket = 274,
displayport_aux = 275,
linux_sll2 = 276,
sercos_monitor = 277,
openvizsla = 278,
ebhscr = 279,
vpp_dispatch = 280,
dsa_tag_brcm = 281,
dsa_tag_brcm_prepend = 282,
ieee802_15_4_tap = 283,
dsa_tag_dsa = 284,
dsa_tag_edsa = 285,
elee = 286,
zwave_serial = 287,
usb_2_0 = 288,
atsc_alp = 289,
etw = 290,
netanalyzer_ng = 291,
zboss_ncp = 292,
usb_2_0_low_speed = 293,
usb_2_0_full_speed = 294,
usb_2_0_high_speed = 295,
auerswald_log = 296,
zwave_tap = 297,
silabs_debug_channel = 298,
fira_uci = 299,
}
function Pcap:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Pcap:_read()
self.hdr = Pcap.Header(self._io, self, self._root)
self.packets = {}
local i = 0
while not self._io:is_eof() do
self.packets[i + 1] = Pcap.Packet(self._io, self, self._root)
i = i + 1
end
end
--
-- See also: Source (https://wiki.wireshark.org/Development/LibpcapFileFormat#Global_Header)
Pcap.Header = class.class(KaitaiStruct)
function Pcap.Header:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Pcap.Header:_read()
self.magic_number = self._io:read_bytes(4)
if not(self.magic_number == "\212\195\178\161") then
error("not equal, expected " .. "\212\195\178\161" .. ", but got " .. self.magic_number)
end
self.version_major = self._io:read_u2le()
if not(self.version_major == 2) then
error("not equal, expected " .. 2 .. ", but got " .. self.version_major)
end
self.version_minor = self._io:read_u2le()
self.thiszone = self._io:read_s4le()
self.sigfigs = self._io:read_u4le()
self.snaplen = self._io:read_u4le()
self.network = Pcap.Linktype(self._io:read_u4le())
end
--
-- Correction time in seconds between UTC and the local
-- timezone of the following packet header timestamps.
--
-- In theory, the accuracy of time stamps in the capture; in
-- practice, all tools set it to 0.
--
-- The "snapshot length" for the capture (typically 65535 or
-- even more, but might be limited by the user), see: incl_len
-- vs. orig_len.
--
-- Link-layer header type, specifying the type of headers at
-- the beginning of the packet.
--
-- See also: Source (https://wiki.wireshark.org/Development/LibpcapFileFormat#Record_.28Packet.29_Header)
Pcap.Packet = class.class(KaitaiStruct)
function Pcap.Packet:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Pcap.Packet:_read()
self.ts_sec = self._io:read_u4le()
self.ts_usec = self._io:read_u4le()
self.incl_len = self._io:read_u4le()
self.orig_len = self._io:read_u4le()
local _on = self._root.hdr.network
if _on == Pcap.Linktype.ppi then
self._raw_body = self._io:read_bytes(utils.box_unwrap((self.incl_len < self._root.hdr.snaplen) and utils.box_wrap(self.incl_len) or (self._root.hdr.snaplen)))
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = PacketPpi(_io)
elseif _on == Pcap.Linktype.ethernet then
self._raw_body = self._io:read_bytes(utils.box_unwrap((self.incl_len < self._root.hdr.snaplen) and utils.box_wrap(self.incl_len) or (self._root.hdr.snaplen)))
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = EthernetFrame(_io)
else
self.body = self._io:read_bytes(utils.box_unwrap((self.incl_len < self._root.hdr.snaplen) and utils.box_wrap(self.incl_len) or (self._root.hdr.snaplen)))
end
end
--
-- Number of bytes of packet data actually captured and saved in the file.
--
-- Length of the packet as it appeared on the network when it was captured.
--
-- See also: Source (https://wiki.wireshark.org/Development/LibpcapFileFormat#Packet_Data)