.cap file format of Microsoft Network Monitor, v2.x: Lua parsing library

Microsoft Network Monitor (AKA Netmon) is a proprietary Microsoft's network packet sniffing and analysis tool. It can save captured traffic as .cap files, which usually contain the packets and may contain some additional info - enhanced network info, calculated statistics, etc.

There are at least 2 different versions of the format: v1 and v2. Netmon v3 seems to use the same file format as v1.

Application

Microsoft Network Monitor, v2.x

File extension

cap

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.7

References

This page hosts a formal specification of .cap file format of Microsoft Network Monitor, v2.x using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Lua source code to parse .cap file format of Microsoft Network Monitor, v2.x

microsoft_network_monitor_v2.lua

-- 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 stringstream = require("string_stream")

require("windows_systemtime")
require("ethernet_frame")
-- 
-- Microsoft Network Monitor (AKA Netmon) is a proprietary Microsoft's
-- network packet sniffing and analysis tool. It can save captured
-- traffic as .cap files, which usually contain the packets and may
-- contain some additional info - enhanced network info, calculated
-- statistics, etc.
-- 
-- There are at least 2 different versions of the format: v1 and
-- v2. Netmon v3 seems to use the same file format as v1.
-- See also: Source (https://learn.microsoft.com/en-us/windows/win32/netmon2/capturefile-header-values)
MicrosoftNetworkMonitorV2 = class.class(KaitaiStruct)

MicrosoftNetworkMonitorV2.Linktype = enum.Enum {
  null_linktype = 0,
  ethernet = 1,
  ax25 = 3,
  ieee802_5 = 6,
  arcnet_bsd = 7,
  slip = 8,
  ppp = 9,
  fddi = 10,
  ppp_hdlc = 50,
  ppp_ether = 51,
  atm_rfc1483 = 100,
  raw = 101,
  c_hdlc = 104,
  ieee802_11 = 105,
  frelay = 107,
  loop = 108,
  linux_sll = 113,
  ltalk = 114,
  pflog = 117,
  ieee802_11_prism = 119,
  ip_over_fc = 122,
  sunatm = 123,
  ieee802_11_radiotap = 127,
  arcnet_linux = 129,
  apple_ip_over_ieee1394 = 138,
  mtp2_with_phdr = 139,
  mtp2 = 140,
  mtp3 = 141,
  sccp = 142,
  docsis = 143,
  linux_irda = 144,
  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,
  bacnet_ms_tp = 165,
  ppp_pppd = 166,
  gprs_llc = 169,
  gpf_t = 170,
  gpf_f = 171,
  linux_lapd = 177,
  bluetooth_hci_h4 = 187,
  usb_linux = 189,
  ppi = 192,
  ieee802_15_4 = 195,
  sita = 196,
  erf = 197,
  bluetooth_hci_h4_with_phdr = 201,
  ax25_kiss = 202,
  lapd = 203,
  ppp_with_dir = 204,
  c_hdlc_with_dir = 205,
  frelay_with_dir = 206,
  ipmb_linux = 209,
  ieee802_15_4_nonask_phy = 215,
  usb_linux_mmapped = 220,
  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,
  dvb_ci = 235,
  mux27010 = 236,
  stanag_5066_d_pdu = 237,
  nflog = 239,
  netanalyzer = 240,
  netanalyzer_transparent = 241,
  ipoib = 242,
  mpeg_2_ts = 243,
  ng40 = 244,
  nfc_llcp = 245,
  infiniband = 247,
  sctp = 248,
  usbpcap = 249,
  rtac_serial = 250,
  bluetooth_le_ll = 251,
  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,
}

function MicrosoftNetworkMonitorV2:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function MicrosoftNetworkMonitorV2:_read()
  self.signature = self._io:read_bytes(4)
  if not(self.signature == "\071\077\066\085") then
    error("not equal, expected " ..  "\071\077\066\085" .. ", but got " .. self.signature)
  end
  self.version_minor = self._io:read_u1()
  self.version_major = self._io:read_u1()
  self.mac_type = MicrosoftNetworkMonitorV2.Linktype(self._io:read_u2le())
  self.time_capture_start = WindowsSystemtime(self._io)
  self.frame_table_ofs = self._io:read_u4le()
  self.frame_table_len = self._io:read_u4le()
  self.user_data_ofs = self._io:read_u4le()
  self.user_data_len = self._io:read_u4le()
  self.comment_ofs = self._io:read_u4le()
  self.comment_len = self._io:read_u4le()
  self.statistics_ofs = self._io:read_u4le()
  self.statistics_len = self._io:read_u4le()
  self.network_info_ofs = self._io:read_u4le()
  self.network_info_len = self._io:read_u4le()
  self.conversation_stats_ofs = self._io:read_u4le()
  self.conversation_stats_len = self._io:read_u4le()
end

-- 
-- Index that is used to access individual captured frames.
MicrosoftNetworkMonitorV2.property.frame_table = {}
function MicrosoftNetworkMonitorV2.property.frame_table:get()
  if self._m_frame_table ~= nil then
    return self._m_frame_table
  end

  local _pos = self._io:pos()
  self._io:seek(self.frame_table_ofs)
  self._raw__m_frame_table = self._io:read_bytes(self.frame_table_len)
  local _io = KaitaiStream(stringstream(self._raw__m_frame_table))
  self._m_frame_table = MicrosoftNetworkMonitorV2.FrameIndex(_io, self, self._root)
  self._io:seek(_pos)
  return self._m_frame_table
end

-- 
-- Format version (minor), BCD.
-- 
-- Format version (major), BCD.
-- 
-- Network topology type of captured data.
-- 
-- Timestamp of capture start.

MicrosoftNetworkMonitorV2.FrameIndex = class.class(KaitaiStruct)

function MicrosoftNetworkMonitorV2.FrameIndex:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function MicrosoftNetworkMonitorV2.FrameIndex:_read()
  self.entries = {}
  local i = 0
  while not self._io:is_eof() do
    self.entries[i + 1] = MicrosoftNetworkMonitorV2.FrameIndexEntry(self._io, self, self._root)
    i = i + 1
  end
end


-- 
-- Each index entry is just a pointer to where the frame data is
-- stored in the file.
MicrosoftNetworkMonitorV2.FrameIndexEntry = class.class(KaitaiStruct)

function MicrosoftNetworkMonitorV2.FrameIndexEntry:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function MicrosoftNetworkMonitorV2.FrameIndexEntry:_read()
  self.ofs = self._io:read_u4le()
end

-- 
-- Frame body itself.
MicrosoftNetworkMonitorV2.FrameIndexEntry.property.body = {}
function MicrosoftNetworkMonitorV2.FrameIndexEntry.property.body:get()
  if self._m_body ~= nil then
    return self._m_body
  end

  local _io = self._root._io
  local _pos = _io:pos()
  _io:seek(self.ofs)
  self._m_body = MicrosoftNetworkMonitorV2.Frame(_io, self, self._root)
  _io:seek(_pos)
  return self._m_body
end

-- 
-- Absolute pointer to frame data in the file.

-- 
-- A container for actually captured network data. Allow to
-- timestamp individual frames and designates how much data from
-- the original packet was actually written into the file.
-- See also: Source (https://learn.microsoft.com/en-us/windows/win32/netmon2/frame)
MicrosoftNetworkMonitorV2.Frame = class.class(KaitaiStruct)

function MicrosoftNetworkMonitorV2.Frame:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function MicrosoftNetworkMonitorV2.Frame:_read()
  self.ts_delta = self._io:read_u8le()
  self.orig_len = self._io:read_u4le()
  self.inc_len = self._io:read_u4le()
  local _on = self._root.mac_type
  if _on == MicrosoftNetworkMonitorV2.Linktype.ethernet then
    self._raw_body = self._io:read_bytes(self.inc_len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = EthernetFrame(_io)
  else
    self.body = self._io:read_bytes(self.inc_len)
  end
end

-- 
-- Time stamp - usecs since start of capture.
-- 
-- Actual length of packet.
-- 
-- Number of octets captured in file.
-- 
-- Actual packet captured from the network.