Read a libpcap Savefile Without Guessing the Bytes
A colleague hands you a raw .pcap file and no context, and this is how you work out what it actually contains before you trust anything in it. You will identify the format from the first bytes, and explain packet lengths and timestamps without changing the capture itself. The examples use tcpdump 4.99.4 with libpcap 1.10.4, from Ubuntu package libpcap0.8t64 version 1.10.4-4.1ubuntu3.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, a readable capture file, and the installed tcpdump command. Reading an existing file is normally unprivileged. Capturing new traffic may need elevated privileges or extra Linux capabilities, but that is a different guide entirely.
1. Confirm the tools and preserve the original
Start with read-only checks that need no sudo and never open the capture for writing:
$ command -v tcpdump
/usr/bin/tcpdump
$ tcpdump --version
tcpdump version 4.99.4
libpcap version 1.10.4 (with TPACKET_V3)
$ dpkg-query -W -f='${Package} ${Version}\n' libpcap0.8t64
libpcap0.8t64 1.10.4-4.1ubuntu3
Replace /path/to/capture.pcap in every command below with your real path. Before you run anything that writes output, make a copy or pick a new destination. Never redirect onto the only copy of a capture: > truncates its destination before the command has even succeeded.
Checkpoint
The input is readable, and you know exactly which file must stay untouched. If it holds sensitive traffic, restrict access to the copy and keep it away from an online analyser.
2. Ask libpcap to read the file
Let a real libpcap consumer parse the file before you go poking at raw bytes yourself. This is the practical test for a recognisable savefile header and records:
$ tcpdump -nn -tttt -r /path/to/capture.pcap
reading from file /path/to/capture.pcap, link-type EN10MB (Ethernet), snapshot length 262144
2026-09-25 18:20:31.123456 IP 192.0.2.10.443 > 192.0.2.20.51000: ...
Your link type, snapshot length, timestamps and packet lines will all differ. -r reads an existing file, -nn keeps addresses and ports numeric, and -tttt prints a human-readable date and time. Treat the sample line as an illustration of the shape, not a value to expect verbatim.
An empty capture can still be valid: the file header may exist with zero packet records inside it. Just as easily, a file that opens with plausible-looking text is not automatically a pcap file. Treat tcpdump's own parser result as your first real checkpoint.
3. Inspect the 24-byte file header
The classic savefile header is 24 octets. View only those bytes, so a large capture does not flood your terminal:
$ file /path/to/capture.pcap
/path/to/capture.pcap: pcap capture file, ...
$ xxd -g 1 -l 24 /path/to/capture.pcap
00000000: d4 c3 b2 a1 02 00 04 00 00 00 00 00 00 00 00 00 ................
00000010: 00 00 04 00 01 00 00 00 ........
The exact file description and bytes depend on whatever wrote the capture. In this little-endian example, the first four bytes are d4 c3 b2 a1, the normal microsecond format when read by a host with the opposite byte order to the writer. A reader uses that magic value to decide whether multi-byte fields need swapping.
The usual magic value is 0xa1b2c3d4 in the writer's byte order. A related value, 0xa1b23c4d, marks the same layout but with nanosecond timestamps instead of microseconds. Do not treat the byte sequence above as a universal signature to paste into a script: byte order changes it.
After the magic number come a two-byte major version and a two-byte minor version, currently 2 and 4 according to the installed manual. Next are two four-byte fields for time-zone offset and timestamp accuracy, both of which should read zero. The final two four-byte fields give the snapshot length and the link-layer header type.
Checkpoint
You can say whether the file uses microsecond or nanosecond timestamps, and you have not treated the first four bytes as a native integer without thinking about byte order.
4. Interpret snapshot length and packet lengths
Snapshot length is a capture limit, not a promise that every packet is that size. If it reads N, a packet longer than N bytes is stored only up to its first N bytes. The link-layer type tells libpcap how to read the packet's raw beginning, and tcpdump normally reports it in its file-reading message.
Each packet record opens with a 16-octet header holding four four-byte values: seconds since 1 January 1970 UTC, the fractional part in microseconds or nanoseconds, the number of captured bytes, and the number of bytes that would have existed without snapshot truncation. The captured length is usually called caplen, the original length len.
When caplen and len differ, the capture limit cut the packet short. That matters for analysis: a missing payload can make a protocol decoder give up early, even though the original length still shows more data existed. Equal values just mean the snapshot limit did not shorten this particular packet, not that the network packet was small in any other sense.
Use tcpdump's verbose packet output as a second, operational check rather than calculating offsets by hand first:
$ tcpdump -nn -vvv -r /path/to/capture.pcap | head -n 20
reading from file /path/to/capture.pcap, link-type EN10MB (Ethernet), snapshot length 262144
...
The pipe only limits what gets displayed, it does not alter the capture. If you need the output for a report, redirect it into a new text file in a directory you have already checked.
5. Diagnose the common failure modes
A truncated dump file message while reading the header, packet header or packet data means the file is shorter than its own length fields require. Check its size and compare it against a known-good copy:
$ stat --format='size=%s bytes mode=%A path=%n' /path/to/capture.pcap
size=0 bytes mode=-rw------- path=/path/to/capture.pcap
$ tcpdump -nn -r /path/to/capture.pcap
tcpdump: truncated dump file; tried to read 4 file header bytes, only got 0
Do not repair a damaged capture by inventing lengths or padding it with zeroes. Get the file again from its producer, or work from a verified backup instead. Some tools may still show earlier records when only the final packet is incomplete, but that does not make the file whole.
If the parser reports an unknown or unsupported link type, the savefile header may be perfectly intact while your installed libpcap simply lacks the decoder for that link-layer value. Record the header and tool versions, then try the file against a compatible libpcap build. Never silently relabel the link type, that changes how every single packet gets interpreted.
If a command cannot open the path at all, check it and its permissions without changing them:
$ test -r /path/to/capture.pcap && echo readable
readable
$ ls -l /path/to/capture.pcap
Reach for elevated privileges only when the filesystem genuinely requires them, and prefer granting read access to a controlled copy instead. Root is not a format decoder and should never be the first response to a parsing error.
Done means
- File readable.
tcpdump -rcan read the capture, or you have recorded a precise truncation or unsupported-format error. - Header understood. You identified the 24-octet header's byte order, timestamp precision, version, snapshot length and link-layer type.
- Packet structure clear. You know each packet has a 16-octet header and can tell captured length from original length.
- Original preserved. The capture stayed unchanged, and diagnostic output went somewhere else entirely.
- No shortcuts taken. You avoided root, avoided guessing a link type, and never treated a truncated file as complete evidence.