Back to blog
Networking

tcpdump: Packet Capture From the Command Line

Introduction

Wireshark is great when you have a graphical interface. But when you are working on a remote server over SSH, or on a minimal Linux system, you need something that works entirely from the command line. tcpdump is that tool. It captures packets, filters them, and displays or saves them, all from the terminal. Once you get comfortable with it, you can do remarkably precise packet analysis without ever opening a GUI.

Basic Usage

The simplest way to run tcpdump is as root (or with sudo), followed by the interface you want to capture from. You specify the interface with -i.

sudo tcpdump -i eth0

This captures everything on the eth0 interface and prints a summary of each packet. To see your available interfaces, you can use ip a on Linux, which shows all network interfaces including the loopback. The loopback interface, usually named lo, carries traffic sent to 127.0.0.1, traffic between your machine and itself. If you are running a local web server and want to capture that traffic, you need to specify the loopback interface, not eth0.

Useful Flags

A few flags make tcpdump significantly more useful in practice. The -n flag disables name resolution, by default, tcpdump tries to resolve IP addresses to hostnames and port numbers to service names, which adds latency and can be misleading. Using -n gives you raw IP addresses and port numbers, which is almost always what you want for analysis.

The -v flag enables verbose output, showing additional IP header fields like TTL, IP ID, and fragmentation information. For work involving IP fragmentation, you need -v to see those fields at all. The -X flag adds a hex and ASCII dump of each packet's payload, which lets you inspect the actual data being transferred.

sudo tcpdump -n -v -X -i eth0

Writing to and Reading from Files

tcpdump can save captured packets to a pcap file with -w, and read them back later with -r. This is essential for saving captures to analyze later or share with someone else. The files are compatible with Wireshark.

sudo tcpdump -n -v -i eth0 -w capture.pcap   # write to file
tcpdump -n -v -r capture.pcap               # read from file

The -c flag stops the capture after a specified number of packets. This is useful when you want to capture exactly two packets, a stimulus and its response, without leaving the capture running.

sudo tcpdump -n -v -i eth0 -w output.pcap -c 2

Filters

Filters are where tcpdump becomes powerful. You can add a filter expression at the end of the command to only capture packets that match. The filter syntax is based on Berkeley Packet Filter (BPF) expressions.

sudo tcpdump -n -i eth0 icmp                     # ICMP only
sudo tcpdump -n -i eth0 host 192.168.1.100       # to/from this IP
sudo tcpdump -n -i eth0 tcp port 80              # HTTP traffic
sudo tcpdump -n -i eth0 udp port 53              # DNS queries
sudo tcpdump -n -i eth0 "icmp or udp port 5000"  # ICMP or UDP on port 5000

You can combine filters with and, or, and not. Parentheses group conditions. Quoting the filter with double quotes avoids issues with shell interpretation of special characters.

Filtering for Fragmentation

tcpdump allows direct access to packet fields using byte offsets, which makes it possible to filter on fragmentation flags and offsets. This is especially useful when studying IP fragmentation or isolating specific fragment types in a noisy capture.

The IP fragmentation flags and offset live in bytes 6 and 7 of the IP header. The more-fragments (MF) flag is bit 5 of byte 6, and the fragment offset spans the remaining 13 bits. You can filter for first fragments (MF=1, offset=0), last fragments (MF=0, offset non-zero), and middle fragments (MF=1, offset non-zero) using expressions that test these bit positions.

# First fragment: MF set, offset zero
sudo tcpdump -n "((ip[6] & 0x20) != 0) and ((ip[6:2] & 0x1fff) == 0)"

# Last fragment: MF clear, offset non-zero
sudo tcpdump -n "((ip[6] & 0x20) == 0) and ((ip[6:2] & 0x1fff) != 0)"

Snaplen

By default, tcpdump only captures the first 65535 bytes of each packet (more than enough for most purposes). The -s flag lets you set the snapshot length. Using -s 0 captures the full packet. For most analysis work you do not need to change this, but for very specific investigations where you need complete packet contents, it is good to know about.

Reading Output

Understanding tcpdump's output format takes a little practice. Each line starts with a timestamp, then source and destination information, then a protocol summary. For IP packets with verbose output, you see the TOS value, TTL, IP ID, fragmentation flags, protocol, and length. Here is what an ICMP port unreachable looks like in tcpdump output:

18:20:47.737024 IP (tos 0xc0, ttl 64, id 59435, offset 0, flags [none],
proto ICMP (1), length 56)
    192.168.2.143 > 192.168.2.144: ICMP 192.168.2.143 udp port 10005
    unreachable, length 36

Once you know what each field represents, you can read these summaries quickly and spot anything unusual.

Conclusion

tcpdump is not flashy, but it is indispensable. The combination of flexible filters, file I/O, and fine-grained control over output detail makes it the right tool for a lot of situations where Wireshark is unavailable or impractical. Spending time learning the filter syntax and the output format pays off every time you need to capture and analyze traffic in a terminal environment.