Skip to content

Capture Files

A capture on a terminal scrolls away, and the interesting packet is always the one that scrolled. Writing captures to a file is the habit that turns tcpdump from a live toy into a record: the file can be re-read, re-filtered, summarised, attached to a bug report, or opened in Wireshark on another machine — and it says exactly what it said the first time.

Writing: -w

$ tcpdump -i lo -nn -Z root -w specimen.pcap "tcp port 45080 or icmp"
  (second terminal: curl -s http://127.0.0.1:45080/; ping -c 2 127.0.0.1)
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16 packets captured
32 packets received by filter
0 packets dropped by kernel

$ ls -l specimen.pcap
-rw-rw---- 1 root nogroup 1908 Oct 20 21:47 specimen.pcap

$ file specimen.pcap
specimen.pcap: pcap capture file, microsecond ts (little-endian) - version 2.4 (Ethernet, capture length 262144)

Sixteen packets — the whole web conversation plus two pings — in 1,908 bytes of pcap, the standard capture format: a small header, then each packet's timestamp, true length, captured length, and bytes. With -w, tcpdump prints nothing per packet; the chatter goes to the file and only the footer remains on stderr. (The footer counts all three numbers, as in chapter 2.)

The -Z root needs its sentence, because it is the one flag here that is the build machine's, not tcpdump's. Run as root, tcpdump drops privileges to an unprivileged user (tcpdump) and makes the savefile that user's. On this build machine the ownership change is refused by the environment, and without -Z the run fails outright — chapter 9 keeps the error and the 24-byte header-only file it leaves behind. -Z root says "drop to root instead," which the environment accepts. On an ordinary machine, run tcpdump as root (or with sudo) and plain -w works exactly as documented; if you ever meet the ownership error on a locked-down box of your own, you now own its fix too.

A copy of this very file ships as examples/specimen.pcap, so the rest of the chapter works before you've captured anything.

Reading: -r, and filtering twice

$ tcpdump -r specimen.pcap -nn
21:47:29.638439 IP 127.0.0.1.33162 > 127.0.0.1.45080: Flags [S], seq 2946274604, win 65495, ...
... (all sixteen packets, in capture order) ...
21:47:29.951156 IP 127.0.0.1 > 127.0.0.1: ICMP echo reply, id 16842, seq 2, length 64

Reading is printing, from the file instead of the wire — every display flag works, and so do filters, applied again, at read time:

$ tcpdump -r specimen.pcap -nn icmp
21:47:29.645408 IP 127.0.0.1 > 127.0.0.1: ICMP echo request, id 16842, seq 1, length 64
21:47:29.645419 IP 127.0.0.1 > 127.0.0.1: ICMP echo reply, id 16842, seq 1, length 64
21:47:29.951141 IP 127.0.0.1 > 127.0.0.1: ICMP echo request, id 16842, seq 2, length 64
21:47:29.951156 IP 127.0.0.1 > 127.0.0.1: ICMP echo reply, id 16842, seq 2, length 64

That pair of habits — capture wide, filter at leisure — is the professional pattern. The filter at capture time is a decision you can't unmake; the filter at read time is a question you can keep asking. Capture-time filters still earn their place on busy links (chapter 8's drops are why), but when disk is cheaper than regret, save more than you think you need.

-tttt belongs to reading: it prints each packet's full date beside the time, turning a wall of 21:47:29s into a timeline a report can quote:

$ tcpdump -r specimen.pcap -nn -tttt | head -3
2026-10-20 21:47:29.638439 IP 127.0.0.1.33162 > 127.0.0.1.45080: Flags [S], seq 2946274604, win 65495, ...

Rotation: -G and -W

A capture left running needs a leash. -G seconds starts a new file every so often (the filename is a strftime pattern, so the time is in the name); -W count caps how many files the capture keeps:

$ tcpdump -i lo -nn -Z root -G 2 -W 3 -w rot-%H%M%S.pcap icmp
  (second terminal: ping -c 8 -i 0.7 127.0.0.1)
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
Maximum file limit reached: 3
13 packets captured

$ ls -l rot-*.pcap
-rw-rw---- 1 root nogroup 252 Oct 20 21:48 rot-214813.pcap
-rw-rw---- 1 root nogroup 480 Oct 20 21:48 rot-214815.pcap
-rw-rw---- 1 root nogroup 708 Oct 20 21:48 rot-214817.pcap

Three files, two seconds apart, and tcpdump stopped itself at the limit ("Maximum file limit reached" — with -W and no other bound, reaching the cap ends the capture rather than wrapping forever; read the manual page before leaving one running for a weekend). Thirteen of the burst's sixteen packets made it into files before the stop — rotation is a budget, and the footer keeps the accounts. For a bounded watch, the shape is -G 3600 -W 24: a day of hourly captures, and then it stops — disk use decided in advance, not discovered later.

Check: read the shipped examples/specimen.pcap with a filter that matches nothing in it — udp, say (the file holds TCP and ICMP only). The output is empty and instant, and nobody waited on a network for it. That emptiness is free: it's the capture- time emptiness of chapter 9 that costs you the evidence.