You can capture network traffic with tcpdump and then filter it down to specific hosts or IP addresses, which is incredibly useful for debugging network issues.
Here’s tcpdump in action, capturing traffic to and from a specific IP address, 192.168.1.100:
sudo tcpdump -i eth0 host 192.168.1.100
This command will show you all packets flowing between your machine (where tcpdump is running) and 192.168.1.100, regardless of the port or protocol. The -i eth0 part specifies the network interface to listen on; replace eth0 with your actual interface name (e.g., enp0s3, wlan0).
Let’s break down the mental model. tcpdump is a command-line packet analyzer. It sits on a network interface and, by default, captures everything it sees. That’s a lot of noise. The power comes from its filtering capabilities. These filters are applied before packets are even displayed or saved, dramatically reducing the volume of data you need to sift through.
The host keyword is one of the simplest and most powerful filters. When you use host <ip_address>, tcpdump will match packets where the source IP or the destination IP is <ip_address>. This gives you a two-way view of the communication.
What if you only want to see traffic from a specific host? You can use src host.
sudo tcpdump -i eth0 src host 192.168.1.100
Conversely, to see traffic to a specific host:
sudo tcpdump -i eth0 dst host 192.168.1.100
You can also filter by network, not just a single IP. For instance, to capture all traffic within the 192.168.1.0/24 subnet:
sudo tcpdump -i eth0 net 192.168.1.0/24
This is equivalent to tcpdump -i eth0 'src net 192.168.1.0/24 or dst net 192.168.1.0/24'.
Combining filters is where things get really interesting. You can use and (or &&) and or (or ||) to build complex expressions. For example, to see traffic between 192.168.1.100 and 192.168.1.101:
sudo tcpdump -i eth0 host 192.168.1.100 and host 192.168.1.101
Or, to see traffic from 192.168.1.100 to any host on port 80 (HTTP):
sudo tcpdump -i eth0 src host 192.168.1.100 and dst port 80
The port keyword, when used without src or dst, implies src port or dst port. So, port 80 means "either the source port is 80, or the destination port is 80."
When you combine host and port, tcpdump is smart enough to understand you want traffic from the host to the port, or from the port to the host. So, host 192.168.1.100 and port 80 would match:
192.168.1.100:<any_port> -> <any_ip>:80<any_ip>:80 -> 192.168.1.100:<any_port>
If you want to be explicit and only capture traffic from 192.168.1.100 to a specific port, you’d use src host and dst port:
sudo tcpdump -i eth0 src host 192.168.1.100 and dst port 80
And to capture traffic to 192.168.1.100 from a specific port:
sudo tcpdump -i eth0 dst host 192.168.1.100 and src port 80
The filter expressions are evaluated from left to right, and parentheses can be used for grouping, though they often need to be escaped with a backslash or quoted. For example, to capture traffic from host A to host B OR from host A to host C:
sudo tcpdump -i eth0 'src host 192.168.1.100 and (dst host 192.168.1.101 or dst host 192.168.1.102)'
The single quotes are important here to prevent the shell from interpreting the parentheses.
The most surprising thing about tcpdump filters is how they relate to the Berkeley Packet Filter (BPF) syntax. tcpdump uses a simplified front-end that translates your human-readable filters into BPF instructions. These instructions are then loaded directly into the kernel’s packet filtering engine. This means the filtering happens at the lowest possible level, before the packet even reaches userspace, which is why it’s so efficient and doesn’t drop packets on the floor due to slow processing.
Understanding how to combine host, src, dst, net, and port with logical operators (and, or, not) is the key to effectively narrowing down your tcpdump captures.
The next step is often to save these filtered captures to a file for later analysis with tools like Wireshark.