Capture the Right Packets with tcpdump

Run tcpdump with no filter on a busy host and you get a wall of noise instead of the one connection you actually care about. This guide gets you a small, targeted capture, a saved file you can replay later, and the habits that stop a capture from filling a disk or leaking data it shouldn't. Allow 10 to 15 minutes for a first check.

You need a Linux shell, the tcpdump package, and permission to capture on the chosen interface. Reading an existing capture file normally needs no elevated privilege; live capture often does.

1. Check the installed build

Start by recording the version and available interfaces, not by guessing. This guide was tested with tcpdump 4.99.4, libpcap 1.10.4 and OpenSSL 3.0.13.

$ tcpdump --version
tcpdump version 4.99.4
libpcap version 1.10.4 (with TPACKET_V3)
$ tcpdump -D
1.enp0s31f6 [Up, Running, Connected]
2.docker0 [Up, Running, Connected]
...

2. Compile and review a filter before capturing

A filter expression is the most useful safety boundary tcpdump gives you: it decides which packets are even looked at. Compile one without starting a capture by using -d:

$ tcpdump -d -i enp0s31f6 'tcp port 443'
(000) ldh      [12]
...
(014) ret      #262144
(015) ret      #0

The instruction list can differ with the link-layer type; what matters is that tcpdump accepted the expression. Quoting protects it from shell metacharacters and keeps it together as one argument. The example above selects TCP traffic on port 443. Other narrow, useful forms:

Do not confuse a display preference with a filter. -n stops address and port name lookups; the expression is what decides which packets are selected. Keeping -n on avoids delays and misleading reverse-DNS traffic during an incident.

3. Take a bounded live capture

Use -c while exploring, so the command exits after a known number of packets instead of running until you remember to stop it:

$ sudo tcpdump -i enp0s31f6 -n -c 20 'tcp port 443'
tcpdump: listening on enp0s31f6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:34:56.123456 IP 192.0.2.20.51512 > 198.51.100.20.443: Flags [S], seq 123, win 64240, length 0
...
20 packets captured
20 packets received by filter
0 packets dropped by kernel

The addresses above are examples, not what you should expect to see. Without -c, press Control-C to stop. Check the final counters before you trust the capture: a non-zero dropped count means the kernel could not keep up, and the trace is incomplete.

Tip: if you hit a permission error, check the interface and account first. Use sudo only for the capture itself and follow your distribution's policy for granting packet-capture access; do not make a broad, permanent privilege change just to dodge one prompt.

4. Save packets for repeatable analysis

-w writes raw packets to a pcap savefile instead of printing decoded lines. Treat the result as sensitive: a capture can contain credentials, tokens, personal messages and internal addresses, so write it somewhere protected.

$ umask 077
$ sudo tcpdump -i enp0s31f6 -n -c 100 -w /tmp/tcpdump-https.pcap 'tcp port 443'
tcpdump: listening on enp0s31f6, link-type EN10MB (Ethernet), snapshot length 262144 bytes
100 packets captured
...

Read it back as an unprivileged user if file ownership allows:

$ tcpdump -r /tmp/tcpdump-https.pcap -n -c 5
reading from file /tmp/tcpdump-https.pcap, link-type EN10MB (Ethernet), snapshot length 262144
12:34:56.123456 IP 192.0.2.20.51512 > 198.51.100.20.443: Flags [S], seq 123, win 64240, length 0
...

Reading a savefile needs no capture privilege at all. If the original capture was intentionally broad, apply a second filter while reading it:

$ tcpdump -r /tmp/tcpdump-https.pcap -n 'tcp[tcpflags] & tcp-syn != 0'

That expression pulls out packets carrying the TCP SYN flag. No output lines is not the same as a failed read; it may just mean the file has no matching packets. Keep the original file until the investigation is closed.

5. Choose output that answers the question

Start with the default summary line. Add detail only when you need it: -e for Ethernet addresses, -v, -vv or -vvv for protocol detail, -X or -A only when payload inspection is actually justified. More detail means more noise, and possibly sensitive content sitting in a terminal or log file.

$ tcpdump -r /tmp/tcpdump-https.pcap -nn -tttt -c 3 'host 192.0.2.20'
reading from file /tmp/tcpdump-https.pcap, link-type EN10MB (Ethernet), snapshot length 262144
2026-09-27 12:34:56.123456 IP 192.0.2.20.51512 > 198.51.100.20.443: Flags [S], seq 123, win 64240, length 0
...

-nn turns off both hostname and service-name conversion. -tttt prints a date and time that is easier to line up against other logs. A matching timestamp is not proof that two packets came from the same process or connection; correlate it with ports, addresses and other evidence before you conclude anything.

6. Handle large or long-running captures carefully

A long capture can fill a filesystem and quietly retain more confidential data than you meant to keep. Bound it with -c, narrow the expression, and check the destination filesystem before you start. For rotation, -G needs a time format in the -w filename:

$ sudo tcpdump -i enp0s31f6 -n -G 60 -W 5 -w '/tmp/trace-%Y%m%d-%H%M%S.pcap' 'host 192.0.2.10'

This asks for 60-second files, five of them, rotating. Test rotation with a short interval and a disposable directory first: a filename format that isn't actually unique per file will silently overwrite an earlier one. -W caps the file count, it is not a retention policy, so check disk usage and file count afterwards.

Warning: stop a running capture with Control-C, and if it was started in the background, identify the exact process before signalling it. Do not kill unrelated tcpdump processes or delete evidence before you have recorded its path and purpose. Remove old capture files through your normal approved data-retention process, not ad hoc.

7. Diagnose an unhelpful trace

Zero packets usually means one of: wrong interface, filter too narrow, traffic is encrypted, or the event just didn't happen during the window you captured. Re-run tcpdump -D, confirm the interface is up, and try a bounded broad filter such as arp or icmp on a quiet maintenance window before you conclude the capture itself is broken. Do not leave a broad capture running while you troubleshoot.

Packet counts need context, not just a glance. "Received by filter" has platform-dependent meaning, and "dropped by kernel" reports loss from insufficient capture buffer space, where the operating system exposes that figure at all. If drops climb, narrow the filter, shorten the capture, or look at the capture buffer with -B. A bigger snapshot length also costs more processing and can increase loss on a busy link; the installed default is 262144 bytes, so change it only when you actually need more or less packet data.

When tcpdump prints a truncated marker such as [|tcp], the snapshot didn't include enough bytes to decode that layer. A smaller snapshot saves space but can discard useful transport or application detail; a larger one costs memory and CPU. Make that trade-off on purpose, especially on a busy link.

Done means