default

Coders for the classic libpcap (.pcap) capture file format.

Examples

Round-trip a complete little-endian capture file

import { assertEquals } from "@std/assert";
import {
  pcapFile,
  PCAP_MAGIC_MICROS,
  LINKTYPE,
} from "@binstruct/pcap";

const coder = pcapFile("le");
const value = {
  header: {
    magic: PCAP_MAGIC_MICROS,
    versionMajor: 2,
    versionMinor: 4,
    thisZone: 0,
    sigFigs: 0,
    snapLen: 65535,
    network: LINKTYPE.ETHERNET,
  },
  records: [
    {
      tsSec: 1_700_000_000,
      tsUsec: 250_000,
      inclLen: 4,
      origLen: 4,
      data: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
    },
    {
      tsSec: 1_700_000_001,
      tsUsec: 0,
      inclLen: 2,
      origLen: 1500,
      data: new Uint8Array([0x12, 0x34]),
    },
  ],
};

const buffer = new Uint8Array(128);
const written = coder.encode(value, buffer);
const [decoded] = coder.decode(buffer.subarray(0, written));

assertEquals(written, 24 + 16 + 4 + 16 + 2);
assertEquals(decoded.records.length, 2);
assertEquals(decoded.records[0].data, value.records[0].data);
assertEquals(decoded.records[1].origLen, 1500);

Detect endianness, then decode

import { assertEquals } from "@std/assert";
import {
  detectPcapMagic,
  pcapFile,
  PCAP_MAGIC_MICROS,
  LINKTYPE,
} from "@binstruct/pcap";

const original = pcapFile("be");
const buffer = new Uint8Array(64);
original.encode({
  header: {
    magic: PCAP_MAGIC_MICROS,
    versionMajor: 2,
    versionMinor: 4,
    thisZone: 0,
    sigFigs: 0,
    snapLen: 1500,
    network: LINKTYPE.RAW,
  },
  records: [],
}, buffer);

const info = detectPcapMagic(buffer);
assertEquals(info, { endianness: "be", nanos: false });

const reader = pcapFile(info!.endianness);
const [decoded] = reader.decode(buffer);
assertEquals(decoded.header.network, LINKTYPE.RAW);

Composition with the rest of @binstruct/*

Pcap stores raw link-layer payloads. The natural use is to read a capture, then hand each record.data to a sibling coder for the link type advertised in the global header.

Walk an inet stack: pcap → IPv4 → UDP (LINKTYPE.RAW)

import { assertEquals } from "@std/assert";
import { LINKTYPE, PCAP_MAGIC_MICROS, pcapFile } from "@binstruct/pcap";
import { ipv4Packet } from "@binstruct/ipv4";
import { udpPacket } from "@binstruct/udp";
import { parseAddressv4 } from "@hertzg/ip/addressv4";

const ip = ipv4Packet();
const udp = udpPacket();

// Synth a UDP-over-IPv4 packet to put in the capture.
const udpBytes = new Uint8Array(12);
udp.encode({
  srcPort: 53,
  dstPort: 49152,
  length: 12,
  checksum: 0,
  payload: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
}, udpBytes);

const packet = new Uint8Array(32);
ip.encode({
  versionIhl: { version: 4, ihl: 5 },
  typeOfService: 0,
  totalLength: 32,
  identification: 0,
  flagsFragmentOffset: {
    reserved: 0,
    dontFragment: 0,
    moreFragments: 0,
    fragmentOffset: 0,
  },
  timeToLive: 64,
  protocol: 17,
  headerChecksum: 0,
  sourceAddress: parseAddressv4("192.0.2.1").address,
  destinationAddress: parseAddressv4("192.0.2.2").address,
  options: new Uint8Array(0),
  payload: udpBytes,
}, packet);

const cap = pcapFile("le");
const buf = new Uint8Array(24 + 16 + packet.length);
const written = cap.encode({
  header: {
    magic: PCAP_MAGIC_MICROS,
    versionMajor: 2,
    versionMinor: 4,
    thisZone: 0,
    sigFigs: 0,
    snapLen: 65535,
    network: LINKTYPE.RAW,
  },
  records: [{
    tsSec: 0,
    tsUsec: 0,
    inclLen: packet.length,
    origLen: packet.length,
    data: packet,
  }],
}, buf);

// Walk the stack on read.
const [{ records }] = cap.decode(buf.subarray(0, written));
const [parsedIp] = ip.decode(records[0].data);
const [parsedUdp] = udp.decode(parsedIp.payload);

assertEquals(parsedIp.sourceAddress, parseAddressv4("192.0.2.1").address);
assertEquals(parsedUdp.srcPort, 53);
assertEquals(parsedUdp.payload, new Uint8Array([0xde, 0xad, 0xbe, 0xef]));

Walk the full inet stack (LINKTYPE.ETHERNET via @binstruct/inet)

import { assert, assertEquals } from "@std/assert";
import { LINKTYPE, PCAP_MAGIC_MICROS, pcapFile } from "@binstruct/pcap";
import { inetFrame } from "@binstruct/inet";
import { ETHERTYPE_IPV4 } from "@binstruct/ipv4";
import { IP_PROTOCOL_UDP } from "@binstruct/udp";
import { parseAddressv4 } from "@hertzg/ip/addressv4";

const inet = inetFrame();

// Build an Ethernet → IPv4 → UDP frame in one pass.
const frame = new Uint8Array(14 + 32);
inet.encode({
  dstMac: new Uint8Array([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]),
  srcMac: new Uint8Array([0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb]),
  etherType: ETHERTYPE_IPV4,
  payload: {
    versionIhl: { version: 4, ihl: 5 },
    typeOfService: 0,
    totalLength: 32,
    identification: 0,
    flagsFragmentOffset: { reserved: 0, dontFragment: 0, moreFragments: 0, fragmentOffset: 0 },
    timeToLive: 64,
    protocol: IP_PROTOCOL_UDP,
    headerChecksum: 0,
    sourceAddress: parseAddressv4("192.0.2.1").address,
    destinationAddress: parseAddressv4("192.0.2.2").address,
    options: new Uint8Array(0),
    payload: {
      srcPort: 53,
      dstPort: 49152,
      length: 12,
      checksum: 0,
      payload: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
    },
  },
}, frame);

const cap = pcapFile("le");
const buf = new Uint8Array(24 + 16 + frame.length);
const written = cap.encode({
  header: {
    magic: PCAP_MAGIC_MICROS,
    versionMajor: 2,
    versionMinor: 4,
    thisZone: 0,
    sigFigs: 0,
    snapLen: 65535,
    network: LINKTYPE.ETHERNET,
  },
  records: [{
    tsSec: 0,
    tsUsec: 0,
    inclLen: frame.length,
    origLen: frame.length,
    data: frame,
  }],
}, buf);

// Read back and walk the stack in one shot.
const [{ records }] = cap.decode(buf.subarray(0, written));
const [decoded] = inet.decode(records[0].data);

assert(!(decoded.payload instanceof Uint8Array));
assert("protocol" in decoded.payload);
assertEquals(decoded.payload.sourceAddress, parseAddressv4("192.0.2.1").address);
assert(!(decoded.payload.payload instanceof Uint8Array));
assert("srcPort" in decoded.payload.payload);
assertEquals(decoded.payload.payload.srcPort, 53);
assertEquals(decoded.payload.payload.payload, new Uint8Array([0xde, 0xad, 0xbe, 0xef]));

Functions

f
detectPcapMagic(buffer: Uint8Array): PcapMagicInfo | null

Inspects the first four bytes of a buffer to identify the pcap magic.

f
pcapFileBe(): Coder<PcapFile<PcapGlobalHeader, PcapRecord>>

Creates a coder for a complete pcap capture file fixed to big-endian byte order. Exactly pcapFile("be"), spelled so it can be called with no arguments.

f
pcapFileLe(): Coder<PcapFile<PcapGlobalHeader, PcapRecord>>

Creates a coder for a complete pcap capture file fixed to little-endian byte order. Exactly pcapFile("le"), spelled so it can be called with no arguments.

f
pcapFileWith<THeader, TRecord>(
headerCoder: Coder<THeader>,
recordCoder: Coder<TRecord>
): Coder<PcapFile<THeader, TRecord>>

Creates a coder for a complete pcap capture file using the supplied header and record coders.

f
pcapGlobalHeader(endianness?: PcapEndianness): Coder<PcapGlobalHeader>

Creates a coder for the pcap global header in the requested byte order.

f
pcapRecord(endianness?: PcapEndianness): Coder<PcapRecord>

Creates a coder for a single pcap record (16-byte header plus payload).

Interfaces

I
PcapFile

Decoded representation of a complete pcap capture file.

I
PcapGlobalHeader

Decoded representation of the 24-byte pcap global header.

I
PcapMagicInfo

Result of probing a buffer's first four bytes for a pcap magic number.

I
PcapRecord

Decoded representation of a single pcap record.

Type Aliases

T
LinkType = number

Numeric link-layer header type, as stored in the pcap global header.

T
PcapEndianness = "le" | "be"

Byte order to use for all multi-byte integers in the pcap stream.

Variables

v
LINKTYPE: { NULL: number; ETHERNET: number; AX25: number; IEEE802_5: number; ARCNET_BSD: number; SLIP: number; PPP: number; FDDI: number; RAW: number; IEEE802_11: number; LINUX_SLL: number; PPP_HDLC: number; IEEE802_11_RADIOTAP: number; USB_LINUX: number; BLUETOOTH_HCI_H4: number; LINUX_SLL2: number; }

Common link-layer header type values used in the pcap global header.

v
PCAP_DEFAULT_ENDIANNESS: PcapEndianness

Byte order assumed by the pcap coder factories when none is supplied.

v
PCAP_MAGIC_MICROS: 2712847316

Logical magic number for microsecond-resolution captures.

v
PCAP_MAGIC_NANOS: 2712812621

Logical magic number for nanosecond-resolution captures.