Capture Filters
vs. Display Filters

01 / Overview

Wireshark gives you two completely independent filtering mechanisms. They look similar on the surface — both let you write filter expressions to isolate traffic — but they operate at different stages of the capture pipeline, use entirely different syntax engines, and serve different purposes.

Capture Filter
BPF — Before the disk

Runs in the kernel via libpcap / Npcap. Packets that don't match are never written to the capture buffer. Low overhead, limited syntax.

Display Filter
DFL — After the disk

Applied inside Wireshark's dissector engine after packets are captured. All packets are kept; non-matching ones are merely hidden. Rich, protocol-aware syntax.

Understanding this distinction is the most important conceptual leap for anyone moving from casual to serious packet analysis.

02 / Capture Filters

Capture filters use Berkeley Packet Filter (BPF) syntax — the same language used by tcpdump. They are compiled into kernel bytecode by libpcap and evaluated in the kernel's network stack before a packet ever reaches userspace.

⚠️
Set it before you start Once a capture session is running you cannot change the capture filter. Packets that were already dropped are gone forever. Plan ahead.

Basic Host & IP Filters

Capture Filter — BPF
# Capture only traffic to/from a specific host
host 192.168.1.100

# Only traffic from a source IP
src host 10.0.0.5

# Only traffic to a destination IP
dst host 10.0.0.5

# Capture an entire subnet
net 192.168.1.0/24

Protocol Filters

Capture Filter — BPF
# Only TCP traffic
tcp

# Only UDP traffic
udp

# Only ICMP (ping) packets
icmp

# Only ARP packets
arp

Port Filters

Capture Filter — BPF
# Capture only HTTP traffic (port 80)
tcp port 80

# HTTPS traffic
tcp port 443

# DNS queries
udp port 53

# A port range (e.g., all registered ports)
tcp portrange 1024-65535

Boolean Combinations

Capture Filter — BPF
# TCP on port 80 OR 443
tcp port 80 or tcp port 443

# Traffic from 192.168.1.5 that is NOT DNS
src host 192.168.1.5 and not udp port 53

# Entire subnet excluding a noisy broadcast address
net 10.0.0.0/8 and not host 10.255.255.255

# SYN packets only (TCP flag bit 0x02 set)
tcp[13] == 0x02
💡
When to use capture filters Use them on high-throughput links where storing every packet is impractical, or when disk space is limited. Also ideal for long-running captures where you know exactly what you're looking for upfront.

03 / Display Filters

Display filters use Wireshark's own Display Filter Language (DFL) — a rich, protocol-aware expression engine that understands every field in every dissector Wireshark supports. You can filter on deeply nested protocol fields, compare values, and even match on byte sequences.

ℹ️
Non-destructive by design Display filters never delete packets. Toggle them freely. All captured packets remain in memory; the filter only controls what the GUI shows.

Protocol & Field Filters

Display Filter — DFL
// Show only HTTP packets
http

// Show only DNS packets
dns

// Show only TLS (HTTPS handshakes, etc.)
tls

// Show only ARP packets
arp

IP Address Filters

Display Filter — DFL
// Traffic to or from an IP
ip.addr == 192.168.1.100

// Only from a source
ip.src == 10.0.0.5

// Only to a destination
ip.dst == 10.0.0.5

// Entire subnet using CIDR
ip.addr == 192.168.1.0/24

// Exclude your own machine's loopback
!ip.addr == 127.0.0.1

TCP / UDP Port Filters

Display Filter — DFL
// HTTP on port 80
tcp.port == 80

// HTTPS
tcp.port == 443

// DNS (UDP)
udp.port == 53

// Source port greater than 1024 (ephemeral client port)
tcp.srcport > 1024

// Port range using range operator
tcp.port in {80 443 8080 8443}

TCP Flag Filters

Display Filter — DFL
// Only SYN packets (TCP handshake initiators)
tcp.flags.syn == 1 and tcp.flags.ack == 0

// SYN-ACK (server response in 3-way handshake)
tcp.flags.syn == 1 and tcp.flags.ack == 1

// RST packets — connection resets
tcp.flags.reset == 1

// FIN packets — graceful teardown
tcp.flags.fin == 1

HTTP-Specific Filters

Display Filter — DFL
// Only HTTP GET requests
http.request.method == "GET"

// HTTP POST requests
http.request.method == "POST"

// HTTP 4xx client errors
http.response.code >= 400 and http.response.code < 500

// Filter by URL containing a keyword
http.request.uri contains "login"

// Filter by Host header
http.host == "example.com"

DNS Filters

Display Filter — DFL
// DNS queries only (QR bit = 0)
dns.flags.response == 0

// DNS responses only (QR bit = 1)
dns.flags.response == 1

// DNS queries for a specific domain
dns.qry.name contains "example.com"

// NXDOMAIN responses (non-existent domain)
dns.flags.rcode == 3

String & Content Matching

Display Filter — DFL
// Case-sensitive substring match
frame contains "password"

// Regular expression match (Perl-compatible)
http.request.uri matches "\\.(php|asp|aspx)$"

// Match on raw bytes (hex)
frame[0:2] == 0xff:0xd8  // JPEG magic bytes

04 / Side-by-Side Comparison

Property Capture Filter Display Filter
When applied Before packet is stored After packet is captured
Syntax engine BPF (Berkeley Packet Filter) Wireshark DFL
Execution layer Kernel (libpcap / Npcap) Userspace (Wireshark dissectors)
Change during capture ❌ No ✅ Yes, anytime
Drops packets ✅ Permanently ❌ Just hides them
Protocol awareness Layer 3/4 only All layers, all dissectors
Performance impact Very low (kernel JIT) Higher (userspace eval)
Regex support ❌ No ✅ Yes (matches)
Field access (e.g., http.host) ❌ Not available ✅ Full field tree
tcpdump compatible ✅ Yes ❌ No

05 / Combining Both Filters

The most powerful workflows combine a broad capture filter to keep the capture file manageable with precise display filters to zero in on specific packets during analysis.

Example: Investigating a Web Server

Step 1 — Capture Filter (BPF)
# Only capture traffic to/from the web server
host 203.0.113.42 and (tcp port 80 or tcp port 443)
Step 2 — Display Filters (DFL, applied after capture)
// First pass: find all 5xx server errors
http.response.code >= 500

// Second pass: isolate slow requests (large TCP window scaling)
tcp.analysis.ack_rtt > 0.3

// Third pass: look for suspicious POST bodies
http.request.method == "POST" and frame contains "eval("

Example: Network Troubleshooting Workflow

Combined Workflow
# CAPTURE FILTER — narrow to the troubled subnet
net 172.16.0.0/16 and not udp port 5353  # exclude mDNS noise

── after capture, switch to display filters ──

// Find TCP retransmissions
tcp.analysis.retransmission

// Find duplicate ACKs (indicator of loss)
tcp.analysis.duplicate_ack

// Packets with TTL under 5 (near expiry — routing loop?)
ip.ttl < 5

// Zero-window — receiver buffer full
tcp.analysis.zero_window

06 / Common Mistakes

Using Display Filter syntax in the Capture Filter bar

❌ Wrong — DFL syntax in capture filter
# This will FAIL — ip.addr is a DFL field, not valid BPF
ip.addr == 192.168.1.1  ← invalid in capture filter bar
✅ Correct BPF equivalent
host 192.168.1.1

Forgetting that capture filters are permanent

⚠️
Don't be too aggressive with capture filters If you're unsure what traffic you need, prefer a wide capture filter (or none) and refine with display filters later. Dropped packets can't be recovered.

Negation gotcha with ip.addr

⚠️ Subtle bug — this does NOT do what you think
// Intended: exclude all traffic to/from 10.0.0.1
!(ip.addr == 10.0.0.1)

// PROBLEM: ip.addr matches BOTH src and dst.
// A packet FROM 10.0.0.1 → 8.8.8.8 still passes
// because ip.dst != 10.0.0.1 is true.

// ✅ Correct approach:
!ip.src == 10.0.0.1 and !ip.dst == 10.0.0.1

07 / Quick Reference Cheatsheet

Capture Filter Primitives
  • host <ip>
  • src/dst host <ip>
  • net <cidr>
  • port <n>
  • portrange <n-m>
  • tcp / udp / icmp / arp
  • and / or / not
  • tcp[offset] == val
Display Filter Operators
  • == != > < >= <=
  • and / or / not / !
  • contains "string"
  • matches "regex"
  • in {val1 val2 ...}
  • [n:m] byte slice
  • ~ (alias for matches)
  • bitwise_and mask