tcpdump Cheatsheet
Port and Protocol Filters
Use this tcpdump reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Ports
sudo tcpdump -i eth0 -nn port 443 sudo tcpdump -i eth0 -nn tcp port 443 sudo tcpdump -i eth0 -nn 'tcp dst port 443' sudo tcpdump -i eth0 -nn 'tcp portrange 8000-8100' sudo tcpdump -i eth0 -nn 'port 80 or port 443'
| Filter | Matches |
|---|---|
port 53 | TCP and UDP and SCTP, source or destination |
tcp port 53 | TCP only, either direction |
src port 53 | Source port only |
dst port 53 | Destination port only |
portrange 8000-8100 | Any port in the inclusive range |
tcp portrange 1-1024 | TCP well-known ports |
port not 22 | Everything except port 22 |
port domain | Service name from /etc/services, resolves to 53 |
Bare port N is wider than people expect. It expands to a check on
TCP, UDP and SCTP, across IPv4 and IPv6, plus a fragment test. Prefix the
transport (tcp port, udp port) both for correctness and for speed.
Service names work but hurt readability, and /etc/services differs across
distributions. Use numbers.
Transport protocols
sudo tcpdump -i eth0 -nn tcp sudo tcpdump -i eth0 -nn udp sudo tcpdump -i eth0 -nn icmp sudo tcpdump -i eth0 -nn icmp6 sudo tcpdump -i eth0 -nn 'tcp or udp' sudo tcpdump -i eth0 -nn 'not (tcp or udp or icmp)'
| Keyword | Protocol |
|---|---|
tcp | Shorthand for ip proto \tcp or ip6 proto \tcp |
udp | UDP, both address families |
icmp | ICMPv4 only |
icmp6 | ICMPv6, including neighbor discovery |
sctp | SCTP |
arp / rarp | Address resolution, layer 2 |
esp / ah | IPsec |
ip proto 47 | GRE by number |
ip proto \gre | GRE by name, backslash required |
\ before a protocol name is not optional. tcp, udp and icmp are
reserved words in the filter grammar, so ip proto tcp is a syntax error
while ip proto \tcp compiles. In a single-quoted shell string one
backslash is enough.
Application protocols by port
pcap has no application-layer awareness, so "capture HTTP" means "capture the ports HTTP usually runs on".
| Protocol | Filter |
|---|---|
| DNS | 'udp port 53 or tcp port 53' |
| DNS over TLS | tcp port 853 |
| DHCPv4 | 'udp port 67 or udp port 68' |
| HTTP | 'tcp port 80 or tcp port 8080' |
| HTTPS / TLS | tcp port 443 |
| QUIC / HTTP-3 | udp port 443 |
| SSH | tcp port 22 |
| SMTP | 'tcp port 25 or tcp port 587 or tcp port 465' |
| NTP | udp port 123 |
| SNMP | 'udp port 161 or udp port 162' |
| Syslog | udp port 514 |
| LDAP | 'tcp port 389 or tcp port 636' |
| Postgres | tcp port 5432 |
| MySQL | tcp port 3306 |
| Redis | tcp port 6379 |
| MongoDB | tcp port 27017 |
| Kafka | tcp port 9092 |
| mDNS | udp port 5353 |
| SIP | 'port 5060 or port 5061' |
| RDP | tcp port 3389 |
| VXLAN | udp port 4789 |
| WireGuard | udp port 51820 |
A service on a non-standard port is invisible to a port filter. When you do not know the port, filter by host and read what comes back.
ICMP types by name
pcap defines symbolic names for ICMP types, which beats memorizing numbers.
# Pings out and replies back sudo tcpdump -i eth0 -nn 'icmp[icmptype] == icmp-echo or icmp[icmptype] == icmp-echoreply' # Only the errors, which is what you want for MTU and routing bugs sudo tcpdump -i eth0 -nn -v 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'
| Name | Type | Meaning |
|---|---|---|
icmp-echo | 8 | Ping request |
icmp-echoreply | 0 | Ping reply |
icmp-unreach | 3 | Destination unreachable |
icmp-sourcequench | 4 | Source quench, obsolete |
icmp-redirect | 5 | Redirect |
icmp-timxceed | 11 | TTL exceeded, what traceroute reads |
icmp-paramprob | 12 | Parameter problem |
icmp-tstamp | 13 | Timestamp request |
icmp-tstampreply | 14 | Timestamp reply |
Path-MTU black holes are ICMP type 3 code 4:
sudo tcpdump -i eth0 -nn -v 'icmp[icmptype] == icmp-unreach and
icmp[icmpcode] == 4'If that filter is silent while large transfers hang, something upstream is dropping the "fragmentation needed" message, which is the classic PMTUD failure.
Fragments break port filters
A port lives in the transport header, which only exists in the first
fragment. Later fragments carry no ports, so tcp port 80 silently drops
them.
# Only non-first fragments sudo tcpdump -i eth0 -nn 'ip[6:2] & 0x1fff != 0' # First fragments and unfragmented packets only sudo tcpdump -i eth0 -nn 'ip[6:2] & 0x1fff = 0' # Anything fragmented at all: MF bit set or a nonzero offset sudo tcpdump -i eth0 -nn 'ip[6] & 0x20 != 0 or ip[6:2] & 0x1fff != 0'
ip[6:2] is the 16-bit flags-plus-fragment-offset field. 0x1fff masks
off the three flag bits and leaves the 13-bit offset. ip[6] & 0x20 tests
the More Fragments bit on its own.
Size filters
sudo tcpdump -i eth0 -nn greater 1400 sudo tcpdump -i eth0 -nn less 100 sudo tcpdump -i eth0 -nn 'len > 1400 and len < 1500'
greater, less and len all compare the whole frame length as it
was on the wire, not the payload. To find TCP segments carrying data,
tcp[13] & 8 != 0 (PSH set) is a rough proxy, and the exact test is the
payload-length expression in the byte-offsets topic.