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 gestureAction
Enter in the filter barApply
Start typing in the packet listWireshark begins filling in a display filter
Type a field prefixAutocomplete dropdown of matching field names
The X at the right of the barClear the filter
The bookmark ribbon at the leftSave, load, and manage named filters
Right-click a field → Apply as FilterBuild the filter from the selected packet
Right-click → Prepare as FilterSame, but leaves it unapplied for editing
Right-click → Apply as ColumnTurn 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.

SymbolWordMeaning
==eq, any_eqAny occurrence of the field is equal
!=ne, all_neAll occurrences are not equal
===all_eqAll occurrences are equal
!==any_neAny occurrence is not equal
> <gt ltGreater, less
>= <=ge leGreater or equal, less or equal
&&andLogical and
||orLogical or
!notNegation
&bitand, bitwise_andBitwise 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.1 matches almost every packet, because a frame has two ip.addr occurrences and one of them differs. Write !(ip.addr == 10.0.0.1) instead.

Search, Match, and Membership

OperatorLeft side must beExample
containsString, bytes, or a protocolhttp contains "User-Agent"
matches, ~String or bytes, PCRE2, case-insensitivehttp.host ~ "\\.cdn\\."
in { }Any field, set or rangestcp.port in {80, 443, 8080}
~ "(?-i)…"Force case-sensitivehttp.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.

FormMeaning
[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:

FunctionReturns
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

FieldMatches
ip.addr / ip.src / ip.dstIPv4 address, any / source / destination
ipv6.addrIPv6 equivalent
eth.addr / eth.src / eth.dstMAC address
ip.ttl, ip.flags.df, ip.frag_offsetHops, don't-fragment, fragmentation
tcp.port / tcp.srcport / tcp.dstportTCP ports
udp.port, udp.lengthUDP
tcp.stream, udp.streamConversation index, the follow-stream key
tcp.len, tcp.seq, tcp.ack, tcp.nxtseqSegment length and sequence numbers
tcp.flags, tcp.flags.syn, tcp.flags.reset, tcp.flags.strFlag bits and the ··········A·· string
tcp.window_size_value, tcp.options.mss_valFlow control and MSS
tcp.analysis.flags, tcp.analysis.ack_rttDissector-computed problems and RTT
tcp.completenessWhether the stream has SYN, data, and FIN
http.request.method, http.request.uri, http.request.full_uriHTTP request line
http.response.code, http.response.phrase, http.timeResponse and latency
http.host, http.user_agent, http.content_type, http.file_dataHeaders and body
tls.handshake.type, tls.handshake.version, tls.handshake.ciphersuiteTLS handshake
tls.handshake.extensions_server_nameSNI, the hostname in cleartext
tls.record.content_type, tls.alert_message.descRecord layer and alerts
dns.qry.name, dns.qry.type, dns.flags.rcode, dns.time, dns.aDNS
icmp.type, icmp.codeICMP
arp.opcode1 request, 2 reply
frame.number, frame.len, frame.protocolsFrame metadata
frame.time, frame.time_relative, frame.time_delta, frame.time_epochTimestamps
_ws.col.info, _ws.col.protocolThe 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).