Networking

Capture traffic with tcpdump

Watch the packets a server sends and receives, filtered down to one host or port, and read a TCP handshake, a reset, and a connection nobody answers. Then write a capture to a file for Wireshark.

Written againstDebian 12Ubuntu 24.04RHEL 9tcpdump 4.99libpcap 1.10
Reading time
5 min
Commands to copy
7
Last checked
24 Oct 2026

When a connection fails and neither side’s log says why, the packets do. tcpdump prints every packet that matches a filter, as it passes the network interface. Capturing needs root, so the capture commands here start with sudo. Install it with sudo apt install tcpdump or sudo dnf install tcpdump if it’s missing.

Watch packets as they pass

shell
$ sudo tcpdump -i any -nn port 53tcpdump: data link type LINUX_SLL2tcpdump: verbose output suppressed, use -v[v]... for full protocol decodelistening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes14:20:01.123456 eth0  Out IP 10.0.0.5.41234 > 192.0.2.53.53: 4711+ A? example.net. (29)14:20:01.135790 eth0  In  IP 192.0.2.53.53 > 10.0.0.5.41234: 4711 1/0/0 A 203.0.113.10 (45)

-i any listens on every interface, and each line then names the interface and the direction. -nn prints addresses and port numbers instead of looking up names, which keeps tcpdump from sending DNS queries of its own. Ctrl+C stops it. To stop by itself after a number of packets, add -c 20. sudo tcpdump -D lists the interfaces you can name instead of any.

Each line reads: the time, then source address and port, then destination address and port, then what the packet carries. Above, 10.0.0.5 asks 192.0.2.53 for the A record of example.net (query ID 4711), and the answer 12 ms later has one record.

Narrow it down with a filter

The filter goes at the end of the command. Quote it when it contains brackets, &, or |, so the shell passes it on unchanged. Combine filters with and, or, and not.

FilterMatches
host 192.0.2.20Packets to or from that address
src host 192.0.2.20Packets from that address only (dst for the other way)
net 10.0.0.0/24Packets to or from any address in that network
port 443TCP or UDP port 443, either direction
tcp port 5432TCP only
icmpPings and the error messages routers and hosts send back
'tcp[tcpflags] & (tcp-syn|tcp-rst) != 0'Connection attempts and resets only, without the data in between
not port 22Everything except SSH

Read a TCP connection

A TCP connection starts with three packets. tcpdump shows the TCP flags in brackets: S is SYN, . is ACK, P is push (data), F is FIN and R is reset.

shell
$ sudo tcpdump -i eth0 -nn 'host 192.0.2.20 and port 5432'# TCP options left out of each line14:31:07.501112 IP 10.0.0.5.51522 > 192.0.2.20.5432: Flags [S], seq 1983746601, win 64240, length 014:31:07.502004 IP 192.0.2.20.5432 > 10.0.0.5.51522: Flags [S.], seq 2210349102, ack 1983746602, win 65160, length 014:31:07.502030 IP 10.0.0.5.51522 > 192.0.2.20.5432: Flags [.], ack 1, win 502, length 0

SYN, SYN-ACK, ACK: the handshake completed in under 1 ms, so the network and the server’s firewall are fine. When the port is closed, the server answers the SYN with a reset instead. That’s what a client reports as Connection refused:

shell
14:33:40.118201 IP 10.0.0.5.51530 > 192.0.2.20.5433: Flags [S], seq 377120919, win 64240, length 014:33:40.119013 IP 192.0.2.20.5433 > 10.0.0.5.51530: Flags [R.], seq 0, ack 377120920, win 0, length 0

When nothing answers, the client sends the same SYN again, with the same sequence number, after 1, 2, 4 and 8 seconds. A client reports that as a timeout. Run the same capture on the server: if the SYNs don’t arrive there, something on the way drops them. If they arrive and get no answer, the server’s own firewall drops them.

shell
14:35:02.000100 IP 10.0.0.5.51544 > 192.0.2.20.6379: Flags [S], seq 99120011, win 64240, length 014:35:03.012400 IP 10.0.0.5.51544 > 192.0.2.20.6379: Flags [S], seq 99120011, win 64240, length 014:35:05.060300 IP 10.0.0.5.51544 > 192.0.2.20.6379: Flags [S], seq 99120011, win 64240, length 0

To test the port from the client side first, see Test whether a TCP port is reachable.

Write a capture to a file

-w writes the raw packets to a pcap file instead of printing them. tcpdump 4.99 keeps up to 262,144 bytes of each packet by default, which is the whole packet, so the file holds everything Wireshark needs.

shell
$ sudo tcpdump -i eth0 -nn -w /tmp/db.pcap 'host 192.0.2.20 and port 5432'tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes^C412 packets captured412 packets received by filter0 packets dropped by kernel

Debian, Ubuntu, and RHEL build tcpdump to switch from root to its own tcpdump user once the interface is open, so write the file to a directory that user can write to, such as /tmp. A file in your home directory usually fails with Permission denied.

Keep long captures from filling the disk

A busy interface writes gigabytes an hour. For a capture that runs until a problem happens again, let tcpdump rotate the files:

shell
# start another file every 100 MB, keep the latest 10$ sudo tcpdump -i eth0 -nn -w /tmp/web.pcap -C 100 -W 10 'port 443 and not port 22'# start another file every hour, named by its start time$ sudo tcpdump -i eth0 -nn -w '/tmp/web-%Y%m%d-%H%M.pcap' -G 3600 'port 443 and not port 22'

-C counts in millions of bytes. With -W, tcpdump numbers the files and overwrites the oldest, so the capture stays at about 1 GB here. -G on its own keeps every hourly file, so check the disk while it runs (Find what’s filling a disk).

Read it back or open it in Wireshark

tcpdump reads its own files with -r, and a filter narrows the file down the same way it narrows a capture:

shell
$ tcpdump -nn -r /tmp/db.pcap 'tcp[tcpflags] & tcp-rst != 0'$ scp server.example.net:/tmp/db.pcap .

On your own machine, open the file in Wireshark. Statistics, Conversations lists every connection in it, and Follow, TCP Stream on any packet shows that connection’s data in order.

Last checked on 24 October 2026 against Debian 12, Ubuntu 24.04, RHEL 9, tcpdump 4.99, and libpcap 1.10. If a step doesn’t match what you see, contact us with the command and what it printed.