tcpdump’s not keyword is surprisingly powerful for carving out exactly the traffic you don’t want to see, making your captures much cleaner.

Let’s say you’re debugging a web server and want to see only the HTTP traffic, but your network is noisy with DNS requests, NTP pings, and general background chatter. You could try to list all the ports for HTTP (80, 8080, etc.), but that’s brittle and misses encrypted traffic. A much better approach is to exclude the noise.

Here’s how you might capture HTTP traffic while excluding DNS (port 53) and NTP (port 123):

sudo tcpdump -i eth0 'tcp and port 80 and not (udp port 53 or tcp port 53 or udp port 123 or tcp port 123)'

This command tells tcpdump to capture packets on eth0 that are TCP, destined for port 80, but exclude any packets that are either UDP or TCP on port 53 (DNS) or UDP or TCP on port 123 (NTP).

The real magic of not (or !) in tcpdump comes from its ability to negate complex expressions. You can chain multiple not conditions or use parentheses to group exclusions. This is incredibly useful when you have a specific type of traffic you need to isolate from a much larger, more general flow.

Consider a scenario where you’re troubleshooting an application that uses a specific port, say 8000, but you’re being flooded with SSH (port 22) connections from a known management subnet (192.168.1.0/24). You want to see your application traffic but ignore the routine SSH probes.

sudo tcpdump -i eth0 'port 8000 and not (src net 192.168.1.0/24 and dst port 22)'

Here, we’re capturing traffic on port 8000, but we’re specifically excluding any traffic originating from the 192.168.1.0/24 subnet that is destined for port 22. This effectively filters out the SSH noise from that particular source while still allowing other SSH traffic if it were relevant.

The not operator works by inverting the truthiness of the expression it precedes. If the expression inside the not evaluates to true for a packet (meaning the packet matches the exclusion criteria), the not makes it false, and tcpdump discards it. Conversely, if the expression inside not is false, not makes it true, and tcpdump keeps it, provided it also matches the rest of your filter.

Let’s say you want to capture all ICMP traffic except for echo requests (pings) from a specific host, 10.0.0.5.

sudo tcpdump -i eth0 'icmp and not (icmp[icmptype] == 8)'

This command captures all ICMP packets but excludes those where the ICMP type field (the first byte of the ICMP header, which is icmp[0]) is equal to 8 (ICMP Echo Request). If you wanted to exclude pings from a specific host, you’d combine it:

sudo tcpdump -i eth0 'icmp and not (src host 10.0.0.5 and icmp[icmptype] == 8)'

This is more precise than just excluding all pings; it only excludes pings from 10.0.0.5.

The power of not is amplified when dealing with complex protocols where you might want to see specific sub-streams but exclude others. For instance, if you’re analyzing a protocol that uses a control channel and a data channel on different ports, you could exclude the control channel traffic if it’s not your primary focus.

A common mistake is to try to use not to exclude a protocol entirely, like not udp. This is generally not how you’d approach it; you’d typically build a positive filter for the protocol you do want (e.g., tcp) and then use not to exclude specific conditions within that protocol.

Another advanced use case is excluding traffic to or from specific internal IP addresses that are known to be noisy or irrelevant to your current investigation. If you have a network monitoring appliance at 192.168.1.100 that generates a lot of broadcast or multicast traffic you don’t care about, you can filter it out:

sudo tcpdump -i eth0 'not (src host 192.168.1.100 or dst host 192.168.1.100)'

This captures everything except traffic to or from that specific IP.

When constructing complex not filters, remember the order of operations. tcpdump evaluates expressions from left to right, respecting parentheses. and has higher precedence than or. not applies to the expression immediately following it. So, not a and b is equivalent to (not a) and b, not not (a and b). Always use parentheses to group your exclusions clearly, especially when combining and and or within the not clause.

The most surprising aspect of not for many users is its ability to filter out entire classes of packets that might otherwise overwhelm their analysis. Instead of painstakingly listing every allowed port or protocol, you can often achieve the same or better results by simply stating what you don’t want to see. This is particularly true in high-traffic environments where identifying specific flows requires aggressive filtering.

The next thing you’ll likely run into is needing to capture packets based on their payload content, which tcpdump also supports through its content and pcre matchers.

Want structured learning?

Take the full Tcpdump course →