Wireshark Cheatsheet
Display Filters
Use this Wireshark reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
The Filter Bar
Display filters run against already-captured packets, so they are undoable and
can be changed as often as you like. The bar turns green for a valid filter,
yellow for a valid but ambiguous one (usually a != that does not mean what you
think), and red for a syntax error.
| Key or gesture | Action |
|---|---|
Enter in the filter bar | Apply |
| Start typing in the packet list | Wireshark begins filling in a display filter |
| Type a field prefix | Autocomplete dropdown of matching field names |
The X at the right of the bar | Clear the filter |
| The bookmark ribbon at the left | Save, load, and manage named filters |
| Right-click a field → Apply as Filter | Build the filter from the selected packet |
| Right-click → Prepare as Filter | Same, but leaves it unapplied for editing |
| Right-click → Apply as Column | Turn the field into a packet-list column |
Ctrl+. / Ctrl+, | Next / previous packet in this conversation |
Alt+→ / Alt+← | Selection history, like browser forward and back |
A bare protocol name is a valid filter and means "this packet contains that
layer": dns, tls, http2, quic, icmp, arp, bootp (DHCPv4 is
dhcp in modern versions).
Comparison and Logic
Every operator has an English and a C-style spelling. The English form avoids
shell quoting problems when you paste the filter into tshark -Y.
| Symbol | Word | Meaning |
|---|---|---|
== | eq, any_eq | Any occurrence of the field is equal |
!= | ne, all_ne | All occurrences are not equal |
=== | all_eq | All occurrences are equal |
!== | any_ne | Any occurrence is not equal |
> < | gt lt | Greater, less |
>= <= | ge le | Greater or equal, less or equal |
&& | and | Logical and |
|| | or | Logical or |
! | not | Negation |
& | bitand, bitwise_and | Bitwise AND on integers and slices |
The any and all prefixes work with any comparison, which is how you say
"every port in this frame is above 1024".
all tcp.port > 1024 any ip.addr != 1.1.1.1
The classic trap:
ip.addr != 10.0.0.1matches almost every packet, because a frame has twoip.addroccurrences and one of them differs. Write!(ip.addr == 10.0.0.1)instead.
Search, Match, and Membership
| Operator | Left side must be | Example |
|---|---|---|
contains | String, bytes, or a protocol | http contains "User-Agent" |
matches, ~ | String or bytes, PCRE2, case-insensitive | http.host ~ "\\.cdn\\." |
in { } | Any field, set or ranges | tcp.port in {80, 443, 8080} |
~ "(?-i)…" | Force case-sensitive | http.user_agent matches "(?-i)curl" |
tcp.port in {443, 4430..4434} ip.addr in {10.0.0.5 .. 10.0.0.9} http.request.method in {"GET", "HEAD"} frame contains "password" tcp.payload contains 47:45:54:20 # "GET " as bytes dns.qry.name matches "(?i)metrics|telemetry"
contains fails on atomic fields (an integer or an IP address has no substring).
Use in { } for those, or string(field) contains "…".
Slices, Layers, and Functions
Slices index into string and byte fields, zero-based, and negative offsets count from the end.
| Form | Meaning |
|---|---|
[i:j] | Start at i, take j bytes |
[i-j] | Offsets i through j inclusive |
[i] | One byte at i |
[:j] | First j bytes |
[i:] | From i to the end |
[-4:] | Last four bytes |
eth.src[0:3] == 00:1a:2b # OUI, so a vendor filter http.content_type[0:4] == "text" frame[100-199] contains "wireshark" ip.addr#2 == 192.168.30.40 # inner layer of a tunnel tcp.port#[2-4] # layers 2 through 4 @browser.comment == 73:74:72:69 # raw undecoded bytes
Functions available in the filter language:
| Function | Returns |
|---|---|
upper(f) / lower(f) | Case-folded string, for case-insensitive == |
len(f) | Byte length of a string or bytes field |
count(f) | How many times the field appears in the frame |
string(f) | Non-string field as a string, for matches |
vals(f) | The field's value string, as shown in a custom column |
dec(f) / hex(f) | Unsigned integer as decimal or hex text |
max(a,b,…) / min(…) / abs(f) | Numeric helpers |
ip_rfc1918(f) | True for private-use IPv4 |
ip_multicast(f) / ip_linklocal(f) / ip_ula(f) | Address class tests |
len(http.user_agent) > 200 count(ip.addr) > 2 # tunnelled or encapsulated lower(http.host) == "example.com" string(frame.number) matches "[13579]$" ip.src == 8.8.8.8 and not ip_rfc1918(ip.dst)
Arithmetic works too, with curly braces for grouping because parentheses are reserved for logic. Subtraction needs a leading space.
udp.dstport >= udp.srcport + 1 tcp.dstport >= 4 * {tcp.srcport + 3} ip.len - tcp.hdr_len > 1400
Fields You Will Actually Type
| Field | Matches |
|---|---|
ip.addr / ip.src / ip.dst | IPv4 address, any / source / destination |
ipv6.addr | IPv6 equivalent |
eth.addr / eth.src / eth.dst | MAC address |
ip.ttl, ip.flags.df, ip.frag_offset | Hops, don't-fragment, fragmentation |
tcp.port / tcp.srcport / tcp.dstport | TCP ports |
udp.port, udp.length | UDP |
tcp.stream, udp.stream | Conversation index, the follow-stream key |
tcp.len, tcp.seq, tcp.ack, tcp.nxtseq | Segment length and sequence numbers |
tcp.flags, tcp.flags.syn, tcp.flags.reset, tcp.flags.str | Flag bits and the ··········A·· string |
tcp.window_size_value, tcp.options.mss_val | Flow control and MSS |
tcp.analysis.flags, tcp.analysis.ack_rtt | Dissector-computed problems and RTT |
tcp.completeness | Whether the stream has SYN, data, and FIN |
http.request.method, http.request.uri, http.request.full_uri | HTTP request line |
http.response.code, http.response.phrase, http.time | Response and latency |
http.host, http.user_agent, http.content_type, http.file_data | Headers and body |
tls.handshake.type, tls.handshake.version, tls.handshake.ciphersuite | TLS handshake |
tls.handshake.extensions_server_name | SNI, the hostname in cleartext |
tls.record.content_type, tls.alert_message.desc | Record layer and alerts |
dns.qry.name, dns.qry.type, dns.flags.rcode, dns.time, dns.a | DNS |
icmp.type, icmp.code | ICMP |
arp.opcode | 1 request, 2 reply |
frame.number, frame.len, frame.protocols | Frame metadata |
frame.time, frame.time_relative, frame.time_delta, frame.time_epoch | Timestamps |
_ws.col.info, _ws.col.protocol | The rendered column text |
Verify any field name locally rather than guessing:
tshark -G fields | awk -F'\t' '$3 ~ /^tls\.handshake/ {print $3"\t"$2}'
Ready-Made Filters
# Handshakes and resets only tcp.flags.syn == 1 and tcp.flags.ack == 0 tcp.flags.reset == 1 tcp.flags == 0x0011 # exactly FIN+ACK # Anything the TCP dissector flagged tcp.analysis.flags tcp.analysis.retransmission or tcp.analysis.fast_retransmission tcp.analysis.zero_window or tcp.analysis.window_full tcp.analysis.duplicate_ack and tcp.analysis.duplicate_ack_num >= 3 # HTTP http.request http.response.code >= 400 http.request.method == "POST" and http.content_type contains "json" http.time > 1 # TLS tls.handshake.type == 1 # ClientHello tls.handshake.type == 2 # ServerHello tls.handshake.extensions_server_name contains "example.com" tls.record.content_type == 21 # alert tls.alert_message.desc == 48 # unknown_ca # DNS dns.flags.response == 0 # queries only dns.flags.rcode != 0 # errors dns.time > 0.5 dns.qry.name matches "\\.onion$" # One conversation, one direction, one subnet tcp.stream == 7 ip.src == 10.0.0.5 and tcp.dstport == 443 ip.addr == 192.168.1.0/24 !(arp or icmp or stp or lldp or mdns) # cut the LAN noise
Save the useful ones. Analyze → Display Filter Bookmarks (the ribbon on the
left of the bar) stores named filters in dfilters, and
Analyze → Display Filter Macros stores parameterized ones in dmacros. A macro
defined as "hostpair" {ip.addr == $1 and ip.addr == $2} is invoked as
$hostpair(10.0.0.1, 10.0.0.2).